From 3bc662d7cd159c362a2153ff4a7a3e4745204038 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:05:07 +0900 Subject: [PATCH 001/238] docs(gaps): refresh protected main and open PR baseline --- docs/product-technical-gap-baseline.md | 43 +++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index aa1bcf250..c5ad7c74a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,7 +1,7 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 05:01 KST. Protected `main` was -> `04e6b610655d0db91d5f7ba9486bdda1440e0b19`. This local branch is not +> Dashboard delivery snapshot: 2026-08-26 07:04 KST. Protected `main` is +> `7e9030c9a8ee2684e680c63013b304b435ba646e`. This local branch is not > protected-main release evidence. ## Operations Dashboard PRD/TRD traceability @@ -60,14 +60,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 16 open PRs and 10 open issues. The exact-head +At this snapshot there were 11 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 05:01 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 07:04 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, @@ -76,39 +76,38 @@ lifecycle claim. ## 1. Exact-head and governance evidence -The protected default branch was `04e6b610655d0db91d5f7ba9486bdda1440e0b19` -when this baseline was refreshed. The live queue contained 16 open PRs and 10 +The protected default branch is `7e9030c9a8ee2684e680c63013b304b435ba646e` +at this refresh. The live queue contains 11 open PRs and 10 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 | | ---: | --- | --- | -| #663 | `be361f10` | project ontology traversal plus cutoff/snapshot-frozen project focus and labels | -| #662 | `92534118` | fail-closed injectable TEPP status/read boundary; the owning executable HTTP route remains unavailable | -| #661 | `11206c58` | Rust-estimated reconstruction fixture weights replace hand-authored reconstruction-test dictionaries | -| #660 | `c10cae01` (observed parent) | backend runtime repair plus the #664 semantic-unit stack; this documentation commit advances the head after capture | -| #659 | `e948bd27` | ontology node readability and tokenized UI fills | +| #663 | `81bb8295` | project ontology traversal plus cutoff/snapshot-frozen project focus and labels; DIRTY and review-required | +| #660 | `7e9030c9` | protected-main merge completed; backend runtime and semantic-unit stack now delivered | +| #659 | `ccdfc6f1` | ontology node readability and tokenized UI fills; checks pending and review-required | | #658 | `fe830b0a` | evidence-honest Global Ask cutoff with revision-interval live-after semantics | | #657 | `64f48679` | Dashboard case-metric contract work | | #644 | `d9ff9980` | native-surface code splitting with modal-focus regression coverage | | #643 | `0a1f8ec1` | accessible status-notice surfaces | | #640 | `2d50fa01` | operations-dashboard contract alignment | | #639 | `aee02dca` | terminal checks observed; exact-head independent approval still required | -| #636 | `f7b9a65f` | terminal checks observed; exact-head independent approval still required | -| #632 | `32c7d359` | active semantic provenance repair head; hosted checks and independent review required | -| #631 | `c0022c97` | terminal checks observed; exact-head independent approval still required | -| #629 | `4b4d6707` | terminal checks observed; exact-head independent approval still required | -| #579 | `689a21b6` | leftover interaction-map coordinate persistence; exact-head independent approval still required | +| #632 | `a4059113` | active semantic provenance repair head; DIRTY with one stale Scorecard failure and pending checks | +| #631 | `665046dc` | ADR decomposition documentation; blocked on review and hosted checks | +| #629 | `6d2fb7b3` | provider-work release and bounded reads; blocked on review and hosted checks | No row above is merge evidence. Immediately before any lifecycle action, 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 #664 merged as `b2e48d5b0db59f5aa434e2a293cd182ee810c019` -into #660's non-default branch. Its semantic-unit implementation is therefore -stack evidence only until #660 passes the protected-`main` gate. +PR #664 first merged into #660's non-default stack as +`b2e48d5b0db59f5aa434e2a293cd182ee810c019`; PR #660 then passed the protected +gate as merge commit `7e9030c9a8ee2684e680c63013b304b435ba646e`. The combined +semantic-unit and backend contract implementation is now protected-main +delivery evidence, while downstream authorized-runtime acceptance remains +open. PR #607 first merged as `61fd631c7bb3c57113fd19763c2c43161eeb2824` into #606's non-default branch. PR #606 subsequently passed the protected gate, @@ -375,14 +374,14 @@ this file per §3.5 of the prior snapshot). | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | 3 open PRs at snapshot: #627 and #628 are current-main performance follow-ups, while reopened #579 retains hosted and independent-review gates | Terminal exact-head checks, no unresolved threads, independent exact-head approvals, protected squash-merge SHA | +| Protected release | Protected `main@7e9030c9` includes the #660/#664 semantic-unit and backend contract stack. Eleven PRs remain open; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | 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 | | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. An older-image local observation found repeated post-filter queries while `/api/posts` exceeded 30 seconds; ADR 0212 combines two authorized filter-option queries into one round trip without narrowing ABAC-visible options. The observation is not exact-head evidence or a product guarantee, and no physical scan reduction is claimed without an exact-head plan | Rebuild an exact-head application image, run `make load-http` with declared environment concurrency/window, and retain raw distributions and resource configuration. Compare the post-list database plan and latency with ADR 0212 while preserving the complete authorized filter set; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | -| Semantic source rendering | ADR 0223 and migration 0221 give new paragraph, list, table, MathML formula, and caller-parsed conversation-turn units explicit persisted kinds without rewriting historical rows; image regions remain ordered normalized children under ADR 0091. This branch is candidate evidence, not protected-main delivery | Land the exact-head candidate, then prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | +| Semantic source rendering | ADR 0223 and migration 0221 are now delivered through protected `main@7e9030c9` via #664/#660; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Knowledge Graph readability | The black evidence-node root cause is an undefined-token fallback; the design-token repair and long-label/evidence-table coverage remain only on closed, unmerged #490, not protected `main` | Recreate the token repair on a current base and deliver it through protected `main`, then verify light/dark contrast, keyboard graph navigation, full labels, and evidence tables in the authenticated rendered surface | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | @@ -398,7 +397,7 @@ this file per §3.5 of the prior snapshot). | External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | | Product contract authority | This branch recreates the first LineageWeave PRD after superseded #613 closed without merge and records an exact-case ecosystem authority register; TEPP, fast-mlsirm, keyverse, and ThreadWeave have standalone PRDs, while contextual-orchestrator, RankWeave, DiskSage, and wardnet currently rely on product-planning/architecture documents and naruon has only a scoped Topic Intelligence PRD | Land the LineageWeave PRD, keep ADRs normative, and add standalone PRDs in each owning repository before making cross-product release claims beyond its documented boundary | -| Release quality | The #664/#660 stacked tree passed the complete Python suite (1,352 passed, 17 skipped) after #660 removed a duplicate synthetic snapshot digest and restored the TEPP settings contract. This is local candidate evidence, not protected-main delivery | Repository-wide coverage, frontend/Storybook, security, browser, and protected merge evidence on one exact head | +| Release quality | Protected merge #660 is `7e9030c9`; the stacked tree passed the complete Python suite (1,352 passed, 17 skipped) before protected delivery. Frontend/Storybook, security, browser, and authorized-runtime evidence remain separate gaps | Repository-wide coverage, frontend/Storybook, security, browser, and authorized-runtime evidence on one exact head | | PII | Masking would paralyze the product; ADR 0001 forbids identifying artifacts in git | ABAC + authorized runtime; synthetic fixtures in git; no mask-in-place that drops names the operator must read | | Database | PostgreSQL, 3NF, snake_case ≥ two words, hot-partition and lock policy | No file DBs; read/write split if lock management fails; whitelist every migration | From 89df50a3541add176ed3049f480ad63a57285256 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:16:48 +0900 Subject: [PATCH 002/238] docs(gaps): align semantic delivery evidence --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e60efa758..e0def1b32 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -381,7 +381,7 @@ this file per §3.5 of the prior snapshot). | Authorized-corpus runtime | Repository tests use synthetic fixtures; private records remain outside git | Authenticated runtime validation returning only aggregate, non-identifying evidence | | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. An older-image local observation found repeated post-filter queries while `/api/posts` exceeded 30 seconds; ADR 0212 combines two authorized filter-option queries into one round trip without narrowing ABAC-visible options. The observation is not exact-head evidence or a product guarantee, and no physical scan reduction is claimed without an exact-head plan | Rebuild an exact-head application image, run `make load-http` with declared environment concurrency/window, and retain raw distributions and resource configuration. Compare the post-list database plan and latency with ADR 0212 while preserving the complete authorized filter set; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | -| Semantic source rendering | ADR 0223 and migration 0221 are now delivered through protected `main@7e9030c9` via #664/#660; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | +| Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | From 425de3292fc0aec19946e65c7c40ea66bc2a7a1d Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:18:43 +0900 Subject: [PATCH 003/238] docs(gaps): record current PR exact heads --- docs/product-technical-gap-baseline.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e0def1b32..798befdca 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -84,17 +84,17 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #667 | `3bc662d7` | baseline refresh; DIRTY and review-required | -| #663 | `6fd2f701` | project ontology traversal plus cutoff/snapshot-frozen project focus and labels; DIRTY and review-required | +| #667 | `89df50a3` | baseline refresh plus semantic delivery evidence; BLOCKED with review required | +| #663 | `d3bb9348` | project ontology traversal plus cutoff/snapshot-frozen project focus and labels; BLOCKED with review required | | #658 | `f007a5ed` | evidence-honest Global Ask cutoff; BLOCKED with review required | | #657 | `2d9b43b7` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `7fb4d18c` | accessible status notices; BLOCKED with review required | -| #640 | `2d50fa01` | operations-dashboard contract alignment; DIRTY and review-required | -| #639 | `48065ad1` | running-action/config repair; BLOCKED with review required | -| #632 | `29aee18d` | graph-fact provenance repair; BLOCKED and fresh checks required | -| #631 | `665046dc` | ADR decomposition documentation; DIRTY and review-required | -| #629 | `6d2fb7b3` | provider-work release and bounded reads; BLOCKED with review required | +| #640 | `dd134e77` | operations-dashboard contract alignment; BLOCKED with review required | +| #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | +| #632 | `4e3c6272` | graph-fact provenance repair; BLOCKED with review required | +| #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | +| #629 | `0138db5f` | provider-work release and bounded reads; BLOCKED with review required | No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head From e353d37648f372bb22c071f4da69ea57fddd4e6c Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:32:49 +0900 Subject: [PATCH 004/238] docs(gaps): refresh review-thread fixes and exact heads --- docs/product-technical-gap-baseline.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 798befdca..b9fec867b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 07:18 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 07:32 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -67,7 +67,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 07:18 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 07:32 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, @@ -84,17 +84,17 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #667 | `89df50a3` | baseline refresh plus semantic delivery evidence; BLOCKED with review required | -| #663 | `d3bb9348` | project ontology traversal plus cutoff/snapshot-frozen project focus and labels; BLOCKED with review required | -| #658 | `f007a5ed` | evidence-honest Global Ask cutoff; BLOCKED with review required | -| #657 | `2d9b43b7` | TEPP lifecycle persistence; BLOCKED with review required | +| #667 | `425de329` | baseline refresh plus semantic delivery evidence; BLOCKED with review required | +| #663 | `d5edd2b9` | project ontology traversal plus cutoff-snapshot project focus, labels, and explicit MCP admission bounds; BLOCKED with review required | +| #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | +| #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `7fb4d18c` | accessible status notices; BLOCKED with review required | | #640 | `dd134e77` | operations-dashboard contract alignment; BLOCKED with review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | -| #632 | `4e3c6272` | graph-fact provenance repair; BLOCKED with review required | +| #632 | `cad4debf` | graph-fact provenance repair; BLOCKED with review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | -| #629 | `0138db5f` | provider-work release and bounded reads; BLOCKED with review required | +| #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head From 5335011abbc3d70daeb91be7448e41c75ff65a32 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:36:15 +0900 Subject: [PATCH 005/238] docs(gaps): reconcile protected delivery evidence --- docs/product-technical-gap-baseline.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b9fec867b..c078c7a73 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -84,7 +84,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #667 | `425de329` | baseline refresh plus semantic delivery evidence; BLOCKED with review required | +| #667 | `e353d376` | baseline refresh branch observed before this review repair; this documentation commit advances that head, so re-fetch before lifecycle action | | #663 | `d5edd2b9` | project ontology traversal plus cutoff-snapshot project focus, labels, and explicit MCP admission bounds; BLOCKED with review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | @@ -182,6 +182,8 @@ Recent protected-default-branch delivery evidence (squash merges onto | PR | Merged (UTC) | Delivered | | ---: | --- | --- | +| #659 | 2026-08-25 22:04 | ontology node readability, semantic-family design tokens, and exact-value evidence tables | +| #660 | 2026-08-25 21:54 | backend runtime contracts and the #664 semantic-unit stack | | #468 | 2026-08-25 08:44 | fast-mlsirm, Keyverse, contextual-orchestrator, and TEPP integration boundaries | | #493 | 2026-08-25 08:44 | evidence-grounded Event Lineage isolation reasons | | #600 | 2026-08-25 08:44 | then-current exact-head product/technical baseline | From 3bf57fed0b04ec89dd6530e91f9c385070f23949 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:44:09 +0900 Subject: [PATCH 006/238] docs(gaps): refresh current queue heads --- 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 c078c7a73..fbdc56185 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -84,13 +84,13 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #667 | `e353d376` | baseline refresh branch observed before this review repair; this documentation commit advances that head, so re-fetch before lifecycle action | +| #667 | `5335011a` | baseline refresh branch exact head at this snapshot; BLOCKED with review required | | #663 | `d5edd2b9` | project ontology traversal plus cutoff-snapshot project focus, labels, and explicit MCP admission bounds; BLOCKED with review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `7fb4d18c` | accessible status notices; BLOCKED with review required | -| #640 | `dd134e77` | operations-dashboard contract alignment; BLOCKED with review required | +| #640 | `361641ec` | operations-dashboard contract alignment; BLOCKED with review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `cad4debf` | graph-fact provenance repair; BLOCKED with review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From c7550b5cbbd34acc57a0bf1c8d8a2c645fe9272d Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:51:02 +0900 Subject: [PATCH 007/238] docs(gaps): record project history queue --- docs/product-technical-gap-baseline.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index fbdc56185..03536104e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -77,15 +77,16 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 11 open PRs and 10 +at this refresh. The live queue contains 12 open PRs and 10 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 | | ---: | --- | --- | -| #667 | `5335011a` | baseline refresh branch exact head at this snapshot; BLOCKED with review required | -| #663 | `d5edd2b9` | project ontology traversal plus cutoff-snapshot project focus, labels, and explicit MCP admission bounds; BLOCKED with review required | +| #667 | `3bf57fed` | baseline refresh branch exact head observed before this documentation update; BLOCKED with review required | +| #668 | `5ef8db83` | evidence-bound project history projection; BLOCKED with review required | +| #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | From ecdfdba25e48767e95e7c25d39aba2f563f4df7b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:51:39 +0900 Subject: [PATCH 008/238] docs(gaps): refresh project history 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 03536104e..46af4dec8 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -84,8 +84,8 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #667 | `3bf57fed` | baseline refresh branch exact head observed before this documentation update; BLOCKED with review required | -| #668 | `5ef8db83` | evidence-bound project history projection; BLOCKED with review required | +| #667 | `c7550b5c` | baseline refresh branch exact head at this snapshot; BLOCKED with review required | +| #668 | `97c5d397` | evidence-bound project history projection; BLOCKED with review required | | #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | From ef95d32c3993cc579c563b79da13f01979d9c26e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:54:28 +0900 Subject: [PATCH 009/238] docs(gaps): reconcile open pull request counts --- 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 46af4dec8..be763bcf7 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -60,7 +60,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 11 open PRs and 10 open issues. The exact-head +At this snapshot there were 12 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -377,7 +377,7 @@ this file per §3.5 of the prior snapshot). | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eleven PRs remain open; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twelve PRs remain open; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | 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 47bebd263c1a5ecd2e20fb415bf4c99f17d1e669 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:57:52 +0900 Subject: [PATCH 010/238] docs(gaps): refresh operations dashboard head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index be763bcf7..725d39fc2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -91,7 +91,7 @@ context only. | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `7fb4d18c` | accessible status notices; BLOCKED with review required | -| #640 | `361641ec` | operations-dashboard contract alignment; BLOCKED with review required | +| #640 | `9ca05829` | operations-dashboard evidence touch-target repair; BLOCKED with review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `cad4debf` | graph-fact provenance repair; BLOCKED with review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From dbc438e2382a856fc61b2032f829ff9d6ee34258 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:59:42 +0900 Subject: [PATCH 011/238] docs(gaps): record latest operations dashboard head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 725d39fc2..29674289a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -91,7 +91,7 @@ context only. | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `7fb4d18c` | accessible status notices; BLOCKED with review required | -| #640 | `9ca05829` | operations-dashboard evidence touch-target repair; BLOCKED with review required | +| #640 | `bc4a251d` | operations-dashboard evidence touch-target and temporal-producer prerequisite updates; BLOCKED with review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `cad4debf` | graph-fact provenance repair; BLOCKED with review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 3749731083b3154a69615acbb61f1476b709421f Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:03:03 +0900 Subject: [PATCH 012/238] docs(gaps): refresh current project history 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 29674289a..0cf6d5bc3 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -84,8 +84,8 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #667 | `c7550b5c` | baseline refresh branch exact head at this snapshot; BLOCKED with review required | -| #668 | `97c5d397` | evidence-bound project history projection; BLOCKED with review required | +| #667 | `dbc438e2` | baseline refresh branch exact head at this snapshot; BLOCKED with review required | +| #668 | `facbae58` | evidence-bound project history projection with normalized action keys; BLOCKED with review required | | #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | From 7bd9b84b2a54ea397d8957116b3cffcafe9843ae Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:03:51 +0900 Subject: [PATCH 013/238] docs(gaps): reconcile live issue queue --- docs/product-technical-gap-baseline.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 0cf6d5bc3..b8fd0e3e4 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -360,18 +360,11 @@ this file per §3.5 of the prior snapshot). | #269 | Authenticated Global Ask MCP browser-safe and admission-bounded | Ask stack | | #271 | Evidence-honest knowledge-cutoff scope on Global Ask | Ask stack | | #272 | Verify Global Ask KG/ontology/semantic claims with public SearXNG evidence | Ask stack | -| #274 | Persist and explain Event Lineage channel evidence | #387 | | #277 | TEPP: persist accepted receipts, poll completed results, keep measurement authority distinct | #468, #417 | | #280 | Full project-lifecycle history and handover intervals | Tracked with issue #284; no active delivery PR confirmed | | #284 | Authoritative lifecycle ingestion and idempotent reconciliation | No active delivery PR confirmed | -| #289 | Activate the optional lineage LLM channel through a bounded asynchronous rebuild | #434 | -| #336 | Replace pseudo-CalDAV feed with a Naruon-owned calendar projection | Contract on `main` (#355); operator consume wiring in historical branch `feat/naruon-calendar-buyer-wiring-v2170` | | #338 | Evidence-bounded email/project lineage contract for Naruon consumption | #355 | -| #341 | Heterogeneous ontology and provenance explorer separate from Event Lineage | Protected `main` via #349; issue closed | -| #358 | Batch reauthorize persisted post-Ask evidence without N+1 queries | Ask stack | -| #359 | Centralize Global Ask session storage access | Ask stack | -| #363 | Continue ontology neighborhoods beyond the bounded source window | Protected `main` via #349; issue closed | -| #372 | Reconcile lowercase and repository-case public namespace IRIs | Protected `main` via #616; issue closed, with term-kind hardening on #618 | +| #611 | Decompose unshipped ADR 0133–0137 acceptance evidence from PR #490 | No active delivery PR confirmed | ## 5. Open product and technical gaps From d1415db5cdb40eb52de6ddd32650839873e2f420 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:04:50 +0900 Subject: [PATCH 014/238] docs(gaps): refresh status notice head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b8fd0e3e4..c3f964584 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -90,7 +90,7 @@ context only. | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | -| #643 | `7fb4d18c` | accessible status notices; BLOCKED with review required | +| #643 | `3453ab08` | accessible status notices; BLOCKED with review required | | #640 | `bc4a251d` | operations-dashboard evidence touch-target and temporal-producer prerequisite updates; BLOCKED with review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `cad4debf` | graph-fact provenance repair; BLOCKED with review required | From cd4a10cc17b5efed747b8c471cf1908a9bfcf651 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:09:02 +0900 Subject: [PATCH 015/238] docs(gaps): remove closed issue references --- docs/product-technical-gap-baseline.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c3f964584..cd7b16e70 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -381,7 +381,7 @@ this file per §3.5 of the prior snapshot). | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | -| Calendar / Naruon | #355 delivered the projection contract; v2.17.0 wires operator consumption without forwarding the end-user token. Naruon producer, provider/consumer fixtures, and protected merge remain open (#336) | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | +| Calendar / Naruon | #355 delivered the projection contract; v2.17.0 wires operator consumption without forwarding the end-user token. Historical issue #336 is closed; producer/provider acceptance remains a runtime gap | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations live on #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | @@ -406,7 +406,7 @@ before a commercial release claim. Figma File ID `1Su3lDRmiZdcUs47t1QwIX`. | --- | --- | --- | | Accessibility | Partial labels/roles on board, popup, login | WCAG 2.2 AA on login, board, popup, Ask, calendar, admin; focus order; live regions | | Touch & Interaction | Click-first popup and lists | 44px targets, swipe/escape to dismiss popup, no hover-only actions | -| Performance | Board caps and hint render limits exist | Interaction-to-next-paint on board search, DAG, Ask; no N+1 (#358) | +| Performance | Board caps and hint render limits exist | Interaction-to-next-paint on board search, DAG, Ask; no N+1 query regressions | | Style Selection | Korean UI standards merged (#347) | Tokenized light/dark; Anti-Slop-UI density; no decorative noise | | Layout & Responsive | Desktop popup shell | 402px-class phone layout; stacked GNB; readable DAG | | Typography & Color | Badge tokens extracted | Contrast on badges, links, error/status; no raw hex in components | @@ -426,7 +426,7 @@ of leverage; open connector PRs there when the defect is upstream: 4. **TEPP** — calibrated measurement; persist receipts; no local reimplementation. 5. **fast-mlsirm** — GRM/GPCM/CAT/FIPC recovery tests (#451–#454) must stay true-parameter RMSE. 6. **ThreadWeave** — tree assembly. -7. **Naruon** — calendar and email/project lineage projection (#336, #338, #355). +7. **Naruon** — calendar and email/project lineage projection (historical contract #355; open issue #338). 8. **DiskSage / wardnet** — storage and network policy as needed. 9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1259). If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. @@ -472,7 +472,7 @@ review latency are never blockers — keep working while they settle. 2. Merge #387 and #618–#621 only after each exact head shows terminal green required checks plus current-head independent approval. 3. After the queue drains, resume user-visible gaps from §5 in leverage order: - Event Lineage evidence (#387/#274), Naruon calendar (#355/#336), and + Event Lineage evidence (historical implementation references), Naruon calendar (#355), and authenticated operations/ontology publication acceptance. 5. Rename remaining `[Buyer Gap]` issue titles to neutral product-object naming per repository convention (no "Buyer" for internal objects). @@ -494,8 +494,8 @@ review latency are never blockers — keep working while they settle. - Orchestrator / paper-grounded models: ADR 0015, ADR 0076 (Fugu, TRINITY, Conductor) - Ontology / PROV-O / SKOS: ADR 0004, ADR 0011, issue #372 - Analysis runs / TEPP: ADR 0013–0023, issue #79 / #277 -- Calendar / Naruon: issues #336 / #338, PR #355, operator consumption v2.17.0 -- Ask Agent: issues #269–#272, #358–#363 +- Calendar / Naruon: open issue #338, historical contract #355, operator consumption v2.17.0 +- Ask Agent: open issues #269–#272 Citations in doctoring and ADRs use APA 7th. Do not invent a heuristic where the papers leave the decision undecided. From a9731d52dcf0e8ebbd3d2e07a6ba9973cb777728 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:11:42 +0900 Subject: [PATCH 016/238] docs(gaps): record scoped dashboard head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index cd7b16e70..a6a525e31 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -91,7 +91,7 @@ context only. | #657 | `a59a2023` | TEPP lifecycle persistence; BLOCKED with review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `bc4a251d` | operations-dashboard evidence touch-target and temporal-producer prerequisite updates; BLOCKED with review required | +| #640 | `88c0632f` | operations-dashboard evidence touch-target and scoped external headline metrics; BLOCKED with review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `cad4debf` | graph-fact provenance repair; BLOCKED with review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 6a0a4f2a051e99d6ec9a16d15e841cc54fcdd381 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:13:14 +0900 Subject: [PATCH 017/238] docs(gaps): distinguish closed issue delivery history --- docs/product-technical-gap-baseline.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c3f964584..d3e420aea 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -381,7 +381,7 @@ this file per §3.5 of the prior snapshot). | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | -| Calendar / Naruon | #355 delivered the projection contract; v2.17.0 wires operator consumption without forwarding the end-user token. Naruon producer, provider/consumer fixtures, and protected merge remain open (#336) | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | +| Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations live on #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | @@ -406,7 +406,7 @@ before a commercial release claim. Figma File ID `1Su3lDRmiZdcUs47t1QwIX`. | --- | --- | --- | | Accessibility | Partial labels/roles on board, popup, login | WCAG 2.2 AA on login, board, popup, Ask, calendar, admin; focus order; live regions | | Touch & Interaction | Click-first popup and lists | 44px targets, swipe/escape to dismiss popup, no hover-only actions | -| Performance | Board caps and hint render limits exist | Interaction-to-next-paint on board search, DAG, Ask; no N+1 (#358) | +| Performance | Board caps exist, and closed issue #358 delivered batched persisted-Ask reauthorization | Measure interaction-to-next-paint on board search, DAG, and Ask against an exact-head authenticated workload | | Style Selection | Korean UI standards merged (#347) | Tokenized light/dark; Anti-Slop-UI density; no decorative noise | | Layout & Responsive | Desktop popup shell | 402px-class phone layout; stacked GNB; readable DAG | | Typography & Color | Badge tokens extracted | Contrast on badges, links, error/status; no raw hex in components | @@ -426,7 +426,7 @@ of leverage; open connector PRs there when the defect is upstream: 4. **TEPP** — calibrated measurement; persist receipts; no local reimplementation. 5. **fast-mlsirm** — GRM/GPCM/CAT/FIPC recovery tests (#451–#454) must stay true-parameter RMSE. 6. **ThreadWeave** — tree assembly. -7. **Naruon** — calendar and email/project lineage projection (#336, #338, #355). +7. **Naruon** — calendar projection delivered through #355/closed #336; email/project lineage projection remains open as #338. 8. **DiskSage / wardnet** — storage and network policy as needed. 9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1259). If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. @@ -472,7 +472,7 @@ review latency are never blockers — keep working while they settle. 2. Merge #387 and #618–#621 only after each exact head shows terminal green required checks plus current-head independent approval. 3. After the queue drains, resume user-visible gaps from §5 in leverage order: - Event Lineage evidence (#387/#274), Naruon calendar (#355/#336), and + Event Lineage evidence (#387/closed #274), Naruon calendar (#355/closed #336), and authenticated operations/ontology publication acceptance. 5. Rename remaining `[Buyer Gap]` issue titles to neutral product-object naming per repository convention (no "Buyer" for internal objects). @@ -494,8 +494,8 @@ review latency are never blockers — keep working while they settle. - Orchestrator / paper-grounded models: ADR 0015, ADR 0076 (Fugu, TRINITY, Conductor) - Ontology / PROV-O / SKOS: ADR 0004, ADR 0011, issue #372 - Analysis runs / TEPP: ADR 0013–0023, issue #79 / #277 -- Calendar / Naruon: issues #336 / #338, PR #355, operator consumption v2.17.0 -- Ask Agent: issues #269–#272, #358–#363 +- Calendar / Naruon: closed issue #336, open issue #338, PR #355, operator consumption v2.17.0 +- Ask Agent: open issues #269–#272; closed performance/ontology issues #358 and #363 are delivery history, not active work Citations in doctoring and ADRs use APA 7th. Do not invent a heuristic where the papers leave the decision undecided. From d99a9681e4dab05872f7c70161b6bd6983597896 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 07:42:56 +0900 Subject: [PATCH 018/238] fix(ui): guide cancelled analysis runs --- .../2.21.2-cancelled-analysis-next-actions.md | 5 ++ frontend/src/App.test.tsx | 54 +++++++++++++++++++ frontend/src/App.tsx | 16 +++++- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.d/2.21.2-cancelled-analysis-next-actions.md diff --git a/CHANGELOG.d/2.21.2-cancelled-analysis-next-actions.md b/CHANGELOG.d/2.21.2-cancelled-analysis-next-actions.md new file mode 100644 index 000000000..5fb2e6c89 --- /dev/null +++ b/CHANGELOG.d/2.21.2-cancelled-analysis-next-actions.md @@ -0,0 +1,5 @@ +# 2.21.2 Name the next action for every cancelled analysis kind + +Cancelled lineage, TEPP, topic-lineage, and period-report runs now tell the +operator the kind-specific valid next action. A terminal cancellation no +longer leaves the analysis list and detail without guidance. diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 2dee4513d..1110d8fb0 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -2,6 +2,7 @@ import { fireEvent, render, screen, waitFor, within } from "@testing-library/rea import userEvent from "@testing-library/user-event"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import App from "./App"; +import type { AnalysisRunKindCode } from "./api"; import { setLocale } from "./i18n"; import { OIDC_RETURN_URL_STORAGE_KEY } from "./oidcReturnUrl"; @@ -106,6 +107,7 @@ describe("App, authenticated", () => { succeededReportRun?: boolean; succeededTeppRun?: boolean; pendingTeppRun?: boolean; + cancelledRunKind?: AnalysisRunKindCode; pluralAffiliations?: boolean; deferMe?: boolean; deferPostOne?: boolean; @@ -161,6 +163,27 @@ describe("App, authenticated", () => { releasePostOne = resolve; }) : Promise.resolve(); + const cancelledRun = options?.cancelledRunKind + ? { + analysis_run_id: "run-demo-cancelled", + run_kind_code: options.cancelledRunKind, + run_kind_label: { + analysis_run_lineage: "Lineage reconstruction", + analysis_run_tepp: "TEPP measurement", + analysis_run_topic_lineage: "Topic lineage", + analysis_run_report: "Period report", + }[options.cancelledRunKind], + scope_kind_code: "analysis_scope_corporate_entity", + scope_kind_label: "Corporate entity", + scope_entity_name: "Demo Corp", + status_code: "analysis_status_cancelled" as const, + status_label: "Cancelled", + knowledge_cutoff: "2026-01-12T12:00:00Z", + requested_at: "2026-01-12T12:42:00Z", + source_counts: [], + visible_posts: [], + } + : null; const fetchMock = vi.fn((input: RequestInfo | URL, init?: RequestInit) => { const url = String(input); @@ -269,6 +292,9 @@ describe("App, authenticated", () => { jsonResponse({ post_id: "post-1", has_commitment: true, ticket }), ); } + if (url.endsWith("/api/analysis-runs/run-demo-cancelled") && cancelledRun) { + return Promise.resolve(jsonResponse(cancelledRun)); + } if (url.endsWith("/api/analysis-runs/run-demo-report")) { const reportSucceeded = !options?.failedReportRun; return Promise.resolve( @@ -686,6 +712,7 @@ describe("App, authenticated", () => { return Promise.resolve( jsonResponse({ analysis_runs: [ + ...(cancelledRun ? [cancelledRun] : []), ...(createdPendingLineage ? [createdPendingLineage] : []), ...(createdPendingTepp ? [createdPendingTepp] : []), { @@ -3399,6 +3426,33 @@ describe("App, authenticated", () => { expect(screen.queryByRole("heading", { name: "Body this run knew" })).not.toBeInTheDocument(); }); + it.each([ + ["analysis_run_lineage", "Request a new lineage reconstruction from a current snapshot."], + [ + "analysis_run_tepp", + "Connect the measurement service, then ask an administrator to submit a new TEPP run from a current snapshot.", + ], + [ + "analysis_run_topic_lineage", + "Connect the TEPP transport, then ask an administrator to submit new topic-lineage analysis from a current snapshot.", + ], + ["analysis_run_report", "Rebuild the period report from a current snapshot."], + ] satisfies [AnalysisRunKindCode, string][])( + "gives a cancelled %s run its kind-exact next action", + async (runKindCode, nextAction) => { + stubBackend({ cancelledRunKind: runKindCode }); + render(); + + const cancelledRunButton = await screen.findByRole("button", { + name: /Open analysis run: .* · Cancelled · Demo Corp/, + }); + expect(cancelledRunButton).toHaveTextContent(`This run was cancelled. ${nextAction}`); + await userEvent.click(cancelledRunButton); + expect(screen.getAllByText(`This run was cancelled. ${nextAction}`)).not.toHaveLength(0); + expect(screen.queryByRole("button", { name: /Start/ })).not.toBeInTheDocument(); + }, + ); + it("tells a running lineage run to refresh the durable outbox", async () => { stubBackend({ runningLineageRun: true }); render(); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 76ff51dec..e786e112c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2701,8 +2701,22 @@ function analysisRunNextAction(run: AnalysisRun): string | null { } case "analysis_status_running": return "Refresh this run. Start already queued the work on the durable outbox."; - case "analysis_status_succeeded": case "analysis_status_cancelled": + switch (run.run_kind_code) { + case "analysis_run_lineage": + return "This run was cancelled. Request a new lineage reconstruction from a current snapshot."; + case "analysis_run_tepp": + return "This run was cancelled. Connect the measurement service, then ask an administrator to submit a new TEPP run from a current snapshot."; + case "analysis_run_topic_lineage": + return "This run was cancelled. Connect the TEPP transport, then ask an administrator to submit new topic-lineage analysis from a current snapshot."; + case "analysis_run_report": + return "This run was cancelled. Rebuild the period report from a current snapshot."; + default: { + const unexpected: never = run.run_kind_code; + return unexpected; + } + } + case "analysis_status_succeeded": case null: return null; default: { From f78b69c1152bd0d4093980d4663e887ccb9cc352 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 08:13:07 +0900 Subject: [PATCH 019/238] fix(ui): make analysis run actions responsive --- docs/product-technical-gap-baseline.md | 5 +++-- .../cancelled-analysis-runs-desktop.png | Bin 0 -> 84128 bytes .../cancelled-analysis-runs-mobile.png | Bin 0 -> 74045 bytes frontend/src/App.css | 10 ++++++++++ frontend/src/App.tsx | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 docs/screenshots/cancelled-analysis-runs-desktop.png create mode 100644 docs/screenshots/cancelled-analysis-runs-mobile.png diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a6a525e31..5115f8d4a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -372,6 +372,7 @@ this file per §3.5 of the prior snapshot). | --- | --- | --- | | Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twelve PRs remain open; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | +| Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -408,10 +409,10 @@ before a commercial release claim. Figma File ID `1Su3lDRmiZdcUs47t1QwIX`. | Touch & Interaction | Click-first popup and lists | 44px targets, swipe/escape to dismiss popup, no hover-only actions | | Performance | Board caps and hint render limits exist | Interaction-to-next-paint on board search, DAG, Ask; no N+1 query regressions | | Style Selection | Korean UI standards merged (#347) | Tokenized light/dark; Anti-Slop-UI density; no decorative noise | -| Layout & Responsive | Desktop popup shell | 402px-class phone layout; stacked GNB; readable DAG | +| Layout & Responsive | Desktop popup shell; this candidate stacks analysis-run caption, document count, and next action at 390px and retains explicit grid columns at 1440px | Complete 402px-class phone acceptance for remaining panels; stacked GNB; readable DAG | | Typography & Color | Badge tokens extracted | Contrast on badges, links, error/status; no raw hex in components | | Animation | Minimal | Reduced-motion; no blocking animation on evidence open | -| Forms & Feedback | Login, Ask, tickets, admin brand | Inline validation, next-action copy, unavailable vs failed distinction | +| Forms & Feedback | Login, Ask, tickets, admin brand; this candidate gives all four Cancelled analysis kinds an evidence-safe next action | Inline validation and unavailable-vs-failed acceptance across remaining workflows | | Navigation Patterns | Board / customers / calendar / Ask / admin | Deep-link post + OIDC return URL (#426); bookmarkable Ask | | Charts & Data | Period reports, leftover pairs, Rankings, DAG | Honest empty/unavailable; no invented theta; Storybook chart states | diff --git a/docs/screenshots/cancelled-analysis-runs-desktop.png b/docs/screenshots/cancelled-analysis-runs-desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..f1c0f5d563a7ec89a81c60e698c58f2b73d905b9 GIT binary patch literal 84128 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 z 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
Tc)uW)EktlnLVP1N**Z}Q8o_xIo`7OF-X z@#9bm(kG7;_6mJqDhVfu39B}xzPhg~Z}x9a76nhGj^}lLvC#rT&#A|%9955bq@KXb z5%oW@vO4*;}&bG5Z#NSQ4ayZ+w zqQj}TB2U|k%a&NC+UuY?SY0~V!<^5HZ6~h&Jxo98CBhXaW4AVe7v=>+JpD_tHN%{2 z>_Ou{Fu^0sWg~rl>0-Q6mF_@g9duv{v#j)@)EG94mZ9x?%E?_$Pa?c+Jvyp2K$)3J zJwnzd;lTfn(1$5{pFrN|O&tn7Ix-Apsqy@Iys6*Dm};~9?b{s^mn241D55PYwk@JB z%qhf~?c2Ev#_{9GO;K;V2J;2Qxp8hh!iX48GmLLMpIOxdyR+lnQGE>gx2?+D=XW9$ z34BKEkFG3?Q6dVJMm6Yhkara~g;o!xUZ< zi9uj7^|YNqfcT)EAWoi#JG>{7$vK+O=v6qf;{{rbw8@lIs74#=1(`FA5{I?xRlh# z`cTL~^``nZvuUUwKNgMzCx?>!bj-8Ou;1F*dZHWn&qcYDG4CCUhej%@5e47Z3Og*( z8JsT`I31S}!GC32?LZ}J%;}T=Ks6&JDLI3Cg{J@FDWm4X7i4<)duLgcau;kMu=UyP zW!VYM1_gFjcaUaJ30%@&l@bOn?wDcF67d%j*|ynR+e(^FkaA@s0@F0hi_B#?MmY*G zE{BHyg9Rjl)9-UXnt+k3SRaxw#vv+nA?!+NOkJdt>Vm5uK5yzr%AmZMYg8<3ikM%n z%Hwe8XMOnIab10!OEG1OMIeG*g4WYdI*!>2RKm!Xy`H(v#T1X~mbzR#?Q zA(>IN4PMthQAa>`ZWg--M+JK$wMF9x>+DkYYDI0A1n3~U4|lYIj$1vMYL&byYWwnz zr-m6FTup8`%r&i7ncjr4ce}#sV%EpA!4P}VWH*$_l zHDA+c7waZ*KuP^pFr=z)rFwgZS^n*rsEFxdc)uNTXgRFw$>`4oeB7+rp zh+FVV+F5xyDV>xNYrZu2C% zZ?19m`QGAXq>r>x^Uc8f+6g|%7f&xF-@y9W5Bj~2j(s@cjjliN9S6x>%@+zpjgf46 z(Qyw5;HMsm(jvSX=b~R&8a!`J22ZI3-P{w(9(t8Eh52q39oKneq%$H)sV4u1?~l(y z8}@c24#(sND6EP~7Ik*YwSkPM@4Ip$$zA7?CVOh*>A_^==4tv_HOBjkbsK0-5x}-r zoX-KdIDp74e-W&q1pEmw^H~m~`64E^^T`#h0OK{h{8|gCD}3lU2koI0uP4}hFvm)c zKuoTFws>SHCo6HWM`mOUbIBNonX2_(;`&5qd-Va9YkEos=H{hx7 z!7Q^m%eeQWj(ydTao>jcHlA4g*%fTQ)a|!@CIq+n4l&T0y9y)~CZertPR-3kQ>4l9 z?YB%kvaZx)ZUP-m!g7MT7Zwl@>=pVAWP2YSUy0i+0CT;*(0{!o6Hr*?`I=ymc0KkH zLqlxfoWu11h%YMHUE3DFN!l@smJhdBC^;0-de3molq;Y1aI2m>Yb}M4hE>mn>CHch z<*up-P`@WC+AK1E%OU-)VZ%OD+HAUK0HG)x3%-nO>nalX!JrcqbxCqvV#0R{7hF zFSdLAlv)K}4%M~k^yEHBjlP%Kd1FKCQ0U=LUF}k@c85Z7gp`lcE5-!uU){i`Oki=^iNa*jdimAZiPcFoY-J4#USjFN^DoK+*7kylFtn zc1E*l8bmsRsgejnM480&MYRGU(z-4%oa8g=ecSQ(@~a0E;pGjVgI?-PzWw^X~wT&sOe^EkR|8{P`_NqdaM}0zyNk^+i+i zS6z4|%%0AiE}ZgL;bvuJL3C?7V1izSo~AK5;wSc8;)^$-)XoXc8&i;n&a5%sB>wRw3{;L+K7S`)jRY;AZZPVW%CF9tC7iJvBh8u# z!h;;g;#MIlw1qRgA+0*>KLM2GrDzK&SJF@!S4mE2i|(=_C8792x~4Jdr7a$nFc1=d z?gQq8)A~b8XN%ttR^+quF5jX3jz=~Dk$2+}0HRJ4#NR)BA8+gHh=Y$;0eaf84+P`W z-vt1IwsY*=@pB|@DMGTTIy%k?6K}=SYqB0Hy0S&l>u^%DC=eH=;@bKQk@+bqnVjUu zSH;|#UfoH_9Ae1FFEDPS#(k$%!=YU_$m+)5N>b9p-e=IAtErZCt$pbi*eQw^b$uBt z$u$fnr^X)=S2eC9&YFZ3W9!5GR{GAd*0n@=(NdQ;KI zo5<#*=Q?-$=uS%R!fwku_4kfbTLw4Zs~P%^V>x3pTwAld`))avKM+ZLSWZ12K|qz| zW%=A7T&L#%j}03M6f6XUV89ODL9xcVTU)GA@(J{7AeYR6ZAa3hWg{CzWUgt3W#yqH;{~;Z#`J@Mm(Ob}&<27h zk?*-ai(rb%ro9nV-@@;SrJT1b7md0YLC#>Z%u6PG_`&D&nxHb?-EM`t&L1COEA!cU z-SY9TPgSoL^JemZPNI`Mc#HcqJ|{xX%p2z9(&UR68MEvqrrzUK18 zmb~XlXJy?^W(=po5g_kLGKu_Ac{+OT3F@R``4VGPL3ZMu>&q`av|?UiEiyS^y_xzP z-NT7Cg6uV02qT&_=j7~Hoq$~PVk#a{ql$f_p)(|8<2qOy>q?sh^$D*`{ls*103(}@ zw7wtZrgW#>7e2FkgoyVjKyDJ7fZd1m8LM>nH8i&=Pzbn9Q?Pb8<&_wW zLSfLCbs~l-=r;}XQktnGQUP87cGG2FpJRL>wzv1t+@>+Fe{-9Z(pBso`d^f}9{pvO zgQ9DDM$|f5UrKZd;meF-^ewDSm-BYL$PiD0zg19!3cgcEd8o&jVefixU&HNl>y2VA zTkaQs+TGO8o!VU?;k1rQ&1E)}6;yjPpG_MGj+8%M(iT2!apRPodB)0UO)Hy#s(9w5 z@T)f;Eak|&yBwUggM<$`hy}mZCW!!lg76JIttY(|H7|5n3|Jm;6#SUplW-XG=4#YY@(P& z@N)9`^Bmoat!s8M-_fk>&2?GwE=eSE-!X~y@A%9GQ#_z=#cnK}PG(O^6WOYm#>+|V z_EMxdf2q8gDz$+*AvOc!!k$nqip(Otsd`0w{T8gdwzlJSc1{vs180X`ah_^pqVkWz)iqT0q8=&+?-$*w!uyI~%5G*ScDY4echJqU<7F_!j8q}^ zzxO7^Wg5#WJ0%9s8cw_Rp{m=jVOi0hY+>!kI%=wvWP7EyBK!txa+!zA5Ibx zew=)!5$e=ED(bBBjoLYZ{d1_o`b2gS-=eZs^`4`;BbmBB95$@a{i*z(L1VSr^_m3; zScHi(7iZ2ev#~5=Fk5J^9>rOx0DcAv(}^wHc$d)zWcm(!KkI&?#Ey8NS~IOcnxd$f ziO#@TNkw1{fM0p~?JWT3cJYXOba(~*)tiPmh~SP1*k|P07QY6Wi^UOsF}#YwL)c*f z10wwT6HsFzKihj~17ugX5WKaiHXtz5y;6CMBV)l~>~+2l*wHVo6p7+&jfK$~bkIQk zutJcEVp1=mk$irX4e-O2&^ee{ryz~?z;rIu&b#5Zc87l4kJ6nBFM%k~)z!7Gl=xdr zkjT-smi$MD!=z4BI$_lJ{NW#^0T$2w5ADhS>OmHT1x%;^t!%-Q|Ai$z0)mQ(^g-*n z|E9(P8h0*8UXqen{-Ld*6loKQp+#vD%^%x-svG?yBcKt`5QR}KX)$71hSB4?I$~pZ z@15RLkMqtUuPiC)_ph(ObknlR+1O>iC24}?E%wU#=gL_UJ)KnG#d|m$_JxCk!yhse zmdXB54b4S_P2u{XQiX&T`z=I*4>_eB@sF>-`tKf;fBUHZzq~-!=dj|9go&gi6tL90 zIy?V97p?Ymbabw73vEn*n!g}8d=}0~HmUoLQg7<>bDGr(Ru&fjIMsWfIQQoP_g_SW zp6-!p@l#i8Ck%zFx>_~n+4|>yQ1$(0dbf6qkn7*e#o=00m5ONpbxsSJc3~@5d|I)X zq=_VWgTFtC#vV5Icj|hDHXySC{QTeNR`92_z$1XmxUfS(`M1t#ibj^gUj09MZu2By z*kcE>n8ntb_K@j6wE)!!E;+|nca%Q-R+wo#D9q1AP%cnJ6kRp~sc;zx;n6;m(CXQS zkkp!e8CsmNJc_StfFopLVltJ+j-Yh_9&Q10ZLrN+@r1&4*!H^lQ!82EY(TTW9s>Cw z>%;B?<=};oj)pa3m-(;m0wAU+0O2(``w zNNj=AAyBJMhD@0lab;UXrKF_fug3$YRh2}1b1)pxKqT0aetpK6Hj@C;ZfHT@!S7b4 z-VyO%ctpdpR$8p ziA6y-^X{*O?SQiBqUzX*PoM~Lx9#WkeRT-rF$iD=h=dla!1@tM z1raF?!xyk}`@yj#cQ*hoAvjc`;(9?71lSp6l;D!S*yA(_*CP&gUT=fIY{Vpi?;>b1 zCcaq^r@Cin??v-Y>>{D#sZj{_89_uKpyc2sgIXdq^(L!8o3jjwE}HQ;C3G)^!tST` z!nv4u)7&2li7sLc5Jiro1MdMTLv22e19j0p4X~~6JL>U@0L0LjXEwUxA>}(uU!%`% z1xWY68W^T+hT6>*OvjnxR3CQ+x)Mv_owCwSe%!1fN8~%-2H~8xubx>MFL9LD9O7QM z{p{hxmZF0KAe0le95HA_SAbKB*ioNgkg=_nTdC`W0VWmnvIyV7P-WfZg6I;I?O(fV zN1SVbe5ojLBNP}Z*N|HeDiSL_2Vs0VD^pN+FMF@Eg#1^4%V#�`qGUGZFGy8e!hM z-p+%2(@^AGk1AVxA)v=1kLa;JV4C17m(egXgPv*gyIE(bvn+&SK`r*wv z^0suh8hQmDMHy4H&6biW2c6l0s!*jbhH4F@g&Wl}&h?2i$Q`fBiz&6+dU;~%em)pJ zzU{G-M~nsBw?GAho}D7)CmUP=wG5}Jv*RBWeTDokRCXFPLMtQ0^>P^u84PK=0)g>j z(K}OB2LdB#MJV}yhTGmyX`u?*wL@C%G`V)QEH|G+am4%d@~uM+3rxd6G5QK`)GiQG z2Oo$C_xoYFZCEz>_cPeD3eh}^+AqKu#IFkw4%$b%GAYK_AbXr(x7|kiV8rXx>+lEO zqATQ?DC6fa@R1k?eeYG8uL$LM`E|wEOGOE?L>mvMGIA$n=|Lg)nA-+~K6>0da69l# zuy%JFhuGG|OibAGMmrtt@BzoVw#y8`v5mwPdh`GRpC|;2_Kj;=Gqb%phCA0ylg8tY z4AFe&7QwLL88@G7;mq{?BhqAlCr z@T=B{3H6&x+$5IAoz(2nJ$;(EsnD)Ks);+GJI;z~a|wbmXrdDUj^8|r^=aBZrEtO{ zm$)!ZbC$aBa8Jj)plqx^(+-R9eR07zOElQU+ZCL8k}amj}XC?{cH67Z#;t*@F=`3cUvR^teNYnwPPy)2lv0`wM{|wvXZU zDf^n{G-CN~ta+wA?53N^?n1Bn4@@RV{@nY`PCVL4j+W7AS~}(BH`qShjBOh|Dap^I zmCKOc`{`DPm@3FfgV*NN3X{o{Y(=1VFR-L}emw8v8@B14Y*cQljh15!{QIT)|pFaiS@agm^LK9KVx6 z2)|i$<#GtRG88J6NwZL$piTIQS}dLPnlKXB`mS!9Z!gxVp_C{%sDcCRc=i3;K9p+HV{1Rm06R*cE8=*8BtwmuHma6)c zUp-(6r2;AWRO!$;uKFVhCz8z^K&F!WY5AFc+llmht}#U`843f!_{b{xb0}1dm#r@6 zU-E6BMM-W5Z8@oLobVU_vN(uBG$fz4*!pmGW@r9@n81Z<@Nv3|awh$!{kb-MN=*D# z{JDK5fpk6wtFW7H$MBvvOB^nw;l=vUkFo_}hR3-cPCsgS*fI?}(o&ds>JF?JlXB0S zINCZMItaSdhAW9S7|k=NvBk$xxfsdDQWf4>qu+VJ7nuNx(e@MpZkm`_mhqEScIlL{ z>Ii9{V*hP57V;iGhv%T+tIul5O(11e-cJaO9keYoOuKE%arriv3y6e`O$FMkW?}Pe29yq<#P3+;${UJ6{HhW?*qH=yz8JteceU|5I3 zCTP$$r8A_lL5zxkN&g4-Y zU@FV+31|B7J2IN<2qw;%+GR`bQS3S&fARz^?L+PRY^^{^yM~#_5l`=cS{0Pw|`Rl^`EMf zOEHfGOT;)DnVCiLJ9kM1_Q|8AW?(H}+nU!ZR0Y|b+s37MBHQek6cX0H{qC$U#R0yx8p2PUMTJ9rK?2@YT5EO8*db70I`ZOpnc6NFc zhNwAn>{?@(kwIq4)>XKF+BIg$qu-nE3ZhqSD0a5gT6snLY59rrs`OyZyRnj6p*3%8 z9BUr%$&L+CQd%udA7P;s@FOy%Z%V>6sefRCitf-(ti+Zmf88tW`H>^e%GgWW290;E zPMyu~Q()^k*)HM7L5&OH--Z}dqUC*~wtGF{+4IJ-ZJmsVD5z|?PmPv$d(ZGV`Sd7^Q+~B(VSM2d_%c?eDjFu6 zGus!rP50q*0oAbmxwvc(r;IHa&fQ!y`k8N4P*nPj8fp9aEyTGIU#ae-!#eSV1QM!n zh^k^d!$Fvu@d4TlRmFPymfR9*o0u5UF}JyOWR@fC7NZ6uHRyHZLQ?B-HjwTt!BEzK zzmgsSf7%i1It1@6`3_#z@VUNw`Ad+1)VO{41{p_rba&5P`n~*X!#f{DUUHM7o@k}X zzJDRqD<(UhC)7(kZ&%}sotp!&C>QNHmTA!t{RbN=JC>51Zr&@}iqD(YCybD@Fxdyu zAfF2*A%ZH*6Zf9@Baus=xggVCr_S}|xEeUcUJX8V*?i!NkiKAiy%uYaM0cv-jYb3e z3ODulun8Kl2r#lAN!4~Fo_^aq) z_?tfvJ<5Mo7Z{>I2E9o6L50}B9vZ>Rah!F16^^vvbh%d=ePNiq=KnASI9z8|`t#Da zu-oJg6N&fY>VFHe^n8N-LxVfuWfBcCSp<^@<)*KYi9w|1p?gyw2sEhWLsHELkyJ4B zSlDn6VjCKYxv!NV8cFvdyW{?gfR^0v94t;XjBl@ZAkzlN%}B6svzTNbxwJ2x=?pb{`S8sHNTDo@aah>KwBZ71)s6I`82Na29LQ^E16WB_)ZPMWSo^AK32UPsJo(;> z0TBfn3`FQU=nUr=JMdhAxFGSMyXs|Z;WA)(Ysc<*+2fCUHq6Op+JiVhu(X_?MQTX| zOO2=qpZPC*PRm`t;(R+sa{R}%9axKTdZxv&VJiVbx0hhREDba0&%og7D{QQrN7(Zw z8eTuf3M~$k&Tm3{wosNsTOx1;Azn>kE6L6YooRv2X%YQaTQV?U7hqsxDYFNLK6=S~ zVD6+M6fY3Xuh+M)Na+~O#AGa&oVzLNwO09G$8S53kx@J7XsDS?K9t&6VBDkGSqqZ^ zF%+?B-t4J#67i@A@lZb4MJY_wA#6^Wea)*E_=2{560 z?shcZRLb+~3n(21wsSeHef!9rL#LW7W@&7kXjurJYKIK?_Y%MZ$q$0@gnfrQQC%N> zDby*=D?;H?tmJF#LP^Ol*FyrD01T9;voQ10Y~JB;46@1XqpL2r3?TS_8C9>@yFkUj zDdRDsu;&g;?+9tdE5k%`tvK%o#HFXv5;7i+u>j_>NoJatL)PxsI~ZsJE&wJT7mxVC z0Yx4$UK*m_oN<|y5H3xQUJQ6Cl0FtPVKSy3yI<)&;VeF-SChjU+Z)T;LaV@Hwof=F z9K+2Mw#pZf*;l{qr|hzFHE;}9qPtX*2dZ7)Dk`dyxPJy*-*zCI^cjaVw5@TDz9tVH zkpH+c+7~8XZZ9QxJIc2~{O!N^DHIWw5)*X=b2O*gK!|YFS39&DT3J*lj_bUCpIYMg zW!)%2UN>(La*?ycHJ7{h(HVFS}~{Ahtq%nHV< zLbB+>L{0VL`Z&aj!GO-#(gSrB{lEpWJ9s+}>FU0pBkmRDiZGX)3$ z5O0~Ewg+$0ja$JE{FwB@ExYKu29p2xn z{WMT*H)AR{^L}Rrs0sxjqwdm4V%AsJ`s?Nn6Yi$`T0)wO>T;KWqcU+Z`nxUlteDtX z9@F3p^E#L-sW3x8ehg;5=b*V2?S?%GvtZ>g%rWkMagl{b^wDUouhUm|WmCz^k{bvG zreG-Te8=b)UN~w^djnL`J%?%$D~7gcWsu%mGf~w+jpNcsE%j=gje=v1y09Q-d+pdm z&u3zHscKA z8083Lr#qBP*<3ufKJk-rp$Q+NnIu!tYrR!0OfEZ*R>Z5T!m?DEx_YQg|%8IEUgJmnX7F#V{ z*?Ld*oe)c-OUcPh}OVr@973CEepXJ9GWOJ-iT_or! zLsn%B7&4A}+6*LL06oxGG@88r)grRf3UM>HY!%4{cXT|ta3YZL7&GM}^gT3d-kAOM zD{?x(|IRUlH2Lhywu+k@bFNTIoY21SAvCirgRAsB`w(-Qo`k0bwEC>LJ>i4#^<9yH z^P5)=ug>;%6zf@CM#f8of@jjB1Z*viHceA9f81F0aU1Oh(Z)xNMPzT^)0b_ zZMUm0^giOXyyY?lqj8;S-M+fXr=Qv|eojjDB9gOiLZUIRpXwnIz2BcRY!SrkfPX20 zT*TxX2i@=TFUbf-wO1F}*j6INRLE^6iov_rKndzG&@Xf>`#~>|cF4xa>sQq|hMjR& zWTTyN`)N7wOKidKGNH|8!GHWKS^rcl=lGv`GEK#+O?3S|TfM9!m!K*L+*j*~FW+G3 z@x`yki}|h5>%YB5H8!F{SN_KJPe+6g{Kq_Zmq`P)*Vw7;#IEMKl;m3Kkx0@Vdom(T z(FO&6<{?|Y{I}|e%_6(V6z(}-?~AT&U$*3>B_ksn!=^Ex)5AZAt$x1?9(t+Yal1(y z;2lzX*}n|30$+(0JwImiJD>({7nPq2UY9q>!iTO1?akOgQ$zjMd|5*^x~~ zy7|Sn7Ud8A^_R|5z|(<2VJ#M?xw@9J>#iY>n{*VBzuHAh2R~0_1N#WSp_$eYBUKw;^w&qiLW~s&0$Z$cLomxf(Lhk1$TlwB)Ge~Td?4e5CTC%Ah^4`yA#}fPwwum+8=vs zw|1+xDm4{`Vff~JeY*R7`aMJ{D@voIkf1<8L7~gaNUB0XLF++5!S*A;fM>=<5euN8 zu%Kim#ne5r{$|5B;dd|ghQD{0EB=Kf^IonlB@c%hf)W*h#Pst!5;YTq8YwCuAO!NY z$R#pFE^UH5tv+q%shZ|uwWe{`!7iX>X_sMTG>5OI26yzr+hp`_&mY&r)bsAU3qrf4 zdTbn=BtcIOjFD^sCF3mKsymOT`>U}rRG%192F2W zFQq<5UVC?ot3A=AJl55;v*r3CFQdJ@vdMJZpEtXszi?S6y=0T}*j1a!mK!v?t#`b0 zKAtYsV%4iR(}+vsvfg;DRc_Ga@nHJsah6msY|!j<74%Fb;+I4lIaG(d(W_+h0KRIX zmBlgqUsfi3Xv zt>Z=rG7c?LV;92{J2p9LOx}!<2Yzl9FHnhnfSuqG!ms!ZGKv77gm<;&h z782Kx#_N6kH)fxc@4II6$5iGFjiO4U=ML^qGr#R7nLf=h%R#V~OdsR%l-Evrl+^2z zbt4U|7C*d0jH3{mS^qrCn=WiBwBgq^c4pQ?uO`vCRB%Wx9Q5l z-B+*5BsA-f(~lRZzH+S}dXD=^=J-shS}=iYE1Uj&p&6W(7d&d;VjiE)dgl*BV4Gra zi!th~#^sUWg1qDX1w&B@-!L0oqVlk;`jieHW;YByI%=ksR~%L#z5e!cYC2&io9owb zmg{eqadQ!r%%G%MVNmuV>i&tUr?BPxkZ@>)+6E!LfAH-A*f5&Sc#^{Q8pS-*i|;KtjKi!Y<{#Jw8VFjY`%AIv3n!3 zSNiGg_f?PQCiu}hFT1WjR&X?6i#}`JR#20wlMeMVq*?Je~k)GZf*6e<@#}iY#s}( zWC~d#{LroaXkItNlHQ6W6#&x{LoQ@~P_*FsvG(Kg#0U}s>^-Jll@A>`y>+I5(i?oZ znR0y||CNr^Q4#4HpC*_6i6lciZ(Ol!7B9!A`&jZtw?qGj7yj@59k(yo;g}Rhi>5~P zSJ6Wfh;e8Xx7&Ye^5q=j+08rRFZ}P{y+f(%M09$%*kMtwlg;PwFI6vTGJR0gyG%2* zwycOc>h5!PxY+r5w%MZF;uHGDzs~*y^P#nZyT&irYrcA`>&xxtjmT0R>4(~ncjEzK z4=*dNeoyvva(FN1XA>Y<7b!d_hcXP{rdv@K+01ij{LuW}OYcU;>maHl^7*H7zTo4P zSu_7LLYSQYTMy-jG{cSCs4LxNBR2bXGV-FWLEQwuH-^7);&^>-9oT%M4MM_0(H~sY z!(#R~dZN8|F6W~O-+X?fRUlh~aJJE{@q%!Dbm#rFpfLK&>U%*zLITzX$1_u)>g&`p zW2OON6}fkaWIwU>E^?#r>{u~XxR|=czQqt@knyJToY<1eAo(6lS$j{zz@HxmOH($J zr*5K#gs(ndf%+mlmV3PHrSVg*&?u0)VPqt`afxs+RftrsyPa!L=XSq1_ik~oB#aju zJ^Az*Z6|9Rx_aK=Wv)uQk|&Ea4x1NH&4MM9tm4dm~n(YmgMbltZnS z8gob4U*kTyx`3A@>}t`j^#1n2q5SXXAF1!t_j1u$1b!dgyAJnMzF+T_6P9u#pc~2% z=xv7$*Q&U^%Gh}!x{E#Z#}smJQLXj2J3C&ea^J45oh>);E;3p<$A5p=A=G%S;<5hN zO~zNFQLY(ip;e*ne!rCwX z8S*?;S?g+hc#P=Hf0`<>+3{aY&HkkIE79_d0Pk2E?&&RysY;|;WM9kBrcYddFJtf*s(Ohxe|FwL=s;{ha<_v zZXx0J>HOx}+4?A0>8xFB$Fc$ch<)yPOAiT$Q&3xTwC_J z=yoXP@N(y!7)3zMca*+(b-8CYJufxc-X_>5(Y+s-uvyr$le*8xDIq3X? z&I?N2?}asg`!ITmv!!obKlf?NCed2RsTIkTk7o0DV@C!Ag;G+jlN(L1?NPzDHo0DC z{z3UFJ{n3*l=Jhc*1fg7bvypZ5bc>?cA^WZ=eLNv5C0l!Gf&F4cC|zIm{N4- zm>p%J5;_J_gS)z8e!0SR_M%*N=P8PEoeDJ4F&~$AJncMv1g+Y(PKvQ;vV^x?%GVOj z2UB_MSANMP_MURf;WaAkUW!PBT|)CC)8Mfh#0YLA8KycC(r{fqNNLxzj77ef51Lt(kK$!To~XGuy^&^-CN(}h5s&AOM;(kVu?*3kGbUPl-;-)bR4E290r07?pEhKaNa6R}# z@Xjeol~JvwNEln;i-0pU1!AumznrkaWmN$@U%6%}&Ns}T*Rv6Yus{%fnyu0ZC}~R_ zxpVXjAF-vP8Hm=sz^ot_@M^kwusHQ_jB{8*dv$?k8uRdKb?u)2uVG*!|Te$~V ztv=)S{Ft`O9VJK14nPYic=vLqG$1%4^gJ;A19M&k>ltLf1dEpzlvsU8EaW9eD^2+R=u;>{zgz& zll&A>DwM%aX(p5VQ;o$)fA%=&v47-Yo2?$hV?6p=J*4X2wjtwo`Il-*qXktv`SI8< zcbRTcUgL`3l0&|ZiU^82AM4vgZ#ZH>viO`8dEU{ay$Kyh8c61Fjf!8PthT$dpM4Ao zbjvHy^;>=Jys2Sp8bGmCcM!c-SWBi-yDton-ydK9yJmf8Fiyw+Ej(B^4mVEDC@P=A zHU#ot_m5K9%(EBcAH6Nau-#9`7B;+?Clnz2L*VO zH@*(u$Z<=@wh=8g+S3Cs#8_g2m&zor0?Q6*NI_p7mmb5J&(_aK?wcl2Iqh1$Hffzu z42?(Pt}s7Q|0fGzc)2x=enZQuoZn%KKm1u>)-?X9)0sv0x7AYpI1uxooo%$9v^aJg z$+`-DD4sdFJd&udvOj6r7kQLHQ!UdT_q+&}duW%`)6%K?F!1?xjn`2Wtr!D&(BH*o zD2vvk*Q4ur>Aj`_rCR0s7>zMlhyGs&@Or&xmCD-Rp|v~s-WH(sBUI;O^E zY?{BQJy%LGIK7x?5kjQ6w69K~D}1{5sW#asc^tLO^_E+f?UKZ+I+4tdIo=umV&PKX zg?NQ>}N_lSOs*C{Q_vVssjD5p28e%$*t@hz9`!F=h4PFZz1rXhBvYhaVVo9y@J z&w8~!T}shxj(nNYGkxZ@A!1GQ>ysVb&Cz1h*g-|>^GGs7-8Cvw z>u{YJw4qPQ@beSmPzCInb{s{cg3PGMODi*d`M@pm>iKlJexq8kV)h&T4;RzikadrhB-4`b;D3rqrFoYu(g{b$;(W*dx?<^Gza+)d8N!@NB)erXu?6| z!{@PwFJ10^uPm+;r7yNd4rzG@2DO+JRFgxxl{g7EOnXrxzvhx}wXvdV70G`--&V9u z*$ydvMI${@Mk^>+c|{L0*674H;RSO#6#pCzQ?RthBeAKeOmXCnA392 zZS%Pm<73@;o8c!fE4ciARJuvJExV{x=CVf`uVW$x`E)GG6~nhV%;by#aL71W0`75m zQV(hTSOP^di3R!(zvD80i3+$+H*`hfCfmv5v_GJZx#cwd>#Jcv8)^VWWp(Sa{54wZ zpv!pQiOyfA(q#5}ah=F1AiA`ycW!$)*Lw$3B$-`IB9-|AvDYyrQ@A8nbZse5+b7Aj zCC0JeS&#_9rJL1ZUeiBROFzd-glTh_!-NTSf5gfkOfklj^Tj2)@WRyDt8%8zfQg;DUGcvGTU3}J|} zosGfD!}dSr!Jn_Tr0V89K0LW<<9Tc#mQaXs+qmsFBw)6jq9y;Pl%w`TzN+oc_1v>J zE@urwdu=;C9fz^0!O&)kUFjA?P3Do=Jj8)fqevjJyUMLKjSm56K zXH-`mAH_)6uUfCF{fN=t%Yy~X)---bwI@^AyqXV6nl#fQ&I?OHAjOGY_3qf-zdrU* zc(#*j70#uXPk{*jb(+ppTHEW1!+i)pv5Y5u61uTslRh$NZjR5%b1}X*Z(ezX$WG9n z_)abFL1DnJJm^+54?a~gO}`dQc^g}}TW9}<_Pw~hq3>q5k(8XhK+D-gdIi19$r9lw z&&{6Uol%~irxN{&h4e(+nTq*{ZCW2lVfi7Ue-qM;$=l~^X}}0^XypS)w0>$}qn^ym z1RQ!P!pBL0YQ6sEYVY1JYp#k??glF?voYq#@Dr!wUv;O1tcU^bD%Bk5HaXw7M!Y}u z8$3!x^B=p*{z3vV^Cjy>PC(ckc58iT*ll0^!R_607GhtVblJXMtnd_F4fQioZY!q` zu^Dl>;R*E#F9ItXC$H}2ia2(&Ck{|Zj_cp!YUn~d3dq!OLsLh+1wA)+pLyQ0*fsHP z!Fx5&W4_}c_V!UBqBSlEId*e+V5gxatkvK-T553RwC14P_(qZ;C`}VFb~LH>_0*EZ zUPR!g<155omPqf9)AmHS!}nn``9FjaUjk%*X?4a}4(Gsgo4UNZ72zj-(t)BMJF9u^!%l=a`7;QX1vjj#)%m@mP8@}Sd{heK<%!7>Qsu`w$}c|0f;Glr z1ohkp60-Mh@Z+1E>W8|S2T20aL^W@VUc1+Ox zdXA9Q)RFEyw$U_%CL9XR?&z9kHu&(=mkvG<;ss6lxl|d&GLV<@^Ww{FU?*byZ|hZY zCdFm$+D0&(|MN3NygGx73&weuj68E}Z#-qI+tES}IUAx%dybHI%hR>4uO6rqDuq%dGV8HC zD^@E_f1+UC+AehY7&LonJb4oddN_ol;7|EVn{|Y{uXtL139bD!d;NF*qWNZpl+Vd5 zVK?=a3ia*43pKyXUO+o$%QNUiq6t|?+5raa=FlPN zZ*3dAt`3^LZ+>_O$BR6B%vYN;4OmV8&;Z3h1)>^(#%R`;K-C&r@GhF;f$n{(UZqiB zbyN1usz0Sb2E77_$Nk^=8oV4~-v;G;aa;yP`Ls9s;Gf&^67tKw8wRED$0;GgtayHy>>LR z#D1o1UYgQ3WdB>Pq5o4YAGxmNZZh5b>n>cSyrG8EU`*k*?Go)O>K3I!so2UWm&h4) z2cow&bEfe^QWfd3;O_4Xrkwz+e6ZTu>i84;2D}-U<3^WWX2qqBlF$`ixmq^At7?%9 zw7%V3rC3_7i2rjap+Vj*Sc}^TY#NvRT{fZhiXDB1w@_9go`(yyhZmzFlvE#H?sjwE ze`e~ou^dcAe>Xkbop5=)yg0?E-@wInzny0IFA8>sGF%U5rnjZzDZ1H>od!}_8qEg@ z^!FIwUhIw*n<5c)M2-fDc8sKO28PQ!>%A2e%Awao7!)rh(-jDox3^S7?F{< z3>ZgX2L!v-a~+MLAB2R3Q5$C|;z3C?1Hk_sZrgch$a=L!$b`rH+6FHA^Q2nLcd8Pd z8jG)s^&-p+KD~5gY2OyWFJ03AP-mwPDuYRPl(`%)fRNmHo$SnGU@ix~Yk~k!uQ=kb z+)-vKt}$qiOfWO^| z+By&cOh}b8$_AS~vDis5JSnmx9H^GPKUc6p1i)DnbtDnYc6neV}~C6A~%`ssHOtZo}! zk$|~PPE$#Q?HzIqfpt+xXA5+`OJ)Dz9oc6SY9jP29S6DqO&)~{VbH`nV}Q`mC$XY3 zN;~Z8aJJCG=kLr<(%`zt_j$EEOl4#ELf95Oblujoa znTb*m*i#zG;v=8!=E}GKG*ebZIN@1j7(az8n@s<%^9+^O!ljJeB_LldwZ`Z%5$tvS z7N3j=SmSP!HAdx#r~+84&{kvqHGA=(tT`Zzg&+Rb-15eq+qc~9WLV~`Lz%bD?-X+viaiGH|5^5JenCA>!!A^Ym@zMeI=F0Hw!UA@hPTCG9p>mz!-(7! zwX9w^AW!F$&?7V~!qg9q_qm~%LG}V(mwRByTNv`4r%b^!2o8Cn_S5dX63x&rTmd(m z@^{yPZpvC)D3;E9WBKwUZGo^QoPgGcVRFM^3DOJ=rm?F6yBh;R?VdN{^ z66zrxp$a?W@kxf^DZeF%gw>-rBl%#Ch6QI9FBWj+%H1{oJ<32_K$%5QNDbs`SItl< zUVX&ffrXqvB(LlCtO%ckrw+LNcp0jWKq}Q#CX*0XzV}yv!XF$`Q#N2Jm>!%#T}ju^ z+Z_m^qksv_#j+B6)CxSy~Y@1xb zZHra)&^{gG_DceUA$1Mo&KWO<&l$lG!7fziRtBE;4UuY_x20y4cLE;lE^B@W3Q0PF zuP849P2Pv+E-9VCqxdxB<4UPY*#gPP6z+FeSi+glsqdtf9naTkINzBMq@2yZZv4Bx zO5BJ(zL~%0w85<3SG~bo8W3bjVixPbGEP5<`17S6Q!){a>^>m#EN7}&(o6>0uuY*r zhQhzfPconZPP|+0&{WL|DtJvYBmM)HPR{$ZH}jqP{vSS)Y&BHI>yzX$6?iSvw}-xw zv>um;lzZv_PZp4+^y`i5!PNEP$3#_wY!}$vu^KYYz2AZLWk{4UY<`a(l31`2tO1T~ zj@+)5GI5DG^_k+qP@QPi774h~bAM1B_4X&4JTES#VaN(d$*ezULI-*ot)@GWbIo5s z?)d^pp6#Bk$$#I>SEc0cCj4L(O*y=~39%Nv;*jazG zObXsgAd#&-^cbP-9INnPEKey{IOOJ@s5CkkAEMAFZ!(vth$c*V#(FD5FuBSWoRtuv zSVrE3L1cE!pMi59e8lk_A%d0bybKcCr#pJ-JjA$jHp~VLMGmoK6pZIC1cARgxg|8o zFpP8kaZ*ND1n>N57s4CY;mKZQ+bI)#hMOc#AOCd$lK;L~RnQIsx`f0Wl729@;10@7 zd(6mXAZ$o}1-xoHm$(bD=%0cJtA}?qHsR1+N~Y>;Fwh$D6haQ=kJI5tGF3Qo>$n9~ zUHZK5VzQ*tm670m>0vJAz2@6(MFedxW4Un5g+PdU9LHd#ZIwlwV)tTp zK6rNI&Ut8lbF5BUa%{6kZ-xy?W`;cWO*pGGi2V-YYi}-aOph~2oMG3A zgbMIk_mKazC_f?TJmkSm-mAiD$|#Bmo9TwF%Ukq}Np+sSS! zF2p^9At=8c$i8Rr8j= zmH>^7!|V?d#^NvQPVIx~((nX!{%_(s?rS?E+0o_VxJ1ws%g}zaT}jTt0WpME*jD`U zW{5;!%ixSha<^%;vqHYwv(nNBIp(Fe?IwBjCUKfAxmpCod#y$AI)|P~*6*|ZfjyFA z(^j2*6(&?)*$LJShQHG*xwe~C#u4!qkq*>W-~)UglrcGid@&BvbM2~_|6_Ng+Zc2R z+2QajwsRzWV)ub6I4rmkn#XQ^*hfYw!k9I7vIx`lj?f{Z&pPhDusxT<|GuhR=@O=ZejI5MKXK;Jt$W2Sg*oim-86|Qx#@g8E6|?3f^F4ITme=hE ztXHx9B#u11WIhHU5W}yB6?0>tWed4^%clDh2;A=Kv2)6NmW{UJ4I_ri;ih4)Qt2&G zE5^}rNSTzd=%-rM*6JvQ68;ueJST}XMn@j-jeHx;J0QGyB=w>qFPN6By zb^{NscC{H6hSU`*rXjTLV+?85I5J^^r=nBJKq`1TETkZWqSH3vYJ7&_M;`?U7F;~y zj2adaTq0CXkf754UeWwlO6Pxm9@5cB3lc;#XznE=aWnt{ZJG85%X2tep*55Id!ks$ z@VAZ5#nE`7bQ+7U8&C}}@F*#-R672uw|bmyfc^(Ol?+B08{N?ivPoM@f1JTEoGboG z#O?1K&^DkW0^ zkL`kF@O9N*ug#e46F=mB$FHqS6l)TTU5SdBxlF6VfKlz6pu<{#A8&O#DAp<`@);a- z3YjjT9o27e8OL0|f4W%(qQP^2f=(THe#$BPT%RBBD1^M)2vaBpJu1C#j;Aou(X&PT zTdXg(`jhX)?icIqbA^5RhY!w6wJPFBxaCCJ?SSdwl4+8B&+^0RbO1E$kZD>Pvkpv} z7_NG~+YyO;(d*t=(zHPZ@XHNbe0<2>+NA#p5ydjaW>;DVhLN8iYMC^C;DyaTNkx_E z)ExBw1rv`(|Ci@~O)XF^r|X@=rrC~&QXt;}`xTIDF{C`@K=IvEWxR_fKu1OnRD%&b z{-#}J@>;X(yLt&u@0{C3mX*2C&$%bjW5D#|YNE-0Am4Yx{(AxpUScarmz_LBH#G(%IQ* zts?@f3rjuchd7q-hIVu8kFzCS4l3hInJ)n@%EqF6N` zRG@LuS%Loh@+k6cI$!)^XP9Ooob{Fc;%^p<3RkA&xD*nVuQH|c4N zNN|{MsqZ3gWY~hLo0+GeM_o33XGVDmQbZvMxqPT_Fo^%1IQ_ponz(xwegf{YpfVwl zFsvuPJ#9pz;4?Mdtat-x@NZ9)c;23_+qXXbRxeRy>e>8a-y)mNW}L}o?R9f(>)%%^ z@^Ae$eyCp;4-(m|w)leE>9wF$rhNw5-meN@W>z^NsjP<2ySe@gxuLtrHL9S4{Q3m) z6yos^*bHy<>JuPhK|s&46Y%F9)7@Vm=@v*L_g*wEA+cGHBXPQUuY&=|{qw^KXDnvV zrYHCTB6g*~T3I9G)3tU$J0^OoOuFy)3ga&)anS)Tx%oR^2qy=`m@&9{WIjOj-OJ7d zvRe$Lx4t|tUX*4FxEHkTv(PGLc^piYAW?7Z>3D)r62z)GAL##yTifI zuT&ZbKY7Nkfpl@N6W`#=!b8YvFm)1;#}OLA`+F*Dqk^oO)1_L2%l>U? ztBDm_LPpiBw1!n`&#<&jw(v@wJ>~ZG=Y~&~+L^(KmLN>TTHU-v77ClM0?kpjE;`pon3Xq)K)Z4s*-A>jC+T+MC@D8%&9KmeoXdW zp1XJMbL~um({LvDS*5%J3tBz?X_+TuWU8BFwm9=E>dS|d*2V3~HZ`vkhJqt17*MIC zM0J)y>k|(W-(V^Wm~K7(wp|1l-62l!MlW4#9|5ocCyx{feU~~j-LUI@<2ERrUv<8VE$RwtkB;PJ0k&j%cfO4c z9{~Xsj%<@I_FoX;N5{V_@21O`jir=RkO0g0X&=abmb?TuR}i_cigr;6nEO&$NZ%k}O9Q2D=&=spGBH~7ai)ye`Q2r{)&Li2 z9%l?T&LaqaO7Fky!cP3rBSrb*Lr^M7mON;upR|KOiY$ma0tUkjxf;mZ z?C*yR;>h?Mpm{@EYHb&1VwNRQ05+9y3d0~@C|1hlFdx{<^l-RDzag$NrZDh-a&39K zKdeY}yA5imKHx$fTq|sTJRd|V-hZpUk!s-Tk8K+%RW^(%^7tPuo)u3KAYt??H03*O z#z&vKS3xUaULdq+7Nk5fUt?K#AzA76DMtI#Dp9`lOrl5J?nw4xo>=g5qr1p?A58?S z-vdLg54eVuw&h!Zb@O5OVz@zdCPD-i>Uge-ra%Ijus~;Y1XB1btZzf65DJyq0c9q* zN#DuTu}}5R_ZgH)s=jg2mK7Wl1=IkNMjk6xxNI+5euJwz5?9vbsS8dxYf5-JEBu; zm<`<++J2a_@4Gfoctq5kS>k-^(Q*>)Wi*A~N*Wb2twRi&pRN}YcaT-H6i18X3sD~%)8{{wA zH(#aNL1SP3MPmTjK%-d8mHbWA>%bicv`?ax>drAp(NPY2brx%}xbeU2mPztUG=FAR zuasfm%Da9G`%e}y?Mj5Djn)~#PbEal%Gkxa>D2eDyi?ui$tB#?05>|SUqejvLM9=5 zJX%pT^5ZMg-G;_|!(WAB!+=`8Iz)%!Rg;W6o^P{q9^zkMg;U!k*()j6C?#Mi^macg zwv!BJ06=RxHCPls%6MfdJAZ-HzA1k+G~eO=?-3lVK5lBe@_uou1lDbOL{xQ%X79pI ztt?V;@QAir-Q|jzpK1JJg_m5N&*4b370ELo?O_6mpSevcvp(q zR1j6#@-GAR{Ful@2CJcPA$}$enNTrCL1CnX&L7!K&0*gxwGapurV+La6tlka{P}IMaY_j-l06>O`gs(IID{haj>_9MEt{-lC$+e zaOHa0q^4b|=^PvwcB&qL9!3aYDIZ`3I;S3stcO*{#2}ySM;5Pq#JX_`Cz?fYzXbCb zDJ;hnE6#UOctgP>$&OSz7oaBa_VdS@><|+!TwEu#ju0jAo~B)$&Y}w-)uz-+4Uwi! z3X$fpOnT~xXJZ#(z)3#@K3GFx3O`*=7J2kZJ5Y;-%kuE^cOG!6#KhTcPB$9T;~4#Q zGa}lfNGc>{NGfo|CtI2*Jr+1Vnv_#PMvDK_b7c8W$kYb?Jf$m22LFO$YnhykErt`L zsd@!b0w>3Zsuzo;iYyTZH|iu$4HIk}0ouSmY!e>`X=^x%kS_s;fez|G)2%jZ*q~w{ z8Bp(<;9x6DLdS&%0GocOTjH%GHMu2rnQHR=Z30}X8C}X}`YF~vqn-o={bW3nf)XJ! zrL{{Of!nBM}d< zwmwc==#ARV1=58KDzkh`+dt1j=Q%CtM`fFqRFXkjaGLd7fEJ)J`p}?lSkzI&DTyo3 zyH0gXzlihjzrHcZ(31yip+oiEqa;HnC zTiHT-K|8!5L(2p>;d@l#V}3W-4%{6oCs}Ba_C$D{Zs&Zd;R8jN$2*O_Ukk5^OlQ1c zP~WW}211-5@|$l0?(P5MIlQia>iq>aC+Key9ul1JZG2MD%7eqI1Hj4o65$AH$$GP3 zj+G*My0+0Og94h)*F34yzFq5`;ltjgu$|7iS)!*9DvlzfRl>gEA~1zHa5~=JTZNzJ z`3}EQ)`L#Lq+D+^U+w#F&3Gt<;l9k*%~jgI4UTFwgXI43EO_(#-3ZSBw0vZzxDJfQ{_#VO5IfyQJ1XXSO7<+#M9CTqeXiC37 zwvEma7+R>a_rLzDa~v2R7BOBeuv4=|! zTW~>$XxKFH&8(+=i8P>1e`ig|teqg@?>Cxh)$+U!DKd&1OkupZUbJ`L8(RmHOME8v zu`kog);1o2Fz`Kb5u zdZo@V^o;@6Mi7`5uB!pMf^XQiYWLn>V8}t1SJ?NSD>4kUvGDVmyE%N5JWE(fX@Twp zsBkZoK-IQ88$#q01>EiC@}*))0x5I$SIVRgM)c8RL){%VU%-G{U;IH5E+v6gvKhqK z!Ft_rFh2kl2+mo~mGpO_;#>gaGul(1glL2Ol_NxIjo4 zEKa@WAwdWh4h4bYR303RSd4T>2r?vu_x{KcoSN(M*y9=OSvLqaBY=m24nTpx-DUru zx?aS(WZD-5)}fnAnQo;-Lq1LjYpJ~WI{@Vi=_PVy zfOOD7UFG&xnf8A8ZIc1uB|ufYfO-NG$Str0ObhiC$tHtpY%YR?gHHPP?{sNe6cR{V zgHHaJmSHS#+UCehSXW}S|9(DnS80nk&UNEsa2s%W{Fdj}2t0tK)Di)y@3P*+K* zNO#Hn;}VO^mnW+tfGjQ^=K%!J&NBfrtYS8QNkkstyfo5r>Myo7z$pTFEEzDY&C1da^1MgV=SzUm^ z=YmB2Eb}mZ;!gf?||U${NbPpRt6NZPs@El@Tkh9zA;ok4O{&Hy#dV> zVcT+>UYm5oFt7vIO?_AK1ULd%K)`;9ZH?klsdrchE*YV-E?kf^$3qF<=!r%Ew};r> zKZ#Uu;Iz~M2#*jLE4w^{C4Hs-eGGujsiR%Ftj;OZE#kh$lNM5{amxR0>Ih?D0qAe3 z-tl64F#NnN$Lp=2cgJ@9<@xrYaWgnw$YnJq>fX6J)Yb}2CW<+Np6x;K`)&avx21Q3 ztgXt=V-lFg(=;Dp0oJxJeFvM&qrO#NiOCgVM6<_h9Q|@CH->wdNUK$;*$RwDoZg zGl_f(!TslJv#R^{#;MdSOPF_(J zetiV>7#w>7W`_O&cHlEGzo8w5FRN!20e=Xvzad!IBTs#!%EHn=dBg{VFO z!3%=8LODOkz~T~%0ZVuTCxYX-$u7ZFoSL0pMih)5#zo16I1&IqVZ&l#!`kXuCME(N zyUpWs07Ixs0Bhr*BLfwkg!pO}mnimq%{6PwEwxD%5SpMY-F_jKl6;65Q4)DlFIFV) zOH}bzOl!>q#}jRULNNK~LP-ty>XlY|c|{sE2;YYZIC;AW_&K2DYCBx~e= zy9Q96$~d42YJRt;#*#1v#mNaLz-ePmdG)-7p$)3q^H+}755Va&aSmKYz{}Omc<-ba zH1l1aO!Cw5dfTSV8lZQEp4*>6Pj!zgxOD*xCq|Wp((zIg0FH}OnehO`4NNXn2z|~# zTDy=$RCPjJFr7E-W0fh3%)#kEuJ<%92Fsk1ozF7&v0OB=@F;l7sd*A8NP*R~G2rNHq1Hu^k;MVDYhk}4yuEiKq3gVp1Mj>;wAc{-ngKZ33MzJMzf z-iUq0=R#qKJ8i~5h`cj5#6$;~02y0)KII)(87^WO*C+X4AeL0>>JsUFuBNpBTZvUN zJAuOKkF1Bf7ALXHNR;tkzWy8ejH1(S=K#fRh5DC|Q~4us0J*9wtphhuf*@Mq!v}!( zhXD^01jJ=Q6L3a~VaMF)0b{>?&`NNV!4|cjv^>OZTIP5nY>Sz}#>_%_$HAHI^6eZb zv&cpKxhRW4Vn6yW31Aj`{y-FrGLHFAjMT!4g5CdQ0lC4T*9JI>lGw;eS-cGU6Lk1F z{u_$yUl$zTG!U`J$Pfq+tO0;GiBt+4;av9#6&eMAjAN*QhKP-E>)k(F$S>V>C=Aq~ z;@&tm4-|@{$rJ)M{w9ZYasB}G!i3uh@$$aySG|L4G&m8_1JKRqdW9fkjK3bXx}_ib z(O?;YpekyhqB4vGb$$#`OZm5IIB`r^NJ_5XeaVxgM~M9}&W0bNGvAU8cu6S^0l~K~ z9j{HBUHNQ3j&5YTuiPEgt!g8ulI12Rfl(VoYOKboUQ%t*GfNkaut&=smWsC6h*V`CIO*_1xnMC7tjdG~G`LNv?aQ(= z$hOe!#VK)f=7`%d^xnQwWj%g=dQce$10Oc3d);)TK;sFckDTwGIm~5hv5}S9JI8|~ zfC26+YNCY>p#X`v3P}(e#$Q@h)lnp%tr(KH&WJ@4iufi;q$Y?k^&$5Uc(m2fJCWSB(oJMnQ zOCyub3ALZjxE`;+2?OuQcw%d!s{f;jA&FA^q;QIR|7qn8!dvSF2W+rTAnG2}{Lqf9Sm;FogK*8*7M(r=awKAKr~D%@6!fWL zgXk!Qvg1&*NHx~NIBHZpZuybQl-f+>3Bi2MJ8YXoaAm~A=trhtsH?9-j5SPnsS}R8 zQ%)7TCt2ubS5+>FYk_})!mm^$$86+d+VNq@#>wK@Yomg3G$Y^JWjY4CwXc7k z|M3eRYn%FkPp^L9KFvhWZ0LwQGIKm-sqX_+9%;xizoQI~4CP*6r`iYP&sQ}V_*_KU zii*|{`<^eSaL@3*c`p|Fzm!I7@;V2iVwB(Z!4G%w9&$l%(*|f@Wjmtg>@bq4+S((@ z7}K5O4aiX+^o;v3)q5ZRk*eGUXW~!wPKh0fB7=GB-HWi$Bc+lGwDnD>RGF=Wq49-r z{OYT1sui0#-p0gWRH0So(&icoXMw-aA^F8!;ngi{3FEgUW}(U6f+U`xm`V#52?kbd z>7zpvL>Z(+b@1m1}+UD!l1i{FNo(wO@RUy=DR z9485pI=eJ-9%?tsxD||r`p|C*uuRlt-l24j{!;puEs9|I*_@s&_=h%;u=p+(8=*K~ ztzm$SSer6z9feC$JbuT2qwTGus%*Pc1DoClcbcqtu-KC_cgt|xp z1*KFJGew5tjM_|@f&+#?A zAG!ND?VP^ZTuD`1a%nc7e9ivj7D7>Ck_E+Z`B@{DY}RWU1KP#3xPe{eAdmY4+DB&CfRZgyll~DCv-*%1behB{HNJJetfjJ6CWuKA7~JUmlJ^O+-Y^qYcB=a*jQ~MSc%` z7%R8an*8bmtT~eN#xu92A82Y>MsyAk5vcj!8GT+I`d};$;7Fybl^Y6v$Eqz}lLf}P z--7-G4#a(O7#J$hQI;2eXWkH+_wVq?qfK|?y8WM-(;E;u zB#@2OZcDcZr6CpuqhD*(6THYF&Hs(J@ft7@cmta_3s6I@ zP1Z{9K^+V;NatTNKHIs0*N*nr$6zvbyS(}oS{i`K`?bCs)%sqo?R3W@lif`$W6r&5 zUXQU;e+cvJdYfLv1>it%sa85c%362~&)<%qDJAp51_6@ z%v>cSy4Ie4wJLZsh}P;z(+{`J3f+pdiKBLBZ7(l8$NPOuw0@HeuFN3G(SShB$Z3V@DD+9I`Tgg zByGa~5G2g+BLp+evXuWKNT%!`{&#{z(&#UOWbw13HKUXlDz?#$ZGlBX5cILmM7Aa< z*SE|vaW9cKKUCrOuY}nujCGmI6=)Rd3VO=99755?1}1F`RJG3`zfqjxy`l2b8yczk z-4siJi?Ddre{6CgJR;hm;0}VRB!WJk`+?=U?9^Bi^zx5iF5bmKrpo$V^H?>mpQ978 zj`q0_r9du<#yNie6!eW?Y8O28JEHyX^vDL&f1^i2iEL!Kp`%TL25<%!alr5H-=IIf z$a>X0y*r5mkD{S5f+$Aujtgsay%+wb)DEZ7qQEo+y5Hyr+rkGx_9d_=$GKk<>XUo4D?J#r@+h85gGzpOEtm{?WS zlh|>P(Y*73kE96ygOBuq92dkfYup$GjqD}$#9(AE%U_@C;>Eaey+L|rwnUCye|srO zEU(8Qo%RlQkdsVoiHsqO+1nakpe@$Jdd0r;tMV_1gu3_t3PkcZfWrRestYs|HC`K@ z)Zb1}HRxvA*tynb>X$bVB;b9R`8<4IPndZMx)=~~q4OVxp9SW6!Xse?dfCFeh5MUL zWG982z={Cn;j%GVdlzm*_z7r}e+D!_i_)K`=_ptQO&bWpVEzz>bTBX-;QR^p4+?D_ z0mb!!p#SkozS~0Q9$E%ZfMxJIKoX#7SJ@jFq}o-T?ZN~)57r!z(^sd${3gez(C!M* zmH$u##H8le4|10Xd2ddGhjzuv_B1C!u0P?j1eh!(y;(i;uGh(qE91Gdux=uRk!ZzWJQT6=Dv878d!aK~q0~UJzdH($}iG zmgsamoU`B2srkJiBLoP!FZTky_MG3a-@gT`$h3yWE(=!UBBwl!G~)F~6V(^kT4Qsy zHg?2l&k}#a+KaXYLG}_q@}tY?p{r4_Tv9o}I6!z&bO6gx@Mc5uGTaZx1o5AGehoAN zgbbDJ8<5S7E1clMUWYG=E)BGK1S+x&Nsji#7`11}*9lblABo_m;a()oQ#IT`ZmxB) z5k+$>R3iw@BdxCW^WfT<0mc`0l=wD-L&fU7uOxy!G( z(D?$?yYHZt@qTwIM}V*5r&jae!1vF)IbwS}`x{d|%_4ppWoIoiD7mqv@Hxd=n}b1p8z+lFz4V@C83 z>mFnPTqDN~r>MtnQfMiGpUIqJg-_W^^CHJy8fN4v2v5SI{Fkl~KLx+hgO?ZyO_dI$ zX%_pbs{V|5E#GvJqCJ-+zRNn}?i>ER)Wyl9VA(CInWUgXdeA0Ad^K2Cg*JP=gB_N? z+bIG}p4d^IAhfj)fbf_g;knXp15h3yd#!U!BG&4#d3Et>&%sc}g%)j5`dS`%j3WvL z4@1z+;B5wU?!C$bz)0t#iKIq>q}T3pAKeqhFkDxHmv*q_fLwAk`&5t>rzk3r*t#|L z;!^i3HRa z?NxiHjnZQ?aZj%v$K3l0&l7OG+pu~LMlub2kxyM%)qUUx`YCKA`i~X>b1)HWo7y!Z zC#8^y0M9OhN9Y2;h2;@_!kaB!CCLY^YI#hUnIe9?wm?yc(>r z!hCP($81$>)TgWp9m?~q2Y>{R4Utt+w&b7ez1b<=7c3BgGN{h3YHUm zcZvN_?SS2>?18#q@&?j}V`P(qYBp6IyP&!20mx4)7q(cRhYOK0Tq}YxC^-Vr_E;H_ z*a+p0#O1%f(KzZ&BA4)GSt<*!@Ko2qNTpBTDFpbQ;%D8EQMfZa!Brml*mJoTGcxik z8 zqoctE(#nrzNZ}jh{8crg%c9-02?`cPmt{k!6LI;Ly|hX{Iq52>mSV#)b$1Ax*U&-b z11wA6{W)^$k&TLGrRgLqA=^)}=lOkOztdM&fG_G|vsI|Qy<*)9>?(^A4MDf-Pt@wv z1VNMCC3z6cKU8EGCQx;_T&GCQ-n|~6@TzmYRT#T1m^Ar(Jt0o^RE_uTTE_cnjSVh#MxR**d zzZyrzv*(8k`(V6)PQh;%oq4iHGpY9Yo%!ijD$4|(s!vHi z2i)9lMbQtK27GE_q2rOfLA65>F+4*c)pUm{!?ND>mL^Wnf)gu4r|xwgvTnP6ZCe8k zZkw*IS5@23FN$92y0VWQ)Zn(b!8hXMV!FOqKhZAgM88hOVYT`Eg>Xw?V&T2>7wpyK zk8*=W*9_0Wm6a`2Zr2mpFLY1h;l8uxBBO;!@k>Q~-M2U2CcsvR8s*>1@ZY|1CuK7W zCdRV9yS*1B?qLa%CKKtgCUHt91=mlo=44Gc*wlW+%4(RU@R~j`FN?P6l6GKxQ<@Qt zqRXEBiQkftj#mqFMp=BGYRy@I!VU>V4sS0cIg~7BA&nUd^K3Q(8J$r*SOLW5i zW}en%E#~Lh&v4f*$rl%993OnW9L*ZNkZGMqrn&*hITWirQD&v;hx#gEhgOxwfV1== z0cVLN+IY6m7}e}+bunGs`G<%(n?pl6HXTXVx4`79PJ9&$(HK=ymYN74b6XoU343IA zh?Dp(Ych@B`O$x-Hul11Cri>a8JWt6#O1=W3$dk8@%^qs@f(K0G#|KV-^NKY)xT0e z-F4YqEBCwIPEnc6gp8o~{=!52jiI|={3Tbav|#6~iu4_7jGrPjYGf;vGA-*`i;Owh zMLa(PKFX&xnCNBL>2X5tEaNn?9K3n)YRF13huq%lXALqgCkd_Nr9HPxMFi%8IE%iUm?WBwml{ zDw5L&xeYaK(5^=uy(6y?&O5=99ZFh8ttTAe;PX0EdC|S7+f!4`JNtNV`M`Ld#nez{xmWXt75b=<}HfIb7OKn zt;&N{A?4mjla5;Zo?>tsVdtR&$I4ejHofiO}KDmi&B|Ot}Rd0 zh*w~Md0fVQS$ppf-gq2L#4^H)x=cNH9FtCB{FDgCZAHb$Hm+8Fj&Gd${0jz}Yjx$H z!gk9}4u|{La-TW6uYJ8!zM3>iwWh#F>O$}f57)$^I z4i=2@f$^+7MPE9-T(qc9`R(|n~7;}q_rf~cB>VIjFOL&g>6=m6SjUZQc-(Do`_s9zoH)phx+GugY=AQss2RgS6s+3OA(2$EVm zB4Sx%qjCzIeklL+7K3z8Vv^*}Ype-7DGfINtb_Tqy8}6%Udo1E7gvbQ(1;3f^m!(K zHiz7wU6+JeW19GtZ?9Xb7N6IPHbophQ8n<=Yxu^Pm6hc#7yMc5mFrmy`JAQV%6ned zrx|4^ayNES9~ePc$)vixPZRz%GlUhyv`KAh+i@;IASzEP>x zLAKEGLHXfL_*Qb3#>;beK&-GV1rEjNlf90Oq{Qp*>pUM@CY-r6r#96D9C{xf;O_o` zUhWgIThnS(|zZxqbcr7+lr3CY!f$Vlj@Gy{(7Ukm*K z50~q zFwZjcUAYt)ONyod;#sabq;^*#+2<$oR(JywJz%(=X7MS$ZzimS5!18A_d$pq-gtJQ z@$@Q;;6jKhr*1eBXWXK~klHPP3BLx;BN2pD@S$t0y4ndT4<1N6%Ouf7yAYcpcQl_2 zOajkk13Jma^WszfIX~|XhmWN$17Z9HMtJ))sYOr`LMj1?&jN!Ay`1}H^H)DsWu#k@d8CZ%tcu%{T88~R zbB&j&!eyPH7~b`|=2a%Z;ey5$JmwtIlS1L zvr!}330 zrpTW!L}cGqe^qwv(==|*s)4PC-BToY;`LA0S;|*=63&c&wb`>$iTy^sVEXmjw%z*@ z;$G*kTkk&*Rt)W}i+%G@^Kq)IAg&honzcC`D_C{vb+gS>XT+;*NyPcw#-VNe{?5DI zWcq?gxA62Vq0VCha?0gz;mYCm4YisBwVosQL#1C|wOM)pMVNS~)@|@q*HuF`WG_Ca5!04Jx#yA< zgPXJs7{|nqGy3C@csd^I0+5+dB+>CxtiNR+9eymznEaMql!2XI-}B?${?tdDk&z|m zBIu#QDx!Kii!5HHtx^R=eRiZxwUA5s?x^wkqDkpw0v|hn}c~ zAOo(AiFstW^2N}PJGNa&vTN4JD5N5>UE)zVA`n}v6WJfc^1_q3K8%6OMuO?3eD_zy zHg_O`w@WCZ3uEB>&!4iY&FXB2B+*^Gq%yY6Tk}<{;;i)ED2GBw9vLD?NiF=H|3ZZc ziM=)6yeNq$7ZvUjljQCYurixv*w)oP@0b-AjsyLpQ0{$c%z=| zjN>dzBJ`-XF4?nFs#>|0toH=CVSG?v?2t?nQMp7%-((Tn9$rg-LlI#EeZ0hab5nbD z9n)K$D^AyF7$)=-o7}Nm@U^?$-16(<-g_ca(RnB{6q$5~M6oSfI|xee0+Jt+xMuRp zm$F@)2X;-Q`Rb{=G-pRUSZe;;8Vv=(c{dhUr?9c5nJQK8XiTHgH2 zec4WY#>h=4NC)>mkJ(B(JyQDS7Ke)^NBWyDUK~O);$D*%&TVmZ>pycH9#qKQ@l!?m zjfF<}y~?v%Z6)KFJ9A_snq99D@Np#1X(4%3tT;LY{F?ibrZiFaIhe4$x?x9Ybe0GnF z9JO*yQOhNtFO?xAY0RIOTm^@MD*{T8XG|p9qwoI+k{><_I>1L&IQz0wz7oU<c#s3dp|*0a^q$cv;u7*PqBx@ZvV2>{h{b*?yG}0l8L(ae-D#!mDO>%fEKb?3C3Hm zfD0_Hi6>WLVw0rCJ8!3p@!oL2ZCQ6b*uNQ6v%px)pt3aafp>UJe5Kr~n6v!B7rIsH zC9H-3h42kI7Z#iw*DK&$2XWYbI8Q*Mgke`j-EA`Im>5;J5*7)x686AU4qA0vr4Ms4@Hj}8Vr~PL~!CwF^Jb-2<`ff z3v`}IwYx*l5MYIllixbr6@yA*CL7y@Q9r@|d=V>PK>i{%J_K#~U?=m2#i&<#Q@QZ@j)b^_n@xS2*jI!*+gr*~!dp$%Fv$2RB=V@L0SGSv;WE z@ThO6Vn(BBtE?5gRwrYu_H{4iuE7KPO+>o_m-gZE_}*QA6C2PJwJDDV0o8WNuit^k zuBdY&r`#P*pPL8?Ik-uPI3VfUl#VF)+Ag#iDSGgoKBnu2!D@~B{&+Y;L*0{}T21nO z3vF*Hkg8f}H&Zb8hJD(8SYXRyRzpZ=+F z>T`3Socik()#`756m+D<&!*@*iY!3CqmuWPW<$|+nW3se4OL4gr@c+)*VcW9T%BD> z%B~*7cm){dD3I4C4!2$xjrQ8@AxDJ%$tTy1wrx%vCLv@tSI^~xRe<%cwcy|XtbbER z-bQ2&fN>Y%j>{{G+15C>^@TBkR`>Q*X`1q`P>I^+|qpgp@Yp}ReOFN8I3CIhb`(u_3b z!eyT)(qv8%6iSv6oVSp7AbBqJ$xarnIkq<&CqF+Uiz1yOYxGPo!fCP^hbuqJWW!g|8S0UGV?gH}mh`(%=6kFU`0z zQR&*`MrQL`!W9s}mWudoNC?=vfCu%YXatOu_lCJ%NM0w%hCvHs`*Yrbvm=Tp_X9X^ zefz>NUl?vBCIS%99OF9L(_f~RC8^zq__&ZbG7ZNm?2!}km6^*qaP~7rGqMj&K>dFW zNelLe-EQ%z%I|2UIKUEa!1aZ{qwNxFG{YgZ%pHw7!;t2M0xy?m$FoZmQVTG=hZZuN zlo=*&AX$I0@0*3<`OX0ytbvfGm2$?aE(TmHtoeNGhk(68^$ph0M}BM~JB>twBV^g3 zFb45IS+8JxEf+vv3L8!S6Ka?n?1SO<9gq1yo~HXWOsiMrU^7CG${x{xH7NrE>K=J% z=V@I0rumY8^qSczkfw{{5O=3W3j_Brc0EWifK0;5yr&P0bHAA|4iJ^F>ns3WS%A3d z0djd5i~kvf4FDGUIt(2z5EWHy^!bSmL|FWSzV0nEHB623pge``YO=ipt}XySzs*PhD*r^nr0V=xHA5nUKh?~6}*E7L071)I<{ZkX%S*Ukc3 zj0^n`442iQ=XHTbOFHUmE2$gI`@R)6u@p%~fGrt^OG*nV1JZ2dT%{B2oop%-tXI*~ zA3osJ^I((?ALZQ&7F*Z&5a2Mr0!_}Vn>%d;{d4wLpb!kM6Z58MH&}qhH$irv&eXCaOjWexJ8n0@gJnROV{VN?QNryO`lS_{T6NX#rB!HD!pCcAB`ub;p{idmo} zp!G0%V`r{r#8R@Skl}hFIT!(uI4@Y0ps%C&0yd@lv_CTBGvYl~`f(iE9AHI%j?~~P zNhI+mua+BtmuT^FE`}R9Qf32L(&macVV={aPp9rNMe!y^mD9OgFrGyoWw-;?4VZr+ zX^9CQIt_vhPYPjU$>Ib6_yk5=L1%mV_hy&-av2FY4JN}_CBmVQ>QnquDMFOwGt!EOhoK%G0{Ya~7#jmZxu^3vyA?p5c zB1klU*Em`|mQqmV9ZpeB%Dl2VV9|Qpu9w6{@)T9-*I3RqFqV6RN+}iy{8>cRs96}n z0X1_f?NmN61(2eL>7b*CL9-0AWe}E1|NINAepq)=J_79jFeV~F?syq?7jmkI z_9aNnizBJG@1qvUi9@7hUghIZ>U~+g5&h#VDUqkpM$qC?s&+uEi~T!xbF0S`2gCRM zG=o|=MLsZ^v!(Gq53lm9Akz{ZW`yzwZ$a@#BANY#o=~MBVtpKr8^rg3VS?|{oDuN+ z=#L`hl@|s>d@T@6?AdqP@zOK-8zZ;xDoi7nFJxD^KL!}bw`6w)maLz+-2D8p7PIuz zyqSJQ;wq}3NCrU?olRR>%y>X-XS(jTp__E> z^Hx-FouN{)h5w^M2&PLIn;pG-C*C?a&re$2bY-FSLSwyUzlDH@cuA!;gVlU$A&2B9 z>-kf=1%AV_%JIA|4F(fw2CUfD>oUU!A@xL2F}cyUcg{W7#K+i*7|&$Rxw^fxv>`l%VC6#l#Ws+nRMxlngj)1+HTJBpT5n8~*@ zYUC2&+$y}$5a?l3%Fxtht(fAqHj-4Q{-Lf^dfNFVU5)Lf2@ChJ@gi*&@$%;|5($fnDEnuQtg8=F&m=j!A5e)q!H%yi^-u}_*lh|cWoGyIo-y6oyds&tglYhM>BUWbb)a7og zXlJap8w$g|g3^%1G=}Jq&r|m7#>Y*Tz<*(CG3S#q#DC)b{s>@}mJQkyyIH^>r zErYIROdJk`>&lzr`>c*Y!*w9lHpLB2MZDOaUQhXC#OL@n+9~?0y&(=FNA;lOl$cSA zne2!Ef^*e+uhhehEAzLzocR>A7BAO4|E2f?AM=%n%@fiE$Oz13?xLRI=OFG%C~N=a z+Hw+ux3tAKVmz;`Hiwa1&?IRodM9E$1Zl=j?~SQr?vrWJ&Y+)|nua|@%-m;(iADa^ zzK3XqI(=V$OKmfmjmbmYUO(-}vH`&#d|t1yrUHyCZc467p>M)3qv&4rV#wnZzhHR% zD~QcCr|9dO?I~ko>He68B@Ww{3D&}4j5T$JmWKwn^hoMDcsfk&uh6IbqXj6g1$#Xz z`x1PfhKU4May{8o-};*x?;Wz~I) z9WH};yFut#Xx|VAUE*ght=kF+0?Y1peMN<4>O*|aNgZb<_e=sHphC(FImJKuT^Ea5 zO1NodF5KRbFkz-?8;s9*t(jk0_guHnX_`8*nya^*_L);NQRVMqBf4n7mu*yRr_W!$ za^NO-KM;syJt3k{&=qUHLzR?fe8H(#LQ)?kF-;daiHW7avB~jHPvE9_qJdFUZ8q;; zF?Vcgc_?Y1R9&J7Ysk%Qb7&=^!qamfscX2HHp;wdpTAdku1Woo{^*w6D$5S*LiiL9 zF{SdX-c$f9nFmOWwdoN`&>JVn?Vr#@RxxaU^NW-2M(ZI|px z>k{_|SLn>G@tf(e2yRD(rYQ$9e%KWv_+&lj)_n^f7(S~(P|&=(V)J3 z2WyL;^459i`QcNl4PHwoId?Iuyxmnr%))3xzhghxb6_rMV0RUZzZL?@Ww&rqB;5GI~x>;&HPi0;?ELM`Rt#G~789 za98hRGz3$O*9GsJIK4R~U2CHV>&-jwj(@_Rc}r^gK1HaYOic};#U}uSt;pyh(Ij~%?ATmgFcmIY|lnZzH)_SG(ImO^0;F-ECyQ0K0&bvt>$1XMjx zLpy?F^!4`&+snDozj~^ywcR?_x2M~O5Dh*@GO%f?%4i0g}>Q zxi62;PPe$u20XnDIMZRh?d)W=+!_1qcmNZh?9<*h^t7aCokctBoEKSLKIZ|2AEcEG zK@|l#LG2Nn(mbbs4xe8RnXXIVh)TF_o05ChfrU&E%KQpJNY&)>mQb8^{tAV%%h8mM zk`kn$3rb{aVNk(!zmcvO^*4fU<}93X9FK=fIg%JAh*7T4i@b-nx>nIzz2V#%vqz1t zvSN0Q9^%nQgVr;k?Si^rf_}GR^cxgjz*DsWAqc@!4Q5PX(2BZ{k-x1W^X>7^kgnem z1lX?3GdG=k{r)%qi%g5?K(vi&oLZNe#!50<=?|kCKQJS}xD-JTf}pBzsDCc{%t;I# zcATIDA^X1U7U-p*@a-@SvuKKBlJQ1|$2F5et!x7EW)Q3e$#%8&ee4Hc4A0i)z!Eek z;v(hYE?L1R@rF95Y@BMG9HsKF*TgNjqDJSkk?FNDxi!~TtY3@_49C2vvP}ejQuev} z51ruf3sneyP@;@B*E!7Mm%SLTauI8vxEY-T4au=#@OZ$W4<3Cu$F8W$9tSq+&r4mf z53|yLxqadnj)`glDX{AMG>?qiBJm6CiW?<~5J28Gbf7Lnq`*q9g1;>TEc`UK56q`o zU6lUEl=y$oPW+$$&Dz+b2RF{p5EC)DmD+^d$w9Jq6r~(6yzbefrgq z+5nUc4Uab3ox7-m4?U;}cpL#m-(KuC{_4F2z!;cpouKi99sK77SO~tr`~)5wQ~(bs zHUaRvwgmZJ=m4-?G|RZ3F9hjlU%)g6jfN)74ZzTI~ICkgj5d-yxDh z>cJq-S;-f8vVlSkuS}MydVOHhrYWn>;ntrPu@5B#O(QJEeF0pOkE`J6=f9^UBmhY( zngVWdewbkbsF(*DC-lFKo7HCD5`m8feZfr|a;D&V>q!&MhkmyyifjX#Cs0#)+L-8| z&48gNtUaPY?txF>dSl25Qq41DPD&Dw~SflLx$=VIQA9L{dP!Rk1c^q5{A2S(8psw$PR&5 z1Fq9Sv~EgBOtHKqLFqJdwF-VF^*08|V&@B@3atEKtC5ED_#5d)0eDfQO#Knybd++P zMKnYc;#*RAKY(E~*l-ziG+;e@fesGrP~o_Z$t7NYIV-$&5tfA{(7$hr7BBX#HsLoU+Zj-%Efse?hJ<$Rp z=MM$7!~WvRY2?PidJ4pEf*~sr9DMo(V!C{WI5iVt%3g_0SZ@l3$X5btg~IKfzA`c~ z1Up>#vw+FZ&5@3H(A{PWvXGmdhp0lN0=8#~8Ij`#DT@NQ*V_##Re1jVJ2#InmIXl; zu@GcYfSPUyd(lEVPg`c!gEEY3_XpttU;yP1ohq2d=@=RoC$j&0@M0)YeASB3Ao@%2H+4(GNV8*2ggLx zLWH2^Im^JRb{2de6zfg2&nuwKE!Sd;x$(RX7HJ8r&Q2z9hpQMChf4>ZN-UIMSSZ2p zL)}0-9(x-AMc&{02-R2onK{_a_#lJSQwc|mUp-tcEZ+Se0Q%I53A8CC$tPX(fckT! z8bmPm8F)$li=clum$r34%Bhwq*@J=~BTVvdc*seoXn1YBd|Y(GJ7Z5Y9-R$4Z}$VX za7?zpR<8f!Kf|IQkuXYouE9;q6afZX6zsyAL&nad71w~gJcLHud;Rn9omljq2cDHQ z2nE@Lp9KxiYr;wjz6a2>WKTDn&iPKEy@kVs$7{Tt;R^(*3@PDi>0#yq2t9~_ziz<_ z0^IRi_)yW|jv!tNpJE=Nj$)($^YMW#2zF%M2{pKvqG1ihA_AgX&SUkt90Z6C!4V9( zEbktWGc$j)>tVj6{Q$OhxVvVjo5B51akdWvsBxfQFJrx*!ZD!olDC@-Q>{LguGLLZxghQK4c zKVr3yr}3-723f)pdd!2C5~a(EM@#@XjhSO z1^TEn_*GSANZ6f$vum$l^H-R51^aF9y%r*W865LgGZmGj#@v9t&4`0bmLKdia0I%< z^g!RG$S`&70RdAKs>)b&0(K&%Z^-)j+*keq>_m?%5PfSWp5!1@cx z-w)m~)s}~|y^!lm=;I3&rr`?#IRDwS`uUB9|HZw-u?9cUaYT)<^p|>9-uRn*zxZqm zk`MJhPKmX|ib|(yyP-hP+tLIFR`Vt8To{z!eW#07kb|j@A<2;iI}I*DSW5m$a*W1W zV!zA}83C}ZKnezWvle?w4F|sa!mhZSU}uM(Q?dk|mcspHKL`6BEPv;JlkcSeknj95 z6Jd%jWd?TyqWn3eAS)Ri23&~RtXebp^6;XE7>B*f6-`xb>~s1v6DSnWt`6{{p(9K4 zGXgD@$kT0Tdf$RcjU$KH&`|J1NmiTKD}%{R=@n?Yvg2y64yBL#V^b(Q`;6s8*6}f3 zY(=J$EJyN!^NxXO(S4Sy+XT0Zn|5}!h=|GjZK~{T>ut&5iA#)HZP`L(Mfl}W-#$Q~ zVWEORFH0zxKt!q)Z6eKS%PBZiE4ecy6}NaSY|<1S5)jrs_{sP2*7y=Ljw776aQW=D zh14IoEeEu!!$k&`AOYkyS>mmlnkA?1N!iqtX`Q-nnSVR;T8M?%U=z=P!rm=3xe}@; z8hVy1o4cwweX4|qIF%_Qgv1d(mh9$21tbw&>0=b3mcnwIQty8|CBIc7h2#>9l%_WF zkkVGzupQxO5IB9k0qfx~%q>F6dtf8155}~X%{2ZCgAb<0au2(HeRsSx0rwv*;2$KO zPT?OUzWqs!Xf$;eOx%(iVf|1T;Y(lR2ozc>z~fJ#$C zYKz7uY-68NpWG6AzQ^fjBg;#hR{vyHnCpEo&AX?PXc7H3YG4oJ3O8PtmMRgbB;SU8j5v_6KS85Go2Q z9tC+fy3nTP$Lyz1i8IYy6sK3>2(#m;fsNl9rwb17A-{(k(>z#gmhsvBbwmxFH|Oy> zKR>5Z?AS{}qs=6f*u@R%$TTinf2aW=2If;Mc@Yk4m18h+ozfGEuSgP$6{X{7*oh2G@45 z=Z9KaspM{)mAi(PV1VlOT23Y-DwCYe?O;@vTN_D;e+9$f)-jnd8}6t5AJQAk&W216 zivy`rLP+IT7(QjQV0Br#3aBiiC`A_ys3W_sr%^?ARCwZbVshA`I)-!WV^@%y`gIYp z$Pym=Z+_I)LtP@H+(VdN2PN#NA^6<%Hr-QQ3eZKyB1MQh2k76wIGQduOf`g5|K3%l zhYQ);47q?#fc%X<>_+4A;8QBcKSL^N_{lz>iG}&}GXG)aZ*;I<3MYd`uNiBZm@)aO zc*}evwZ=s`ZdE}S@o3S{(jSV3@0QF1EROSyOaQku)`vSTM|7Wx;_9r1HO`pj%bRZD zIZJ~fRiBzKU-r7ilp3M)+hy>akP(j@zc~Upc}gx9_V`Fsu@&ItAEc3v4G8}yC!fL~ zU^MP9wT_wg)9Vx1G@Kqw(nOrk%~)9-J;h)pfQE75u~DK%UQ;03!Mrq|gw&iQq4%hp zC6kL6nd62NNuH3t-LDm9MV7+Y=jnOm#OgG9xmw|EGwC(AopaGikoDUN1?t=bAy!)M z^Tk|Qv~u}n?EaP^=JahA9F?Iqu31}H zHR_#?2|~74W`uGHD_Hb1 zrhCmax1Z-4q+aD34%FkoQ2%Q6+I9NH-ZLJqr=LR0{DneQ*>UD^rxdkpf}MIvFJks% zg7=sljnAiAB)Q0@F2nrvxTd1Bb0&EDlbe7{+`V!cZytVb$H@0oS8A>h{NTL$POCMw zi_wt4W+HOXx!a<3TEvt}9(~G?RFTk5NAIS0%!u%d<4e^>zSC_m78XKSim#fx!3nYl z<7k_Su>7vtz0j@*$&?NUNDr30-SZOc$_Z3$T}}KZjR6DPN~XZKmRsqhA}CwkV{B|b zc;p3tr(hGQtwf<})<{lAl?obkeS|huH__V&i_le-s zf}#yS9Ngb=F(qm=5?uCqF~KqoyhU$sB-xW+#FhJwp*k%Psk{s@J;%Yx#U5C2!}qtC z7`3MI!wE4dmE8$!b@~P`9b^l|S*LWJ;Jxrzdd6=XoD$%3JJ1{(I>$rL)>K2BYD=eMrAd%MjQExHf&0rHs*>~UuqtljU;(PZs+8!xw$GJ@6qJT zm(F;L!ehF4*?F-hA@U=wX#KC?%NQ>ew#Wua)XoOK8Bzv8)r$hH_|;OXrowyUyv zm1OM}mB(^74u#b91S#Jd3O1Lzd(LBTAaevNpFLqOF{o@m0c(u7w#}3qPU)IKl2@kM82B&L^P z$9-<9)K!6yx9K~L(qN0ci|GNA&fc4f({!(YL+@>OyNPAcjKyuRiBKrm!m8(}F!TbQMk0OLp zUoBe*7wf=gj zUzQjq!_(_0DH-4Jn=MV>_Pi+6cnua%A#FHd5wRNY8I3egA*!vNew+r;-JmGPtM z+!^@rN~-rE4sky&5|q&uNO~$FEU!FpPfw2~D!-|f+7E(t?Pep<$VHnm{iXZ#20v@9 z`cG|#YCU?Uj0Thi8k9KVwJ$Icl@#~M(6_U(o!=W3z~+mNd*#BCFZvchkY+69@hg~|Cgi1zo966vVV^gn{qQu8i3rO3Tj%E0XoZV8OBam1pSo0yO+tYp0Et$RT__0_vlfG)y z;e(BddN*!%7qVtyKdAs54)_e{rz85}_j??FzK@_Hee^E4=9a9NM!I5E1K~cbpdgFtmB1i-(FUawQA~ykt23uJR;DiWWFoIrp^A2WE4ON)RbM=N=;U8`Z=D}BN)MdV1 zbW{aB_44KKPg}i}o($w`Eg7GS5LH@xTc*b{;5*2H5B`bcKQjtv-4}b z$77O9!F7&Rc(W2Z6~OEd1aD3vv{Ti@RBkB;FNr*U;@6gYv^-gj$MEYQKRulX$s1m^ z7CD&4Wbl(y>hWA9L(9TavRU~OP0upU143(IRljS|_C zy{%;mx8lUw$FNM`^ z?n>1|4#*MXRs9+0p(~wAyZib?btK4R>0k+Sdh#KV^On>z%+X6or32(`o3Y1WU*TxP zwvY9>h3(z6v3u>eMtLAs;NXsK*|LnB7BRTaDdX*C-*eCsn5#g1|>bB2x(hKe4 zNugCtPme5pOO5PpH?^p~cqwyF%IZtHaGWDzR3(Ob`c$YwW0{`sy{4-z*T#M^(DN!z zsvW17Brj>ymg27U%zcqmsZ=W2yR7v)wxNpF`*P+ASe3;MYZRZbjl;i4^j}AKe4?6{ zyCy(86-o#cIBVEcE}aY`aQyZKU-#XAIcC@Hsah(0<~ygfH`pls5IND%B#)VyQ(-Kw$6z&tJ!wzG^7H_`%Gd9qfx!r* zgm@eQr?+SI?&{bXSoE78&23LA8yYthD9pe>0-a}5#2{*$ka?DEf=)Ap zP?=A4Rf#qCgxaBc?&{Hz7=aNNOcJ`?#vL+lIYaCS9Fu`*q&Fnk51iSm_dP+DckePX z)&u>rAD~G4k4llA9jlpQAN>~Khw6ZHr8vdJp3{KJgzYL}r1!EB5{ItBo&?r8`fCpj;ICyj z2rt+jctT(YP#Y-vKG0Evk;nyB zG&pT$IfJjd;(3*s@p4r~&)H+Oo(gro-)%m=2i6d4&_Af~Us?bR7!5#D_j0r*1ZNWx zh7uqnJX2Difmpr{(Ej&cT#taw(Q0kKf}0RQ#>q}2CozdU1V!hl&|yk7FQIf_We&D^ zc7Esn+zvRtbBp?pi*aYyq}*eYO58>L*YPRR=}b`u-skBP-ixJ{hZMUFG^l(Sbi_+*xb4qU{IC9g6Q7 zFSj5Yqb0Y(arj3r0~7w@XMZHOFG>PY$;k-FeY%P=8ajMP;uX1zDa-a;OU%+*IGD?oiNIM|UkYNBwdxChalmBA&UgV-I>5J1T@Hb(UqN$vWTOM~_BPkj5s=*Q@H zo$y8;G&|hK1g8Z!Jrm)`;sv*+(zz0_8RW{h%Qcsi_YJX9`!o89xeueikUv4L^P8pZ zGClz8;zuBp1N;4RXb!_{;A&y-|-);XfGHRy@do~7w^p* z4Le!EpuMwj3eiA{JGm}|y8p+Y)2$}$b=&dge*@J2#Z-HsQ;ubT_+{hN$qqk`OMp=5 zNDdi(MkV|k?SD#@l#~~Alpy0+)qeRXaioHP?d9YWtuIOjkARY^-X|I+erS9c`+ot| z&UH6rUXGsLaxgHEFncvjLWBe|>F(}Ey1SGRm6A}pOS&6GKpI3sPy}&ON=r8=NJ*)PG$`;IZ5`~KyC@j`$*57PL}YJO0LWICJV6TZ7b(}BxmZM|}W z)rEzsh=YtTg%w?FQdmE8RfV}KX53s=Y$unuJY zM_CbY!*l^xeMHYK!&zd9y@Rqd)`L`k1B|yBvJ!Lkp5`d6WA-Dv06j1eOol@AyaQke^?-aEaxq@8m4YyuHXjnB z?!5Jf%iQ1?4+d~VEDAI$!(V$K7A=zT(_6Gf_5%RuQ8E9als4VtDAy|pggz*4W=a`f zUN0nL_!BNjvD1M}_!LA!p7T>0lGtZ}q5XeJq=9{f5PSne<)bJ%%wRvorxuk2%I4*3mwEAZ z0l2q;FF_Lay_xhDp(@}UN|2cU0FNLc8c!HAFqkXG6KztiyGXFz2q7+@-UXpYD71Jl z4#|QW2GL3a(n%$3*MY+|l*k3KOdu~P^k0n!3@j%XSSpm6_c}hiOMfPxX=fH=Ls6JG zzdqzkLr2#Amm5;d!J{DZOfE#4h+t-x4LstE2Ka5o4X9M0Lw;-^&BcF*HGhW=qp7bz zM@z|tUdU!~1I>lRIz#&nCrs){g!5vxsQ`vXHavo3|CF4AY8Heo-oT+#%6z^rKuq&< z!D|d@TmtnpY`@U>{U9oT1qA4^)!sio^1(3)9~$57mLqs#<*dAVCD;a13)Ia_7Igyq z)E%(rbMKKL<={j(uYp#(E`7~v5h)OdU&A$!#WxSq<|^hmkaq~qBNfZ^J3!G!$PN{m z1@f0Ze0O9DOdC{7aq%#GRLm z(*)q3SiviQ1e94{o^1?-;iOPh(R^wTm5)%ghF8)+t42JbjH4m$RmOWmQP_Rp4wP0w zR*Fq1koZq|C32_~?}tL#70}y^eefYY%m1#n0jNPMe2${eVIv+E_`=Ekn$W`+#4~U* zHB>2!O%vYz4b`yEP(}J_r2-@R;rg?Mvj|dxa3V%;Aq}m)qU*qL*h_+jUrF*jIj-7^x!eb#4fXPuJ;?|t1;g5tfFLnSDeTAt z)%`?45Bt|qNb05-47hRJ1bXCS%ZMCPtkHk>Iz!7k>9hMVAcV2W1st$S zgEW|y`zZ-zs_`1FxGgU3nUV(HQ_XpX+-x-B!y7qt{TSY%`>U$QrcK!J?sh$^IL!5m z441DvvQ#+>{Eh@lhX=39toiZEf-CWxJB39i28HJ~#H)vdW}@#|hr{E6H1I1)%fqr{LGpB^r<^_HWkjt# zH#j+l4{4FOrOL?T&Nu@TKGDE^$*Xg|kPb>j>wI-;jf<1#w}N&$UrY?{BM}EZTl{Oh zW?{dXe*c|SZLfqAXxStMpuxS#O!86@`Mu&brD3$l?a%G)?}(m!bqm`8Jq2OBz@4{E zZOnx)e!0qW*ufBqnBd$X89(R#0;bwA7`6Rhww_sBu&VIHTnh`nw(zagGv{tgcvVC8 zlmqoS*d8Q9pbKbRKmYv7n%EwhHm&H`U`?F4!1k2&Fg!y_dE?(7@M!n0_N9&q3rU%= z-+b~WO!*YY;gOz^D|L^+lp?xtd{vktpu@QPObvoqq@$+(LUBa|zu_bx?7vEgdttNG zz^QiiIEpMs{o$3!`|4y)z0;0fI5{@gG9n>OKnTN`*y|XsXkpJ9=9|d+~e}49mdJ88D`t6M`dFj!N+PVK>Rh^x zxh!MXZ&-O2BYQezPGpHlpo!SJVvn`4tDm+XSlUQVU`gD(Z9cf%yi;hrV(ta!R$2sq z&q`OiM-lGTr>9MyQaqU@o3MX>3{)zP#SQCwxr3o!XQGIf`~lM-$6hCkkV@oH_rZ$p zhV5``0r8e25O8EwSLugP)Zt@_z@GTrrGh2G9zKqyHXaRg`Dto~QUv;??3?#V*S6W( zT|}eM)P_)Yq^T2iUxLsbbO>=pwMek@o4TuNt4>kzud1njg=@@u_=qU}CexFsP-y8{ z${p3^5NkMevP&W8U@yPiA)auc41}rz|J`%o>tFg}{rRb4p8i};@K;u$WXlSnw|?sp zwMDm&!xrBOsX)%q?YMRvmlcu+nCfWK?515Rin&qsyhK^aA38aha|J&vkan5TuHCqp zS;P+&v!)ffJs3Dxd1lERx{B*31!2)?8G;`;!@n;GuZ2~Z-EX3pz?WrzXvH4;g@sd) z+)VC}Jb&jC)=Tt|Yc*vR7Ja%%K6Dm|HDZ8$$8mwqsMMsNYTD`6XAZxv<6>hriNuDr zpri!-Zrt*d67C_D4MD}A<`&`t$LSQ>tSHB>Deu|Z#IoEU8LG-3er7CpIkj|twnuR{ zma?a6*d0+Z?lfqlv72+h_1l6m2~zfiEO+!*QSN^CW*2;Nf0{%elSjpPkixPvUpBaSgADqy(`~zEOI`I0vT4Elb&QQxW(+mT{SzhZUfu-t+c_g)Ofn z*;kgYbjb&eJB4URHSvEcpto`6P9YA#bW}O^l@bx-2z`}R^Tume3T>*+d2Ix(yyLP? z`xQ{*u648*6CQo;;nk_Fr!_mVFi$5wdzBFA3gXlW^8;HJ)3SyJzLlo!c#9d7u}HYro&LQRw$cx5O@v z4Lc&t%GZ%ZCyaEz%^%gO*c7+3VpiXqgSxG|JiYS#yB%R2ZNhU~OnoBP5}NM)yLMgar>`+ zN!ktzH0Gk-&88%e=g3RmO;+wV*=(TV$oR;t_Tdg1ODWM~2xVUr8j2H3{5JLm&Hb94 z{yp@K7mZ8I-Iz1WS42cv_0^|+1$`ysTm|`ORm@|kt(i|%+6t(`!un-}?Ap3^t)6J! z$eGfV6Y`C)!x*(Y@PJvEdoT>&>DrU-=ORS@S))H_?A?jp4wPAcF%$lXn=5!Hk7k^z z@ahN0*jDdKi3gj1pRtc*rUWJN`pFdAd^uzViI`*=)tgX$F8eL~?6bP)ne-xlJQFCT zP)SH-y(CGI%Q8D*xrVKRnwn$6U!C6-F)BTQ`nFg0kRmkpJM-_S1dT!NaT^?prCCLs z%pX^j)kW;JYIkspZ)`C|Y?yK5P(5`1uKF)sKt=#J?FUMZ5EP?I-fa38?A#*cdt@hr zDz1K4k4kQZe-S<0fk`e;PtH(PZq!+OXCG#&LBC~*#C zE8j=!BCvX*|~`FKP7)&z5pLVENn; zVvN4r;MaW1vdR|B6yZQSw;bxrOoUY$cUg&eP%p^O{r*mcc3Y9x#hIv=vP8tOAPkSo z8d-s5RVi&x5x^-%n=*G806`Q8eJAN>jbH*byg2UgvTO?ucn<0%Uzny^_F%{xfn3gz zhE4#DeXPN_4(9Vb7dDQK>)}D&fs{oQw1Vncj<<#n_#H`;o0|0iZ{Ov>@AA zBu2W%At4w5>{vpEkMisHr^@lkVGKSS78xtkd17?g6qbPuF+X1dA_g)=*tnk8;4zE0 z!+HkxGNwVohryr&ADkOS5!)D9*&HSK2s=Xi&yNU+a;wRmiK1(_c&~kLnj63-v_@8z z*V>a?o5ziqg$E#Y+f+Ko`V%z_WhNU%i98R`oI%lyb)6O;gg_s>y!-|KeiJ4l`qLsl zv9G%kzC9B{X~M9!w*JN7>@buy;(R8CkGOCC?MpcqAC41BZg^q(U;IsU5lkUHaMDne zp%#0J*gjibxj+*7YKiuxeD25!t-&m0yjEJna8$<8ug?9q2%ODmuMx8iz8!{4NIqcm z!v|o`7q&+D4`LY@Y`tJ%1@$cr$YsH>N~=E&d_ioG+*<`$zJtOzuLo%EhJRa9gs~7Y z@4~k74zm!C`7|03o^+4pn_po0Rb*5Un=OHW&q`4b^iNtlmXg%ddEKyM5Ih)X^keW@ z3ddN%GRmL@GUk^2KYy^}ED^aC;W_Mv|5R%y1#Fed`@0gPZY+g>Nx<;j4~Yze3-upa z7Eyl_s{b7y_&>f^F{-EnxuoF=fOWYN=%8Pw6}zC;16wq052TZWY8lklVxJ*-z#AgX z!2t`EzX~vI4nHLV(RCAiobb-CkK{E10}5!R6tv_4vw&>*JRqxd27DBLHXwsPfT)Dg z+IjT$TYnFj#=m!i7;jtOS_=pj*a-kWg<|JTs7lHm1by66gA*zKT%QqmYhk6CaA_-@ zKN^wcGh&RZ0|6`1wQCw~fcdP(x&S!BIm4E1zUJKbQoPDv?&-ZE_E<2@lz5MQOV-aFrmAO!iL%xIF^s`x3~jfd_6n zURhabNV*|$R}p=F_X_o7^#4@2xfMiMfv@|ZMl+Yuwl~QglPs*YknfiG?Ub9gX^(&U z`;(A<)g|gV1yyPv-K!sh`AQdE!94>E@*%R}7+Y5D*FG-M$%TQ?GVL{MoWX?92}uG1sB($oS(nc9OWc zf;wg#F+_KVbJ*ZCKiC6uHQ4gpdL4G)9!`LT;_3h}qy! z)M1C~K7J}uKXGZ@jwhr~ucJPmFzORo+ojV;QSd5UgfAmwK8^T<Czyypc0Sxf$DlZwY8BuOW zFqPV8c!t8*ghR#|#yNj$iqQPJ`?3O{L!e6VTIeDK}CQ~3ehIH0v2fJYLvkE22mqJG?B{XJa1b?~xf z!(4L;14`LHMc3v|W23b7NR7py4>nm?socM7u211n1J5Oqly1l@hUU3F06U+D6^lSs z-*dU0xi>tfND>#|XsY+#$;1jxYRY2W4(CFY<=}A3;LsmcePXo14i6z6y3afFjj6Sa z6k~FS=~8yWhwB5~=SU4ZWF&lskMj>oKp>OkaY-yaw@GE%!|?Nw9NVoL3gZ_A1t9(9 z0gTi8@sP(3ORDTDWh*f^pOomcB9iA6{azRgKPqd~Pmopr#MPVS$yM^6=kIA%Zt0Z( zJ_+#bJ^-Rf`u09C-ITu34;aDV^s39M9D(Cty8>zUnht>HC6q46+Vmi3@a6$vUR$7X z{ZsGdC_kj?yKC0uyKMmv^9kA{?idsK0zL(a z@m}~9;B`XeNj+og>4NH5m^))&1BlStkhmM*8&fR{XbKqM!XGvSIGlh0no``Ek|R*g z>H@sxme1gxMb2Jsi?*LPBHu?}BaYgUy-RTHZVM?3nn}WxTazaK7*CQk6gc>ECk7)N4j)-rTS;NT}-ingFB4Z^D zENP^yM;Mo~JLr$q{!vJeh}}QFasyg{dG)qcxbZ6~o%ep9AI7FNV_rSB4wg!^}=e4RFu`eKhO zEpe@wMsoY>_T#zyNuIK(=_*&0_lM9aZ*yPcglh=(FguYX(lIZdpcoJ7l-DMwrhb0+ znR0Q|jULU;@BfV44k=>0NpP(jMXhsLPS|}=xWsY?c;5-1oCNsrC*A>Z&hz8@8YIu{e{4@Eo6dKB%o4-0(<}^B)@G(x-c`?4C z#xk&f3~37|aD4ppCB@)t0DDRK3G0uEN?pMeeLeu8^T<#=SlyV-AJso>hDHi zCL^^F<)(>SNY~Nc(eLP1gpNrsTq0)5VXXQKcP29_^48nJfUi`m1fp5el1ur|&T3s) zZc^kh zPpLalF{6)Bx!1DLm3wFuxmh!_cYemJq)ZBu@n@$%Rhx1@6S|60D#l8AYU@NSccz2-^ku+9%h>h?qM3#;anlEEdy6d;_8ABc;CB3gTdmVceIPrN%Hy zhcJwdSW6lD)EA~iy{$jLbKj^4PijTF+{|24_|HdLdp!Or zF`*e&M{lzgY@^>%s^|j-n&9`|&!J?WR%39NmL&eDfadh5Sh+~)Az93+^{cr6HL8V& z>;kyq84cY79J~&oD{5q!`NnUxm2x!g>tu#h#mf7q6gc%5{FsS;onrPA zJp8gNg(xJmJ3eKoI*M)simR#1PXk875<35prF|~C@K@`oSO{G?uSHf=gKXlqh8g+> zh6mSy_2oU{$0NEmSHc1XOMK<2`l4zQ{+0muzXS=eRT^56kEvj|MJrw$W5eB%jV5A9 zOET8;usgG?cf0IK;U5dZ{o?N{mgB1#=ayzGB&W%KD z$$!+qceW?OHb`X@x6)Cdr9pbMoFAN+=*iqh6JL zZ_55oc--!Ws(AO~(%pqsdP4uipIPtJu1Zf}t*E;0NG4G+Cn@iYkY1;=m( z_Jt4h_cpP-3B9~PT)eQQw%Eb8Z|4D6%Y#kJcY%+2Q`Rug;ozBWe=;%K_E5$zENueV z(;S99I=SGShF44XoIhtdv~#XL3$1-wlNa~ZLE~4VQ5$3ux$5rM0g3=4M45wx_iK|o zU}}R^l9uH|(AWDPYo36IIdEvC8HT#e5sHOK%Q~Cr)AS-I2bfYVP0VR9!IX-67nH@-C`+o;W7P4Hw7v5_v%|CcvWAR4o^0|>8V+ZSe#k9w5c3%ievLBE&jYWH2r(i$& z{Yo~dkq*J!uVd^T0@@`>$6rOaztc4wjmX{Ct0-U6cD*aicG5@;8ItKeA^Yzs%==*) zWx|K~jN8Zv@}GMQcdKokihy4R(>CK9fNLP^naHR*6r&a7uAsFY$(MQ*WD83tH$Y4I zk{*>~<}f*|93fbgvtSDxpxZD3k2?=l1J%&H0fN*P-|go&2nK%4)H3}3-n4-fWHi8x znApZ-hqVv%?&6|?+O0SDRS%wY!O$22vR+t%#aX^6#R>ma4dpjLi*T7#66qo)ZWvZ` z#q&+b@ zYbyu0oM5o4j^J$=!knfn(}R4LJ7Lb{dGPH$yxC1}22|r;2x0*2fsK!^`-mN%PWhWu z`Wm>!>r-@yy{c>Omc#4XY5W}WG#xS-CLCU(!d4Q6r$b?KFDvPbaYQINF#&^Mi3Z2> zXx8TAEGA9_kI0vXawhvaBm}#mfJDwF2uj#qy!|zHbt%h%|9*&uZR}bpBvw}fR}Od4 z_Ue~U_)#IS%~X!V=qT*FWfqh-jxs|nWTOJc_m!u>df8fm#51*&x#tyHfucl1Ujx86 z&|W7(`;MG~CUFje$uYS*Kp7dM9eU{Y*%SwN>sE4HS;l=3Ql@x6fqL>zrSsCL~8y7o#S*3Umfd_NCR)1*iX>I*iqAA+; zdui$u_>W2ziG)9^-W$V{5an&4^3^P@X%IKl^v% zsxTe;B-?k(sp^;1UOm78AS1aTQ!M(|tYzF$c?Qo#VztaD~M3*9!qLC7y4cQRwI$?S&yG# z>yH#RSm;Vd_Fgo|tlqYzTx{w7Xq)G7VR1^q`a8F4IbvwJpyk%;MN;mX_X1lh$0YGg zP7C&J`Ar!i@0BW#1%}fweUoAZlsO&BIF|0q9xX|z?EaaFT~qAi_w*KP=2}#e{6nnU zw_@tL8hh}BF$Lu$OEcddF9jJzNHD3fXz&glB)#rWwJfN?`ir=Aw={?4b92r|$~s*U+@{}VoS5C6+L2!oMkG~k?G_wJsS^jlqoDRc11}X?RNA&=9FF= zn2w=W+daK0-P@ET*0g8xmJ&}+6X&bAGP?&Uo%WyU-t>GD3!3K)w-q35c!HdhWi1LC z^D60Et}?KShL+KyUF?kIE6-$EOLKaht*gv%rn9`1jlXAJNUK&dW_Wztq~?kKD;sAu z@1Di}S^IAjGh`SPmN83CtnRf2{1eBhansN0cx`|3$+D#?FDU+6VZ{uhbiyjdzAs{^ zSmG|_CrT!5Hz=ewBgaXlo{37IV5rAvfP?+6JL$lWaVfosiIao!IawwivnKkN9%WNa z?u1pv#}TER^d?-K|N5i_4 zd?QoU9BU9Zk*7`s5$GuCp0=@aXtim?^V@H$BD5YPH!%s3q*w`vE&)rgc3uKH(te>_@ z@o1Iqw=d>T9kX$;eHl5PaUFGxS}$9d4e+8-H6(d_yQ*~pVjPt3k?*Mm!Y)YSxaCE=2N@3^!N>e-ZEbT8bk(;s`(f$;S2sWgfjA>|HlRrY z9HF>dTUz#HIkNAu+C_Fo`rZoUN}8<-0{ji+5HhX-`klJJfYft_?8*1Tu1b@=|9#?V zALt1$0V!h6l*9!InZvulpMVxPkc7dyL~FflAB#s7ai{5MQoH^1D~;FDiYJnM$?XPp z1>e7aKaWpwTxi;du`B67qCd_E0YRDxpg_kNbZqY_?w$kaN!4fk-lFtXdJ<@5w`c1j zyFmSR*S+&9P+rz>V1i1q3G{r<+0zi(9EdkmRZ$rD(cHnhpe8#}LueN0>feigpWnd* zX@v&Q<}N&5L-4e9nh$s1a&3O55RN*12#s6`42e~4pX$Hh3cNKa(;%KZ1;x$W6yjv2 zE&`fih`-etewWe7*6Xp=17t=0Tme!$=<_JmoVK??Q&otpZCb_2znZ%b2cXCepi25o zA))mB4b$8AQr|)v0ZIqzH;mUKBnL6&?=}7dYc5q#3^b-JSz~b_LAfAzcW;+JT_<&ZQ%S?%m<8FW8_=`W z>oW{e%AdSo^9pPd{W*@8qN%G3=L@>%3~@orPp?j-Fm0ASGbrs1CsS3-FFK4==5R#iw%?*yfR)n0b0?=}DPqANsUXO77ie7corm`(!R^D8qRE{y>w3X= z#PoxU(G>;0)NedwizdE<%0lg);0NMnWQ0}R*R*A2(sUQDCrc126tcx&fEbbZ?wEY* zKWQ|)e21HWa(=4@Z1NKBA;(Lh?X2~w*x zvu$erg$2wiYrTB;YYr$-!_7X~HW<|5x66jwjJqpjWMq`lf5jFb_q(lv&s7BRMYZ`( zNwO0m7Vm|Cjr~F*vEUvVKm4HfT@2%|%@2uVlxF$3UtJuTjITZ^_rw7wW%x@fL8~hy zv~w$xla(Bq6!a*CxN|6CJt!(JAUs~dh`+3g^0bI^Ak&U@n|+1y4T%^#LH(++%&@)m zj%FyyUxk`FNy;e7Sx{QX;)u@Tv1hLh49yGLnbssZ^XCGSe;FZa}}?w27B zASdi)`D&AOJy<1lZP4Y)%&4Y=%ivYOC%KyV>HvICLS6^5~9bC*1`&R9?xGaQl*#~ zaf@0xnzeHv&Zt9lW$P4&%I$)~J5ym!@;BvG-XfQhtKruq^cAvc)ECm7{LE;avgUA_ z`5$$<2pQZ^$uZ*Sj3#52hHYC$2v;13W9s2;^nOzZvOTPbXi>_iQP&tn@2!gYF6*;r za9;g%I7-jU;2!3+zPD>fY|($cRAKu%R7>TiBu}pZF@?LWkm4}-N$VtRs3X=)`Wzm# zDW!|S#jfs|8>gJg%HG2PrC`{@(twrfczBo#i{RI`d#*R0F9_)k@ z;KXbC3%hV!^^lq9!Hf6kLaFZ*{-E56*{f!K!(in+KHk=OFpEzcU%clEFO#pppih;0 zy}1tInq*5;4KuzmqEGJvj^GAK&H~*0lY>nGamwK>{!etjT)TkqS zORsu8;fT_(jx2-xspiSclIR7NEF}3O+jG^0JG%|vSJIgHk)sTvh5zfRd$S80&_#bB z@1iWGNm^EVfvY5W-KG>z*V~4QJ&>kbuR--M)dre06)Q%AzKoF)j5e_p=5o_`t%w<% zzhBWdMY7{v=59FrnA5R14LzXOTQDy@g(Eh~SW6?Rwcmqf z=*Pi2;hE00KzKsuP#kxdaRR5`#wDq|lAS#D zzitTPYp@X=XT-2ta={w)cA4v6OtnawO{6?~ORdT_5N|!d$x}tSMf+WOFNC{W- zy0DuQH-~Vo2Iu671|7dsFn#)@|K6Vszdk`d-nLaa{eY$Sd?^DBx?EcKKKwFl?{ zrAj%E)7uSYFBNzLq!TWf0>6AhH|nuw<@Fy|E+@^?SI}DTTBGr1aB@L68E8|HLuP}o~o`0+;*Av!Z^n**1WLqbxuz82C220>dbh`hRjvoC@*QI2jw^%CS zKqQfz3PUan$&etik)gb~SxaKn)u+QmNK@|tU*p)b0a8OWL-Kg~X-9)Ef4>0@A&b2t z31q@gFtsS!C9Vk=E}zmq{eoL&NSef;e9s2MOJyT*Z=i@ZYrw~rgsUQCpODW?8xPBf z{F%}Ys=T<`kiDYxKo`a>`l?%w*u4o`zlm|{o-Ak!)?TZ!mnOP9-1y=eT_Vj`ve$#Q z1AiG=-(Y1@nL4~j9-c&wM1j2$gS{T;8lp|FOp8IB>iY?K*ol)%(W5np9bFlJO=;gzm07&)pY$w(jFHV7a(na z<;_z$oFP_yN{8b*&~1IFH0%y(1-cI$XdrWW3VU3bf9>{T0dfW2=2^kK&Z3r7Y{B)pJ@gW`YL-?)a2!P5BtOOdloM4O_-o6l@phr8 z6G;o6SSJc}CMb{&bb`WX%@gd2Jh%Sh4Fy(b=8lpfN!E#MG;mulVDl&AOjmU~IJYix%t;2J1D3Vu7Yxq5^~t}Ys`upSF$<#?=NTAE05&_&O9xrd z;LC3b8T~!qxXAb{$dVz+C;~|PftO|JRv1W@8ZZmszwpwxA`9Q5(1NFkedLPn0A;6$8p z*g*0@ikHn#K;#~Y?QMI+2{5{yF&bh0#9gS>a1Yhf(gFuC_0GeU#G|XH737&9`S)SlPFHpZ1)>W!XpPK4$HWbBcS$p?3i=Cbnp>n_cG| zW;f>A+ko(VHpQrT5S!Ras@?e<(Kk_{&v4els;a58dPtVjaxm)HfOdK{U_hOS`4Bki znQGHi?BPrrY46IneoOt;B%;=TcqJsy z79im`EOwn7q86?oPITfE0#->DIzg|mI(c*J32hP-Tw16kMUX3~Cg8ohRDg(8B%)#I zP;W?WD}D?6NzOwYO&#G=kW@smSmiH-zum-~Z-Yr>Z~`?78|+M(*;kjtK<6?qnaUwJ zXNU3-pHZzpTY#Z3j&Hpx{4K)=$z5vqRt!hBh&Z?^)mvEF*n%nLg8f0W;23{Ku8(|Z zc562axd!o4aXq6-WG)}EV6jt3=9q5=Npwy`u4CQjM-yN-$Rtg|bKNgQNw%V;p|_yV zb(QTs6se9hBvTFjTEm$@_#anp%);Mn46^>?fNJa&<6KN*!CeB{3&N+IT3wOc3QVjO zW$QZn`Vt5%^4;k>XViNBxwe*`?xG7IBUVPneryh>#!RdO2kX-XttV+L4g~qJ@X(-y z^&jm3O9lS~%Q5P0z@_C#rrj}bu_zy3K`kMjv>kji9&25W(rj9WvR1|d%@fXq(v98! zvlvLN#Xm8SMq6XRK>o5FLNJgop}V1%pM9NW{K|8?)g)YRWU8!%(lnOuYU^nY=Iz!d z-RRj_$m(X0e7pB-&6c?+yN)2?TQS&A%?=(-9HA!CDNd< zf(?0r_8w@CJp1VU;7)%B3!wLV(4rVdLkcgwd`NH#ZObM{6dV|Eg601R`_hLkdn}+Q zcWSrhAM-7c>&ElU>x~ezYy?kiRj7(h6u1C1X}ucAltEJpOZUzg6Y!Nqq2v?nDqWvn#+hL zpk;?C+M&Sbnh|rfqjXtcp&1+pKzSUNK(rnJOmf1v0c-(!2u;Roh_8{1(;&kpxsU0!!V5)?4UqTQ0B_OJHz;4_{PQ(3vg)v|kDkZ494`dNRvIXt`+C~ii6-6f zFr-Qc(v7J74I%~#Jo1N-M^L}npFf5D(i5c5U!&MXp32w{p$Z@ZlWy3mAZdN_E_67L1nLsvaI}Y32~(ln^OBq1Yoi zbK8$j?lfrk-AuEW!?5sSzO9k5vAj<)`l83YOXFhTj~7i!*XbZ>t4D|yX>u7aR$MTI z>oA%02jVkE*F8~Rm;k9ZedxKzAhEhD=G8%;hwl`f&*A#a5&Q+|tP9a61L@L$_u#{m z!J~-2il**xn8*GA@P&^+Ccv4FDUkfM&!w00w+DHkf}BH>{6tO?9lkPmle(qeC(-_{ zBcwigUuz+H*yVnAi^_8pO?#EXhri4lI6fxcQF<}XA!0wQ;4+b%j(*m|C^DnY%t>+E zJH2(i`CH-ZB>`oMU!n`y}F(c~fh5*6Tl7`z>^_Ll7KPu`1 zG>D-(5r^oQ{(Fznez;p-GEHABpaq6fC2jL7Bye1cLgB2HjE4*CzYi|$2;jYvGvYvx zpHA-a8zy2W?924QDjZr@G@tShM)6|ZizlK~qYdac3l)}+cK}FIIZc(RKodXHc6j?n z&U`PnoAP|v1-0Q@wboPqKc%p?8JC!}b$pbbA&aa>O#0co*L+*M_evjQ|ag{(g+ygF@FNr}Q8k_ug0`oh?tOr%x0OMdTQ4 z2h5=jX_rs5J@JxzP#^It;?#W*@9X8WDp27v`-bJiRp>(IcnV;oQhOIF_AYQ_%3C(D1i>-VSXkDr0W@rDVD2 z5^UhbETpov!+uK5#V_$|kIrYg=N$kGj{zN0M#8DBYp`Uh46FvPmQzySpFP z@94^&{HA=#`D!b-eR4Kx%#2|qp_^eZ$nbof!0uJNV-CsiIox_TYVQ>6QDWu=qc9lY z=vYz#ac%qj`KKb=zfY^NdZxyU72go#i4rx zz=FL42F_p?Img!shNVKmlZ|RefB#h*0RQyv2Pg%qzptq7%Eg?$Z?}q*>XpNNL}mnn zP1`EP;)M{k_r(=pg%~|vXB=3G&rb1YikQShHF0LgWaK%S zT$d3H3x1CxEcK*OgSA<0I(+^7VLT5I?DYE9Ct2~G-&wJ$2LJ4dksR2eY)3{WsBL_x zroitoP4&dtLF4Bi5eZEl*TcFlY$Q=i0H$qS;kZ{{V6GP0S9Xk-C3;(&vOi0O8m|tI zb~9(@tE(x%Az+V0+jHQ-DwMG+SbqhNbA|hfTLeKSF*Yu}EwRIUvq%s6spa8SbE4ez z!4;|}QXT_3&%zkYn8IXzWH8d0Z8{1AH@QeiEwekbRM@3hPj$)0R0i%IRInEL_p_F; zlVX@>R}ii@#?w=5)8H7bu(8Sap+x0%=YC|)HWhtlg5<&{2^XwSe7Pb z*zsyDlo_+FIGfimA#&G$i$gDb%>2Ebbw{KVE(5I^8C}g`T+|&=654@xJvLIQ8vnRv zJs2F{$_@{C!<(q%pI^-KS3(?iHi`(*`J&$uwSTbk%nH}C^aRJ(DEsc;x*WMi2AMj2 z+*co6DJJt~a8Q*(je3Mmz;11zuV|QgiK(x644}jNNbakuhO(7L|C4`IUcfE=3!aSN zjmgZ+gcGjyE@uPisS%jr+igNHB0M*I8uP~&MA)GDT&lBGhlDvuOR&ji-TmJSGrS1; zcbK7S{GkAx(j!1wX}vy8u%8k?{wo+(BUqZto;`#1gzZdYJ%F&2-OdU?94PV*Qiw93 zAr=10XKU8**Qq%az=0eJ$ppw;qtwg39ttj%56`qIj;?-z<7gX_-1;iY%OO{M>0`6c zkDIN!XW;tS%CrBq`}q>mV~Yt+KunBhabsP;uE?lu^V92!#W`=tk=qcSM#rR;bibm@ ziV5znjW1nfx=`0 z3u+4CJ~st1Nh$3B9_Y2+12+T{*SEqBPSj6_sqWp^AAx#_{5Lm>HjLIDJa)TY4azWQ zZkd{htqIsYaQ`RFka8l-U_*Lj(jM{$wE5a(ULS6lQmJY>3+FiYaCNM!ead`n_7L85 zJN)3YxE0*~m&qzPB_ZKKPfd=$m6eqN&9<^sQBh$ma&s{xn%V3(#jp3)V2|oAzuJP7=?7&RWq;_mPv&6+xu@21YjpD_UD@? zD~gX^EC9$L7yWM_14OvdV7CJGzFe3KK=_T-|h3j5X zmlAf{zaa)h;O~Ke44*3HvC>Z=jSp%x`q1qM@gY@yiB3U5an<0?a<@nX2<8V9$^AFR z0gwVv?C?s2!!?q-d*rE73vN0*z@id&Lby$wqK-3>%Cd|~pei-^@utefn@e}MSrRhB z;4-!8CED+9%$A3U-*8mj!Q4VtZI0wZm*HiP}3r2S`laHcY(bw0sIV zaiFEkg1z(FEE!wH0Ww2B><2m!c z1W^Um!iW?ab*H4bY=f-mqJPpihntvBITJ31%?-&I{`(pRAfw=QAp^Nv>-Jv|ZZ;Id z`2>!=TS>2p*8m0zzIz>lPyi_uQzvcyE#D8k{+*!hH?ye_YxC~9-0TT#YI4w50Nxp^ zOj0p z)Dpx~ut2rI?j_+e=M8fy^3-QP^oMh=?6^5CsMXIJ?g>NjnDet>h_tEiJd(%q`mjSq ziVHM7psb=VUwTc!PX=xtKt#sD_>IrtdCOthhZ$95h2`OVjk(CD6;D{6@gAKvhFd=7 zGX4rz^Ntb^;Xc7&d+tdl>c=aXD==;c0bvbIML(fIH5i6=5ceO00>Uw$>I{?wAR=6R zXDIzJxkj-2iw_}~v+nnJ0K^Iy?@DCr1=uHmHO7l}`8*d7>wioKisewQfDhEO{p}X_6m6s3{S=ag&hxRoz8s1m?{ft#ijGTu% zXy6pf<;v99qD3={>mkH8>=ghbP;MJ4^5Kw1{?{cFXd_o!;lfS7GFtixNO519TXRIt9YCEbzJ^}XxIOr4hhS|# zn3;WGDQhItQr96?uJbmf! zWr!#NOhor$MB;P^$%r^C#8}sUJP;f~gn-$cAZMlSb8Yy6c0;3mBFI1eTyvKk9A0!P zjZY&16qACRua7<`NzYct;|?ey!a31Uj=1$W*WUY7#WGpZf?0MjU){p}`#!TalwZI} z89+fLp&IK&zEchOd_A^cw|ahJQw%{5_)ByeMQZvfzv918w+0W~9u|Vb6v>Vs0v<>1 zcDTzSr;qa57>)+kvDV$8re_q#{yXp=IkJ#z z{q2_D4e)o^Tv4e>waPD9}Txo#p}^bMext^6xLx;#mKeXEnHfbCycfF%Il;{pf2 zvKg_6O1s~FQG#bp72h{cq`nkES>UstGO?!+?n&DG+%A7OPMtQ6QGCsb>5p=BCW|O- zFJ46#0O%g7QN1ola2Q70Tjx%g0>IU4VH7v7>eBmZz!!jwh7!=pf=;&teW2W8tqEI4 zL~2+9XXhoU`)Ur_utKm^rhwO1xEqQfjZ7}{?b?|7tIptSKReM6T}rnx@ZT@k&kfy~ zrIm7BkmT>#`r>UbCN|~Nk8wNdr5XoNn!5++-Q|K&VP zJ68Gb-NDf(CZNiS@whYMJ|Z?l`Ry5@j)vuf9tuL;J2a7{?@3nK_so}?GxGD3mhf*n zc8(&}c*)%`&!G2?e!Vo==;4eB*v}oDYvb{l*;?g=OVeMbka?0f|Asp^+00g`$)*g$ zy<(Q9ZYhpkSgX+>zF<$sKB^o}2O~7hDeQh``itww3sbKh^ewv3t-g9O<99b^(_|Z5 zo4JCf?ZDhasiX5Ko^&#KR*n72TzD@64r;YC7QU+ObaWA|_ol$N*Xr}+`{cn8(9vwW zoD+V8{o11KnaKVNo$2t7zvfL7N>xsZG%)qmwQ|BK15SDCRq#2fu@lGX4)hGF#E;r2 z70XP{sqNmt*|gwvl!rs0#kzmdNLplMRc{?G_qsbS7eQ1p#Y3EZ%XHy_jhq!}!}q*kA7YhOp`{}2In-DRlo^38&0IGZ2f?pM5};m0}gpLJN(R8kbi z+UZFpw6PlCBfgzS`O379+P0U?R_k>-rH*bU22s7|3@5=3**iqGvvO~_fs{G@@$%pL z+Uze~D4o6@f|x`#bD4^)ag2yqy4;afo>Ob4WI8RV{0qRaL%Qi--fYfy$zqGcX)||( zW_YFLF>Nw!ykhTS+@H;;d>yBH8gGKhhyr;V3xdO;G!Le)FIdG+iZ&v(-FM*Jqx}85 z$Utcq_m9T^Roz)fRk?3_U%DHlySs%2h_ECUh_oUh(gM;UAl=c2#Y_m*hMq`Eh;K1;0V=tf1TE?5_nIrLEd0$RqiKAENt?RCULFh%eV`z77%xn&Qp zhol6V1=+ab-y+Xu%qxC*@?xFcf`_R)xR@l3*sSXShF0SEAr!C;(lq01I5c#Y4+S`Q zM+UjC4qN-n)V%sdWZJJX$hKP-)!6;%r>4`HP@BQv{x=2|$KTyKQ(tPL7k$yBnhJb( zrY9)o%*GdfQn_q}5bWQFeJo<~dMgtuSq;9FV~NyBRLgjqy~o;E+LWR<&Ox!T-+Rqy zJ)|t6YWK=!cC7v~-FI{W*%vu`3qf3}haNUccM2EVddx$Ip?8-mMG{vwX!RyW zCSs=?Kqa?1#S1TCNmnx=E*2&^Rfa02=G7tMQ4#Hfz)i#zVr@R^Lc{7y<6zH563@y{ zj(K0-m+ZV7(cT--7tq{S`Vt28gA`-|mA3RH1{eg@`NT|Ja}^Y98SCK*e>2@B;IHhD zze7a}yMZ=OE{{^>tVTZ*k*RqaR`>b{W(;$Ww-0n)V!|Fl@fGLYeCS_H=FLsQ#jlgg zao>vTIUlTqlV)Z3CCss}FtMKF?N{5vUTMKnxhSQ!8pYpUK~amFOz?4~Fn!=?v&9|K zSCq8Yw4VRAlV~*b0M9wRQKj3@3`+6!!~%>ZVPv{O7az13PN3GLFIt{zx(ApZEbGdC z4%6h>=Qmz0ddUn`70$wDX!B=^;7)%rs*sr1;gjHL%9ffFDNJH(f#q}$6X`%K=kmUz z)MZK)YBhZta5w4!#DhU_7YtjWzQSX6XrWK;b7lHuiqimR`Ix@mx^ovu7D`}H_CdqI zB%*u8lD`>-F{m6IKmHtH6Y{&UU(^C%s>67diP9p*F^lGYBfFMOHdq~JL5#;t#NJbi z41&6lpv1Y4Vp!nP6G+6+MjEy9-)o1(&=!26{g~;zLEmSoM3@p$_r7*WSyJWU=l9!~ zT!r_LRX78vLcqb+5>#f>AbC&d%Ru!$ukzh$9SYsN@5>m+sR#&=KalhT%-Su{8feb%^LD(&{iu2O8 zV_!7AC5m@Mh3{sy_0MT#$4r=prG8l24I~$cwt9it(^h4~FNO&tncZ+}ZF7SfB_CoS zQz7B=DJo~zS4xOO9=Dcs8wO>oKQX1QRmYiqA>Y*~9=C@bS=qAbBa_~vh<3~=4;N3UD&0-5c|7Fst^!{k z+=qmcZ1V5oPdzczfgwcKFt@ejNYCCW2kx=NJeD% zuyX`?XoZXi8fa68BFSF#qsy#*0(+v3V4H#EUjnP`4ruEc%LLj_mp&kmutL?Ql8tYD zj~Mz`N@>qn;$@SWr^g;4jFmo^-vT?svK`c7Sfg))S44W=1#gGhgR8_+7b6mP^(mn==5_0*Qr{e; zE#lsKt5wFCbI{$nVv3(#+S@21-dHQqN0-)qCyv81^w@WXWiZ)Y&~h(kiO*vL>dgsJ zc|pg_@$1e8c6L_=uIlrP`aGu}^0;sY5eK*Mupu&jm`l}R1qQD@ucU|KQER6oh(<#R zA5S(Z?a#w)Dr905ko z0GDP-eyMv%X+ekGj*ynR!O6GvSps!~-~UFU#7XVW40fNrLdz?uO82{p3he2yi_aja zsij2V^sGJ};0Re+1?~Ht!k`3}RXi-E%<$e37evTjnQjo!MrP(W3nPXLi8;02y??kl z*Bi@%@Lp6}7h_7ukWbU(aPH7l;a+)t^r@Uj>-Li9Lzw9Y1w$|+un#sI@x8QNFUzQL$v>YuxT8G6nj9d)cC3)NC%g-wWVrQdHVtmsE*PBR5$_P9j=o@ ziY-!+U;Ey-kG=DpT_BGwfA&bpp|Ie>PzgA5=s&0g^n(Mnl^A9>dBG%jz$^UJh7J?M z7W8_pz_>OTW~SSilo?F=M!y{9B&fa#55uz?{vRlQp0i!4d!u^~QjU`dAT#v+IefCa z7eY@Uck=<#`w66G-3Iwo7qOa^L5@jNfnze+i-o4J0^{<)xHN(oWSwc*+rca=m^zG& z$s_{4j*ku0?8#T5q26;w@IVHeM*sCLnK&O0{9l~i7!d}tq~3$d2g$PxEr3Azz!M(; z`6k2=NVY2}iks`8TfsrIkpNv>2{9bjN+G`wSP*;tKl%j$ii0R+#Pm{<^k@gw`F-*6 ztq-6*s zw7_~nuf6oC0LU?u-X4W!6G$@1#|)(eI2) zVtJ7Bn1wd5tsS?QIe~zww#5h%P=6gxERgNH+2(G7`bB5tc7Q+bYkAo-2)@f_^k1b{ zF`xxRU^sPyv~bvgLm`0(KDGinoyZ$#!B&vmE3E5(W9$}DZx*2BrnvyeMTz8|9`I*X z#1yMA|Bv@l|CJZw4~JszpwAEJ;UNh+$Ss^La5gLS&&K2+z=o8+x0WF)dK*GPjfyi%@LU|0V1ZT8P7XSq@I~c_t)*VuS*%283TSTcf*B!}h zG6C+2wv5;T!bSVOP8p=$oPwUyb4ArCjwKW}4aAv1+yJALAI=|IKyCgK@Ys=)~qG;6?`F}9|!*U+)E1)J?ERXu-)BoV+)y=&bY0>&y)!6-j~2$ zj^BnEzh4u{cBa!IaFuTWAAyB8QgnGv1I;b$B6Uqr0132Ulp~{DqPZN;uS&ZK%0aNk z_1DjDiRC1g`9DjE_rK2A+Jrp@$%ku*ZsU_4>pHGN=K30Jer5_>Cv0E8G|q zk+K$~eG>w{BtmT%|0HD^+V~X0%nptE43SKURn}9C#zClt;e;WSmex|JmxKI#E)(Ah z{Pb9ky>wbJ^K0p@n-0_Pz3CI6gph*t4~4#d2*bi*3pv0ntMJ-@n6*pY;6{$Ut8p7< z@4E}9C-ky*1w>(XyI87r+WJfC^w;f9EF`mc;S!Y*IU6n=F#YE4)(aH_4_AD9Y>YFxtY*y1Y*p*k3igKJ~Rq(k6 z8GVI-;a*ly8KQa#UYy=wF6_>RbBQTrNvmFjb&j|lVR78rR}N|*N;}i*Gwm4m{$2UA zGwLS}qXk-nK>DQkb{VxTCkU@t$wZIH2@O6tub6EylsAI<1fPx|o7Z+$2ypYXeM`u5{!e#EHOzf;-S?kJFT-0wsV6~cGf?3ocQfG61FZ{rgAX}Me4JT6j) z)XHT7Z_lnw82gu*TY>(Bd^i7U8R@n-!;NxJfNdU9+V@|hjBmUfQJ|Z|A$t%fc5YL- ze>yEzp7gQeIpY-Sydqi;({223g;Lgbk9PCcRff_@`O1#e<}M*kY4|sB?_LoYvE&)i zrdAdFnM~o|+Sn-H0fQ~o2XTB!G)W#@FHq$5LNVG~^h!Do(CfJyuX!7H)#xBqeg)R(+CDQu&SK=n6#330$PvNKnD=2_`;| zKKUyKpqEwqT~M%!rCiP}U6wRV0nUIU#v%b5bSAN14wrgdvOx+Ty!oxSlJ*SjF43My z$1*Z{`los$I=Gy>#7i9y8uip1B^H0`C2<IT& zj7in%Blvp34>VU2w2ycb!>%01370cRFy(53rrLu?X*^uF(Kreur(Zx^^keTnp4{!x zXR-AqQ^>avWL!tt&;-R@di_({(C)g@sz5qXd>_boHoipnwuKm_BW|{8|Moz?x0AY! z;zXRwn5XVGPfG$~oPtS)@QZ3+xbYh*8shZDZMGRfueBAD+(D=>)fugooML#y(|v21 z`-s>F)H0U4;)|}}F8Mz-B=W?i&_>;o{30<5=e3;jtGjEYk!HmNJTG;#QqYULxgzVO zfL2Q;%3HzAcrN;P(HUPAvn+y>xkPc?L@I|_K)h78q+H%hXvA&^ZKKMB*{DR$kzXi& z2e+)+!cI~8vuA%J2|%6aebESeUVCut)ly>0NIkF8)@-Z(45!7x(RS1zMS0B%XlBBP z>>!W9`T@^Ux=r9A&0ywpkIOY@bddPegB?yjg>l{~y#0B0vuQm@nTwHQ*EodALv}v- zm)V{5f1=_=mB(GtQOLmSB1@0F9Ct${dmGR;4cRop6;CGKIBvLNT_c^tik7> z_g6yL57AcfOw!qgGmZwQi*c^2RG^8|%eGj%Mc+JJmkLtRU_76waR8n}9pjqq@MqR6 z>AWZX6Y>BvCV9zdnZ0sDGpZBkjaUIU78jj-7*M4ClkF&S>7mjjMacF;gk<;U4zf47 zw+e0rO+j>EHN8JIejvot9?MsYAr=!cq~Y+sg$us)g*C0s0k+t z!4|7XJ|@C-UGi-1mb|K_3tef_aEAbHZwLQ5{86hj ztRn^-@FVEVNln5nW!Xr-%u};n%(Rs2N!#Gkdj~gi1Ra&mt(k%52vRBcbX;xtFyu+7 zbpxBAl;xt7bdWyn>H_&v-m5 z@b5{70J2WVYJ)A2sxJ-O!TSp(FM)5zCzyneKjI4IH0Rv90wnM^a~?nxqQov<_5cEz zU|h}1143XL=fKPaK;3X5EQWZQqn{PUtE{&KPrqAmZ$h~!*?Rki$0eArt-d4&<1`dN z{g4j^)5sl|FJUtFYE6VTVKj>alFB3;umB3bePU`Jk??EgJ#H750 zq_CjA`b*K+Y^o3f6WpI8bVXat^-?48DcW<<^!>EnBDak56w30NVYQWNOJ`FFj|isV zPCTp5Edm4t_%Oh*k?6%E?E&osNDnX{D-6UgCA7Px-$k~s;|A|{T~SvA>b<_FX$?w6 ztk59azbbje7+M3nrvzR8YOF{($d>#!#DjJiC2`F!sNn{g4sKuUqfeu6rV@<$g|}&v z+H`@RmlvLeWc$kJ&)?6tzu|$UUcD#&m6>c%-e-M0oM96dd`z^U15T?^30rX%LVoqOpz`H^aN?S)$Ug~M&W8H zZiWStmm1BPdoHbDDm@jPZ;S0`-zhUFs{rdUU`nl)JCMXE9b?O+xabKHfSU7?6#_(; zf*xQSnarOg-R5}3A%2+%X{QWy3LIyW;dx##AHHjnM5&)9pCy;Lon*Dx5xygKn@wTw z`vNpwzm>uk^P+p`gL-Yr4RPvcfv~2e(#e$wXXxp{SH*3=SmpCd~9j(WYe>%8^r#_q>_{- zenVM_%6z~m67D~9<=rP!-s#}DqVP?0QQEx zo1+OO2mdC_;Gdo}|M=S2q$k+3PyvHk96H+D(4$~7qgdanSLFTJr24*z_m051@^kgry$VN~`SYTa4`m`#VG+uuX`1L5AGhK3m}`pq)) zs(DiOL(qDz3InJp8!Qj>lb(+xw6VQksKG0rdAbWFS*LxCNo#!Vapn%VuAE)n zmrYHVg^W>=dG0{Lto(H1uRjK@rgR@PjTjY;Ch@*~7^5w!1?k}jLsoblrB-&b(%cRu z3#}kgLWBOtaEd8Cex;oO?w^lAie zI@_i3@5W9?isT=D{6h;U9gq}ghtD1>?`u<;Kv2uvY%eiKkTs%H6dlh|$9y>eJ!f0= zV=rvtElEtfo-Y%0;9-t48B{}bfen{XZ*}_Smw~Hcq!$vc-0#R;{T5reQE9q_`-hW$u znR(`W=29SVFjUjy;RisRY}}5aV+@3Js__$A2ty!ARarJ__=DTXWb}ApBVi*lX0c4d zE}>Xyd1E~KzrY*X_r)|SKz5)hcA6}UzfU)US+^@0pkEX8VTrzGI`HPgVyJSkA$I)SeT8LrI zfw!~tX!%{W>VFApNC=K#IdG7(4&@+r!RbU(y6iacr8NkbdE}-6yN<*{NR!*R{)lUN zn@iwuIy6eK7|Bxi=2au<`!O!#>W=3(Mo>6dIu27!oemQtWY@bXtu?%jXvt7-O9aoL#nV*2j z2^DMl0^wC3`sVmslGm=qfs9$PHXOs+$Ke9o?9D!7pl! zEwPJ8kBL`Z?BmVqmF?)5%p;VC0}_%bJ(jQUVqN#x>IAEE*5 z!WM+g>c&ogp*c`It}ny~y#8Q0jx7HL%aMNOjr?;G6)y&=$MU%e_0q1qXK%bL-tRT3 z6e=^xkHRYbbXiG`cb`sZexg{|WwQS@sL3&!l!0)Iv~Pt6q@b){uBht>OoOQ}Z6!Im zA>9R?Yx)((av}6&mwiqbABX?!f~@xDEb_PD^Y8?0WwxJr{u!fOk&7XnPk`-UF-EIR z^WlGeTho{88IZ{GTEj*{)__T6VCed#d8$9yj_*_$w!^1Y*(n~60QW<0CyPq8vk`te zM+C?22yOBTf%=9*7L(Ul-3pbs+)I$eAGeE+WLianSaA6QC0>#F;KV>WgWX*6`{%j? zgIRnns-HMS-v2$q?qhFA-eC;aNawy*DG7APaM8b}JH#?CZ{e%TaThhl zp@c3nuX1u}#LqgOdE0zBn5X(@rS$KMwR^ZFJik4O8x?hY_VBlKqI!gQR~jTP!##)J z7Uk>+ZZx9^rY-xRF}#Ut3*Gs+MA#KU=s-NTC7&?I@2jEEar^q#F)UtO+ZJu;_T8rS zXJD)|`3JV6=T{lykMNgqdmTyg1r~zcojeu1#pRP^qC9PWkO4Jup%En$bA+VlpsR~| zOyiN4OVlR5?41#^Q!HUQ7t#7_MEOPajtUpYHCOze5AqXfxM~r0IwRX^8ukA4 zao)KOZvClj{ckRw=o4&u`QVmtq*B|eCgt|*8mMUJW@O$pEVR^~+H zsks$kSBAgEpFQWN#M=Az^u%rATA&QMrQE1TnQe(5>v6|Zykl4PPW%8u1G_rr=2Pt}tGE4!^Wiu8^JZ-RMkzK9Qc3TG(hSO~1X zUEzi~WjV+TL$6qs@UHV#2_!%~8TR(dg%iqXe!DgIH*iLS>AsZD+lTMb1epx)^FMkh$pQp? zJ>*h<6U)X?Z#u`_Qlm!J2dJ4ok0JPngsymwK)P0yYDnN?n3paG{=($^?@nt=?c4M~ zxd|O+0=0t`l=R9_PK@_DLm3e6U@D=bw#$BlUq7K@Ptc zqJ6f}(-x{gdq!+M1-rb2ap;+^F-bsHH_Y{>tBhjZBVQS#n=5hZpqQRBg6|$h!eR|M zYAnB@7%lXf)B?HS+f)?|apDe~;P4u68O0%OeRafWyq+MYxFI~oyioSmRnw&R&?G^i z+AGLK%k6oit4M~1v6I$e%`Qv|s!!ovp#6h<*Lb{rVNR&?6=VyE?uVn$e-3Oz>4~Ai zy;laphd^z&2f-pY0h2`q?=smoN^+nw2?+ns0Lt9Hh0E08YwOejfn0~c%mOj*q3ZYYr1umEcP)2yzke~795^^yuB1oz-AQz_sdg&{c}C5dcvG6w{L#6(dRy5u&%n8MpC2f_ud~lSKq#k$Y}G>ov|o zryWoy>pWW2mYVc`-wm@tYH^i%B+;`D>6F7>c^cU|pfMnTH6sltNur;|Kb2W7#qq+g z9W|PI579n+iMI%qdZEq=kMHs;+&1IVXX*qy=767>cdO%C$8h~ zb3I49+Q=J8QiAM0dOyuakYj+KbDz3GEw4c!YtiuCduGZ~jkqrZL5Dkx>Ilw(kt-RD zXHxU0iVWb7EwNuEF208+l(0il@;7ws&w?M*NKe0(3nrAX@c*l1hN-9FwCdq|bv}?+ zse1x>j^&$}lmdyWs+NowzpE%S?99XeeJ+CvGns_Ef^rrSGfE|WAufDy%y{RJ`o9s6CNFcuN^qkw}g`9${ zEV+dn%nc<}8JQWoE3Yw86vnq7ZfYQ*z$nk~$%m)3tn9#rbC8SJ3lnh~e+XL#M zWG`BIeAZ!JfR`%ZQI>~}0rjD;T|(S)yL1gF)cOR0v1&sKi1%-*2E&27!qZ@TUl9h! zjUDK3I$e=VNvlh!C=8wG3crAK$Rn+_`C??)1xCkn2vwH{=$KbJ@;AVqV%YIHw!DI6l7;- zLu!J|2@J=+gM2Uo9r(kFihDHo!4o0wnX4Rp2NVa)0tu1x=ZL9@HbB{hk0GN?RtUWR z8{nb=+JA&a&Mw998rYE_?ZNrPBBE_Kf-nOMFXVffUwq=UK%xsSzEol!yyR( zbZMK-I_uKHJXlrgR-p3kf8sjVnBE1_RmAD@=Fg8nd77Kf0GIu3Xs*3B;KVbmxKePm63*xU1b-*u-A*5#?4K(48&(-)OaBbveNZPw`tF#zBMAz&c%_2css)W+d&7O*sZ{Rzsi=Pkk$@|?i_2LL@uPH8n9Ucbj! zIc3_ji{t?EkaOZG&sCsMlrY~4@pOdT6Hbj_*!=QaPZQwW7|V>u(wFiOb4M6evd#O9 ziRMA2kgV+8$Cwn;IjT1dZ(X9_lbKMEIaizcc)^9A(AVoYPMv&N5zS=FAsg$c0F5S+3RMD`B`I@2MLd-~ZPCJG`+d$sQ} z11Xk~oW>Z-VOfrjohii1;h0Gw5R8&46<|9HYk~bxa$XT}3C<*RocmWC#vUY}Jhf=5 zZJ~S_G0b;ClAP7PP-KESOHfqJY@GG=J-M;DxgG;kV)f}F!ovLDE{F0N zB&m#W^;E(f381F(n;TRqopuu>D2mUNRlguVC$O7LjzM#?x2eR4;Q(+$|D}f+UqUfgZC*byB((9C;Aixf%^}3~#3gLLBUxs*8 z**TY?6qHWcQMXuWml)RJQAi%MNI9`Sdnl%M!Q;g>h8qZloN}%i$Ma5zk16!FTr^*s z$B|j`(K;q~l8^<2&57nktHqI^b*bR0So8wfRi_qD?SivuFp738_g2Z^70sO!jY*>R*VBimX1gMuH*XJe30WmxL@Uv%$ABG~6$FX!A{a zR8M*q)fA|IbiP!(dIn)@^TeVlV~pYU1mWh|p~|)NiSc}M1jlM6KY2HbD<`*fJn~`- z+_&|`H}f1C84O2%SM0`1)yfM1~kF)xWL2I`gWvApCScH&n55tu7nKv(1TE8#+ zPDwCS@g61!{6wmh|9+m1UEepTW7?+Gpc1AeoH|{XWOOCE;%!`#OCPvG``&Vk@G#<{ zu7KkOZ{ms%MuZ~_CPWji+<4o`>LO*U10}AZTPcpaKpupR_B}_R0w1ybTEi*clUiV> z6Mv+xXF3TruC%OkR59Y=l++S~;v;-bC&E(vNK={!iVeO}ZM! zpOJ``eL7_SbTxuX<;9yraF>y?s{Lm5W9t+}bW&v%M6W38th9)2SlL7lrusQ>4L{l@ z7trqH51dd(sThs>QxhDJ)Kjv?hN`O2+GhpV@?54H*O$W0>y@0<3a{z(%y47@ceOCq zIbPgsTvSkbl-0fJ1Oqu;N?|rW{#k7v&FD%-{=ROim$sA}&3ol-n{X5}^8dClnx9+|ziJH^t4jEJ)DhzpPMlM)}x<#+5@JrSi^mL=oH^sm92b zlsN8dC}YP0M2F0|6n>qP=r>K#&5s0>sl)CtAI*!Ze5dRkRdvIF^>Xq>Vl$I7Z^Lip%xK7Q8We9^@Q$Z4QF2_Q>Oj2jX`~-Bwp%+iO`UX zWQuF2ZbsJGTZ5GNh1yc56Ra}#lIjFF@}tn26dq{*2^|Wvh#8rbxAyhsyx9I+jk;0m zja7tLYpimz+4>0LIjI1}R%si6{QAS&dC&2&i;r?oJ=Opa%Ud%SNQxh!G7jBGO zjVC-;_|Dci4^e8b05lCu>y)%>D<6gr-(F@@Wa8>f1RPU=zOXmz&qMj}L3 zk}r>Ga`ZJd!pA9>28z(%ivnsWD-8zodzFV!Bxbqo%b_+N_jZS9Gu}P_;IEO6T+0os z?Ps&m2pS_1P!sruug?vQ3MD?Q}zn!Ss2k9jZ= zOaB=pGJPrz(^r_@^v(1=)-Of^#az7rHXu*1$3QZ@0Hhv)6a`zBp(cgUxIm1)G?Y~Z z)@rbLDyJ3d6!!131s1`A`D-7((AX1imX578uxCMz%^@e^s{01QA-a*dJ zpFs$6y$|E`yQ2G$RIFgrL-^?K4o1TQ{I*tl0muu-E9tM~fk97x;dBEkK>Jd;-2bh- z((~1ryi&}p?+~KIB4Mdv602f8bd;Dqp)Tl4h(Dui8vmecc!$m^z|S1E6Fb8Kp`;hD z%Z&vVsc_{E#URbjVm8}@4(%eGaFg?!%;+sbW?5&SjfXi*H$#0|@*4gbuGzuQK}q14 zz~2qQCD0T%@k=DA)OYgCd5o<9(Qo~%)c9JnkJB7+Ko!<3hVlO?{0JgT0c6PRf~o*B z$&5SFq`p^F0rH%j-=;-L?&D|8Ll{(}Q;k~}i_Zi*NOs)OxO4{^&3o z&>BCo#(zL-C|v%E)_gb`_+LkB7`QKcKqg|5qCQsRm!Ch>Mw|nV^kJ=}md^WQrTE(A(#eUkJ5XR8J4u@{C7x5BP+#l`KUX#8DVDbY7c$Y;T%l^*54 zXynjj_*IVYh1 + + {historyError ?

{historyError}

: null} {!seededOnly && (
{ + const url = String(input); + if (url.endsWith("/api/posts/post-1/chat/conversations/conversation-post-1")) { + return jsonResponse({ + conversation_id: "conversation-post-1", + title: "Saved post question", + older_cursor: null, + exchanges: [ + { + turn_id: "turn-1", + question_text: "Which site visit was saved?", + answer_text: "The saved post answer stays grounded in the linked source.", + cited_post_ids: ["post-2"], + cited_posts: [{ post_id: "post-2", post_title: "Linked source post" }], + source_post_ids: ["post-1", "post-2"], + }, + ], + }); + } + if (url.includes("/chat/conversations")) { + return jsonResponse({ + conversations: + fixture === "saved" + ? [ + { + conversation_id: "conversation-post-1", + title: "Saved post question", + updated_at: "2026-08-21T00:00:00Z", + turn_count: 1, + }, + ] + : [], + }); + } + return jsonResponse({ + post_id: "post-1", + exchanges: [ + { + question_text: "What happened between these events?", + answer_text: "The seeded follow-up after the site visit.", + cited_post_ids: ["post-2"], + cited_posts: [{ post_id: "post-2", post_title: "Linked source post" }], + }, + ], + }); + }; +} + +const meta = { + title: "Workspace/ChatPanel", + component: ChatPanel, + args: { + postId: "post-1", + accessToken: "synthetic-story-token", + }, + parameters: { layout: "padded" }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const SeededDump: Story = { + render(args) { + installFixture("empty"); + return ; + }, +}; + +export const SavedHistory: Story = { + render(args) { + installFixture("saved"); + return ; + }, +}; + +export const Phone: Story = { + ...SavedHistory, + parameters: { + layout: "padded", + viewport: { defaultViewport: "mobile1" }, + }, +}; + diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx new file mode 100644 index 000000000..7688a6079 --- /dev/null +++ b/frontend/src/ChatPanel.test.tsx @@ -0,0 +1,73 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { ChatPanel } from "./App"; +import { setLocale } from "./i18n"; + +function jsonResponse(body: unknown) { + return new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); +} + +afterEach(() => { + vi.unstubAllGlobals(); + setLocale("en"); +}); + +describe("ChatPanel conversation history", () => { + it("reopens an owned conversation and returns to the seeded new-conversation state", async () => { + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { + const url = String(input); + if (url.endsWith("/chat/conversations/conversation-1")) { + return jsonResponse({ + conversation_id: "conversation-1", + title: "Saved question", + older_cursor: null, + exchanges: [{ + turn_id: "turn-1", + question_text: "What was saved?", + answer_text: "Only authorized saved evidence.", + cited_post_ids: [], + cited_posts: [], + source_post_ids: ["post-1"], + }], + }); + } + if (url.endsWith("/chat/conversations")) { + return jsonResponse({ + conversations: [{ + conversation_id: "conversation-1", + title: "Saved question", + updated_at: "2026-08-26T00:00:00Z", + turn_count: 1, + }], + next_cursor: null, + }); + } + return jsonResponse({ + post_id: "post-1", + exchanges: [{ + question_text: "Seed question", + answer_text: "Seed answer", + cited_post_ids: [], + cited_posts: [], + }], + }); + })); + + render(); + + expect(await screen.findByText("Seed answer")).toBeInTheDocument(); + await userEvent.selectOptions( + screen.getByLabelText("Conversation history"), + "conversation-1", + ); + expect(await screen.findByText("Only authorized saved evidence.")).toBeInTheDocument(); + + await userEvent.click(screen.getByRole("button", { name: "New conversation" })); + await waitFor(() => expect(screen.getByText("Seed answer")).toBeInTheDocument()); + expect(screen.queryByText("Only authorized saved evidence.")).toBeNull(); + }); +}); diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 2c812ccaa..415442dc3 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -333,6 +333,7 @@ export interface CitedPostEvidence { export interface ChatAnswer { post_id: string; + conversation_id?: string; answer_text: string; cited_post_ids: string[]; cited_posts?: CitedPostRef[]; @@ -351,6 +352,25 @@ export interface ChatHistory { exchanges: ChatExchange[]; } +export interface PostAskConversationSummary { + conversation_id: string; + title: string; + updated_at: string; + turn_count: number; +} + +export interface PostAskConversationPage { + conversations: PostAskConversationSummary[]; + next_cursor?: { updated_at: string; conversation_id: string } | null; +} + +export interface PostAskConversation { + conversation_id: string; + title: string; + exchanges: ChatExchange[]; + older_cursor?: string | null; +} + export interface CitedPostImage { post_id: string; unit_index: number; @@ -1125,13 +1145,33 @@ export function fetchPostChat(accessToken: string, postId: string): Promise { +export function askPostChat( + accessToken: string, + postId: string, + question: string, + conversationId?: string | null, +): Promise { return backendFetch(`/api/posts/${postId}/chat`, accessToken, { method: "POST", - body: JSON.stringify({ question }), + body: JSON.stringify({ question, ...(conversationId ? { conversation_id: conversationId } : {}) }), }); } +export function fetchPostChatConversations( + accessToken: string, + postId: string, +): Promise { + return backendFetch(`/api/posts/${postId}/chat/conversations`, accessToken); +} + +export function fetchPostChatConversation( + accessToken: string, + postId: string, + conversationId: string, +): Promise { + return backendFetch(`/api/posts/${postId}/chat/conversations/${conversationId}`, accessToken); +} + /** How often the queued Ask job is polled, and for how long overall. * A live orchestrator answer can take minutes under shared-gateway load, * so the ceiling is generous; the poll interval keeps the reader's diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 2d19b1cb8..87dbf4989 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -310,6 +310,9 @@ const TRANSLATIONS: Partial>> = { "첨부 이미지를 해독할 수 없습니다. 원문을 다시 내보내고 다시 여세요.", "What happened between these events?": "이 사건들 사이에 무슨 일이 있었나요?", "Ask about this lineage": "이 계보에 대해 질문", + "Conversation history": "대화 기록", + "New conversation": "새 대화", + "Conversation history could not be loaded.": "대화 기록을 불러올 수 없습니다.", "No reconstructed lineage yet. Rebuild after seeding posts.": "아직 재구성된 계보가 없습니다. 글을 시드한 뒤 다시 만드세요.", "Reconstructed lineage": "재구성된 계보", @@ -810,6 +813,9 @@ const TRANSLATIONS: Partial>> = { "无法解码嵌入图像。请重新导出原始文章后再打开。", "What happened between these events?": "这些事件之间发生了什么?", "Ask about this lineage": "询问此谱系", + "Conversation history": "对话历史", + "New conversation": "新对话", + "Conversation history could not be loaded.": "无法加载对话历史。", "No reconstructed lineage yet. Rebuild after seeding posts.": "尚未重建事件谱系。生成文章种子后再重建。", "Reconstructed lineage": "已重建的事件谱系", @@ -1322,6 +1328,9 @@ const TRANSLATIONS: Partial>> = { "埋め込み画像をデコードできませんでした。原文を再エクスポートして、もう一度開いてください。", "What happened between these events?": "これらのイベントの間に何が起きましたか?", "Ask about this lineage": "この系譜について質問", + "Conversation history": "会話履歴", + "New conversation": "新しい会話", + "Conversation history could not be loaded.": "会話履歴を読み込めませんでした。", "No reconstructed lineage yet. Rebuild after seeding posts.": "再構成された系譜はまだありません。投稿をシードしてから再構成してください。", "Reconstructed lineage": "再構成された系譜", @@ -1822,6 +1831,9 @@ const TRANSLATIONS: Partial>> = { "Không thể giải mã hình ảnh nhúng. Hãy xuất lại bài viết gốc rồi mở lại.", "What happened between these events?": "Điều gì đã xảy ra giữa các sự kiện này?", "Ask about this lineage": "Hỏi về dòng sự kiện này", + "Conversation history": "Lịch sử hội thoại", + "New conversation": "Cuộc hội thoại mới", + "Conversation history could not be loaded.": "Không thể tải lịch sử hội thoại.", "No reconstructed lineage yet. Rebuild after seeding posts.": "Chưa có dòng sự kiện được tái dựng. Hãy tạo dữ liệu mồi rồi tái dựng lại.", "Reconstructed lineage": "Dòng sự kiện đã tái dựng", diff --git a/migrations/0223_post_ask_conversation_history.sql b/migrations/0223_post_ask_conversation_history.sql new file mode 100644 index 000000000..cd8e0f17f --- /dev/null +++ b/migrations/0223_post_ask_conversation_history.sql @@ -0,0 +1,48 @@ +-- ADR 0228: persist account-owned Ask conversations on each visible post. +-- Third normal form: session identity, turn text, and citation/source +-- relations are separate tables. Index leads with user_account_id so a +-- frequently asked post cannot become a single hot partition key. + +create table if not exists post_ask_session ( + post_ask_session_id uuid primary key, + post_id uuid not null references source_post(post_id) on delete cascade, + user_account_id uuid not null references user_account(user_account_id) on delete cascade, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create index if not exists post_ask_session_account_post_idx + on post_ask_session (user_account_id, post_id, updated_at desc); + +create table if not exists post_ask_turn ( + post_ask_session_id uuid not null + references post_ask_session(post_ask_session_id) on delete cascade, + turn_ordinal integer not null check (turn_ordinal > 0), + question_text text not null, + answer_text text not null, + created_at timestamptz not null default now(), + primary key (post_ask_session_id, turn_ordinal) +); + +create table if not exists post_ask_turn_citation ( + post_ask_session_id uuid not null, + turn_ordinal integer not null, + citation_ordinal integer not null check (citation_ordinal >= 0), + cited_post_id uuid not null references source_post(post_id) on delete cascade, + primary key (post_ask_session_id, turn_ordinal, citation_ordinal), + foreign key (post_ask_session_id, turn_ordinal) + references post_ask_turn(post_ask_session_id, turn_ordinal) + on delete cascade +); + +create table if not exists post_ask_turn_source ( + post_ask_session_id uuid not null, + turn_ordinal integer not null, + source_ordinal integer not null check (source_ordinal >= 0), + source_post_id uuid not null references source_post(post_id) on delete cascade, + primary key (post_ask_session_id, turn_ordinal, source_ordinal), + unique (post_ask_session_id, turn_ordinal, source_post_id), + foreign key (post_ask_session_id, turn_ordinal) + references post_ask_turn(post_ask_session_id, turn_ordinal) + on delete cascade +); diff --git a/migrations/rollback/0223_post_ask_conversation_history.sql b/migrations/rollback/0223_post_ask_conversation_history.sql new file mode 100644 index 000000000..5a820c07a --- /dev/null +++ b/migrations/rollback/0223_post_ask_conversation_history.sql @@ -0,0 +1,4 @@ +drop table if exists post_ask_turn_citation; +drop table if exists post_ask_turn_source; +drop table if exists post_ask_turn; +drop table if exists post_ask_session; diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py new file mode 100644 index 000000000..57051eeb6 --- /dev/null +++ b/tests/test_post_ask_history.py @@ -0,0 +1,276 @@ +"""Regression tests for account-owned per-post Ask history queries.""" + +from __future__ import annotations + +import asyncio +from datetime import UTC, datetime +from uuid import UUID + +import pytest + +from backend.app.post_ask_history import ( + PostAskEvidenceChanged, + _visible_post_ids_batch, + conversation_exists, + list_conversations, + persist_turn, +) + + +class _Connection: + """Capture bound SQL calls without needing a database for query-shape tests.""" + + def __init__(self, rows: list[dict[str, object]] | None = None) -> None: + self.rows = rows or [] + self.calls: list[tuple[str, tuple[object, ...]]] = [] + + async def fetch(self, query: str, *arguments: object) -> list[dict[str, object]]: + self.calls.append((query, arguments)) + return self.rows + + async def fetchval(self, query: str, *arguments: object) -> object: + self.calls.append((query, arguments)) + if "exists(" in query: + return True + if "coalesce(max(turn_ordinal)" in query: + return 1 + return None + + async def fetchrow(self, query: str, *arguments: object) -> dict[str, object] | None: + self.calls.append((query, arguments)) + return {"post_ask_session_id": arguments[0]} + + async def execute(self, query: str, *arguments: object) -> str: + self.calls.append((query, arguments)) + return "INSERT 0 1" + + def transaction(self) -> _Connection: + return self + + async def __aenter__(self) -> _Connection: + return self + + async def __aexit__(self, *_exc: object) -> None: + return None + + +def test_list_conversations_binds_account_post_and_cursor() -> None: + """Pagination and post scope remain parameters, never interpolated SQL.""" + connection = _Connection( + [ + { + "post_ask_session_id": UUID("00000000-0000-0000-0000-000000000001"), + "conversation_title": "First", + "updated_at": datetime(2026, 1, 2, tzinfo=UTC), + "turn_count": 1, + }, + { + "post_ask_session_id": UUID("00000000-0000-0000-0000-000000000002"), + "conversation_title": "Second", + "updated_at": datetime(2026, 1, 1, tzinfo=UTC), + "turn_count": 2, + }, + ] + ) + cursor_time = datetime(2026, 1, 3, tzinfo=UTC) + + result = asyncio.run( + list_conversations( + connection, + "account-1", + "post-1", + limit=1, + before_updated_at=cursor_time, + before_conversation_id=UUID("00000000-0000-0000-0000-000000000003"), + ) + ) + + query, arguments = connection.calls[0] + assert "{cursor_clause}" not in query + assert "post_ask_session" in query + assert arguments == ( + "account-1", + "post-1", + cursor_time, + UUID("00000000-0000-0000-0000-000000000003"), + 2, + ) + assert len(result["conversations"]) == 1 + assert result["next_cursor"] is not None + assert result["conversations"][0]["conversation_id"] == "00000000-0000-0000-0000-000000000001" + + +def test_conversation_exists_requires_account_and_post() -> None: + """A conversation id from another post or account must not match.""" + connection = _Connection() + conversation_id = UUID("00000000-0000-0000-0000-000000000009") + + found = asyncio.run( + conversation_exists(connection, "account-1", "post-1", conversation_id) + ) + + query, arguments = connection.calls[0] + assert "post_ask_session" in query + assert arguments == (conversation_id, "account-1", "post-1") + assert found is True + + +def test_visible_post_ids_batch_uses_fixed_source_and_citation_queries() -> None: + """Both relation types use fixed identifiers rather than interpolated SQL.""" + for source, table, column in ( + (True, "post_ask_turn_source", "source_post_id"), + (False, "post_ask_turn_citation", "cited_post_id"), + ): + connection = _Connection( + [ + { + "turn_ordinal": 1, + "post_id": "post-1", + "post_title": "Synthetic source", + "visibility_code": "workspace", + "corporate_entity_id": "entity-1", + "author_account_id": "account-1", + "source_detail_state_code": "current", + } + ] + ) + by_turn = asyncio.run( + _visible_post_ids_batch( + connection, + UUID("00000000-0000-0000-0000-000000000004"), + [1], + lambda row: row["post_id"] == "post-1", + source=source, + ) + ) + post_ids, rows = by_turn[1] + + query, arguments = connection.calls[0] + assert table in query + assert column in query + assert "relation.{" not in query + assert "source_draft_code" in query + assert "source_deleted_flag" in query + assert arguments[1] == [1] + assert post_ids == ["post-1"] + assert rows["post-1"]["post_title"] == "Synthetic source" + + +def test_visible_post_ids_batch_stays_at_one_query_regardless_of_turn_count() -> None: + """Query count must not grow with the number of turns being reauthorized.""" + connection = _Connection([]) + + by_turn = asyncio.run( + _visible_post_ids_batch( + connection, + UUID("00000000-0000-0000-0000-000000000004"), + list(range(1, 51)), + lambda row: True, + source=True, + ) + ) + + assert len(connection.calls) == 1 + assert set(by_turn.keys()) == set(range(1, 51)) + assert all(ids == [] and rows == {} for ids, rows in by_turn.values()) + + +def test_visible_post_ids_batch_never_leaks_a_row_into_the_wrong_turn() -> None: + """A row is partitioned to its own turn_ordinal, never a neighboring turn.""" + connection = _Connection( + [ + { + "turn_ordinal": 1, + "post_id": "post-turn-1", + "post_title": "Turn 1 post", + "visibility_code": "public", + "corporate_entity_id": "entity-1", + "author_account_id": "account-1", + "source_detail_state_code": "current", + }, + { + "turn_ordinal": 2, + "post_id": "post-turn-2", + "post_title": "Turn 2 post", + "visibility_code": "public", + "corporate_entity_id": "entity-1", + "author_account_id": "account-1", + "source_detail_state_code": "current", + }, + ] + ) + + by_turn = asyncio.run( + _visible_post_ids_batch( + connection, + UUID("00000000-0000-0000-0000-000000000004"), + [1, 2, 3], + lambda row: True, + source=False, + ) + ) + + assert by_turn[1][0] == ["post-turn-1"] + assert by_turn[2][0] == ["post-turn-2"] + assert by_turn[3] == ([], {}) + + +def test_persist_turn_creates_a_new_session_then_writes_the_turn() -> None: + """A completed answer is stored under the calling account and post.""" + connection = _Connection() + conversation_id = asyncio.run( + persist_turn( + connection, + "account-1", + "post-1", + None, + "Which site visit was saved?", + "The saved post answer stays grounded in the linked source.", + ["post-1", "post-2"], + ["post-2"], + ) + ) + + statements = [query for query, _arguments in connection.calls] + assert any("insert into post_ask_session" in query for query in statements) + assert any("insert into post_ask_turn" in query for query in statements) + assert any("insert into post_ask_turn_source" in query for query in statements) + assert any("insert into post_ask_turn_citation" in query for query in statements) + session_arguments = next( + arguments + for query, arguments in connection.calls + if "insert into post_ask_session" in query + ) + assert session_arguments[0] == conversation_id + assert session_arguments[1:] == ("post-1", "account-1") + + +def test_persist_turn_aborts_when_a_citation_loses_authorization() -> None: + """The transaction fails closed if cited evidence is no longer visible.""" + connection = _Connection([ + { + "post_id": "post-2", + "post_title": "Synthetic source", + "visibility_code": "workspace", + "corporate_entity_id": "entity-2", + "author_account_id": "account-2", + "source_detail_state_code": "current", + } + ]) + + with pytest.raises(PostAskEvidenceChanged): + asyncio.run( + persist_turn( + connection, + "account-1", + "post-1", + None, + "What changed?", + "A complete answer.", + ["post-1", "post-2"], + ["post-2"], + can_see_post=lambda _row: False, + ) + ) + + assert any("for share of post" in query.lower() for query, _ in connection.calls) From 29d05e4e70d2780d9b791ab541ed2521a28e5648 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:16:36 +0900 Subject: [PATCH 048/238] docs(gap): track per-post Ask delivery evidence --- docs/operability/http-concurrency-evidence.md | 10 ++++++++++ docs/product-technical-gap-baseline.md | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/operability/http-concurrency-evidence.md b/docs/operability/http-concurrency-evidence.md index ae3684142..56fbde830 100644 --- a/docs/operability/http-concurrency-evidence.md +++ b/docs/operability/http-concurrency-evidence.md @@ -70,6 +70,16 @@ above on an application-ready stack to obtain the product measurement. ## Older-image diagnostic observation +On 2026-08-26, the application-ready local synthetic stack completed a +5-VU, 15-second k6 run with five iterations and 0 failed requests. Ask enqueue +was 967.49 ms; Ask polling averaged 11.94 seconds; ordinary authenticated +posts/lineage reads averaged 34.53 seconds (p95 43.26 seconds). The run used +the stack's deployed image rather than this candidate head, so it proves only +that the existing HTTP boundary remains responsive without request failures +while also exposing unacceptable reader latency for investigation. It is not +an ADR 0228 capacity result or an SLO. Rebuild the exact candidate image and +repeat with resource and query-plan telemetry before attributing the delay. + On 2026-08-25, an application-ready local Compose stack configured with four worker VUs completed zero full iterations in two observations. In the second 30-second observation, Ask enqueue took 2.69 seconds, the maximum completed diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a355b4633..e905d4b5f 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -388,13 +388,13 @@ feature is equivalent. | ADR 0133 — source-reference research | No `source_reference_research` persistence, post-admin action, or reader contract exists. The existing relation-verification client verifies an already extracted organization and is not the cited-resource discovery workflow | Missing | Add the ADR first, then one bounded SearXNG → contextual-orchestrator judgment slice with public-host/redirect rejection, normalized provenance, synthetic SSRF tests, and no entity binding from a search hit alone | | ADR 0134 — token-backed exception messages | Protected main has no shared `StatusNotice`; #643 (`3453ab08`) is the active current-main implementation candidate | In progress, not protected delivery | Land #643 only after exact-head checks and independent approval; then migrate remaining raw/color-only exception surfaces with Storybook unavailable/retry scenes | | ADR 0135 — analysis-kind exact next actions | Protected main has no `analysisRunGuidance`; merged stack #669 (`21bb799c`) is included in #667's non-default branch with cancelled-run guidance and responsive layout | In progress, not protected delivery | Land #667 with exact-head UI tests and desktop/mobile screenshot evidence; follow with the remaining kind × status Storybook interaction matrix without inventing TEPP or report actions | -| ADR 0136 — per-post Ask history | No `post_ask_session` or `post_ask_turn` schema/API exists on protected main | Missing | Add the ADR and normalized account + post scoped tables, hot-post-safe index, batched visibility reauthorization, list/select/new UI, cross-account/post rejection tests, and citation-revocation evidence | +| ADR 0136 — per-post Ask history | Protected main has no `post_ask_session` or `post_ask_turn`; the current stacked candidate records the superseding ADR 0228 and adds normalized account + post scoped tables, an account-leading index, batched visibility reauthorization, list/select/new UI, cross-scope rejection, and citation-revocation rollback | In progress, not protected delivery | Re-fetch the candidate's exact head, complete hosted checks and independent approval, then verify the migration and authenticated UI against an exact-head stack; do not treat local tests or screenshots as release evidence | | ADR 0137 — cross-post customer identity | No `customer_identity_judgment`, `customer_identity_binding`, or `corporate_entity_name_history` schema exists on protected main | Missing | Add the ADR before implementation; retain `(source_system_code, source_customer_code)` identity, require multiple eligible posts and external cited corroboration, persist abstention/tie states, and consume owning-library judgment evidence without local scoring | -The next implementation order is ADR 0134/#643 and the stacked ADR 0135 work because -their focused current-base heads already exist. ADR 0133, ADR 0136, and ADR -0137 must each start from a new ADR-first current-main PR; none is authorized -for wholesale replay from #490. +ADR 0134/#643 and ADR 0135/#669 have focused delivery heads. ADR 0136 is now a +separate ADR-first candidate reusing only the reviewed persistence contract, +not #490's 321-file tree. ADR 0133 and ADR 0137 remain missing and each requires +its own current-main decision and focused PR. ## 5. Open product and technical gaps From 9e2e97a7f4e7ebf8f970cbe31322a61f01d98934 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:19:11 +0900 Subject: [PATCH 049/238] test(storybook): normalize mocked request URLs --- frontend/src/ChatPanel.stories.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/ChatPanel.stories.tsx b/frontend/src/ChatPanel.stories.tsx index 0b6607ba2..d44e3d2c0 100644 --- a/frontend/src/ChatPanel.stories.tsx +++ b/frontend/src/ChatPanel.stories.tsx @@ -12,7 +12,7 @@ function jsonResponse(body: unknown, status = 200) { function installFixture(fixture: Fixture) { globalThis.fetch = async (input) => { - const url = String(input); + const url = typeof input === "string" ? input : input.url; if (url.endsWith("/api/posts/post-1/chat/conversations/conversation-post-1")) { return jsonResponse({ conversation_id: "conversation-post-1", @@ -93,4 +93,3 @@ export const Phone: Story = { viewport: { defaultViewport: "mobile1" }, }, }; - From c653663270a0f2b35fe58667983816103584ad85 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:25:08 +0900 Subject: [PATCH 050/238] fix(ask): preserve process-unit authorization context --- backend/app/post_ask_history.py | 3 +++ tests/test_post_ask_history.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 959e0f6b1..7b3c7a412 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -141,6 +141,7 @@ async def _visible_post_ids_batch( select relation.turn_ordinal as turn_ordinal, relation.source_post_id::text as post_id, relation.source_ordinal as ordinal, post.post_title, post.visibility_code, post.corporate_entity_id, + post.process_unit_id, post.author_account_id, post.source_detail_state_code from post_ask_turn_source relation join source_post post on post.post_id = relation.source_post_id @@ -158,6 +159,7 @@ async def _visible_post_ids_batch( select relation.turn_ordinal as turn_ordinal, relation.cited_post_id::text as post_id, relation.citation_ordinal as ordinal, post.post_title, post.visibility_code, post.corporate_entity_id, + post.process_unit_id, post.author_account_id, post.source_detail_state_code from post_ask_turn_citation relation join source_post post on post.post_id = relation.cited_post_id @@ -291,6 +293,7 @@ async def _ensure_citations_visible( """ select relation.cited_post_id::text as post_id, post.post_title, post.visibility_code, post.corporate_entity_id, + post.process_unit_id, post.author_account_id, post.source_detail_state_code from post_ask_turn_citation relation join source_post post on post.post_id = relation.cited_post_id diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py index 57051eeb6..c15ef4993 100644 --- a/tests/test_post_ask_history.py +++ b/tests/test_post_ask_history.py @@ -151,6 +151,7 @@ def test_visible_post_ids_batch_uses_fixed_source_and_citation_queries() -> None assert "relation.{" not in query assert "source_draft_code" in query assert "source_deleted_flag" in query + assert "post.process_unit_id" in query assert arguments[1] == [1] assert post_ids == ["post-1"] assert rows["post-1"]["post_title"] == "Synthetic source" @@ -274,3 +275,7 @@ def test_persist_turn_aborts_when_a_citation_loses_authorization() -> None: ) assert any("for share of post" in query.lower() for query, _ in connection.calls) + assert any( + "post.process_unit_id" in query and "for share of post" in query.lower() + for query, _ in connection.calls + ) From 51b9dfaf7bb6ab824bd30ac7e7874c2d15f08e89 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:25:43 +0900 Subject: [PATCH 051/238] test(storybook): accept every fetch input shape --- frontend/src/ChatPanel.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/ChatPanel.stories.tsx b/frontend/src/ChatPanel.stories.tsx index d44e3d2c0..395a324dd 100644 --- a/frontend/src/ChatPanel.stories.tsx +++ b/frontend/src/ChatPanel.stories.tsx @@ -12,7 +12,7 @@ function jsonResponse(body: unknown, status = 200) { function installFixture(fixture: Fixture) { globalThis.fetch = async (input) => { - const url = typeof input === "string" ? input : input.url; + const url = input instanceof Request ? input.url : String(input); if (url.endsWith("/api/posts/post-1/chat/conversations/conversation-post-1")) { return jsonResponse({ conversation_id: "conversation-post-1", From ac7eb4e68285b35fb39439f8fb02d159d5add494 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:29:22 +0900 Subject: [PATCH 052/238] docs(gaps): record stacked Ask history candidate --- docs/product-technical-gap-baseline.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a355b4633..edf90179d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -14,6 +14,7 @@ | Project-specific journey | Explicit source/semantic project membership plus event-time ordering | Candidate API and ordered journey UI implemented; authenticated runtime acceptance pending | | Repeat issue to design improvement | `repeat_issue`, `issue_pattern`, and `improvement_action` cited facts | Candidate semantic contract; design-system connector acceptance pending | | Natural-language Ask with evidence, report, alert, MCP | Persisted semantic-unit embeddings plus versioned delivery/resource contract | Candidate implementation uses whole-question embedding retrieval with no lexical fallback; authenticated runtime acceptance pending | +| Per-post Ask continuity | ADR 0228; account/post-scoped normalized sessions and current-authorization citation projection | Stacked PR #677 candidate implementation and regression/Storybook evidence; parent #667 must merge first, then #677 must be retargeted to `main` and revalidated | | Similar VOC, customer cohort, prior action | Persisted repeat-issue candidate semantics plus orchestrator pair adjudication and extractive evidence | Candidate live post endpoint and post-detail UI implemented; authenticated runtime acceptance pending | | TEPP independent Event Lineage anchor | Accepted, persisted TEPP criterion bound to exact snapshot/cutoff before fast-mlsirm activation | Consumer PR #606 is on protected main; TEPP producer PR #237 remains open, so no end-to-end accepted artifact is release evidence yet | | Temporal Lineage topics and multilevel important posts | ADR 0210; TEPP posterior topic/plausible-value contract followed by fast-mlsirm observed-information case-deletion influence | Product/technical contract is protected on `main`; neither required Rust CPU/GPU producer envelope is shipped, so the Dashboard surface remains unavailable (ADR 0208: no local Python substitute) | @@ -60,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 13 open PRs and 10 open issues. The exact-head +At this snapshot there were 14 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 12:20 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 09:27 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, @@ -77,14 +78,15 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 13 open PRs and 10 +at this refresh. The live queue contains 14 open PRs and 10 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 | | ---: | --- | --- | -| #667 | `0653f0d9` | baseline refresh branch exact head at this snapshot; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #677 | `51b9dfaf` | ADR 0228 account-owned per-post Ask conversation history; stacked on #667, so parent protected merge and `main` retarget precede fresh exact-head review/check evidence | +| #667 | `a7a64453` | baseline refresh branch pre-refresh head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `1b8e1a99` | evidence-bound project history projection with ADR renumbering, request guards, and source-code/time-basis display repair; BLOCKED with review required | | #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | From 10c4e1d65363761d1edf6e90c7ebad18d92e0408 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:31:59 +0900 Subject: [PATCH 053/238] docs(gaps): record current stacked queue --- docs/product-technical-gap-baseline.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index edf90179d..761e46d56 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 14 open PRs and 10 open issues. The exact-head +At this snapshot there were 15 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,15 +78,16 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 14 open PRs and 10 +at this refresh. The live queue contains 15 open PRs and 10 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 | | ---: | --- | --- | +| #678 | `662a62fb` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `51b9dfaf` | ADR 0228 account-owned per-post Ask conversation history; stacked on #667, so parent protected merge and `main` retarget precede fresh exact-head review/check evidence | -| #667 | `a7a64453` | baseline refresh branch pre-refresh head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #667 | `ac7eb4e6` | baseline refresh branch pre-refresh head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `1b8e1a99` | evidence-bound project history projection with ADR renumbering, request guards, and source-code/time-basis display repair; BLOCKED with review required | | #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | @@ -94,7 +95,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `674f2805` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and RankWeave-owned RRF evidence; BLOCKED with hosted checks queued and no independent approval | +| #640 | `0f0cf4a8` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and RankWeave-owned RRF evidence; BLOCKED with hosted checks queued and no independent approval | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 70af96b043cd07befb6023b415c811abfb9f35b4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:45:45 +0900 Subject: [PATCH 054/238] fix(ask): preserve localized and race-safe conversation history --- backend/app/post_ask_history.py | 18 +++++++-------- frontend/src/App.tsx | 39 ++++++++++++++++++++++++++------- frontend/src/api.ts | 12 +++++++--- frontend/src/i18n.ts | 4 ++++ 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 7b3c7a412..116cffc87 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -62,14 +62,11 @@ async def list_conversations( rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli """ select session.post_ask_session_id, - coalesce( - (select left(turn.question_text, 80) - from post_ask_turn turn - where turn.post_ask_session_id = session.post_ask_session_id - order by turn.turn_ordinal - limit 1), - 'New conversation' - ) as conversation_title, + (select left(turn.question_text, 80) + from post_ask_turn turn + where turn.post_ask_session_id = session.post_ask_session_id + order by turn.turn_ordinal + limit 1) as conversation_title, session.updated_at, count(turn.turn_ordinal)::int as turn_count from post_ask_session session @@ -272,7 +269,7 @@ async def fetch_conversation( "source_post_ids": source_ids, } ) - title = title_question[:80] if title_question else "New conversation" + title = title_question[:80] if title_question else None return { "conversation_id": str(header["post_ask_session_id"]), "title": title, @@ -290,7 +287,7 @@ async def _ensure_citations_visible( ) -> None: """Lock and re-authorize new citations before their transaction commits.""" rows = await conn.fetch( - """ + f""" select relation.cited_post_id::text as post_id, post.post_title, post.visibility_code, post.corporate_entity_id, post.process_unit_id, @@ -299,6 +296,7 @@ async def _ensure_citations_visible( join source_post post on post.post_id = relation.cited_post_id where relation.post_ask_session_id = $1 and relation.turn_ordinal = $2 + and ({SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')}) for share of post """, conversation_id, diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 834963651..d6037082c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -61,6 +61,7 @@ import { type ChatAnswer, type ChatExchange, type PostAskConversationSummary, + type PostAskConversationPage, type CorporateEntityRef, type CustomerMasterEntity, type CustomerMasterResponse, @@ -272,6 +273,7 @@ export function ChatPanel({ const [exchanges, setExchanges] = useState([]); const [seededExchanges, setSeededExchanges] = useState([]); const [conversations, setConversations] = useState([]); + const [conversationCursor, setConversationCursor] = useState(null); const [conversationId, setConversationId] = useState(null); const [historyError, setHistoryError] = useState(null); const [answer, setAnswer] = useState(null); @@ -281,6 +283,7 @@ export function ChatPanel({ const [seededOnly, setSeededOnly] = useState(false); useEffect(() => { + let active = true; setExchanges([]); setSeededExchanges([]); setConversations([]); @@ -292,19 +295,31 @@ export function ChatPanel({ setEvidencePostId(null); fetchPostChat(accessToken, postId) .then((history) => { - setSeededExchanges(history.exchanges); - setExchanges(history.exchanges); + if (active) { + setSeededExchanges(history.exchanges); + setExchanges(history.exchanges); + } }) - .catch(() => setExchanges([])); + .catch(() => { if (active) setExchanges([]); }); fetchPostChatConversations(accessToken, postId) - .then((page) => setConversations(page.conversations)) - .catch(() => setHistoryError(t("Conversation history could not be loaded."))); + .then((page) => { + if (active) { + setConversations(page.conversations); + setConversationCursor(page.next_cursor ?? null); + } + }) + .catch(() => { if (active) setHistoryError(t("Conversation history could not be loaded.")); }); + return () => { active = false; }; }, [postId, accessToken]); + const conversationRequest = useRef(0); async function selectConversation(nextId: string) { + const requestId = ++conversationRequest.current; setHistoryError(null); + setAnswer(null); try { const conversation = await fetchPostChatConversation(accessToken, postId, nextId); + if (requestId !== conversationRequest.current) return; setConversationId(conversation.conversation_id); setExchanges(conversation.exchanges); } catch { @@ -313,6 +328,7 @@ export function ChatPanel({ } function startNewConversation() { + ++conversationRequest.current; setConversationId(null); setExchanges(seededExchanges); setQuestion(""); @@ -346,7 +362,7 @@ export function ChatPanel({ cited_post_ids: result.cited_post_ids, cited_posts: result.cited_posts, }; - return [...prev.filter((row) => row.question_text !== next.question_text), next]; + return [...prev, next]; }); } catch (err) { setError(orchestratorUnavailableMessage(err, "Chat")); @@ -415,17 +431,24 @@ export function ChatPanel({ {t("Conversation history")} + {conversationCursor ? ( + + ) : null} diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 415442dc3..55a47b1a9 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -354,7 +354,7 @@ export interface ChatHistory { export interface PostAskConversationSummary { conversation_id: string; - title: string; + title: string | null; updated_at: string; turn_count: number; } @@ -1160,16 +1160,22 @@ export function askPostChat( export function fetchPostChatConversations( accessToken: string, postId: string, + cursor?: { updated_at: string; conversation_id: string }, ): Promise { - return backendFetch(`/api/posts/${postId}/chat/conversations`, accessToken); + const query = cursor + ? `?before_updated_at=${encodeURIComponent(cursor.updated_at)}&before_conversation_id=${encodeURIComponent(cursor.conversation_id)}` + : ""; + return backendFetch(`/api/posts/${postId}/chat/conversations${query}`, accessToken); } export function fetchPostChatConversation( accessToken: string, postId: string, conversationId: string, + beforeTurn?: number, ): Promise { - return backendFetch(`/api/posts/${postId}/chat/conversations/${conversationId}`, accessToken); + const query = beforeTurn === undefined ? "" : `?before_turn=${beforeTurn}`; + return backendFetch(`/api/posts/${postId}/chat/conversations/${conversationId}${query}`, accessToken); } /** How often the queued Ask job is polled, and for how long overall. diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 87dbf4989..fbce9e137 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -311,6 +311,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "이 사건들 사이에 무슨 일이 있었나요?", "Ask about this lineage": "이 계보에 대해 질문", "Conversation history": "대화 기록", + "Load more": "더 보기", "New conversation": "새 대화", "Conversation history could not be loaded.": "대화 기록을 불러올 수 없습니다.", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -814,6 +815,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "这些事件之间发生了什么?", "Ask about this lineage": "询问此谱系", "Conversation history": "对话历史", + "Load more": "加载更多", "New conversation": "新对话", "Conversation history could not be loaded.": "无法加载对话历史。", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -1329,6 +1331,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "これらのイベントの間に何が起きましたか?", "Ask about this lineage": "この系譜について質問", "Conversation history": "会話履歴", + "Load more": "さらに読み込む", "New conversation": "新しい会話", "Conversation history could not be loaded.": "会話履歴を読み込めませんでした。", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -1832,6 +1835,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "Điều gì đã xảy ra giữa các sự kiện này?", "Ask about this lineage": "Hỏi về dòng sự kiện này", "Conversation history": "Lịch sử hội thoại", + "Load more": "Tải thêm", "New conversation": "Cuộc hội thoại mới", "Conversation history could not be loaded.": "Không thể tải lịch sử hội thoại.", "No reconstructed lineage yet. Rebuild after seeding posts.": From f7f4580b7ea64d90f78a46730e0c8f0fe2c0f707 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:47:24 +0900 Subject: [PATCH 055/238] docs(gaps): refresh current exact heads --- docs/product-technical-gap-baseline.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 761e46d56..fc550e3f2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 15 open PRs and 10 open issues. The exact-head +At this snapshot there were 16 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,16 +78,17 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 15 open PRs and 10 +at this refresh. The live queue contains 16 open PRs and 10 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 | | ---: | --- | --- | +| #679 | `c60dcb3a` | ADR 0229 persisted public-claim envelope with unique ADR numbering; BLOCKED with exact-head checks and independent review required; normal squash auto-merge enabled | | #678 | `662a62fb` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `51b9dfaf` | ADR 0228 account-owned per-post Ask conversation history; stacked on #667, so parent protected merge and `main` retarget precede fresh exact-head review/check evidence | -| #667 | `ac7eb4e6` | baseline refresh branch pre-refresh head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #667 | `10c4e1d6` | baseline refresh branch pre-refresh head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `1b8e1a99` | evidence-bound project history projection with ADR renumbering, request guards, and source-code/time-basis display repair; BLOCKED with review required | | #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | @@ -95,7 +96,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `0f0cf4a8` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and RankWeave-owned RRF evidence; BLOCKED with hosted checks queued and no independent approval | +| #640 | `72ef6dd6` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and fail-closed legacy RankWeave evidence; BLOCKED with hosted checks queued and no independent approval | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 2c32393222af13611a19ab0f3816cb7785ebebad Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:48:33 +0900 Subject: [PATCH 056/238] docs(gaps): record current Ask repair heads --- 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 fc550e3f2..ab04a893a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 09:27 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 09:50 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, @@ -85,10 +85,10 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #679 | `c60dcb3a` | ADR 0229 persisted public-claim envelope with unique ADR numbering; BLOCKED with exact-head checks and independent review required; normal squash auto-merge enabled | +| #679 | `640e530c` | ADR 0229 persisted public-claim envelope with unique ADR numbering and async public-claim verification repair; BLOCKED with exact-head checks and independent review required | | #678 | `662a62fb` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | -| #677 | `51b9dfaf` | ADR 0228 account-owned per-post Ask conversation history; stacked on #667, so parent protected merge and `main` retarget precede fresh exact-head review/check evidence | -| #667 | `10c4e1d6` | baseline refresh branch pre-refresh head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #677 | `70af96b0` | ADR 0228 account-owned per-post Ask conversation history with localized titles, cursor transport, stale-response guards, repeated-turn preservation, and eligibility recheck; BLOCKED with hosted checks and independent review required | +| #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `1b8e1a99` | evidence-bound project history projection with ADR renumbering, request guards, and source-code/time-basis display repair; BLOCKED with review required | | #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | From 84a9de342a4f793fc8dd8ba99a29e0c55537faf0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:54:34 +0900 Subject: [PATCH 057/238] docs(gaps): add customer-copy PR and schema RCA heads --- docs/product-technical-gap-baseline.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index ab04a893a..a78408c3d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 09:50 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 10: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, @@ -78,25 +78,26 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 16 open PRs and 10 +at this refresh. The live queue contains 17 open PRs and 10 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 | | ---: | --- | --- | +| #680 | `9f841cc1` | customer-facing ranking copy removes internal engine names and provides localized retry/search-next-action guidance; BLOCKED with hosted checks and independent review required | | #679 | `640e530c` | ADR 0229 persisted public-claim envelope with unique ADR numbering and async public-claim verification repair; BLOCKED with exact-head checks and independent review required | | #678 | `662a62fb` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `70af96b0` | ADR 0228 account-owned per-post Ask conversation history with localized titles, cursor transport, stale-response guards, repeated-turn preservation, and eligibility recheck; BLOCKED with hosted checks and independent review required | | #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `1b8e1a99` | evidence-bound project history projection with ADR renumbering, request guards, and source-code/time-basis display repair; BLOCKED with review required | -| #663 | `7ac1483e` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; BLOCKED with review required | +| #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `72ef6dd6` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and fail-closed legacy RankWeave evidence; BLOCKED with hosted checks queued and no independent approval | +| #640 | `96981865` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and fail-closed legacy RankWeave evidence; BLOCKED with hosted checks queued and no independent approval | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 4260af2c5f4a2fc78949df98794837f15a4a898b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:58:05 +0900 Subject: [PATCH 058/238] fix(ui): make recovery copy customer-actionable --- backend/app/main.py | 15 ++++++++++++--- frontend/src/App.test.tsx | 14 +++++++------- frontend/src/App.tsx | 24 ++++++++++++++---------- frontend/src/ChatPanel.test.tsx | 31 ++++++++++++++++++++++++++++++- frontend/src/i18n.ts | 8 ++++---- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index b0bc28a58..6ea717364 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -3000,7 +3000,10 @@ async def _persist_post_ask_turn( "Post chat is temporarily unavailable because authorized evidence changed. Retry the question.", ) from exc except PostAskConversationNotFound as exc: - raise HTTPException(status.HTTP_404_NOT_FOUND, "conversation not found") from exc + raise HTTPException( + status.HTTP_404_NOT_FOUND, + "This conversation is no longer available. Choose another conversation or start a new one.", + ) from exc @app.get("/api/posts/{post_id}/chat") @@ -3050,7 +3053,10 @@ async def chat_about_post( if request.conversation_id is not None and not await post_ask_conversation_exists( conn, account.user_account_id, post_id, request.conversation_id ): - raise HTTPException(status.HTTP_404_NOT_FOUND, "conversation not found") + raise HTTPException( + status.HTTP_404_NOT_FOUND, + "This conversation is no longer available. Choose another conversation or start a new one.", + ) stored = await fetch_persisted_chat(conn, post_id, question) if stored is not None: source_ids = [post_id] @@ -3202,7 +3208,10 @@ async def read_post_chat_conversation( before_turn_ordinal=before_turn, ) if conversation is None: - raise HTTPException(status.HTTP_404_NOT_FOUND, "conversation not found") + raise HTTPException( + status.HTTP_404_NOT_FOUND, + "This conversation is no longer available. Choose another conversation or start a new one.", + ) return conversation diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 1110d8fb0..3d0b14722 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -3276,7 +3276,7 @@ describe("App, authenticated", () => { expect(list).toHaveTextContent("TEPP measurement · Failed · Demo Corp"); expect(list).toHaveTextContent("Period report · Succeeded · Demo Corp"); expect(list).toHaveTextContent( - "Open this run to see why it failed, then connect the measurement service and re-run.", + "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again.", ); expect(list).toHaveTextContent("3 documents"); expect(list).not.toHaveTextContent("postgresql://"); @@ -3430,11 +3430,11 @@ describe("App, authenticated", () => { ["analysis_run_lineage", "Request a new lineage reconstruction from a current snapshot."], [ "analysis_run_tepp", - "Connect the measurement service, then ask an administrator to submit a new TEPP run from a current snapshot.", + "Ask an administrator to enable measurement and submit a new run from a current snapshot.", ], [ "analysis_run_topic_lineage", - "Connect the TEPP transport, then ask an administrator to submit new topic-lineage analysis from a current snapshot.", + "Ask an administrator to enable topic-lineage analysis and submit a new run from a current snapshot.", ], ["analysis_run_report", "Rebuild the period report from a current snapshot."], ] satisfies [AnalysisRunKindCode, string][])( @@ -3453,7 +3453,7 @@ describe("App, authenticated", () => { }, ); - it("tells a running lineage run to refresh the durable outbox", async () => { + it("tells a running lineage run how to check for results", async () => { stubBackend({ runningLineageRun: true }); render(); @@ -3461,12 +3461,12 @@ describe("App, authenticated", () => { name: "Open analysis run: Lineage reconstruction · Running · Demo Corp", }); expect(lineageButton).toHaveTextContent( - "Refresh this run. Start already queued the work on the durable outbox.", + "This run is in progress. Refresh it to check for results.", ); await userEvent.click(lineageButton); expect(screen.getByRole("button", { name: "Start reconstruction" })).toBeInTheDocument(); expect( - screen.getAllByText("Refresh this run. Start already queued the work on the durable outbox."), + screen.getAllByText("This run is in progress. Refresh it to check for results."), ).not.toHaveLength(0); }); @@ -3486,7 +3486,7 @@ describe("App, authenticated", () => { ); expect(lineageButton).not.toHaveTextContent("measurement service"); expect(teppButton).toHaveTextContent( - "Open this run to see why it failed, then connect the measurement service and re-run.", + "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again.", ); expect(teppButton).not.toHaveTextContent("reconstruction"); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d6037082c..584b7998a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -308,7 +308,7 @@ export function ChatPanel({ setConversationCursor(page.next_cursor ?? null); } }) - .catch(() => { if (active) setHistoryError(t("Conversation history could not be loaded.")); }); + .catch(() => { if (active) setHistoryError(t("Conversation history could not be loaded. Start a new conversation or try again later.")); }); return () => { active = false; }; }, [postId, accessToken]); @@ -323,7 +323,7 @@ export function ChatPanel({ setConversationId(conversation.conversation_id); setExchanges(conversation.exchanges); } catch { - setHistoryError(t("Conversation history could not be loaded.")); + setHistoryError(t("Conversation history could not be loaded. Start a new conversation or try again later.")); } } @@ -444,9 +444,13 @@ export function ChatPanel({ {conversationCursor ? ( ) : null}
+ {conversationId && conversationOlderCursor ? ( + + ) : null} {historyError ?

{historyError}

: null} {!seededOnly && (
diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 37d15825d..7fc282ef0 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -24,7 +24,7 @@ describe("ChatPanel conversation history", () => { return jsonResponse({ conversation_id: "conversation-1", title: "Saved question", - older_cursor: null, + older_cursor: "2", exchanges: [{ turn_id: "turn-1", question_text: "What was saved?", @@ -35,6 +35,21 @@ describe("ChatPanel conversation history", () => { }], }); } + if (url.endsWith("/chat/conversations/conversation-1?before_turn=2")) { + return jsonResponse({ + conversation_id: "conversation-1", + title: "Saved question", + older_cursor: null, + exchanges: [{ + turn_id: "turn-0", + question_text: "What came first?", + answer_text: "The earlier authorized evidence.", + cited_post_ids: [], + cited_posts: [], + source_post_ids: ["post-1"], + }], + }); + } if (url.endsWith("/chat/conversations")) { return jsonResponse({ conversations: [{ @@ -65,6 +80,8 @@ describe("ChatPanel conversation history", () => { "conversation-1", ); expect(await screen.findByText("Only authorized saved evidence.")).toBeInTheDocument(); + await userEvent.click(screen.getByRole("button", { name: "Load earlier messages" })); + expect(await screen.findByText("The earlier authorized evidence.")).toBeInTheDocument(); await userEvent.click(screen.getByRole("button", { name: "New conversation" })); await waitFor(() => expect(screen.getByText("Seed answer")).toBeInTheDocument()); diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 0fe04fe43..c09956a87 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -312,6 +312,7 @@ const TRANSLATIONS: Partial>> = { "Ask about this lineage": "이 계보에 대해 질문", "Conversation history": "대화 기록", "Load more": "더 보기", + "Load earlier messages": "이전 메시지 불러오기", "New conversation": "새 대화", "Conversation history could not be loaded. Start a new conversation or try again later.": "대화 기록을 불러올 수 없습니다. 새 대화를 시작하거나 나중에 다시 시도하세요.", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -816,6 +817,7 @@ const TRANSLATIONS: Partial>> = { "Ask about this lineage": "询问此谱系", "Conversation history": "对话历史", "Load more": "加载更多", + "Load earlier messages": "加载更早的消息", "New conversation": "新对话", "Conversation history could not be loaded. Start a new conversation or try again later.": "无法加载对话历史。请开始新对话或稍后重试。", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -1332,6 +1334,7 @@ const TRANSLATIONS: Partial>> = { "Ask about this lineage": "この系譜について質問", "Conversation history": "会話履歴", "Load more": "さらに読み込む", + "Load earlier messages": "以前のメッセージを読み込む", "New conversation": "新しい会話", "Conversation history could not be loaded. Start a new conversation or try again later.": "会話履歴を読み込めませんでした。新しい会話を開始するか、後でもう一度お試しください。", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -1836,6 +1839,7 @@ const TRANSLATIONS: Partial>> = { "Ask about this lineage": "Hỏi về dòng sự kiện này", "Conversation history": "Lịch sử hội thoại", "Load more": "Tải thêm", + "Load earlier messages": "Tải tin nhắn trước đó", "New conversation": "Cuộc hội thoại mới", "Conversation history could not be loaded. Start a new conversation or try again later.": "Không thể tải lịch sử hội thoại. Hãy bắt đầu cuộc hội thoại mới hoặc thử lại sau.", "No reconstructed lineage yet. Rebuild after seeding posts.": From 224ee340e359b94a9da64e22e3ff34e0da9ac392 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:03:36 +0900 Subject: [PATCH 060/238] docs(gaps): refresh current PR repair heads --- docs/product-technical-gap-baseline.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a78408c3d..f41c4df4e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 10:00 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 10:10 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, @@ -86,18 +86,20 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #680 | `9f841cc1` | customer-facing ranking copy removes internal engine names and provides localized retry/search-next-action guidance; BLOCKED with hosted checks and independent review required | -| #679 | `640e530c` | ADR 0229 persisted public-claim envelope with unique ADR numbering and async public-claim verification repair; BLOCKED with exact-head checks and independent review required | -| #678 | `662a62fb` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | -| #677 | `70af96b0` | ADR 0228 account-owned per-post Ask conversation history with localized titles, cursor transport, stale-response guards, repeated-turn preservation, and eligibility recheck; BLOCKED with hosted checks and independent review required | +| #681 | `a99bf374` | fail-closed lineage-weight owner contract pin; UNSTABLE stack with hosted checks pending | +| #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | +| #679 | `194f5a3f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | +| #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | +| #677 | `27835005` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | | #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | -| #668 | `1b8e1a99` | evidence-bound project history projection with ADR renumbering, request guards, and source-code/time-basis display repair; BLOCKED with review required | +| #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `96981865` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and fail-closed legacy RankWeave evidence; BLOCKED with hosted checks queued and no independent approval | +| #640 | `169f599f` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and fail-closed legacy RankWeave evidence; BLOCKED with hosted checks queued and no independent approval | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 4394c0ff42e1cd3efcca4a4436461b75346feb85 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:04:31 +0900 Subject: [PATCH 061/238] docs(gaps): record latest owner-contract and claim heads --- 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 f41c4df4e..08377e464 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -86,9 +86,9 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #680 | `9f841cc1` | customer-facing ranking copy removes internal engine names and provides localized retry/search-next-action guidance; BLOCKED with hosted checks and independent review required | -| #681 | `a99bf374` | fail-closed lineage-weight owner contract pin; UNSTABLE stack with hosted checks pending | +| #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | | #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | -| #679 | `194f5a3f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | +| #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `27835005` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | | #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | From fc27077a7119835283a51bcea83b161995e7adbf Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:08:44 +0900 Subject: [PATCH 062/238] docs(gap): record public claim verification head --- docs/product-technical-gap-baseline.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 08377e464..27809dd68 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 07:32 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 10:25 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 16 open PRs and 10 open issues. The exact-head +At this snapshot there were 18 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,13 +78,14 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 17 open PRs and 10 +at this refresh. The live queue contains 18 open PRs and 10 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 | | ---: | --- | --- | +| #682 | `bf86f740` | typed public-claim verification filters cited claims before the bounded candidate budget and rejects generic `/search` result URLs; hosted checks queued and independent review required | | #680 | `9f841cc1` | customer-facing ranking copy removes internal engine names and provides localized retry/search-next-action guidance; BLOCKED with hosted checks and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | | #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | From 81c0a0d2d8bc47b12c17e49b88c9e2e684d6c1e7 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:11:53 +0900 Subject: [PATCH 063/238] docs(gap): record customer-copy audit head --- docs/product-technical-gap-baseline.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 27809dd68..35ede0b20 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 10:25 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 10:35 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -86,6 +86,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #682 | `bf86f740` | typed public-claim verification filters cited claims before the bounded candidate budget and rejects generic `/search` result URLs; hosted checks queued and independent review required | +| #680 | `9efe21d0` | customer-facing ranking copy also removes the fused-ranking implementation label from the accessible list name; hosted checks requeued and independent review required | | #680 | `9f841cc1` | customer-facing ranking copy removes internal engine names and provides localized retry/search-next-action guidance; BLOCKED with hosted checks and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | | #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | From ab1d203facbd83525f03413332ea5fcc4b0831fd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:11:59 +0900 Subject: [PATCH 064/238] docs(gaps): remove stale duplicate PR head --- docs/product-technical-gap-baseline.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 27809dd68..10b9a2cd7 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -86,12 +86,11 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #682 | `bf86f740` | typed public-claim verification filters cited claims before the bounded candidate budget and rejects generic `/search` result URLs; hosted checks queued and independent review required | -| #680 | `9f841cc1` | customer-facing ranking copy removes internal engine names and provides localized retry/search-next-action guidance; BLOCKED with hosted checks and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | | #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | -| #677 | `27835005` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | +| #677 | `aede5911` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | | #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | From 8979c9b01ae526e108171a17aa0e571613b6acdf Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:15:14 +0900 Subject: [PATCH 065/238] docs(gap): refresh dashboard copy audit head --- 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 b1e606057..a4d6eff83 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 10:35 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 10:50 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -87,11 +87,11 @@ context only. | ---: | --- | --- | | #682 | `bf86f740` | typed public-claim verification filters cited claims before the bounded candidate budget and rejects generic `/search` result URLs; hosted checks queued and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | -| #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | +| #680 | `9efe21d0` | customer-facing ranking copy with localized retry/search guidance, explicit non-calibrated interpretation, and no fused-ranking implementation label; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `aede5911` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | -| #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #667 | `81c0a0d2` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | @@ -99,7 +99,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `169f599f` | operations-dashboard evidence touch-target, scoped metrics, Rust residual interaction-map consumption, ABAC/UUID repairs, and fail-closed legacy RankWeave evidence; BLOCKED with hosted checks queued and no independent approval | +| #640 | `c77acc77` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From b1c4b3e730ceaef617fa0ff3070b7058dc828dcf Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:20:10 +0900 Subject: [PATCH 066/238] docs(gap): record latest customer-copy and dashboard heads --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a4d6eff83..47491a7c6 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 10:50 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:05 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -87,7 +87,7 @@ context only. | ---: | --- | --- | | #682 | `bf86f740` | typed public-claim verification filters cited claims before the bounded candidate budget and rejects generic `/search` result URLs; hosted checks queued and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | -| #680 | `9efe21d0` | customer-facing ranking copy with localized retry/search guidance, explicit non-calibrated interpretation, and no fused-ranking implementation label; hosted checks requeued and independent review required | +| #680 | `b0e4d2c9` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, and related-concepts/author-context/earlier-source-version labels; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `aede5911` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | @@ -99,7 +99,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `c77acc77` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; hosted checks requeued and independent review required | +| #640 | `c5555ce4` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; current head includes merged Ask evidence-timeline stack; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 296bf4069a30110d60aaad8dd6cb3dcfd9c861dd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:23:34 +0900 Subject: [PATCH 067/238] docs(gap): record ask verification repair 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 47491a7c6..a7340b625 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:05 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:25 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -85,7 +85,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #682 | `bf86f740` | typed public-claim verification filters cited claims before the bounded candidate budget and rejects generic `/search` result URLs; hosted checks queued and independent review required | +| #682 | `aae2b4bb` | typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, and rejects hidden evidence from public egress; hosted checks requeued and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | | #680 | `b0e4d2c9` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, and related-concepts/author-context/earlier-source-version labels; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | From 11f7643c3bae9318f8fa362c6fe5fd40c1da849c Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:24:52 +0900 Subject: [PATCH 068/238] fix(chat): separate saved turns from demo cache --- frontend/src/App.tsx | 3 ++- frontend/src/ChatPanel.test.tsx | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index cdea6057b..cff451080 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -343,6 +343,7 @@ export function ChatPanel({ async function handleAsk(asked = question) { if (!asked.trim()) return; + const startsConversation = conversationId === null; setLoading(true); setError(null); try { @@ -367,7 +368,7 @@ export function ChatPanel({ cited_post_ids: result.cited_post_ids, cited_posts: result.cited_posts, }; - return [...prev, next]; + return startsConversation ? [next] : [...prev, next]; }); } catch (err) { setError(orchestratorUnavailableMessage(err, "Chat")); diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 7fc282ef0..d40c41a45 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -17,6 +17,41 @@ afterEach(() => { }); describe("ChatPanel conversation history", () => { + it("replaces demo cache rows when the first saved turn starts", async () => { + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { + const url = input instanceof Request ? input.url : String(input); + if (url.endsWith("/chat") && init?.method === "POST") { + return jsonResponse({ + answer_text: "Saved answer", + cited_post_ids: [], + cited_posts: [], + conversation_id: "conversation-2", + }); + } + if (url.endsWith("/chat/conversations")) { + return jsonResponse({ conversations: [], next_cursor: null }); + } + return jsonResponse({ + post_id: "post-1", + exchanges: [{ + question_text: "Demo question", + answer_text: "Demo answer", + cited_post_ids: [], + cited_posts: [], + }], + }); + })); + + render(); + + expect(await screen.findByText("Demo answer")).toBeInTheDocument(); + await userEvent.type(screen.getByPlaceholderText("What happened between these events?"), "Save this"); + await userEvent.click(screen.getByRole("button", { name: "Ask" })); + + expect(await screen.findByText("Saved answer")).toBeInTheDocument(); + expect(screen.queryByText("Demo answer")).toBeNull(); + }); + it("reopens an owned conversation and returns to the seeded new-conversation state", async () => { vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : String(input); From 9dfa7846b9d92b922d47434c5de4e6ee83c6307b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:25:07 +0900 Subject: [PATCH 069/238] docs(gaps): record saved-turn cache boundary --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 583131e65..2d8f91b50 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -91,7 +91,7 @@ context only. | #680 | `fbc0987f` | customer-facing ranking copy with localized retry/search guidance and explicit non-calibrated interpretation; BLOCKED with hosted checks and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | -| #677 | `27835005` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | +| #677 | `11f7643c` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, eligibility recheck, and separation of demo cache rows from saved turns; hosted checks and independent review required | | #667 | `10c4e1d6` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | From fad35d9b620d6b025fc725d2559eff9ab191d19e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:25:32 +0900 Subject: [PATCH 070/238] docs(gap): record ranking guidance test 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 a7340b625..418c400a2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:25 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:40 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -87,7 +87,7 @@ context only. | ---: | --- | --- | | #682 | `aae2b4bb` | typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, and rejects hidden evidence from public egress; hosted checks requeued and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | -| #680 | `b0e4d2c9` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, and related-concepts/author-context/earlier-source-version labels; hosted checks requeued and independent review required | +| #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | | #677 | `aede5911` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | From f40816bf534471a65a5d16f0a59d1be97decf81d Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:26:11 +0900 Subject: [PATCH 071/238] docs(gap): record final ask verification stack 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 418c400a2..683437c0b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:40 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:50 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -85,7 +85,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #682 | `aae2b4bb` | typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, and rejects hidden evidence from public egress; hosted checks requeued and independent review required | +| #682 | `0aa3113e` | typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices; hosted checks requeued and independent review required | | #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | From 6cd0b14e53eec86e7f53395df1d2d345319f7c44 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:16:02 +0900 Subject: [PATCH 072/238] feat(ask): persist per-post conversation history --- CHANGELOG.md | 2 + backend/app/main.py | 123 +++++- backend/app/post_ask_history.py | 408 ++++++++++++++++++ backend/tests/test_api.py | 6 + .../adr/0228-post-ask-conversation-history.md | 81 ++++ docs/adr/README.md | 1 + docs/storybook-inventory.md | 3 + frontend/src/App.css | 30 ++ frontend/src/App.tsx | 75 +++- frontend/src/ChatPanel.stories.tsx | 96 +++++ frontend/src/ChatPanel.test.tsx | 73 ++++ frontend/src/api.ts | 44 +- frontend/src/i18n.ts | 12 + .../0223_post_ask_conversation_history.sql | 48 +++ .../0223_post_ask_conversation_history.sql | 4 + tests/test_post_ask_history.py | 276 ++++++++++++ 16 files changed, 1276 insertions(+), 6 deletions(-) create mode 100644 backend/app/post_ask_history.py create mode 100644 docs/adr/0228-post-ask-conversation-history.md create mode 100644 frontend/src/ChatPanel.stories.tsx create mode 100644 frontend/src/ChatPanel.test.tsx create mode 100644 migrations/0223_post_ask_conversation_history.sql create mode 100644 migrations/rollback/0223_post_ask_conversation_history.sql create mode 100644 tests/test_post_ask_history.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 641306055..b10777aaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to this project are documented here. Format follows ### Added +- Account-owned per-post Ask conversations can be listed, reopened, and + continued with current authorization reapplied to cited evidence (ADR 0228). - Persist explicit paragraph, list, table, MathML formula, and caller-parsed conversation-turn semantic-unit kinds without inferring absent boundaries. - Event Lineage now persists each reconstructed connection's independent diff --git a/backend/app/main.py b/backend/app/main.py index 08ff32428..b0bc28a58 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -130,6 +130,14 @@ gather_chat_sources, persist_post_chat, ) +from backend.app.post_ask_history import ( + PostAskConversationNotFound, + PostAskEvidenceChanged, + conversation_exists as post_ask_conversation_exists, + fetch_conversation as fetch_post_ask_conversation, + list_conversations as list_post_ask_conversations, + persist_turn as persist_post_ask_turn, +) from backend.app.post_content_queue import ( ensure_post_content_job, post_content_api_status, @@ -2954,6 +2962,7 @@ class ChatRequest(BaseModel): """JSON body for ``POST /api/posts/{post_id}/chat``.""" question: str + conversation_id: UUID | None = None class GlobalAskRequest(BaseModel): @@ -2962,6 +2971,38 @@ class GlobalAskRequest(BaseModel): question: str +async def _persist_post_ask_turn( + conn: asyncpg.Connection, + account: CurrentAccount, + post_id: str, + conversation_id: UUID | None, + question: str, + answer_text: str, + source_post_ids: list[str], + cited_post_ids: list[str], +) -> UUID: + """Persist a completed turn after reauthorizing every citation.""" + try: + return await persist_post_ask_turn( + conn, + account.user_account_id, + post_id, + conversation_id, + question, + answer_text, + source_post_ids, + cited_post_ids, + can_see_post=lambda row: _can_see_post(account, row), + ) + except PostAskEvidenceChanged as exc: + raise HTTPException( + status.HTTP_503_SERVICE_UNAVAILABLE, + "Post chat is temporarily unavailable because authorized evidence changed. Retry the question.", + ) from exc + except PostAskConversationNotFound as exc: + raise HTTPException(status.HTTP_404_NOT_FOUND, "conversation not found") from exc + + @app.get("/api/posts/{post_id}/chat") async def read_post_chat( post_id: str, @@ -3006,16 +3047,31 @@ async def chat_about_post( post = await _load_visible_post(post_id, account, pool) post_metadata = build_post_llm_metadata(post_id, post) async with pool.acquire() as conn: + if request.conversation_id is not None and not await post_ask_conversation_exists( + conn, account.user_account_id, post_id, request.conversation_id + ): + raise HTTPException(status.HTTP_404_NOT_FOUND, "conversation not found") stored = await fetch_persisted_chat(conn, post_id, question) if stored is not None: source_ids = [post_id] source_ids.extend(cid for cid in stored["cited_post_ids"] if cid != post_id) + conversation_id = await _persist_post_ask_turn( + conn, + account, + post_id, + request.conversation_id, + question, + stored["answer_text"], + source_ids, + list(stored["cited_post_ids"]), + ) return { "post_id": post_id, "answer_text": stored["answer_text"], "cited_post_ids": stored["cited_post_ids"], "cited_posts": stored["cited_posts"], "source_post_ids": source_ids, + "conversation_id": str(conversation_id), } with use_llm_metadata(post_metadata): with traced( @@ -3067,8 +3123,19 @@ async def chat_about_post( "Saved evidence is still available.", ) from exc cited_ids = list(answer.cited_post_ids) + source_ids = [source.post_id for source in sources] async with pool.acquire() as conn: await persist_post_chat(conn, post_id, question, answer.answer_text, cited_ids) + conversation_id = await _persist_post_ask_turn( + conn, + account, + post_id, + request.conversation_id, + question, + answer.answer_text, + source_ids, + cited_ids, + ) await publish_activity_event( valkey, post_id, @@ -3081,10 +3148,64 @@ async def chat_about_post( "answer_text": answer.answer_text, "cited_post_ids": cited_ids, "cited_posts": cited_post_summaries(sources, cited_ids), - "source_post_ids": [source.post_id for source in sources], + "source_post_ids": source_ids, + "conversation_id": str(conversation_id), } +@app.get("/api/posts/{post_id}/chat/conversations") +async def read_post_chat_conversations( + post_id: str, + limit: int = Query(50, ge=1, le=50), + before_updated_at: datetime | None = Query(None), + before_conversation_id: UUID | None = Query(None), + account: CurrentAccount = Depends(get_current_account), + pool: asyncpg.Pool = Depends(get_pool), +) -> dict[str, Any]: + """List this account's saved Ask conversations on one visible post.""" + await _load_visible_post(post_id, account, pool) + if (before_updated_at is None) != (before_conversation_id is None): + raise HTTPException( + status.HTTP_422_UNPROCESSABLE_CONTENT, + "before_updated_at and before_conversation_id must be provided together", + ) + async with pool.acquire() as conn: + return await list_post_ask_conversations( + conn, + account.user_account_id, + post_id, + limit=limit, + before_updated_at=before_updated_at, + before_conversation_id=before_conversation_id, + ) + + +@app.get("/api/posts/{post_id}/chat/conversations/{conversation_id}") +async def read_post_chat_conversation( + post_id: str, + conversation_id: UUID, + limit: int = Query(50, ge=1, le=50), + before_turn: int | None = Query(None, ge=1), + account: CurrentAccount = Depends(get_current_account), + pool: asyncpg.Pool = Depends(get_pool), +) -> dict[str, Any]: + """Load one owned transcript with currently authorized citations.""" + await _load_visible_post(post_id, account, pool) + async with pool.acquire() as conn: + conversation = await fetch_post_ask_conversation( + conn, + account.user_account_id, + post_id, + conversation_id, + lambda row: _can_see_post(account, row), + turn_limit=limit, + before_turn_ordinal=before_turn, + ) + if conversation is None: + raise HTTPException(status.HTTP_404_NOT_FOUND, "conversation not found") + return conversation + + @app.post("/api/ask", status_code=status.HTTP_202_ACCEPTED) async def ask_agent( request: GlobalAskRequest, diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py new file mode 100644 index 000000000..959e0f6b1 --- /dev/null +++ b/backend/app/post_ask_history.py @@ -0,0 +1,408 @@ +"""Account-owned persistence for Ask conversations on one visible post. + +ADR 0228 reuses the ADR 0126 list/select/new contract with a required +post_id scope. Conversation ids are never Global Ask session ids. +""" + +from __future__ import annotations + +from collections.abc import Callable, Iterable +from datetime import datetime +from typing import Any +from uuid import UUID, uuid4 + +import asyncpg + +from .post_eligibility import SOURCE_POST_ELIGIBILITY_SQL + + +class PostAskConversationNotFound(LookupError): + """The requested conversation is absent, on another post, or another account.""" + + +class PostAskEvidenceChanged(RuntimeError): + """A cited post became unauthorized before the new turn could commit.""" + + +async def conversation_exists( + conn: asyncpg.Connection, + user_account_id: str, + post_id: str, + conversation_id: UUID, +) -> bool: + """Return whether this account owns the conversation on ``post_id``.""" + return bool( + await conn.fetchval( + """ + select exists( + select 1 + from post_ask_session + where post_ask_session_id = $1 + and user_account_id = $2 + and post_id = $3 + ) + """, + conversation_id, + user_account_id, + post_id, + ) + ) + + +async def list_conversations( + conn: asyncpg.Connection, + user_account_id: str, + post_id: str, + *, + limit: int = 50, + before_updated_at: datetime | None = None, + before_conversation_id: UUID | None = None, +) -> dict[str, Any]: + """Return this account's conversations on ``post_id``, newest first.""" + rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli + """ + select session.post_ask_session_id, + coalesce( + (select left(turn.question_text, 80) + from post_ask_turn turn + where turn.post_ask_session_id = session.post_ask_session_id + order by turn.turn_ordinal + limit 1), + 'New conversation' + ) as conversation_title, + session.updated_at, + count(turn.turn_ordinal)::int as turn_count + from post_ask_session session + left join post_ask_turn turn + on turn.post_ask_session_id = session.post_ask_session_id + where session.user_account_id = $1 + and session.post_id = $2 + and ( + $3 is null + or $4 is null + or session.updated_at < $3 + or (session.updated_at = $3 and session.post_ask_session_id < $4) + ) + group by session.post_ask_session_id, session.updated_at + order by session.updated_at desc, session.post_ask_session_id desc + limit $5 + """, + user_account_id, + post_id, + before_updated_at, + before_conversation_id, + limit + 1, + ) + page_rows = rows[:limit] + next_cursor = None + if len(rows) > limit and page_rows: + last = page_rows[-1] + next_cursor = { + "updated_at": last["updated_at"], + "conversation_id": str(last["post_ask_session_id"]), + } + return { + "conversations": [ + { + "conversation_id": str(row["post_ask_session_id"]), + "title": row["conversation_title"], + "updated_at": row["updated_at"], + "turn_count": row["turn_count"], + } + for row in page_rows + ], + "next_cursor": next_cursor, + } + + +async def _visible_post_ids_batch( + conn: asyncpg.Connection, + conversation_id: UUID, + turn_ordinals: list[int], + can_see_post: Callable[[asyncpg.Record], bool], + *, + source: bool, +) -> dict[int, tuple[list[str], dict[str, asyncpg.Record]]]: + """Reauthorize every turn's sources or citations in one query. + + Fetches all `turn_ordinals` at once instead of one query per turn, so a + conversation's query count stays constant regardless of how many turns + it has. Returns each turn's currently-visible post ids and rows, keyed + by turn ordinal; a turn with no visible rows still gets an empty entry. + """ + by_turn: dict[int, tuple[list[str], dict[str, asyncpg.Record]]] = { + ordinal: ([], {}) for ordinal in turn_ordinals + } + if not turn_ordinals: + return by_turn + if source: + rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli + f""" + select relation.turn_ordinal as turn_ordinal, + relation.source_post_id::text as post_id, relation.source_ordinal as ordinal, + post.post_title, post.visibility_code, post.corporate_entity_id, + post.author_account_id, post.source_detail_state_code + from post_ask_turn_source relation + join source_post post on post.post_id = relation.source_post_id + where relation.post_ask_session_id = $1 + and relation.turn_ordinal = any($2::int[]) + and ({SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')}) + order by relation.turn_ordinal, relation.source_ordinal + """, + conversation_id, + turn_ordinals, + ) + else: + rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli + f""" + select relation.turn_ordinal as turn_ordinal, + relation.cited_post_id::text as post_id, relation.citation_ordinal as ordinal, + post.post_title, post.visibility_code, post.corporate_entity_id, + post.author_account_id, post.source_detail_state_code + from post_ask_turn_citation relation + join source_post post on post.post_id = relation.cited_post_id + where relation.post_ask_session_id = $1 + and relation.turn_ordinal = any($2::int[]) + and ({SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')}) + order by relation.turn_ordinal, relation.citation_ordinal + """, + conversation_id, + turn_ordinals, + ) + for row in rows: + if not can_see_post(row): + continue + ordinal = int(row["turn_ordinal"]) + post_id = str(row["post_id"]) + ids, id_map = by_turn[ordinal] + ids.append(post_id) + id_map[post_id] = row + return by_turn + + +async def fetch_conversation( + conn: asyncpg.Connection, + user_account_id: str, + post_id: str, + conversation_id: UUID, + can_see_post: Callable[[asyncpg.Record], bool], + *, + turn_limit: int = 50, + before_turn_ordinal: int | None = None, +) -> dict[str, Any] | None: + """Return one owned transcript with currently authorized citations.""" + header = await conn.fetchrow( + """ + select post_ask_session_id + from post_ask_session + where post_ask_session_id = $1 + and user_account_id = $2 + and post_id = $3 + """, + conversation_id, + user_account_id, + post_id, + ) + if header is None: + return None + + title_question = await conn.fetchval( + """ + select question_text + from post_ask_turn + where post_ask_session_id = $1 + order by turn_ordinal + limit 1 + """, + conversation_id, + ) + if before_turn_ordinal is None: + turns = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli + """ + select turn_ordinal, question_text, answer_text + from post_ask_turn + where post_ask_session_id = $1 + order by turn_ordinal desc + limit $2 + """, + conversation_id, + turn_limit + 1, + ) + else: + turns = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli + """ + select turn_ordinal, question_text, answer_text + from post_ask_turn + where post_ask_session_id = $1 + and turn_ordinal < $2 + order by turn_ordinal desc + limit $3 + """, + conversation_id, + before_turn_ordinal, + turn_limit + 1, + ) + has_older = len(turns) > turn_limit + turns = list(turns[:turn_limit]) + turns.reverse() + ordinals = [int(turn["turn_ordinal"]) for turn in turns] + sources_by_turn = await _visible_post_ids_batch( + conn, conversation_id, ordinals, can_see_post, source=True + ) + citations_by_turn = await _visible_post_ids_batch( + conn, conversation_id, ordinals, can_see_post, source=False + ) + exchanges: list[dict[str, Any]] = [] + for turn in turns: + ordinal = int(turn["turn_ordinal"]) + source_ids, _ = sources_by_turn[ordinal] + cited_ids, cited_rows = citations_by_turn[ordinal] + exchanges.append( + { + "turn_id": f"{conversation_id}:{ordinal}", + "question_text": turn["question_text"], + "answer_text": turn["answer_text"], + "cited_post_ids": cited_ids, + "cited_posts": [ + {"post_id": post_id_value, "post_title": cited_rows[post_id_value]["post_title"]} + for post_id_value in cited_ids + ], + "source_post_ids": source_ids, + } + ) + title = title_question[:80] if title_question else "New conversation" + return { + "conversation_id": str(header["post_ask_session_id"]), + "title": title, + "exchanges": exchanges, + "older_cursor": str(turns[0]["turn_ordinal"]) if has_older and turns else None, + } + + +async def _ensure_citations_visible( + conn: asyncpg.Connection, + conversation_id: UUID, + turn_ordinal: int, + cited_post_count: int, + can_see_post: Callable[[asyncpg.Record], bool], +) -> None: + """Lock and re-authorize new citations before their transaction commits.""" + rows = await conn.fetch( + """ + select relation.cited_post_id::text as post_id, + post.post_title, post.visibility_code, post.corporate_entity_id, + post.author_account_id, post.source_detail_state_code + from post_ask_turn_citation relation + join source_post post on post.post_id = relation.cited_post_id + where relation.post_ask_session_id = $1 + and relation.turn_ordinal = $2 + for share of post + """, + conversation_id, + turn_ordinal, + ) + if len(rows) != cited_post_count or any(not can_see_post(row) for row in rows): + raise PostAskEvidenceChanged + + +async def persist_turn( + conn: asyncpg.Connection, + user_account_id: str, + post_id: str, + conversation_id: UUID | None, + question: str, + answer_text: str, + source_post_ids: Iterable[str], + cited_post_ids: Iterable[str], + can_see_post: Callable[[asyncpg.Record], bool] | None = None, +) -> UUID: + """Append one completed turn and return the conversation id.""" + source_ids = list(dict.fromkeys(str(post_id_value) for post_id_value in source_post_ids)) + source_set = set(source_ids) + cited_ids = list( + dict.fromkeys(str(post_id_value) for post_id_value in cited_post_ids if str(post_id_value) in source_set) + ) + async with conn.transaction(): + if conversation_id is None: + conversation_id = uuid4() + await conn.execute( + """ + insert into post_ask_session (post_ask_session_id, post_id, user_account_id) + values ($1, $2, $3) + """, + conversation_id, + post_id, + user_account_id, + ) + else: + conversation = await conn.fetchrow( + """ + select post_ask_session_id + from post_ask_session + where post_ask_session_id = $1 + and user_account_id = $2 + and post_id = $3 + for update + """, + conversation_id, + user_account_id, + post_id, + ) + if conversation is None: + raise PostAskConversationNotFound + + ordinal = int( + await conn.fetchval( + "select coalesce(max(turn_ordinal), 0) + 1 from post_ask_turn where post_ask_session_id = $1", + conversation_id, + ) + ) + await conn.execute( + """ + insert into post_ask_turn + (post_ask_session_id, turn_ordinal, question_text, answer_text) + values ($1, $2, $3, $4) + """, + conversation_id, + ordinal, + question, + answer_text, + ) + for source_ordinal, source_post_id in enumerate(source_ids): + await conn.execute( + """ + insert into post_ask_turn_source + (post_ask_session_id, turn_ordinal, source_ordinal, source_post_id) + values ($1, $2, $3, $4) + """, + conversation_id, + ordinal, + source_ordinal, + source_post_id, + ) + for citation_ordinal, cited_post_id in enumerate(cited_ids): + await conn.execute( + """ + insert into post_ask_turn_citation + (post_ask_session_id, turn_ordinal, citation_ordinal, cited_post_id) + values ($1, $2, $3, $4) + """, + conversation_id, + ordinal, + citation_ordinal, + cited_post_id, + ) + await conn.execute( + "update post_ask_session set updated_at = now() where post_ask_session_id = $1", + conversation_id, + ) + if can_see_post is not None: + await _ensure_citations_visible( + conn, + conversation_id, + ordinal, + len(cited_ids), + can_see_post, + ) + assert conversation_id is not None + return conversation_id diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index 45ed5d9d4..e8a483835 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -217,6 +217,11 @@ / "migrations" / "0183_source_post_event_occurred_at.sql" ) +_POST_ASK_HISTORY_MIGRATION = ( + Path(__file__).resolve().parents[2] + / "migrations" + / "0223_post_ask_conversation_history.sql" +) def _postgres_available() -> bool: @@ -372,6 +377,7 @@ def seeded_db(demo_analyst_token): cur.execute(_LEFTOVER_MAP_UNEXPLAINED_MIGRATION.read_text()) cur.execute(_LEFTOVER_MAP_CROSS_SHARE_MIGRATION.read_text()) cur.execute(_LEFTOVER_MAP_RECONSTRUCTION_MIGRATION.read_text()) + cur.execute(_POST_ASK_HISTORY_MIGRATION.read_text()) cur.execute( "insert into common_lookup_value (lookup_category, lookup_code, lookup_label) values " "('corporate_entity_level', 'group', 'Group'), " diff --git a/docs/adr/0228-post-ask-conversation-history.md b/docs/adr/0228-post-ask-conversation-history.md new file mode 100644 index 000000000..775599294 --- /dev/null +++ b/docs/adr/0228-post-ask-conversation-history.md @@ -0,0 +1,81 @@ +# ADR 0228: Persisted per-post Ask conversation history + +* Status: Accepted +* Date: 2026-08-23 +* Figma: File ID `1Su3lDRmiZdcUs47t1QwIX` +* Related: [0090](0090-global-ask-lineage-timeline-expansion.md), [0118](0118-uiux-standard-guide-v3-design-overhaul.md) + +## Context + +The post popup **Ask about this lineage** surface stored one shared +`post_chat_result` row per +`(post_id, question_norm)` and rendered a linear transcript plus re-ask +chips. Leaving the popup, switching questions, or starting a new thread +could not reopen an earlier account-owned conversation on that post. + +That is a different metaphor from the conversation-history sidebar the +reader already uses on Ask Agent. Seeded fixture answers remain the +orchestrator-off demo cache; they are not a substitute for account-owned +history. + +## Decision + +Persist per-post Ask conversations under the authenticated `user_account` +and the visible `source_post`: an explicit +conversation id, list/select/new, and visibility-filtered citations on +read. Do not represent this id as a Global Ask session id or as a fake +post-scoped orchestrator session id. + +Normalized tables: + +* `post_ask_session` — one conversation per account and post +* `post_ask_turn` — ordered questions and answers +* `post_ask_turn_citation` / `post_ask_turn_source` — cited and retrieved + posts + +The composite index `(user_account_id, post_id, updated_at desc)` leads +with the account so a hot post cannot concentrate list traffic on one +partition key. A turn is written only after a complete answer exists +(seeded cache hit or orchestrator object). History reads re-apply current +post visibility before returning titles or citations. + +`post_chat_result` stays the post-level seeded/cache store used when the +orchestrator is off. Account history is additional, not a replacement. + +## Consequences + +* A reader can list saved questions on a post, reopen one and see its + turns, and start a new conversation without losing the list. +* A user cannot read another account's post conversation by changing a + UUID, and cannot load a conversation against a different post id. +* Revoked post visibility removes that post's citation projection; the + stored answer remains account-owned transcript data. +* TEPP topic modeling of how many posts can connect, and how many + lineages form under temporal precedence, remains deferred. +* Reauthorization for a conversation's turns is batched + (`_visible_post_ids_batch`, one query per relation type per page instead + of per turn), preventing transcript length from creating an N+1 query path. +* `persist_turn` now re-authorizes every citation inside its own commit + transaction (`_ensure_citations_visible`, row-share-locked, raising + `PostAskEvidenceChanged` -> 503). A citation that loses authorization + between source-gathering and commit therefore aborts the whole turn. + +## Implementation Plan + +* **Affected paths:** `migrations/0223_post_ask_conversation_history.sql`, + `backend/app/post_ask_history.py`, `backend/app/main.py`, + `frontend/src/api.ts`, `frontend/src/App.tsx` (`ChatPanel`), + `frontend/src/i18n.ts`, `tests/test_post_ask_history.py`, + `frontend/src/ChatPanel.test.tsx` +* **Pattern:** require `post_id` and `user_account_id` scope on every query. +* **Verification:** backend tests drive `list_conversations`, + `fetch_conversation`, and `persist_turn`. Frontend tests click New + conversation, select a saved conversation, and assert the matching turns. + +## References — APA 7th + +World Wide Web Consortium. (2013). *PROV-O: The PROV ontology* (W3C +Recommendation). https://www.w3.org/TR/prov-o/ + +World Wide Web Consortium. (2024). *Web Content Accessibility Guidelines +(WCAG) 2.2* (W3C Recommendation). https://www.w3.org/TR/WCAG22/ diff --git a/docs/adr/README.md b/docs/adr/README.md index eadef2874..144eeb426 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -17,6 +17,7 @@ decision from them. | [`ONTOLOGY_NAMESPACE_INVENTORY.md`](../doctoring/ONTOLOGY_NAMESPACE_INVENTORY.md) | [0207](0207-repository-case-ontology-namespace-canonical.md), [0157](0157-public-ontology-namespace-identity.md) | | [`image-content-schema.md`](../image-content-schema.md) | [0066](0066-position-preserving-image-content.md) | | [`storybook-inventory.md`](../storybook-inventory.md) | [0118](0118-uiux-standard-guide-v3-design-overhaul.md), [0184](0184-ontology-provenance-explorer.md) | +| Per-post Ask conversation history | [0228](0228-post-ask-conversation-history.md) | | [`POSTGRESQL_CONCURRENCY_REFERENCES.md`](../doctoring/POSTGRESQL_CONCURRENCY_REFERENCES.md) | [0204](0204-analysis-run-short-transaction-delivery.md) | | [`operability/http-concurrency-evidence.md`](../operability/http-concurrency-evidence.md) | [0204](0204-analysis-run-short-transaction-delivery.md), [0212](0212-single-query-authorized-post-filter-options.md) | | Evidence operations Dashboard (`/`) | [0206](0206-evidence-operations-dashboard.md) | diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md index 7ec497477..e33e39498 100644 --- a/docs/storybook-inventory.md +++ b/docs/storybook-inventory.md @@ -30,5 +30,8 @@ https://www.w3.org/community/reports/design-tokens/CG-FINAL-format-20251028/ Storybook. (2026). *Storybook for React & Vite*. https://storybook.js.org/docs/get-started/frameworks/react-vite +`Workspace/ChatPanel` covers seeded-only, saved-history, and narrow mobile +states for the ADR 0228 list/select/new conversation controls. + World Wide Web Consortium. (2024). *Web Content Accessibility Guidelines (WCAG) 2.2* (W3C Recommendation). https://www.w3.org/TR/WCAG22/ diff --git a/frontend/src/App.css b/frontend/src/App.css index b7482e61f..4868402b8 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1007,6 +1007,36 @@ gap: 0.5rem; } +.chat-history-controls { + display: flex; + align-items: end; + gap: var(--space-2); + margin-bottom: var(--space-3); +} + +.chat-history-controls label { + display: grid; + flex: 1; + gap: var(--space-1); +} + +.chat-history-controls select { + min-height: 44px; + width: 100%; +} + +.chat-history-controls > button { + min-height: 44px; + white-space: nowrap; +} + +@media (max-width: 640px) { + .chat-history-controls { + align-items: stretch; + flex-direction: column; + } +} + .chat-input-row input { flex: 1; padding: 0.5rem; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6e1fff1c9..834963651 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -27,6 +27,8 @@ import { fetchPostActivity, fetchPostBookmark, fetchPostChat, + fetchPostChatConversation, + fetchPostChatConversations, fetchPostAffiliateTree, fetchPostCounterparties, fetchPostEvaluation, @@ -58,6 +60,7 @@ import { type CalendarResponse, type ChatAnswer, type ChatExchange, + type PostAskConversationSummary, type CorporateEntityRef, type CustomerMasterEntity, type CustomerMasterResponse, @@ -256,7 +259,7 @@ function ChatCitations({ ); } -function ChatPanel({ +export function ChatPanel({ postId, accessToken, nameFirstAsk, @@ -267,6 +270,10 @@ function ChatPanel({ }) { const [question, setQuestion] = useState(""); const [exchanges, setExchanges] = useState([]); + const [seededExchanges, setSeededExchanges] = useState([]); + const [conversations, setConversations] = useState([]); + const [conversationId, setConversationId] = useState(null); + const [historyError, setHistoryError] = useState(null); const [answer, setAnswer] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); @@ -275,22 +282,63 @@ function ChatPanel({ useEffect(() => { setExchanges([]); + setSeededExchanges([]); + setConversations([]); + setConversationId(null); + setHistoryError(null); setAnswer(null); setError(null); setSeededOnly(false); setEvidencePostId(null); fetchPostChat(accessToken, postId) - .then((history) => setExchanges(history.exchanges)) + .then((history) => { + setSeededExchanges(history.exchanges); + setExchanges(history.exchanges); + }) .catch(() => setExchanges([])); + fetchPostChatConversations(accessToken, postId) + .then((page) => setConversations(page.conversations)) + .catch(() => setHistoryError(t("Conversation history could not be loaded."))); }, [postId, accessToken]); + async function selectConversation(nextId: string) { + setHistoryError(null); + try { + const conversation = await fetchPostChatConversation(accessToken, postId, nextId); + setConversationId(conversation.conversation_id); + setExchanges(conversation.exchanges); + } catch { + setHistoryError(t("Conversation history could not be loaded.")); + } + } + + function startNewConversation() { + setConversationId(null); + setExchanges(seededExchanges); + setQuestion(""); + setAnswer(null); + setError(null); + } + async function handleAsk(asked = question) { if (!asked.trim()) return; setLoading(true); setError(null); try { - const result = await askPostChat(accessToken, postId, asked); + const result = await askPostChat(accessToken, postId, asked, conversationId); setAnswer(result); + if (result.conversation_id) { + setConversationId(result.conversation_id); + setConversations((current) => [ + { + conversation_id: result.conversation_id!, + title: current.find((row) => row.conversation_id === result.conversation_id)?.title ?? asked.trim().slice(0, 80), + updated_at: new Date().toISOString(), + turn_count: (current.find((row) => row.conversation_id === result.conversation_id)?.turn_count ?? 0) + 1, + }, + ...current.filter((row) => row.conversation_id !== result.conversation_id), + ]); + } setExchanges((prev) => { const next: ChatExchange = { question_text: asked.trim(), @@ -362,6 +410,27 @@ function ChatPanel({ {landedEvidenceNextAction(firstCitedTitle)}

) : null} +
+ + +
+ {historyError ?

{historyError}

: null} {!seededOnly && (
{ + const url = String(input); + if (url.endsWith("/api/posts/post-1/chat/conversations/conversation-post-1")) { + return jsonResponse({ + conversation_id: "conversation-post-1", + title: "Saved post question", + older_cursor: null, + exchanges: [ + { + turn_id: "turn-1", + question_text: "Which site visit was saved?", + answer_text: "The saved post answer stays grounded in the linked source.", + cited_post_ids: ["post-2"], + cited_posts: [{ post_id: "post-2", post_title: "Linked source post" }], + source_post_ids: ["post-1", "post-2"], + }, + ], + }); + } + if (url.includes("/chat/conversations")) { + return jsonResponse({ + conversations: + fixture === "saved" + ? [ + { + conversation_id: "conversation-post-1", + title: "Saved post question", + updated_at: "2026-08-21T00:00:00Z", + turn_count: 1, + }, + ] + : [], + }); + } + return jsonResponse({ + post_id: "post-1", + exchanges: [ + { + question_text: "What happened between these events?", + answer_text: "The seeded follow-up after the site visit.", + cited_post_ids: ["post-2"], + cited_posts: [{ post_id: "post-2", post_title: "Linked source post" }], + }, + ], + }); + }; +} + +const meta = { + title: "Workspace/ChatPanel", + component: ChatPanel, + args: { + postId: "post-1", + accessToken: "synthetic-story-token", + }, + parameters: { layout: "padded" }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const SeededDump: Story = { + render(args) { + installFixture("empty"); + return ; + }, +}; + +export const SavedHistory: Story = { + render(args) { + installFixture("saved"); + return ; + }, +}; + +export const Phone: Story = { + ...SavedHistory, + parameters: { + layout: "padded", + viewport: { defaultViewport: "mobile1" }, + }, +}; + diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx new file mode 100644 index 000000000..7688a6079 --- /dev/null +++ b/frontend/src/ChatPanel.test.tsx @@ -0,0 +1,73 @@ +import { render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { ChatPanel } from "./App"; +import { setLocale } from "./i18n"; + +function jsonResponse(body: unknown) { + return new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); +} + +afterEach(() => { + vi.unstubAllGlobals(); + setLocale("en"); +}); + +describe("ChatPanel conversation history", () => { + it("reopens an owned conversation and returns to the seeded new-conversation state", async () => { + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { + const url = String(input); + if (url.endsWith("/chat/conversations/conversation-1")) { + return jsonResponse({ + conversation_id: "conversation-1", + title: "Saved question", + older_cursor: null, + exchanges: [{ + turn_id: "turn-1", + question_text: "What was saved?", + answer_text: "Only authorized saved evidence.", + cited_post_ids: [], + cited_posts: [], + source_post_ids: ["post-1"], + }], + }); + } + if (url.endsWith("/chat/conversations")) { + return jsonResponse({ + conversations: [{ + conversation_id: "conversation-1", + title: "Saved question", + updated_at: "2026-08-26T00:00:00Z", + turn_count: 1, + }], + next_cursor: null, + }); + } + return jsonResponse({ + post_id: "post-1", + exchanges: [{ + question_text: "Seed question", + answer_text: "Seed answer", + cited_post_ids: [], + cited_posts: [], + }], + }); + })); + + render(); + + expect(await screen.findByText("Seed answer")).toBeInTheDocument(); + await userEvent.selectOptions( + screen.getByLabelText("Conversation history"), + "conversation-1", + ); + expect(await screen.findByText("Only authorized saved evidence.")).toBeInTheDocument(); + + await userEvent.click(screen.getByRole("button", { name: "New conversation" })); + await waitFor(() => expect(screen.getByText("Seed answer")).toBeInTheDocument()); + expect(screen.queryByText("Only authorized saved evidence.")).toBeNull(); + }); +}); diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 2c812ccaa..415442dc3 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -333,6 +333,7 @@ export interface CitedPostEvidence { export interface ChatAnswer { post_id: string; + conversation_id?: string; answer_text: string; cited_post_ids: string[]; cited_posts?: CitedPostRef[]; @@ -351,6 +352,25 @@ export interface ChatHistory { exchanges: ChatExchange[]; } +export interface PostAskConversationSummary { + conversation_id: string; + title: string; + updated_at: string; + turn_count: number; +} + +export interface PostAskConversationPage { + conversations: PostAskConversationSummary[]; + next_cursor?: { updated_at: string; conversation_id: string } | null; +} + +export interface PostAskConversation { + conversation_id: string; + title: string; + exchanges: ChatExchange[]; + older_cursor?: string | null; +} + export interface CitedPostImage { post_id: string; unit_index: number; @@ -1125,13 +1145,33 @@ export function fetchPostChat(accessToken: string, postId: string): Promise { +export function askPostChat( + accessToken: string, + postId: string, + question: string, + conversationId?: string | null, +): Promise { return backendFetch(`/api/posts/${postId}/chat`, accessToken, { method: "POST", - body: JSON.stringify({ question }), + body: JSON.stringify({ question, ...(conversationId ? { conversation_id: conversationId } : {}) }), }); } +export function fetchPostChatConversations( + accessToken: string, + postId: string, +): Promise { + return backendFetch(`/api/posts/${postId}/chat/conversations`, accessToken); +} + +export function fetchPostChatConversation( + accessToken: string, + postId: string, + conversationId: string, +): Promise { + return backendFetch(`/api/posts/${postId}/chat/conversations/${conversationId}`, accessToken); +} + /** How often the queued Ask job is polled, and for how long overall. * A live orchestrator answer can take minutes under shared-gateway load, * so the ceiling is generous; the poll interval keeps the reader's diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 2d19b1cb8..87dbf4989 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -310,6 +310,9 @@ const TRANSLATIONS: Partial>> = { "첨부 이미지를 해독할 수 없습니다. 원문을 다시 내보내고 다시 여세요.", "What happened between these events?": "이 사건들 사이에 무슨 일이 있었나요?", "Ask about this lineage": "이 계보에 대해 질문", + "Conversation history": "대화 기록", + "New conversation": "새 대화", + "Conversation history could not be loaded.": "대화 기록을 불러올 수 없습니다.", "No reconstructed lineage yet. Rebuild after seeding posts.": "아직 재구성된 계보가 없습니다. 글을 시드한 뒤 다시 만드세요.", "Reconstructed lineage": "재구성된 계보", @@ -810,6 +813,9 @@ const TRANSLATIONS: Partial>> = { "无法解码嵌入图像。请重新导出原始文章后再打开。", "What happened between these events?": "这些事件之间发生了什么?", "Ask about this lineage": "询问此谱系", + "Conversation history": "对话历史", + "New conversation": "新对话", + "Conversation history could not be loaded.": "无法加载对话历史。", "No reconstructed lineage yet. Rebuild after seeding posts.": "尚未重建事件谱系。生成文章种子后再重建。", "Reconstructed lineage": "已重建的事件谱系", @@ -1322,6 +1328,9 @@ const TRANSLATIONS: Partial>> = { "埋め込み画像をデコードできませんでした。原文を再エクスポートして、もう一度開いてください。", "What happened between these events?": "これらのイベントの間に何が起きましたか?", "Ask about this lineage": "この系譜について質問", + "Conversation history": "会話履歴", + "New conversation": "新しい会話", + "Conversation history could not be loaded.": "会話履歴を読み込めませんでした。", "No reconstructed lineage yet. Rebuild after seeding posts.": "再構成された系譜はまだありません。投稿をシードしてから再構成してください。", "Reconstructed lineage": "再構成された系譜", @@ -1822,6 +1831,9 @@ const TRANSLATIONS: Partial>> = { "Không thể giải mã hình ảnh nhúng. Hãy xuất lại bài viết gốc rồi mở lại.", "What happened between these events?": "Điều gì đã xảy ra giữa các sự kiện này?", "Ask about this lineage": "Hỏi về dòng sự kiện này", + "Conversation history": "Lịch sử hội thoại", + "New conversation": "Cuộc hội thoại mới", + "Conversation history could not be loaded.": "Không thể tải lịch sử hội thoại.", "No reconstructed lineage yet. Rebuild after seeding posts.": "Chưa có dòng sự kiện được tái dựng. Hãy tạo dữ liệu mồi rồi tái dựng lại.", "Reconstructed lineage": "Dòng sự kiện đã tái dựng", diff --git a/migrations/0223_post_ask_conversation_history.sql b/migrations/0223_post_ask_conversation_history.sql new file mode 100644 index 000000000..cd8e0f17f --- /dev/null +++ b/migrations/0223_post_ask_conversation_history.sql @@ -0,0 +1,48 @@ +-- ADR 0228: persist account-owned Ask conversations on each visible post. +-- Third normal form: session identity, turn text, and citation/source +-- relations are separate tables. Index leads with user_account_id so a +-- frequently asked post cannot become a single hot partition key. + +create table if not exists post_ask_session ( + post_ask_session_id uuid primary key, + post_id uuid not null references source_post(post_id) on delete cascade, + user_account_id uuid not null references user_account(user_account_id) on delete cascade, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now() +); + +create index if not exists post_ask_session_account_post_idx + on post_ask_session (user_account_id, post_id, updated_at desc); + +create table if not exists post_ask_turn ( + post_ask_session_id uuid not null + references post_ask_session(post_ask_session_id) on delete cascade, + turn_ordinal integer not null check (turn_ordinal > 0), + question_text text not null, + answer_text text not null, + created_at timestamptz not null default now(), + primary key (post_ask_session_id, turn_ordinal) +); + +create table if not exists post_ask_turn_citation ( + post_ask_session_id uuid not null, + turn_ordinal integer not null, + citation_ordinal integer not null check (citation_ordinal >= 0), + cited_post_id uuid not null references source_post(post_id) on delete cascade, + primary key (post_ask_session_id, turn_ordinal, citation_ordinal), + foreign key (post_ask_session_id, turn_ordinal) + references post_ask_turn(post_ask_session_id, turn_ordinal) + on delete cascade +); + +create table if not exists post_ask_turn_source ( + post_ask_session_id uuid not null, + turn_ordinal integer not null, + source_ordinal integer not null check (source_ordinal >= 0), + source_post_id uuid not null references source_post(post_id) on delete cascade, + primary key (post_ask_session_id, turn_ordinal, source_ordinal), + unique (post_ask_session_id, turn_ordinal, source_post_id), + foreign key (post_ask_session_id, turn_ordinal) + references post_ask_turn(post_ask_session_id, turn_ordinal) + on delete cascade +); diff --git a/migrations/rollback/0223_post_ask_conversation_history.sql b/migrations/rollback/0223_post_ask_conversation_history.sql new file mode 100644 index 000000000..5a820c07a --- /dev/null +++ b/migrations/rollback/0223_post_ask_conversation_history.sql @@ -0,0 +1,4 @@ +drop table if exists post_ask_turn_citation; +drop table if exists post_ask_turn_source; +drop table if exists post_ask_turn; +drop table if exists post_ask_session; diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py new file mode 100644 index 000000000..57051eeb6 --- /dev/null +++ b/tests/test_post_ask_history.py @@ -0,0 +1,276 @@ +"""Regression tests for account-owned per-post Ask history queries.""" + +from __future__ import annotations + +import asyncio +from datetime import UTC, datetime +from uuid import UUID + +import pytest + +from backend.app.post_ask_history import ( + PostAskEvidenceChanged, + _visible_post_ids_batch, + conversation_exists, + list_conversations, + persist_turn, +) + + +class _Connection: + """Capture bound SQL calls without needing a database for query-shape tests.""" + + def __init__(self, rows: list[dict[str, object]] | None = None) -> None: + self.rows = rows or [] + self.calls: list[tuple[str, tuple[object, ...]]] = [] + + async def fetch(self, query: str, *arguments: object) -> list[dict[str, object]]: + self.calls.append((query, arguments)) + return self.rows + + async def fetchval(self, query: str, *arguments: object) -> object: + self.calls.append((query, arguments)) + if "exists(" in query: + return True + if "coalesce(max(turn_ordinal)" in query: + return 1 + return None + + async def fetchrow(self, query: str, *arguments: object) -> dict[str, object] | None: + self.calls.append((query, arguments)) + return {"post_ask_session_id": arguments[0]} + + async def execute(self, query: str, *arguments: object) -> str: + self.calls.append((query, arguments)) + return "INSERT 0 1" + + def transaction(self) -> _Connection: + return self + + async def __aenter__(self) -> _Connection: + return self + + async def __aexit__(self, *_exc: object) -> None: + return None + + +def test_list_conversations_binds_account_post_and_cursor() -> None: + """Pagination and post scope remain parameters, never interpolated SQL.""" + connection = _Connection( + [ + { + "post_ask_session_id": UUID("00000000-0000-0000-0000-000000000001"), + "conversation_title": "First", + "updated_at": datetime(2026, 1, 2, tzinfo=UTC), + "turn_count": 1, + }, + { + "post_ask_session_id": UUID("00000000-0000-0000-0000-000000000002"), + "conversation_title": "Second", + "updated_at": datetime(2026, 1, 1, tzinfo=UTC), + "turn_count": 2, + }, + ] + ) + cursor_time = datetime(2026, 1, 3, tzinfo=UTC) + + result = asyncio.run( + list_conversations( + connection, + "account-1", + "post-1", + limit=1, + before_updated_at=cursor_time, + before_conversation_id=UUID("00000000-0000-0000-0000-000000000003"), + ) + ) + + query, arguments = connection.calls[0] + assert "{cursor_clause}" not in query + assert "post_ask_session" in query + assert arguments == ( + "account-1", + "post-1", + cursor_time, + UUID("00000000-0000-0000-0000-000000000003"), + 2, + ) + assert len(result["conversations"]) == 1 + assert result["next_cursor"] is not None + assert result["conversations"][0]["conversation_id"] == "00000000-0000-0000-0000-000000000001" + + +def test_conversation_exists_requires_account_and_post() -> None: + """A conversation id from another post or account must not match.""" + connection = _Connection() + conversation_id = UUID("00000000-0000-0000-0000-000000000009") + + found = asyncio.run( + conversation_exists(connection, "account-1", "post-1", conversation_id) + ) + + query, arguments = connection.calls[0] + assert "post_ask_session" in query + assert arguments == (conversation_id, "account-1", "post-1") + assert found is True + + +def test_visible_post_ids_batch_uses_fixed_source_and_citation_queries() -> None: + """Both relation types use fixed identifiers rather than interpolated SQL.""" + for source, table, column in ( + (True, "post_ask_turn_source", "source_post_id"), + (False, "post_ask_turn_citation", "cited_post_id"), + ): + connection = _Connection( + [ + { + "turn_ordinal": 1, + "post_id": "post-1", + "post_title": "Synthetic source", + "visibility_code": "workspace", + "corporate_entity_id": "entity-1", + "author_account_id": "account-1", + "source_detail_state_code": "current", + } + ] + ) + by_turn = asyncio.run( + _visible_post_ids_batch( + connection, + UUID("00000000-0000-0000-0000-000000000004"), + [1], + lambda row: row["post_id"] == "post-1", + source=source, + ) + ) + post_ids, rows = by_turn[1] + + query, arguments = connection.calls[0] + assert table in query + assert column in query + assert "relation.{" not in query + assert "source_draft_code" in query + assert "source_deleted_flag" in query + assert arguments[1] == [1] + assert post_ids == ["post-1"] + assert rows["post-1"]["post_title"] == "Synthetic source" + + +def test_visible_post_ids_batch_stays_at_one_query_regardless_of_turn_count() -> None: + """Query count must not grow with the number of turns being reauthorized.""" + connection = _Connection([]) + + by_turn = asyncio.run( + _visible_post_ids_batch( + connection, + UUID("00000000-0000-0000-0000-000000000004"), + list(range(1, 51)), + lambda row: True, + source=True, + ) + ) + + assert len(connection.calls) == 1 + assert set(by_turn.keys()) == set(range(1, 51)) + assert all(ids == [] and rows == {} for ids, rows in by_turn.values()) + + +def test_visible_post_ids_batch_never_leaks_a_row_into_the_wrong_turn() -> None: + """A row is partitioned to its own turn_ordinal, never a neighboring turn.""" + connection = _Connection( + [ + { + "turn_ordinal": 1, + "post_id": "post-turn-1", + "post_title": "Turn 1 post", + "visibility_code": "public", + "corporate_entity_id": "entity-1", + "author_account_id": "account-1", + "source_detail_state_code": "current", + }, + { + "turn_ordinal": 2, + "post_id": "post-turn-2", + "post_title": "Turn 2 post", + "visibility_code": "public", + "corporate_entity_id": "entity-1", + "author_account_id": "account-1", + "source_detail_state_code": "current", + }, + ] + ) + + by_turn = asyncio.run( + _visible_post_ids_batch( + connection, + UUID("00000000-0000-0000-0000-000000000004"), + [1, 2, 3], + lambda row: True, + source=False, + ) + ) + + assert by_turn[1][0] == ["post-turn-1"] + assert by_turn[2][0] == ["post-turn-2"] + assert by_turn[3] == ([], {}) + + +def test_persist_turn_creates_a_new_session_then_writes_the_turn() -> None: + """A completed answer is stored under the calling account and post.""" + connection = _Connection() + conversation_id = asyncio.run( + persist_turn( + connection, + "account-1", + "post-1", + None, + "Which site visit was saved?", + "The saved post answer stays grounded in the linked source.", + ["post-1", "post-2"], + ["post-2"], + ) + ) + + statements = [query for query, _arguments in connection.calls] + assert any("insert into post_ask_session" in query for query in statements) + assert any("insert into post_ask_turn" in query for query in statements) + assert any("insert into post_ask_turn_source" in query for query in statements) + assert any("insert into post_ask_turn_citation" in query for query in statements) + session_arguments = next( + arguments + for query, arguments in connection.calls + if "insert into post_ask_session" in query + ) + assert session_arguments[0] == conversation_id + assert session_arguments[1:] == ("post-1", "account-1") + + +def test_persist_turn_aborts_when_a_citation_loses_authorization() -> None: + """The transaction fails closed if cited evidence is no longer visible.""" + connection = _Connection([ + { + "post_id": "post-2", + "post_title": "Synthetic source", + "visibility_code": "workspace", + "corporate_entity_id": "entity-2", + "author_account_id": "account-2", + "source_detail_state_code": "current", + } + ]) + + with pytest.raises(PostAskEvidenceChanged): + asyncio.run( + persist_turn( + connection, + "account-1", + "post-1", + None, + "What changed?", + "A complete answer.", + ["post-1", "post-2"], + ["post-2"], + can_see_post=lambda _row: False, + ) + ) + + assert any("for share of post" in query.lower() for query, _ in connection.calls) From d19808fcc51a5e8127a55aa868c0505d9336bbb3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:44:28 +0900 Subject: [PATCH 073/238] fix(ask): preserve localized and race-safe conversation history --- backend/app/post_ask_history.py | 18 +++++++-------- frontend/src/App.tsx | 39 ++++++++++++++++++++++++++------- frontend/src/api.ts | 12 +++++++--- frontend/src/i18n.ts | 4 ++++ 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 959e0f6b1..5ceeaffc4 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -62,14 +62,11 @@ async def list_conversations( rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli """ select session.post_ask_session_id, - coalesce( - (select left(turn.question_text, 80) - from post_ask_turn turn - where turn.post_ask_session_id = session.post_ask_session_id - order by turn.turn_ordinal - limit 1), - 'New conversation' - ) as conversation_title, + (select left(turn.question_text, 80) + from post_ask_turn turn + where turn.post_ask_session_id = session.post_ask_session_id + order by turn.turn_ordinal + limit 1) as conversation_title, session.updated_at, count(turn.turn_ordinal)::int as turn_count from post_ask_session session @@ -270,7 +267,7 @@ async def fetch_conversation( "source_post_ids": source_ids, } ) - title = title_question[:80] if title_question else "New conversation" + title = title_question[:80] if title_question else None return { "conversation_id": str(header["post_ask_session_id"]), "title": title, @@ -288,7 +285,7 @@ async def _ensure_citations_visible( ) -> None: """Lock and re-authorize new citations before their transaction commits.""" rows = await conn.fetch( - """ + f""" select relation.cited_post_id::text as post_id, post.post_title, post.visibility_code, post.corporate_entity_id, post.author_account_id, post.source_detail_state_code @@ -296,6 +293,7 @@ async def _ensure_citations_visible( join source_post post on post.post_id = relation.cited_post_id where relation.post_ask_session_id = $1 and relation.turn_ordinal = $2 + and ({SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')}) for share of post """, conversation_id, diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 834963651..d6037082c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -61,6 +61,7 @@ import { type ChatAnswer, type ChatExchange, type PostAskConversationSummary, + type PostAskConversationPage, type CorporateEntityRef, type CustomerMasterEntity, type CustomerMasterResponse, @@ -272,6 +273,7 @@ export function ChatPanel({ const [exchanges, setExchanges] = useState([]); const [seededExchanges, setSeededExchanges] = useState([]); const [conversations, setConversations] = useState([]); + const [conversationCursor, setConversationCursor] = useState(null); const [conversationId, setConversationId] = useState(null); const [historyError, setHistoryError] = useState(null); const [answer, setAnswer] = useState(null); @@ -281,6 +283,7 @@ export function ChatPanel({ const [seededOnly, setSeededOnly] = useState(false); useEffect(() => { + let active = true; setExchanges([]); setSeededExchanges([]); setConversations([]); @@ -292,19 +295,31 @@ export function ChatPanel({ setEvidencePostId(null); fetchPostChat(accessToken, postId) .then((history) => { - setSeededExchanges(history.exchanges); - setExchanges(history.exchanges); + if (active) { + setSeededExchanges(history.exchanges); + setExchanges(history.exchanges); + } }) - .catch(() => setExchanges([])); + .catch(() => { if (active) setExchanges([]); }); fetchPostChatConversations(accessToken, postId) - .then((page) => setConversations(page.conversations)) - .catch(() => setHistoryError(t("Conversation history could not be loaded."))); + .then((page) => { + if (active) { + setConversations(page.conversations); + setConversationCursor(page.next_cursor ?? null); + } + }) + .catch(() => { if (active) setHistoryError(t("Conversation history could not be loaded.")); }); + return () => { active = false; }; }, [postId, accessToken]); + const conversationRequest = useRef(0); async function selectConversation(nextId: string) { + const requestId = ++conversationRequest.current; setHistoryError(null); + setAnswer(null); try { const conversation = await fetchPostChatConversation(accessToken, postId, nextId); + if (requestId !== conversationRequest.current) return; setConversationId(conversation.conversation_id); setExchanges(conversation.exchanges); } catch { @@ -313,6 +328,7 @@ export function ChatPanel({ } function startNewConversation() { + ++conversationRequest.current; setConversationId(null); setExchanges(seededExchanges); setQuestion(""); @@ -346,7 +362,7 @@ export function ChatPanel({ cited_post_ids: result.cited_post_ids, cited_posts: result.cited_posts, }; - return [...prev.filter((row) => row.question_text !== next.question_text), next]; + return [...prev, next]; }); } catch (err) { setError(orchestratorUnavailableMessage(err, "Chat")); @@ -415,17 +431,24 @@ export function ChatPanel({ {t("Conversation history")} + {conversationCursor ? ( + + ) : null} diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 415442dc3..55a47b1a9 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -354,7 +354,7 @@ export interface ChatHistory { export interface PostAskConversationSummary { conversation_id: string; - title: string; + title: string | null; updated_at: string; turn_count: number; } @@ -1160,16 +1160,22 @@ export function askPostChat( export function fetchPostChatConversations( accessToken: string, postId: string, + cursor?: { updated_at: string; conversation_id: string }, ): Promise { - return backendFetch(`/api/posts/${postId}/chat/conversations`, accessToken); + const query = cursor + ? `?before_updated_at=${encodeURIComponent(cursor.updated_at)}&before_conversation_id=${encodeURIComponent(cursor.conversation_id)}` + : ""; + return backendFetch(`/api/posts/${postId}/chat/conversations${query}`, accessToken); } export function fetchPostChatConversation( accessToken: string, postId: string, conversationId: string, + beforeTurn?: number, ): Promise { - return backendFetch(`/api/posts/${postId}/chat/conversations/${conversationId}`, accessToken); + const query = beforeTurn === undefined ? "" : `?before_turn=${beforeTurn}`; + return backendFetch(`/api/posts/${postId}/chat/conversations/${conversationId}${query}`, accessToken); } /** How often the queued Ask job is polled, and for how long overall. diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 87dbf4989..fbce9e137 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -311,6 +311,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "이 사건들 사이에 무슨 일이 있었나요?", "Ask about this lineage": "이 계보에 대해 질문", "Conversation history": "대화 기록", + "Load more": "더 보기", "New conversation": "새 대화", "Conversation history could not be loaded.": "대화 기록을 불러올 수 없습니다.", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -814,6 +815,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "这些事件之间发生了什么?", "Ask about this lineage": "询问此谱系", "Conversation history": "对话历史", + "Load more": "加载更多", "New conversation": "新对话", "Conversation history could not be loaded.": "无法加载对话历史。", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -1329,6 +1331,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "これらのイベントの間に何が起きましたか?", "Ask about this lineage": "この系譜について質問", "Conversation history": "会話履歴", + "Load more": "さらに読み込む", "New conversation": "新しい会話", "Conversation history could not be loaded.": "会話履歴を読み込めませんでした。", "No reconstructed lineage yet. Rebuild after seeding posts.": @@ -1832,6 +1835,7 @@ const TRANSLATIONS: Partial>> = { "What happened between these events?": "Điều gì đã xảy ra giữa các sự kiện này?", "Ask about this lineage": "Hỏi về dòng sự kiện này", "Conversation history": "Lịch sử hội thoại", + "Load more": "Tải thêm", "New conversation": "Cuộc hội thoại mới", "Conversation history could not be loaded.": "Không thể tải lịch sử hội thoại.", "No reconstructed lineage yet. Rebuild after seeding posts.": From ceb2f9935fc2c394b3024489b1cda7b024e7cced Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:28:28 +0900 Subject: [PATCH 074/238] docs(gap): record conversation history rebase 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 683437c0b..7ff8a513f 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:50 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 12:05 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -90,7 +90,7 @@ context only. | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | -| #677 | `aede5911` | ADR 0228 account-owned per-post Ask conversation history with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks and independent review required | +| #677 | `d9d14c0c` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks requeued and independent review required | | #667 | `81c0a0d2` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | From 8f535f45f6bc56a99011f4354e7c191b5f24c6a3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:30:27 +0900 Subject: [PATCH 075/238] docs(gap): refresh conversation history 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 7ff8a513f..9c8aa79f8 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 12:05 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 12:20 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -90,7 +90,7 @@ context only. | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | -| #677 | `d9d14c0c` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks requeued and independent review required | +| #677 | `eb4d6932` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks requeued and independent review required | | #667 | `81c0a0d2` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | From caa656a5984da7531ae21e40e1ac270d4b2dabbf Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:31:36 +0900 Subject: [PATCH 076/238] docs(gap): record stacked merges and queue size --- docs/product-technical-gap-baseline.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 9c8aa79f8..d0225c842 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 12:20 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 12:35 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 18 open PRs and 10 open issues. The exact-head +At this snapshot there were 16 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,20 +78,20 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 18 open PRs and 10 +at this refresh. The live queue contains 16 open PRs and 10 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 | | ---: | --- | --- | -| #682 | `0aa3113e` | typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices; hosted checks requeued and independent review required | -| #681 | `3e0fa644` | fail-closed lineage-weight owner contract pin; lockfile parity verified; UNSTABLE stack with hosted checks pending | +| #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | +| #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | -| #678 | `da98de07` | canonical Compose-stack consolidation stacked on #640; parent protected merge and `main` retarget precede fresh exact-head evidence | +| #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | | #677 | `eb4d6932` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks requeued and independent review required | -| #667 | `81c0a0d2` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #667 | `8f535f45` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | @@ -99,7 +99,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `c5555ce4` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; current head includes merged Ask evidence-timeline stack; hosted checks requeued and independent review required | +| #640 | `dae28fb2` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; current head includes merged Ask evidence-timeline and lineage-weight stacks; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 17a1313f8284c3f746e38a3c4ad25daa25537a5e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 09:58:05 +0900 Subject: [PATCH 077/238] fix(ui): make recovery copy customer-actionable --- backend/app/analysis_run_ingestion.py | 6 ++---- frontend/src/App.test.tsx | 4 ++-- frontend/src/App.tsx | 6 ++---- tests/test_analysis_run_create.py | 6 +++--- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/backend/app/analysis_run_ingestion.py b/backend/app/analysis_run_ingestion.py index 7335f6fb9..c7d67de18 100644 --- a/backend/app/analysis_run_ingestion.py +++ b/backend/app/analysis_run_ingestion.py @@ -640,14 +640,12 @@ def _require_lineage_create_kind(run_kind_code: str) -> None: if run_kind_code == _TEPP_RUN_KIND: raise AnalysisRunCreateError( 422, - "Connect a TEPP transport from a Failed TEPP row; this endpoint " - "does not invent a measurement.", + "Ask an administrator to enable measurement, then retry from the failed measurement run.", ) if run_kind_code == _TOPIC_LINEAGE_RUN_KIND: raise AnalysisRunCreateError( 422, - "Connect a TEPP transport from a Failed topic-lineage row; this " - "endpoint does not invent a topic model.", + "Ask an administrator to enable topic-lineage analysis, then retry from the failed run.", ) if run_kind_code == _REPORT_RUN_KIND: raise AnalysisRunCreateError( diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 3d0b14722..67d7c59af 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -675,7 +675,7 @@ describe("App, authenticated", () => { JSON.stringify({ detail: payload.run_kind_code === "analysis_run_tepp" - ? "Connect a TEPP transport from a Failed TEPP row; this endpoint does not invent a measurement." + ? "Ask an administrator to enable measurement, then retry from the failed measurement run." : "Rebuild the period report from the Reports panel.", }), { status: 422, headers: { "Content-Type": "application/json" } }, @@ -3832,7 +3832,7 @@ describe("App, authenticated", () => { ); expect( await screen.findByText( - "Connect a TEPP transport from this Failed row. Request a lineage reconstruction does not invent a measurement.", + "Ask an administrator to enable measurement, then retry from this failed run.", ), ).toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Request a new TEPP measurement" })).not.toBeInTheDocument(); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index cff451080..8f95dd9b0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3334,10 +3334,8 @@ function AnalysisRunsPanel({ {analysisRunCanRequestTeppRetry(selected) && (

{selected.run_kind_code === "analysis_run_topic_lineage" - ? "Connect a TEPP transport from this Failed row. Request a " + - "lineage reconstruction does not invent a topic model." - : "Connect a TEPP transport from this Failed row. Request a lineage " + - "reconstruction does not invent a measurement."} + ? "Ask an administrator to enable topic-lineage analysis, then retry from this failed run." + : "Ask an administrator to enable measurement, then retry from this failed run."}

)} {analysisRunReportPeriod(selected) && onSelectReportPeriod && ( diff --git a/tests/test_analysis_run_create.py b/tests/test_analysis_run_create.py index ef9dc9f71..b28a307e9 100644 --- a/tests/test_analysis_run_create.py +++ b/tests/test_analysis_run_create.py @@ -144,11 +144,11 @@ def test_create_rejects_tepp_and_report_kinds_without_a_fake_score() -> None: with pytest.raises(AnalysisRunCreateError) as tepp: _require_lineage_create_kind("analysis_run_tepp") assert tepp.value.status_code == 422 - assert "invent a measurement" in tepp.value.detail + assert "enable measurement" in tepp.value.detail with pytest.raises(AnalysisRunCreateError) as topic_lineage: _require_lineage_create_kind("analysis_run_topic_lineage") assert topic_lineage.value.status_code == 422 - assert "invent a topic model" in topic_lineage.value.detail + assert "enable topic-lineage analysis" in topic_lineage.value.detail with pytest.raises(AnalysisRunCreateError) as report: _require_lineage_create_kind("analysis_run_report") assert report.value.status_code == 422 @@ -180,7 +180,7 @@ async def _run() -> None: idempotency_key="client-key-1", ) assert err.value.status_code == 422 - assert "invent a measurement" in err.value.detail + assert "enable measurement" in err.value.detail asyncio.run(_run()) From d3a2ad99093873906f5e501a3f6d4e637ce57334 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:34:31 +0900 Subject: [PATCH 078/238] docs(gap): record public envelope guidance head --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index d0225c842..1230f3c94 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 12:35 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 12:55 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -88,10 +88,10 @@ context only. | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | -| #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | +| #679 | `7e6e386a` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | | #677 | `eb4d6932` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks requeued and independent review required | -| #667 | `8f535f45` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #667 | `caa656a5` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | From 4597722b8df6a59e2f956cab76624f97f3fa7ec7 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:34:53 +0900 Subject: [PATCH 079/238] docs(gaps): record customer recovery copy head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 8d25933f6..29a151fa1 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -90,7 +90,7 @@ context only. | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `67706ef5` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, and opt-in search setup; BLOCKED with exact-head checks and independent review required | | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | -| #677 | `eb4d6932` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, eligibility recheck, and separation of demo cache rows from saved turns; hosted checks requeued and independent review required | +| #677 | `17a1313f` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, eligibility recheck, separation of demo cache rows from saved turns, and customer-actionable recovery copy; hosted checks requeued and independent review required | | #667 | `caa656a5` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | From aaca688caf28001b2888e1d76c4abb8aab0034ba Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:36:00 +0900 Subject: [PATCH 080/238] docs(gap): refresh conversation branch reconciliation --- 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 1230f3c94..763389882 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 12:55 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 13:10 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -90,7 +90,7 @@ context only. | #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | | #679 | `7e6e386a` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | -| #677 | `eb4d6932` | ADR 0228 account-owned per-post Ask conversation history rebased onto the current baseline with localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck; hosted checks requeued and independent review required | +| #677 | `bf7d6b88` | ADR 0228 account-owned per-post Ask conversation history reconciled with the latest baseline; localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck remain intact; hosted checks requeued and independent review required | | #667 | `caa656a5` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | From aca75ce8c51e6eaf2767aed0887bd4225d8dd412 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:38:03 +0900 Subject: [PATCH 081/238] docs(gap): record latest source detail copy 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 763389882..66a2e292f 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 13:10 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 13:25 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -87,7 +87,7 @@ context only. | ---: | --- | --- | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | -| #680 | `4e41bcd1` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and complete guidance regression coverage; hosted checks requeued and independent review required | +| #680 | `be34c335` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and source-record detail copy corrected; hosted checks requeued and independent review required | | #679 | `7e6e386a` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | | #677 | `bf7d6b88` | ADR 0228 account-owned per-post Ask conversation history reconciled with the latest baseline; localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck remain intact; hosted checks requeued and independent review required | From 90b0d33024c6a71b2b2edd6b2dfbac9bc42559fa Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:39:22 +0900 Subject: [PATCH 082/238] docs(gap): record portable Rust backend ADR 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 66a2e292f..4c09261e0 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 13:25 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 13:40 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -99,7 +99,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `dae28fb2` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; current head includes merged Ask evidence-timeline and lineage-weight stacks; hosted checks requeued and independent review required | +| #640 | `cb78cd78` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; current head adds the ADR for portable Rust accelerator backends; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From f3da213a54ea2e3af6ea0acb7706d661c6cee860 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:54:24 +0900 Subject: [PATCH 083/238] style(chat): reuse touch-target token --- frontend/src/App.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index 4868402b8..4fc37055c 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1021,12 +1021,12 @@ } .chat-history-controls select { - min-height: 44px; + min-height: var(--size-control-min); width: 100%; } .chat-history-controls > button { - min-height: 44px; + min-height: var(--size-control-min); white-space: nowrap; } From 205b486c1129ac6008eaf91b598674fe901d5c51 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:55:07 +0900 Subject: [PATCH 084/238] docs(gap): refresh current PR queue heads --- docs/product-technical-gap-baseline.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 4c09261e0..0fa331486 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 13:40 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 14:55 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 16 open PRs and 10 open issues. The exact-head +At this snapshot there were 17 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,20 +78,22 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 16 open PRs and 10 +at this refresh. The live queue contains 17 open PRs and 10 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 | | ---: | --- | --- | +| #686 | `7276df4f` | customer-facing copy boundary audit; BLOCKED with review required and hosted checks pending | +| #684 | `cb5e7df7` | measured PostgreSQL runtime tuning plan; merge state unknown while hosted checks are pending | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | -| #680 | `be34c335` | customer-facing ranking copy with localized retry/search guidance, no fused-ranking implementation label, related-concepts/author-context/earlier-source-version labels, and source-record detail copy corrected; hosted checks requeued and independent review required | -| #679 | `7e6e386a` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | +| #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | +| #679 | `c430cfa1` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | | #677 | `bf7d6b88` | ADR 0228 account-owned per-post Ask conversation history reconciled with the latest baseline; localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck remain intact; hosted checks requeued and independent review required | -| #667 | `caa656a5` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #667 | `90b0d330` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | @@ -99,7 +101,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `cb78cd78` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; residual-map axis-share drift is handled fail-closed; current head adds the ADR for portable Rust accelerator backends; hosted checks requeued and independent review required | +| #640 | `4a4acc38` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; current head repairs customer copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From f84be88fb01303038db4ed55d857eebcba378d76 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:55:52 +0900 Subject: [PATCH 085/238] docs(gap): record latest dashboard branch head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 0fa331486..bb5748db5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -101,7 +101,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `4a4acc38` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; current head repairs customer copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks requeued and independent review required | +| #640 | `f88e7c64` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; current head retains customer copy, migration replay safety, id-only Ask citations, and not-applicable topic state while reverting an upstream capability-pin change; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From b74efe0060b93ef3096b83d43eb6ce36c2c455b2 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:58:37 +0900 Subject: [PATCH 086/238] docs(gap): record ontology branch test repair --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index bb5748db5..09b637419 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -96,7 +96,7 @@ context only. | #667 | `90b0d330` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #663 | `74b9a1d9` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; hosted Full-suite transaction root cause repaired; fresh checks pending and review required | +| #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | From 771a518671ea08e97abde002fc3a552789525493 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 10:59:08 +0900 Subject: [PATCH 087/238] docs(gap): refresh concurrent PR heads --- 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 09b637419..4eab4eed1 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,7 +85,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #686 | `7276df4f` | customer-facing copy boundary audit; BLOCKED with review required and hosted checks pending | +| #686 | `dbe851ac` | customer-facing copy boundary audit; BLOCKED with hosted checks pending | | #684 | `cb5e7df7` | measured PostgreSQL runtime tuning plan; merge state unknown while hosted checks are pending | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | @@ -95,7 +95,7 @@ context only. | #677 | `bf7d6b88` | ADR 0228 account-owned per-post Ask conversation history reconciled with the latest baseline; localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck remain intact; hosted checks requeued and independent review required | | #667 | `90b0d330` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | -| #668 | `153add77` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | +| #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | From 0ba4e6095d6577c363c11026068c8eea80031514 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:07:52 +0900 Subject: [PATCH 088/238] test(chat): use canonical history cursor fields --- frontend/src/ChatPanel.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index d40c41a45..d0d494be4 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -136,8 +136,8 @@ describe("ChatPanel conversation history", () => { turn_count: 1, }], next_cursor: { - before_updated_at: "2026-08-26T00:00:00Z", - before_conversation_id: "conversation-1", + updated_at: "2026-08-26T00:00:00Z", + conversation_id: "conversation-1", }, }); } From 530de038d8d3323f9fabdea7ff384a122b5865fb Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:09:19 +0900 Subject: [PATCH 089/238] docs(gap): record semantic backfill and latest PR heads --- docs/product-technical-gap-baseline.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 4eab4eed1..c62aeeb69 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 14:55 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:08 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 17 open PRs and 10 open issues. The exact-head +At this snapshot there were 19 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 10:10 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:08 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, @@ -78,22 +78,23 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 17 open PRs and 10 +at this refresh. The live queue contains 19 open PRs and 10 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 | | ---: | --- | --- | -| #686 | `dbe851ac` | customer-facing copy boundary audit; BLOCKED with hosted checks pending | -| #684 | `cb5e7df7` | measured PostgreSQL runtime tuning plan; merge state unknown while hosted checks are pending | +| #687 | `f3b1ef13` | bounded semantic backfill producer stacked on #640; UNSTABLE with hosted checks queued | +| #686 | `5eec27fc` | customer-facing copy boundary audit with localized action copy and exact `Time axis` label; BLOCKED with review required and hosted checks pending | +| #684 | `d71d0892` | measured PostgreSQL runtime tuning plan; UNSTABLE while hosted checks are pending | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `c430cfa1` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | -| #677 | `bf7d6b88` | ADR 0228 account-owned per-post Ask conversation history reconciled with the latest baseline; localized titles, full conversation/transcript pagination, stale-response guards, repeated-turn preservation, and eligibility recheck remain intact; hosted checks requeued and independent review required | -| #667 | `90b0d330` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | +| #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | +| #667 | `771a5186` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | From dad43e160ede6d1dc9fb5d343225b77efe7d0e34 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:12:18 +0900 Subject: [PATCH 090/238] docs(gap): record semantic worker quality repair --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c62aeeb69..221a90067 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -95,7 +95,7 @@ context only. | #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | | #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | | #667 | `771a5186` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | -| #672 | `5468c04d` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; BLOCKED with hosted checks queued and review required | +| #672 | `3d743ff7` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | From 0f34ff7c795728b123582b8de9b7ff2a1983b3cb Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:13:10 +0900 Subject: [PATCH 091/238] docs(gap): record dashboard stack advancement --- docs/product-technical-gap-baseline.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 221a90067..3ab9976d0 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:08 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:12 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 19 open PRs and 10 open issues. The exact-head +At this snapshot there were 18 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:08 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:12 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, @@ -78,7 +78,7 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 19 open PRs and 10 +at this refresh. The live queue contains 18 open PRs and 10 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. @@ -87,7 +87,7 @@ context only. | ---: | --- | --- | | #687 | `f3b1ef13` | bounded semantic backfill producer stacked on #640; UNSTABLE with hosted checks queued | | #686 | `5eec27fc` | customer-facing copy boundary audit with localized action copy and exact `Time axis` label; BLOCKED with review required and hosted checks pending | -| #684 | `d71d0892` | measured PostgreSQL runtime tuning plan; UNSTABLE while hosted checks are pending | +| #684 | `d71d0892` | MERGED to stack `feat/dashboard-case-metrics` as `49f0369e`; observed PostgreSQL runtime tuning plan is now part of the dashboard stack | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | @@ -102,7 +102,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `f88e7c64` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; current head retains customer copy, migration replay safety, id-only Ask citations, and not-applicable topic state while reverting an upstream capability-pin change; hosted checks requeued and independent review required | +| #640 | `49f0369e` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; stack now includes observed PostgreSQL tuning plan plus customer copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks requeued and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From d3334853ec45a2dc7f259ac92c03884b1c17a9e4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:29:13 +0900 Subject: [PATCH 092/238] docs(gap): refresh customer-copy exact head --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 3ab9976d0..186692839 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:12 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:28 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:12 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:28 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, @@ -86,7 +86,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #687 | `f3b1ef13` | bounded semantic backfill producer stacked on #640; UNSTABLE with hosted checks queued | -| #686 | `5eec27fc` | customer-facing copy boundary audit with localized action copy and exact `Time axis` label; BLOCKED with review required and hosted checks pending | +| #686 | `201f61d2` | customer-facing copy boundary audit removes implementation labels from source details and ranking accessibility text; BLOCKED with review required and hosted checks pending | | #684 | `d71d0892` | MERGED to stack `feat/dashboard-case-metrics` as `49f0369e`; observed PostgreSQL runtime tuning plan is now part of the dashboard stack | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | From 9a9b956af9c39d163378b4bbfd33e37f79da770b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:31:44 +0900 Subject: [PATCH 093/238] docs(gap): record latest customer-copy head --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 186692839..9c3d7a017 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:28 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:32 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:28 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:32 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, @@ -86,7 +86,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #687 | `f3b1ef13` | bounded semantic backfill producer stacked on #640; UNSTABLE with hosted checks queued | -| #686 | `201f61d2` | customer-facing copy boundary audit removes implementation labels from source details and ranking accessibility text; BLOCKED with review required and hosted checks pending | +| #686 | `f27279c5` | customer-facing copy boundary audit removes implementation labels from source details, ranking accessibility text, and ontology empty state; BLOCKED with review required and hosted checks pending | | #684 | `d71d0892` | MERGED to stack `feat/dashboard-case-metrics` as `49f0369e`; observed PostgreSQL runtime tuning plan is now part of the dashboard stack | | #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | | #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | From 2625f5b9196079017fa8a4c41ef39b02edd2bb9f Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:38:03 +0900 Subject: [PATCH 094/238] docs(gaps): reconcile live PR queue evidence --- docs/product-technical-gap-baseline.md | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 9c3d7a017..b0b2c469e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 18 open PRs and 10 open issues. The exact-head +At this snapshot there were 19 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:32 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:36 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, @@ -78,31 +78,28 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 18 open PRs and 10 +at this refresh. The live queue contains 19 open PRs and 10 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 | | ---: | --- | --- | -| #687 | `f3b1ef13` | bounded semantic backfill producer stacked on #640; UNSTABLE with hosted checks queued | -| #686 | `f27279c5` | customer-facing copy boundary audit removes implementation labels from source details, ranking accessibility text, and ontology empty state; BLOCKED with review required and hosted checks pending | -| #684 | `d71d0892` | MERGED to stack `feat/dashboard-case-metrics` as `49f0369e`; observed PostgreSQL runtime tuning plan is now part of the dashboard stack | -| #682 | `0aa3113e` | MERGED to stack `feat/global-ask-semantic-public-current` as `fa245483`; typed public-claim verification filters cited claims before the bounded candidate budget, preserves answers when verification is unavailable, rejects hidden evidence from public egress, and validates empty orchestrator choices | -| #681 | `3e0fa644` | MERGED to stack `feat/dashboard-case-metrics` as `dae28fb2`; fail-closed lineage-weight owner contract pin with lockfile parity | +| #688 | `1e467927` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #687 | `6798c081` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #686 | `b8547687` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `c430cfa1` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | -| #678 | `676fcc5a` | MERGED to stack `feat/dashboard-case-metrics` as `bec013d8`; canonical Compose-stack consolidation | | #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | -| #667 | `771a5186` | baseline refresh branch current head; BLOCKED with review required; stacked #669 and #671 are merged into this non-default branch | | #672 | `3d743ff7` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | +| #667 | `9a9b956a` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `49f0369e` | dashboard ranking and topic-influence surfaces no longer expose provider, hash, or uncertainty-code implementation labels; stack now includes observed PostgreSQL tuning plan plus customer copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks requeued and independent review required | +| #640 | `ed777202` | dashboard ranking and topic-influence stack with customer-facing copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | @@ -410,7 +407,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Thirteen PRs remain open; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 11:36 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -510,8 +507,11 @@ review latency are never blockers — keep working while they settle. 1. Revalidate Strix after protected ContextualWisdomLab/.github#1320, reconcile .github#1263, and land the atomic hourly LineageWeave caller in .github#1288. -2. Merge #618–#621 only after each exact head shows terminal - green required checks plus current-head independent approval. +2. Process the current section 1 inventory in ascending PR order after + dependency review. Stacked #677 depends on #667, while #687 and #688 depend + on #640; no child head may substitute for protected delivery of its base. + Merge only after each exact head shows terminal green required checks plus + current-head independent approval. 3. After the queue drains, resume user-visible gaps from §5 in leverage order: Event Lineage evidence (merged #387; historical issue #274), Naruon calendar (#355), and authenticated operations/ontology publication acceptance. From b9fd426f895ec34ddbc136553df249309b62eeef Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:39:28 +0900 Subject: [PATCH 095/238] docs(gap): refresh dashboard stack exact head --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b0b2c469e..0accd9be5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:32 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:38 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:36 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:38 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, @@ -99,7 +99,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `ed777202` | dashboard ranking and topic-influence stack with customer-facing copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks and independent review required | +| #640 | `fbc129c0` | dashboard ranking and topic-influence stack with localized evidence labels, consistent topic-journey actions, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks and independent review required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 3fd77e60360c12aa0e0ec06a1154d93fdba0c0f9 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:41:46 +0900 Subject: [PATCH 096/238] docs(gaps): record current exact-head queue --- docs/product-technical-gap-baseline.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b0b2c469e..198738c32 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:32 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:39 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:36 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:39 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, @@ -89,17 +89,17 @@ context only. | #687 | `6798c081` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | | #686 | `b8547687` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | -| #679 | `c430cfa1` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | +| #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | | #672 | `3d743ff7` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `9a9b956a` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | +| #667 | `2625f5b9` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `ed777202` | dashboard ranking and topic-influence stack with customer-facing copy, migration replay safety, id-only Ask citations, and not-applicable topic state; hosted checks and independent review required | +| #640 | `fbc129c0` | dashboard ranking and topic-influence stack now localizes evidence-rank labels, uses one topic-journey vocabulary, and makes the PostgreSQL tuning command contract explicit; focused UI and tuning-plan regressions passed, while exact-head hosted checks and independent review remain required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From efe1284175db67402a555dbeb00f65ff4d36c46b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:45:43 +0900 Subject: [PATCH 097/238] docs(gap): capture expanded open-pr queue --- docs/product-technical-gap-baseline.md | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5a73d7a7a..f436f0761 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:39 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:44 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 19 open PRs and 10 open issues. The exact-head +At this snapshot there were 20 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:39 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:44 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, @@ -78,13 +78,14 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 19 open PRs and 10 +at this refresh. The live queue contains 20 open PRs and 10 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 | | ---: | --- | --- | +| #689 | `81a5b1e9` | accepted measurement-owner release pin stacked on #640; hosted checks and independent review pending | | #688 | `1e467927` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | | #687 | `6798c081` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | | #686 | `b8547687` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | @@ -93,7 +94,7 @@ context only. | #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | | #672 | `3d743ff7` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `2625f5b9` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | +| #667 | `b9fd426f` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -242,12 +243,13 @@ requires the ADR 0001 incident process and security/privacy-owner coordination; never force-push or delete evidence ad hoc. The Grok durable hourly loop and the central thin GitHub Actions caller -ContextualWisdomLab/.github#1259 (minute 4, `pr-review-fix-scheduler.yml`) -both target this repository. Do not add a LineageWeave-local duplicate -workflow. ContextualWisdomLab/.github#1258 merged at exact head `897819c4` to -repair the pnpm/coverage-evidence workflow; newly created exact PR heads must -still prove the runtime behavior because merged workflow source alone is not -check evidence. +ContextualWisdomLab/.github#1288 (current head `5cd507f8`, minute 4, +`pr-review-fix-scheduler.yml`) both target this repository. PR #1259 is the +closed predecessor and must not be treated as current scheduler evidence. Do +not add a LineageWeave-local duplicate workflow. ContextualWisdomLab/.github#1258 +merged at exact head `897819c4` to repair the pnpm/coverage-evidence workflow; +newly created exact PR heads must still prove the runtime behavior because +merged workflow source alone is not check evidence. Figma design-system boundary (ADR 0002): File ID `1Su3lDRmiZdcUs47t1QwIX`. The sanitized file now contains synthetic Event Lineage desktop (`5:14`) and @@ -466,7 +468,7 @@ of leverage; open connector PRs there when the defect is upstream: 6. **ThreadWeave** — tree assembly. 7. **Naruon** — calendar projection delivered through merged #355/closed #336; email/project lineage projection remains open as #338. 8. **DiskSage / wardnet** — storage and network policy as needed. -9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1259). If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. +9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1288, current head `5cd507f8`). If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. ## 8. Public ontology publication boundary @@ -506,7 +508,7 @@ each: check reviews → repair → re-verify Checks → merge → continue. Chec review latency are never blockers — keep working while they settle. 1. Revalidate Strix after protected ContextualWisdomLab/.github#1320, reconcile - .github#1263, and land the atomic hourly LineageWeave caller in .github#1288. + .github#1263, and land the atomic hourly LineageWeave caller in .github#1288 after its current-head independent approval and checks complete. 2. Process the current section 1 inventory in ascending PR order after dependency review. Stacked #677 depends on #667, while #687 and #688 depend on #640; no child head may substitute for protected delivery of its base. From 591d2aa7c4b67aa72bad62144c85b280915265c0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:48:58 +0900 Subject: [PATCH 098/238] docs(gaps): record cross-PR contract collisions --- docs/product-technical-gap-baseline.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index f436f0761..755929c4e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -111,6 +111,20 @@ 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. +### Cross-PR contract collision audit + +The current heads cannot be merged in arbitrary order. PR #672 and stacked +PR #677 assign different decisions to ADR 0228 (public-claim verification +versus per-post conversation history). PR #640 and PR #663 likewise assign +different decisions to ADR 0224, while #640 and #672 introduce different +`0211_*.sql` migrations. The `0212_global_ask_knowledge_cutoff.sql` blobs in +#658 and #663 are byte-identical, so that overlap is duplicated delivery rather +than a semantic divergence. Release metadata also diverges: the observed +`pyproject.toml` versions are 2.18.0 on #632/#640/#663/#689, 2.19.0 on #643, +and 2.22.0 on #679. These ADR, migration, and release identities remain merge +blockers until the parent lands and every surviving child is retargeted to +`main`, renumbered where needed, and revalidated on its new exact head. + The hosted Full test for PR #632 at superseded head `cad4debf` failed only in the real-PostgreSQL semantic-nomination test with `InvalidPasswordError`; the other 1,333 tests passed. The run was cancelled after the branch advanced to From 9c0944226a035b35d51d23b2fb9cce7644932e16 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:49:02 +0900 Subject: [PATCH 099/238] docs(gap): refresh queued exact heads --- docs/product-technical-gap-baseline.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 755929c4e..95c58ce32 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:44 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:48 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:44 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:48 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, @@ -86,13 +86,13 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #689 | `81a5b1e9` | accepted measurement-owner release pin stacked on #640; hosted checks and independent review pending | -| #688 | `1e467927` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #688 | `9a8c085c` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | | #687 | `6798c081` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | | #686 | `b8547687` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | -| #672 | `3d743ff7` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | +| #672 | `91caeb02` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #667 | `b9fd426f` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | @@ -100,7 +100,7 @@ context only. | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `fbc129c0` | dashboard ranking and topic-influence stack now localizes evidence-rank labels, uses one topic-journey vocabulary, and makes the PostgreSQL tuning command contract explicit while retaining migration replay safety, id-only Ask citations, and the not-applicable topic state; focused UI and tuning-plan regressions passed, while exact-head hosted checks and independent review remain required | +| #640 | `eaec942f` | dashboard ranking and topic-influence stack now localizes evidence-rank labels, uses one topic-journey vocabulary, and makes the PostgreSQL tuning command contract explicit while retaining migration replay safety, id-only Ask citations, and the not-applicable topic state; focused UI and tuning-plan regressions passed, while exact-head hosted checks and independent review remain required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | From 1dd4ab20b6b079b62bc1706ebfcbf70623804dc7 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:52:10 +0900 Subject: [PATCH 100/238] docs(gap): refresh latest queue heads --- docs/product-technical-gap-baseline.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 95c58ce32..e461f8c4f 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:48 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:51 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:48 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:51 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, @@ -86,15 +86,15 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #689 | `81a5b1e9` | accepted measurement-owner release pin stacked on #640; hosted checks and independent review pending | -| #688 | `9a8c085c` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | -| #687 | `6798c081` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | -| #686 | `b8547687` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | +| #688 | `c8e217ca` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #687 | `827978a5` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #686 | `ea34a797` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | | #672 | `91caeb02` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `b9fd426f` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | +| #667 | `9c094422` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -423,7 +423,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 11:36 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty PRs remain open at the 11:51 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From b3a1c4e66238ce1219c607183d7cbe825cd6922c Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:54:42 +0900 Subject: [PATCH 101/238] docs(gap): record protected queue merge progress --- docs/product-technical-gap-baseline.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e461f8c4f..b3da5c907 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -14,7 +14,7 @@ | Project-specific journey | Explicit source/semantic project membership plus event-time ordering | Candidate API and ordered journey UI implemented; authenticated runtime acceptance pending | | Repeat issue to design improvement | `repeat_issue`, `issue_pattern`, and `improvement_action` cited facts | Candidate semantic contract; design-system connector acceptance pending | | Natural-language Ask with evidence, report, alert, MCP | Persisted semantic-unit embeddings plus versioned delivery/resource contract | Candidate implementation uses whole-question embedding retrieval with no lexical fallback; authenticated runtime acceptance pending | -| Per-post Ask continuity | ADR 0228; account/post-scoped normalized sessions and current-authorization citation projection | Stacked PR #677 candidate implementation and regression/Storybook evidence; parent #667 must merge first, then #677 must be retargeted to `main` and revalidated | +| Per-post Ask continuity | ADR 0228; account/post-scoped normalized sessions and current-authorization citation projection | PR #677 merged into the non-default baseline branch as `80c59672`; retarget to `main` and revalidate after protected parent delivery | | Similar VOC, customer cohort, prior action | Persisted repeat-issue candidate semantics plus orchestrator pair adjudication and extractive evidence | Candidate live post endpoint and post-detail UI implemented; authenticated runtime acceptance pending | | TEPP independent Event Lineage anchor | Accepted, persisted TEPP criterion bound to exact snapshot/cutoff before fast-mlsirm activation | Consumer PR #606 is on protected main; TEPP producer PR #237 remains open, so no end-to-end accepted artifact is release evidence yet | | Temporal Lineage topics and multilevel important posts | ADR 0210; TEPP posterior topic/plausible-value contract followed by fast-mlsirm observed-information case-deletion influence | Product/technical contract is protected on `main`; neither required Rust CPU/GPU producer envelope is shipped, so the Dashboard surface remains unavailable (ADR 0208: no local Python substitute) | @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 20 open PRs and 10 open issues. The exact-head +At this snapshot there were 19 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:51 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:53 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, @@ -78,7 +78,7 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 20 open PRs and 10 +at this refresh. The live queue contains 19 open PRs and 10 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. @@ -91,7 +91,6 @@ context only. | #686 | `ea34a797` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | -| #677 | `0ba4e609` | ADR 0228 account-owned per-post Ask conversation history with canonical cursor-field fixture repair; hosted checks requeued and independent review required | | #672 | `91caeb02` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | | #667 | `9c094422` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | @@ -524,8 +523,9 @@ review latency are never blockers — keep working while they settle. 1. Revalidate Strix after protected ContextualWisdomLab/.github#1320, reconcile .github#1263, and land the atomic hourly LineageWeave caller in .github#1288 after its current-head independent approval and checks complete. 2. Process the current section 1 inventory in ascending PR order after - dependency review. Stacked #677 depends on #667, while #687 and #688 depend - on #640; no child head may substitute for protected delivery of its base. + dependency review. #677 is merged into the non-default baseline branch and + must be retargeted to `main` after #667; #687 and #688 depend on #640. No + child head may substitute for protected delivery of its base. Merge only after each exact head shows terminal green required checks plus current-head independent approval. 3. After the queue drains, resume user-visible gaps from §5 in leverage order: From 4790b43f9ec28c00e9808741ed56c0a2937a6131 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:56:56 +0900 Subject: [PATCH 102/238] docs(gap): refresh current stacked heads --- 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 b3da5c907..879256adc 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:53 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:55 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, @@ -85,15 +85,15 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #689 | `81a5b1e9` | accepted measurement-owner release pin stacked on #640; hosted checks and independent review pending | -| #688 | `c8e217ca` | automatic related-source evidence lookup stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #689 | `81d85a02` | accepted measurement-owner release pin restacked on current #640; hosted checks and independent review pending | +| #688 | `63372cc9` | automatic related-source evidence lookup restacked on current #640; UNSTABLE with hosted checks and stack-base delivery pending | | #687 | `827978a5` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | | #686 | `ea34a797` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `91caeb02` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `9c094422` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | +| #667 | `b3a1c4e6` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | From ed0619217786ddcd674503f194c85657b3e3ca89 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 11:56:56 +0900 Subject: [PATCH 103/238] docs(gap): record baseline parent exact head --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 879256adc..6f7ac6ef8 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:51 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 11:56 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 11:55 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 11:56 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, @@ -422,7 +422,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty PRs remain open at the 11:51 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 11:56 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From b093b7d984c21169b1b50948a08b015628b3465e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 12:06:17 +0900 Subject: [PATCH 104/238] docs(gap): refresh exact-head queue evidence --- docs/product-technical-gap-baseline.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6f7ac6ef8..32bf4117a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 11:56 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 12:08 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -86,14 +86,14 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #689 | `81d85a02` | accepted measurement-owner release pin restacked on current #640; hosted checks and independent review pending | -| #688 | `63372cc9` | automatic related-source evidence lookup restacked on current #640; UNSTABLE with hosted checks and stack-base delivery pending | +| #688 | `ef7aebdd` | automatic related-source evidence lookup restacked on current #640; UNSTABLE with hosted checks and stack-base delivery pending | | #687 | `827978a5` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | -| #686 | `ea34a797` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; BLOCKED with review required and hosted checks pending | +| #686 | `7f0a6fd1` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; five locale/accessibility fixes applied, three Devin threads resolved, hosted checks requeued | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | -| #672 | `91caeb02` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; exact-head worker factory quality repair applied, hosted checks requeued and review required | +| #672 | `ac521a24` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; unexpected external-verification adapter failures now degrade to unavailable with a regression test; one pre-existing pool/embedding review note remains, hosted checks requeued | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `b3a1c4e6` | baseline refresh observed before this documentation-only update; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | +| #667 | `ed061921` | baseline refresh parent is the current exact head; BLOCKED with hosted checks and independent review required; this row is not a prediction of the commit created by the refresh | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head Full-suite authentication and transaction-fixture failures repaired; fresh checks pending and review required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -105,6 +105,11 @@ context only. | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | | #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | +The exact-head check-run scan at 12:08 KST found no `failure`, `cancelled`, or +`timed_out` conclusions on the 19 current heads. Several heads, including +#672 and #686 after their repair pushes, are still queued and therefore have +no terminal gate evidence; review approval is also independently required. + No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head check conclusions. In particular, queued checks are infrastructure state and From efa28fccbbd862f838e1ae6463b1990b5ec05c3f Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 12:07:59 +0900 Subject: [PATCH 105/238] fix(chat): keep repeated turns distinct --- frontend/src/App.tsx | 8 ++++---- frontend/src/ChatPanel.test.tsx | 31 +++++++++++++++++++++++++++++++ frontend/src/api.ts | 1 + 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8f95dd9b0..72c49d433 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -501,9 +501,9 @@ export function ChatPanel({ )} {exchanges.length > 0 && (
- {exchanges.map((exchange) => ( + {exchanges.map((exchange, index) => ( diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index b228f930e..49ff136a5 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -154,6 +154,59 @@ describe("ChatPanel conversation history", () => { expect(screen.queryByText("Only authorized saved evidence.")).toBeNull(); }); + it("ignores an earlier-page response after another conversation is selected", async () => { + let resolveOlder!: (response: Response) => void; + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { + const url = input instanceof Request ? input.url : String(input); + if (url.endsWith("/chat/conversations/conversation-1?before_turn=2")) { + return new Promise((resolve) => { resolveOlder = resolve; }); + } + if (url.endsWith("/chat/conversations/conversation-1")) { + return jsonResponse({ + conversation_id: "conversation-1", + title: "First conversation", + older_cursor: "2", + exchanges: [{ turn_id: "turn-1", question_text: "First?", answer_text: "First answer", cited_post_ids: [] }], + }); + } + if (url.endsWith("/chat/conversations/conversation-2")) { + return jsonResponse({ + conversation_id: "conversation-2", + title: "Second conversation", + older_cursor: null, + exchanges: [{ turn_id: "turn-2", question_text: "Second?", answer_text: "Second answer", cited_post_ids: [] }], + }); + } + if (url.endsWith("/chat/conversations")) { + return jsonResponse({ + conversations: [ + { conversation_id: "conversation-1", title: "First conversation", updated_at: "2026-08-26T00:00:00Z", turn_count: 1 }, + { conversation_id: "conversation-2", title: "Second conversation", updated_at: "2026-08-26T00:01:00Z", turn_count: 1 }, + ], + next_cursor: null, + }); + } + return jsonResponse({ post_id: "post-1", exchanges: [] }); + })); + + render(); + const history = await screen.findByLabelText("Conversation history"); + await userEvent.selectOptions(history, "conversation-1"); + await screen.findByText("First answer"); + await userEvent.click(screen.getByRole("button", { name: "Load earlier messages" })); + await userEvent.selectOptions(history, "conversation-2"); + await screen.findByText("Second answer"); + resolveOlder(jsonResponse({ + conversation_id: "conversation-1", + title: "First conversation", + older_cursor: null, + exchanges: [{ turn_id: "turn-0", question_text: "Earlier?", answer_text: "Stale earlier answer", cited_post_ids: [] }], + })); + + await waitFor(() => expect(screen.queryByText("Stale earlier answer")).toBeNull()); + expect(screen.getByText("Second answer")).toBeInTheDocument(); + }); + it("offers a next action when another history page cannot be loaded", async () => { vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : String(input); From 0a13425412b1871d4dd6fdcebf014c72aebcec04 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 12:49:57 +0900 Subject: [PATCH 117/238] docs(gaps): refresh customer-copy evidence --- docs/product-technical-gap-baseline.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a273ce2a0..49833c6f1 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 12:22 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 12:49 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, @@ -86,14 +86,14 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #689 | `81d85a02` | accepted measurement-owner release pin restacked on current #640; hosted checks and independent review pending | -| #688 | `e5769971` | automatic related-source evidence lookup restacked on current #640; newly analyzed project evidence now durably requeues completed sibling analyses with missing facts, and the current head is UNSTABLE with hosted checks pending | +| #688 | `dd65e92e` | automatic related-source evidence lookup restacked on current #640; newly analyzed project evidence now durably requeues completed sibling analyses with missing facts, and the current head is UNSTABLE with hosted checks pending | | #687 | `827978a5` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | -| #686 | `7bd0da8b` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved and hosted checks remain pending | +| #686 | `c056dad2` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved, ranking guidance has desktop/mobile Storybook screenshot evidence, and hosted checks remain pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `147f208e` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; unexpected verification failures degrade to unavailable, and embedding work is performed before the pool is acquired; hosted checks requeued | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `79b49012` | baseline refresh plus repeated-turn conversation-key repair and legacy ontology identifier separation; current head has no unresolved review threads, while hosted checks and independent approval remain pending | +| #667 | `793931a6` | baseline refresh plus repeated-turn conversation-key repair, stale-history response fencing, and legacy ontology identifier separation; current head has no unresolved review threads, while hosted checks and independent approval remain pending | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head local ontology/migration/docstring checks pass (100 tests) and frontend ontology/token/i18n checks pass (88 tests); hosted checks are terminal successful except queued OpenCode review, and independent review remains required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -105,7 +105,7 @@ context only. | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | | #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | -The exact-head check-run scan at 12:22 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 12:49 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 19 current heads. Several heads, including PR #667, #672, and #686 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -427,7 +427,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 12:22 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 12:49 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 0e95a2003ffc08f9a75ef9026fd105503799176c Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 12:51:58 +0900 Subject: [PATCH 118/238] docs(gaps): record customer-copy branch collision --- docs/product-technical-gap-baseline.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 49833c6f1..76b01f57d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -129,6 +129,12 @@ and 2.22.0 on #679. These ADR, migration, and release identities remain merge blockers until the parent lands and every surviving child is retargeted to `main`, renumbered where needed, and revalidated on its new exact head. +PR #680 and #686 independently edit the same ranking, ontology, and locale +surfaces, and neither exact head contains the other. Land #686 first because it +contains the repository-wide customer-copy boundary audit and rendered +desktop/mobile evidence; then rebase #680 and retain only behavior not already +covered, so a later merge cannot restore implementation-facing copy. + The hosted Full test for PR #632 at superseded head `cad4debf` failed only in the real-PostgreSQL semantic-nomination test with `InvalidPasswordError`; the other 1,333 tests passed. The run was cancelled after the branch advanced to From ba19fc61b085f220445fe8de1c377befeaf0a58e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 12:53:36 +0900 Subject: [PATCH 119/238] fix(chat): clear resolved history warning --- frontend/src/App.tsx | 1 + frontend/src/ChatPanel.test.tsx | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index cda12905d..6e860896f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -339,6 +339,7 @@ export function ChatPanel({ setQuestion(""); setAnswer(null); setError(null); + setHistoryError(null); } async function handleAsk(asked = question) { diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 49ff136a5..30e2f1440 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -234,5 +234,9 @@ describe("ChatPanel conversation history", () => { expect(await screen.findByText( "Conversation history could not be loaded. Start a new conversation or try again later.", )).toBeInTheDocument(); + await userEvent.click(screen.getByRole("button", { name: "New conversation" })); + expect(screen.queryByText( + "Conversation history could not be loaded. Start a new conversation or try again later.", + )).toBeNull(); }); }); From 2a2ec9cf356f2bef41d1dacb95d6240eb3af65fd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 12:57:06 +0900 Subject: [PATCH 120/238] docs(gaps): track analysis-run localization --- docs/product-technical-gap-baseline.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 76b01f57d..15fa241ee 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -474,6 +474,7 @@ before a commercial release claim. Figma File ID `1Su3lDRmiZdcUs47t1QwIX`. | Style Selection | Korean UI standards merged (#347) | Tokenized light/dark; Anti-Slop-UI density; no decorative noise | | Layout & Responsive | Desktop popup shell; this candidate stacks analysis-run caption, document count, and next action at 390px and retains explicit grid columns at 1440px | Complete 402px-class phone acceptance for remaining panels; stacked GNB; readable DAG | | Typography & Color | Badge tokens extracted | Contrast on badges, links, error/status; no raw hex in components | +| Localization | Shared and ontology customer actions are checked across English, Korean, Chinese, Japanese, and Vietnamese on #686; analysis-run guidance still returns untranslated English strings | Route every analysis-run status, empty-corpus, and corpus-guidance message through the shared locale catalog and add a five-locale completeness test before claiming locale-complete operations UX | | Animation | Minimal | Reduced-motion; no blocking animation on evidence open | | Forms & Feedback | Login, Ask, tickets, admin brand; this candidate gives all four Cancelled analysis kinds an evidence-safe next action | Inline validation and unavailable-vs-failed acceptance across remaining workflows | | Navigation Patterns | Board / customers / calendar / Ask / admin | Deep-link post + OIDC return URL (#426); bookmarkable Ask | From 244efc6bbfa783185eac7f8878b5f86169002a5a Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 13:11:33 +0900 Subject: [PATCH 121/238] feat(i18n): localize analysis-run guidance --- CHANGELOG.md | 5 + docs/product-technical-gap-baseline.md | 2 +- .../analysis-run-guidance-ko-desktop.png | Bin 0 -> 54052 bytes .../analysis-run-guidance-ko-mobile.png | Bin 0 -> 41703 bytes frontend/src/AnalysisRunGuidance.stories.tsx | 69 +++++++ frontend/src/App.css | 5 + frontend/src/App.test.tsx | 26 ++- frontend/src/App.tsx | 73 +++---- frontend/src/analysisRunI18n.test.ts | 21 ++ frontend/src/analysisRunI18n.ts | 186 ++++++++++++++++++ 10 files changed, 336 insertions(+), 51 deletions(-) create mode 100644 docs/screenshots/analysis-run-guidance-ko-desktop.png create mode 100644 docs/screenshots/analysis-run-guidance-ko-mobile.png create mode 100644 frontend/src/AnalysisRunGuidance.stories.tsx create mode 100644 frontend/src/analysisRunI18n.test.ts create mode 100644 frontend/src/analysisRunI18n.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e2f1aa98..9719d8595 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ All notable changes to this project are documented here. Format follows ### Added +- Analysis-run next actions, empty-snapshot guidance, and selected-post + guidance now follow the active English, Korean, Chinese, Japanese, or + Vietnamese locale. Customer copy describes the next product action without + exposing internal measurement transport boundaries; Storybook includes + desktop and phone status matrices. - Account-owned per-post Ask conversations can be listed, reopened, and continued with current authorization reapplied to cited evidence (ADR 0228). - Persist explicit paragraph, list, table, MathML formula, and caller-parsed diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 15fa241ee..cdc50b33b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -474,7 +474,7 @@ before a commercial release claim. Figma File ID `1Su3lDRmiZdcUs47t1QwIX`. | Style Selection | Korean UI standards merged (#347) | Tokenized light/dark; Anti-Slop-UI density; no decorative noise | | Layout & Responsive | Desktop popup shell; this candidate stacks analysis-run caption, document count, and next action at 390px and retains explicit grid columns at 1440px | Complete 402px-class phone acceptance for remaining panels; stacked GNB; readable DAG | | Typography & Color | Badge tokens extracted | Contrast on badges, links, error/status; no raw hex in components | -| Localization | Shared and ontology customer actions are checked across English, Korean, Chinese, Japanese, and Vietnamese on #686; analysis-run guidance still returns untranslated English strings | Route every analysis-run status, empty-corpus, and corpus-guidance message through the shared locale catalog and add a five-locale completeness test before claiming locale-complete operations UX | +| Localization | Shared and ontology customer actions are checked across English, Korean, Chinese, Japanese, and Vietnamese on #686. This stacked candidate localizes every analysis-run next action, empty-snapshot message, and selected-post guidance; the five-locale completeness test and Korean desktop/phone Storybook screenshots are retained at `docs/screenshots/analysis-run-guidance-ko-{desktop,mobile}.png` | Land both parent and child through exact-head protected gates, then repeat authenticated screen-reader acceptance on the release head before claiming locale-complete operations UX | | Animation | Minimal | Reduced-motion; no blocking animation on evidence open | | Forms & Feedback | Login, Ask, tickets, admin brand; this candidate gives all four Cancelled analysis kinds an evidence-safe next action | Inline validation and unavailable-vs-failed acceptance across remaining workflows | | Navigation Patterns | Board / customers / calendar / Ask / admin | Deep-link post + OIDC return URL (#426); bookmarkable Ask | diff --git a/docs/screenshots/analysis-run-guidance-ko-desktop.png b/docs/screenshots/analysis-run-guidance-ko-desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..655680b8728954fce97849519afae8836c3cc00f GIT binary patch literal 54052 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%0Dvsbm_rp%2+pbnX-_2ZrF-tR`%rq8SGB6 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 literal 0 HcmV?d00001 diff --git a/docs/screenshots/analysis-run-guidance-ko-mobile.png b/docs/screenshots/analysis-run-guidance-ko-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..d35eb62cd81885d37b0d92ab55dbb9e09cc334b8 GIT binary patch literal 41703 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 b^uo-rGl>1KX>P|cpa_GftDnm{r-UW|$%FAK literal 0 HcmV?d00001 diff --git a/frontend/src/AnalysisRunGuidance.stories.tsx b/frontend/src/AnalysisRunGuidance.stories.tsx new file mode 100644 index 000000000..4a8a91403 --- /dev/null +++ b/frontend/src/AnalysisRunGuidance.stories.tsx @@ -0,0 +1,69 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { expect, within } from "storybook/test"; +import { + analysisRunText, + type AnalysisRunCopyKey, +} from "./analysisRunI18n"; +import { getLocale, setLocale, useLocale } from "./i18n"; +import "./App.css"; + +const RUN_STATES: Array<{ + label: string; + key: AnalysisRunCopyKey; +}> = [ + { label: "계보 재구성 · 대기", key: "pendingLineage" }, + { label: "측정 · 실패", key: "failedMeasurement" }, + { label: "토픽 계보 · 진행 중", key: "running" }, + { label: "기간 보고서 · 취소", key: "cancelledReport" }, + { label: "측정 · 결과 없음", key: "emptyMeasurement" }, + { label: "토픽 계보 · 선택된 글", key: "corpusPendingTopicLineage" }, +]; + +function AnalysisRunGuidanceInventory() { + useLocale(); + return ( +
+

분석 실행 안내

+
    + {RUN_STATES.map((state) => ( +
  • + +
  • + ))} +
+
+ ); +} + +const meta = { + title: "Workspace/AnalysisRunGuidance", + component: AnalysisRunGuidanceInventory, + parameters: { layout: "padded" }, + beforeEach: () => { + const previous = getLocale(); + setLocale("ko"); + return () => setLocale(previous); + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const StatusAndCorpusMatrix: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText("관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", { exact: false })).toBeVisible(); + await expect(canvas.getByText("이 실행이 끝나면 이 글들이 토픽 계보를 구성합니다.")).toBeVisible(); + }, +}; + +export const Phone: Story = { + ...StatusAndCorpusMatrix, + parameters: { viewport: { defaultViewport: "mobile1" } }, +}; diff --git a/frontend/src/App.css b/frontend/src/App.css index 4fc37055c..6e1d7a0f6 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -941,6 +941,11 @@ gap: 0.75rem; } +.analysis-run-item .post-meta { + overflow-wrap: anywhere; + word-break: keep-all; +} + .analysis-run-item.has-document-count.has-next-action { grid-template-columns: minmax(12rem, 1fr) auto minmax(18rem, 2fr); } diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 67d7c59af..76e787529 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -3276,7 +3276,7 @@ describe("App, authenticated", () => { expect(list).toHaveTextContent("TEPP measurement · Failed · Demo Corp"); expect(list).toHaveTextContent("Period report · Succeeded · Demo Corp"); expect(list).toHaveTextContent( - "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again.", + "Open this run to see why it failed. Ask an administrator to restore measurement, then run it again.", ); expect(list).toHaveTextContent("3 documents"); expect(list).not.toHaveTextContent("postgresql://"); @@ -3374,7 +3374,7 @@ describe("App, authenticated", () => { ).toBeInTheDocument(); const teppHistory = screen.getByRole("list", { name: "Analysis run status history" }); expect(teppHistory).toHaveTextContent("Failed 2026-01-12 12:37 · tepp_not_available"); - expect(screen.getByText(/cutoff corpus TEPP would measure/i)).toBeInTheDocument(); + expect(screen.getByText(/selected for measurement at this snapshot/i)).toBeInTheDocument(); expect(teppHistory).not.toHaveTextContent("Succeeded"); }); @@ -3430,11 +3430,11 @@ describe("App, authenticated", () => { ["analysis_run_lineage", "Request a new lineage reconstruction from a current snapshot."], [ "analysis_run_tepp", - "Ask an administrator to enable measurement and submit a new run from a current snapshot.", + "Ask an administrator to restore measurement and submit a new run from a current snapshot.", ], [ "analysis_run_topic_lineage", - "Ask an administrator to enable topic-lineage analysis and submit a new run from a current snapshot.", + "Ask an administrator to restore topic-lineage analysis and submit a new run from a current snapshot.", ], ["analysis_run_report", "Rebuild the period report from a current snapshot."], ] satisfies [AnalysisRunKindCode, string][])( @@ -3453,6 +3453,16 @@ describe("App, authenticated", () => { }, ); + it("shows analysis-run next actions in the selected locale", async () => { + setLocale("ko"); + stubBackend({ cancelledRunKind: "analysis_run_lineage" }); + render(); + + expect(await screen.findByText( + "이 실행은 취소되었습니다. 현재 스냅샷에서 새 계보 재구성을 요청하세요.", + )).toBeInTheDocument(); + }); + it("tells a running lineage run how to check for results", async () => { stubBackend({ runningLineageRun: true }); render(); @@ -3486,7 +3496,7 @@ describe("App, authenticated", () => { ); expect(lineageButton).not.toHaveTextContent("measurement service"); expect(teppButton).toHaveTextContent( - "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again.", + "Open this run to see why it failed. Ask an administrator to restore measurement, then run it again.", ); expect(teppButton).not.toHaveTextContent("reconstruction"); }); @@ -3775,7 +3785,7 @@ describe("App, authenticated", () => { ).not.toBeInTheDocument(); expect( await screen.findByText( - "No posts were available at this cutoff for the period report. Open a later run, or ask an administrator to capture a newer snapshot.", + "No posts were available at this snapshot for the period report. Open a later run, or ask an administrator to capture a newer snapshot.", ), ).toBeInTheDocument(); }); @@ -3790,7 +3800,7 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("These posts are the cutoff corpus TEPP will measure once this run finishes."), + await screen.findByText("These posts will be measured when this run finishes."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); expect(screen.queryByText(/this TEPP run measured/i)).not.toBeInTheDocument(); @@ -3854,7 +3864,7 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("These posts are the cutoff corpus this TEPP run measured."), + await screen.findByText("These posts were measured in this run."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6e860896f..84ccc3d60 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,6 +2,7 @@ import { AdminPanel } from "./components/AdminPanel"; import { LeftoverPairList } from "./components/LeftoverPairList"; import { WorkspaceCalendar } from "./components/WorkspaceCalendar"; import { focusedGraphMustReset } from "./focusedGraphSelection"; +import { analysisRunText } from "./analysisRunI18n"; import { useCallback, useEffect, useEffectEvent, useRef, useState, type ReactNode } from "react"; import { useAuth } from "react-oidc-context"; @@ -2794,13 +2795,13 @@ function analysisRunNextAction(run: AnalysisRun): string | null { case "analysis_status_pending": switch (run.run_kind_code) { case "analysis_run_lineage": - return "Open this run, then start reconstruction. Reconstruction has not started yet."; + return analysisRunText("pendingLineage"); case "analysis_run_tepp": - return "Open this run to confirm which posts TEPP will measure. Measurement has not started yet — this is not a calibrated result."; + return analysisRunText("pendingMeasurement"); case "analysis_run_topic_lineage": - return "Open this run to confirm which posts TEPP will thread into topic lineage. Topic-lineage analysis has not started yet — this is not a calibrated topic result."; + return analysisRunText("pendingTopicLineage"); case "analysis_run_report": - return "Open this run to confirm which posts the period report will use. The report has not been built yet."; + return analysisRunText("pendingReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; @@ -2809,30 +2810,30 @@ function analysisRunNextAction(run: AnalysisRun): string | null { case "analysis_status_failed": switch (run.run_kind_code) { case "analysis_run_tepp": - return "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again."; + return analysisRunText("failedMeasurement"); case "analysis_run_topic_lineage": - return "Open this run to see why it failed. Ask an administrator to enable topic-lineage analysis, then run it again."; + return analysisRunText("failedTopicLineage"); case "analysis_run_lineage": - return "Open this run to see why it failed, then retry reconstruction from a current snapshot."; + return analysisRunText("failedLineage"); case "analysis_run_report": - return "Open this run to see why it failed, then rebuild the period report from a current snapshot."; + return analysisRunText("failedReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; } } case "analysis_status_running": - return "This run is in progress. Refresh it to check for results."; + return analysisRunText("running"); case "analysis_status_cancelled": switch (run.run_kind_code) { case "analysis_run_lineage": - return "This run was cancelled. Request a new lineage reconstruction from a current snapshot."; + return analysisRunText("cancelledLineage"); case "analysis_run_tepp": - return "This run was cancelled. Ask an administrator to enable measurement and submit a new run from a current snapshot."; + return analysisRunText("cancelledMeasurement"); case "analysis_run_topic_lineage": - return "This run was cancelled. Ask an administrator to enable topic-lineage analysis and submit a new run from a current snapshot."; + return analysisRunText("cancelledTopicLineage"); case "analysis_run_report": - return "This run was cancelled. Rebuild the period report from a current snapshot."; + return analysisRunText("cancelledReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; @@ -2854,25 +2855,13 @@ function analysisRunNextAction(run: AnalysisRun): string | null { function analysisRunEmptyPostsHint(run: AnalysisRun): string { switch (run.run_kind_code) { case "analysis_run_tepp": - return ( - "No posts were available at this cutoff for TEPP to measure. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyMeasurement"); case "analysis_run_topic_lineage": - return ( - "No posts were available at this cutoff for topic-lineage analysis. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyTopicLineage"); case "analysis_run_lineage": - return ( - "No posts were available at this cutoff for reconstruction. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyLineage"); case "analysis_run_report": - return ( - "No posts were available at this cutoff for the period report. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; @@ -2889,28 +2878,28 @@ function analysisRunEmptyPostsHint(run: AnalysisRun): string { function analysisRunCorpusHint(run: AnalysisRun): string | null { const isTopicLineage = run.run_kind_code === "analysis_run_topic_lineage"; if (run.run_kind_code !== "analysis_run_tepp" && !isTopicLineage) return null; - const service = isTopicLineage ? "topic-lineage" : "TEPP"; - const result = isTopicLineage ? "a topic-identity result" : "a calibrated result"; - const verb = isTopicLineage ? "thread" : "measure"; - const verbPast = isTopicLineage ? "threaded" : "measured"; switch (run.status_code) { case "analysis_status_failed": - return ( - `These posts are the cutoff corpus ${service} would ${verb}. Connect a TEPP ` + - `transport, then re-run, to replace Failed with ${result}.` + return analysisRunText( + isTopicLineage ? "corpusFailedTopicLineage" : "corpusFailedMeasurement", ); case "analysis_status_succeeded": - return `These posts are the cutoff corpus this ${service} run ${verbPast}.`; + return analysisRunText( + isTopicLineage ? "corpusSucceededTopicLineage" : "corpusSucceededMeasurement", + ); case "analysis_status_pending": case "analysis_status_running": - return `These posts are the cutoff corpus ${service} will ${verb} once this run finishes.`; + return analysisRunText( + isTopicLineage ? "corpusPendingTopicLineage" : "corpusPendingMeasurement", + ); case "analysis_status_cancelled": - return ( - `These posts are the cutoff corpus this ${service} run would have ${verbPast}. ` + - `The run was cancelled before ${result}.` + return analysisRunText( + isTopicLineage ? "corpusCancelledTopicLineage" : "corpusCancelledMeasurement", ); case null: - return `These posts are the cutoff corpus attached to this ${service} run.`; + return analysisRunText( + isTopicLineage ? "corpusAttachedTopicLineage" : "corpusAttachedMeasurement", + ); default: { const unexpected: never = run.status_code; return unexpected; diff --git a/frontend/src/analysisRunI18n.test.ts b/frontend/src/analysisRunI18n.test.ts new file mode 100644 index 000000000..984a264c0 --- /dev/null +++ b/frontend/src/analysisRunI18n.test.ts @@ -0,0 +1,21 @@ +import { afterEach, describe, expect, it } from "vitest"; +import { ANALYSIS_RUN_COPY_KEYS, analysisRunText } from "./analysisRunI18n"; +import { setLocale } from "./i18n"; + +afterEach(() => setLocale("en")); + +describe("analysis-run guidance localization", () => { + it.each(["ko", "zh", "ja", "vi"] as const)( + "translates every next-action and corpus state in %s", + (locale) => { + setLocale("en"); + const english = new Map( + ANALYSIS_RUN_COPY_KEYS.map((key) => [key, analysisRunText(key)]), + ); + setLocale(locale); + for (const key of ANALYSIS_RUN_COPY_KEYS) { + expect(analysisRunText(key), `${locale}:${key}`).not.toBe(english.get(key)); + } + }, + ); +}); diff --git a/frontend/src/analysisRunI18n.ts b/frontend/src/analysisRunI18n.ts new file mode 100644 index 000000000..efd99c9c1 --- /dev/null +++ b/frontend/src/analysisRunI18n.ts @@ -0,0 +1,186 @@ +import { getLocale, type Locale } from "./i18n"; + +const ENGLISH_ANALYSIS_RUN_COPY = { + pendingLineage: + "Open this run, then start reconstruction. Reconstruction has not started yet.", + pendingMeasurement: + "Open this run to confirm which posts will be measured. Measurement has not started yet — this is not a calibrated result.", + pendingTopicLineage: + "Open this run to confirm which posts will form the topic lineage. Analysis has not started yet — this is not a calibrated topic result.", + pendingReport: + "Open this run to confirm which posts the period report will use. The report has not been built yet.", + failedMeasurement: + "Open this run to see why it failed. Ask an administrator to restore measurement, then run it again.", + failedTopicLineage: + "Open this run to see why it failed. Ask an administrator to restore topic-lineage analysis, then run it again.", + failedLineage: + "Open this run to see why it failed, then retry reconstruction from a current snapshot.", + failedReport: + "Open this run to see why it failed, then rebuild the period report from a current snapshot.", + running: "This run is in progress. Refresh it to check for results.", + cancelledLineage: + "This run was cancelled. Request a new lineage reconstruction from a current snapshot.", + cancelledMeasurement: + "This run was cancelled. Ask an administrator to restore measurement and submit a new run from a current snapshot.", + cancelledTopicLineage: + "This run was cancelled. Ask an administrator to restore topic-lineage analysis and submit a new run from a current snapshot.", + cancelledReport: + "This run was cancelled. Rebuild the period report from a current snapshot.", + emptyMeasurement: + "No posts were available at this snapshot for measurement. Open a later run, or ask an administrator to capture a newer snapshot.", + emptyTopicLineage: + "No posts were available at this snapshot for topic-lineage analysis. Open a later run, or ask an administrator to capture a newer snapshot.", + emptyLineage: + "No posts were available at this snapshot for reconstruction. Open a later run, or ask an administrator to capture a newer snapshot.", + emptyReport: + "No posts were available at this snapshot for the period report. Open a later run, or ask an administrator to capture a newer snapshot.", + corpusFailedMeasurement: + "These posts were selected for measurement at this snapshot. Ask an administrator to restore measurement, then run it again.", + corpusSucceededMeasurement: "These posts were measured in this run.", + corpusPendingMeasurement: "These posts will be measured when this run finishes.", + corpusCancelledMeasurement: + "These posts would have been measured. The run was cancelled before a calibrated result was created.", + corpusAttachedMeasurement: "These posts are attached to this measurement run.", + corpusFailedTopicLineage: + "These posts were selected for topic-lineage analysis at this snapshot. Ask an administrator to restore analysis, then run it again.", + corpusSucceededTopicLineage: "These posts formed the topic lineage in this run.", + corpusPendingTopicLineage: + "These posts will form the topic lineage when this run finishes.", + corpusCancelledTopicLineage: + "These posts would have formed the topic lineage. The run was cancelled before a calibrated topic result was created.", + corpusAttachedTopicLineage: "These posts are attached to this topic-lineage run.", +} as const; + +export type AnalysisRunCopyKey = keyof typeof ENGLISH_ANALYSIS_RUN_COPY; + +const ANALYSIS_RUN_COPY: Record< + Locale, + Record +> = { + en: ENGLISH_ANALYSIS_RUN_COPY, + ko: { + pendingLineage: "이 실행을 연 다음 계보 재구성을 시작하세요. 재구성은 아직 시작되지 않았습니다.", + pendingMeasurement: "이 실행을 열어 측정할 글을 확인하세요. 측정은 아직 시작되지 않았으며, 보정된 결과가 아닙니다.", + pendingTopicLineage: "이 실행을 열어 토픽 계보를 구성할 글을 확인하세요. 분석은 아직 시작되지 않았으며, 보정된 토픽 결과가 아닙니다.", + pendingReport: "이 실행을 열어 기간 보고서에 사용할 글을 확인하세요. 보고서는 아직 생성되지 않았습니다.", + failedMeasurement: "이 실행을 열어 실패 이유를 확인하세요. 관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", + failedTopicLineage: "이 실행을 열어 실패 이유를 확인하세요. 관리자에게 토픽 계보 분석 복구를 요청한 다음 다시 실행하세요.", + failedLineage: "이 실행을 열어 실패 이유를 확인한 다음 현재 스냅샷에서 재구성을 다시 시도하세요.", + failedReport: "이 실행을 열어 실패 이유를 확인한 다음 현재 스냅샷에서 기간 보고서를 다시 생성하세요.", + running: "이 실행은 진행 중입니다. 결과를 확인하려면 새로 고치세요.", + cancelledLineage: "이 실행은 취소되었습니다. 현재 스냅샷에서 새 계보 재구성을 요청하세요.", + cancelledMeasurement: "이 실행은 취소되었습니다. 관리자에게 측정 복구를 요청하고 현재 스냅샷에서 새 실행을 제출하세요.", + cancelledTopicLineage: "이 실행은 취소되었습니다. 관리자에게 토픽 계보 분석 복구를 요청하고 현재 스냅샷에서 새 실행을 제출하세요.", + cancelledReport: "이 실행은 취소되었습니다. 현재 스냅샷에서 기간 보고서를 다시 생성하세요.", + emptyMeasurement: "이 스냅샷에는 측정할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", + emptyTopicLineage: "이 스냅샷에는 토픽 계보를 분석할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", + emptyLineage: "이 스냅샷에는 재구성할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", + emptyReport: "이 스냅샷에는 기간 보고서에 사용할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", + corpusFailedMeasurement: "이 글들은 이 스냅샷에서 측정 대상으로 선택되었습니다. 관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", + corpusSucceededMeasurement: "이 실행에서 이 글들을 측정했습니다.", + corpusPendingMeasurement: "이 실행이 끝나면 이 글들을 측정합니다.", + corpusCancelledMeasurement: "이 글들은 측정될 예정이었습니다. 보정된 결과가 생성되기 전에 실행이 취소되었습니다.", + corpusAttachedMeasurement: "이 글들은 이 측정 실행에 연결되어 있습니다.", + corpusFailedTopicLineage: "이 글들은 이 스냅샷에서 토픽 계보 분석 대상으로 선택되었습니다. 관리자에게 분석 복구를 요청한 다음 다시 실행하세요.", + corpusSucceededTopicLineage: "이 실행에서 이 글들이 토픽 계보를 구성했습니다.", + corpusPendingTopicLineage: "이 실행이 끝나면 이 글들이 토픽 계보를 구성합니다.", + corpusCancelledTopicLineage: "이 글들은 토픽 계보를 구성할 예정이었습니다. 보정된 토픽 결과가 생성되기 전에 실행이 취소되었습니다.", + corpusAttachedTopicLineage: "이 글들은 이 토픽 계보 실행에 연결되어 있습니다.", + }, + zh: { + pendingLineage: "打开此运行,然后开始重建。重建尚未开始。", + pendingMeasurement: "打开此运行以确认要测量的文章。测量尚未开始,这不是校准结果。", + pendingTopicLineage: "打开此运行以确认将构成主题谱系的文章。分析尚未开始,这不是校准后的主题结果。", + pendingReport: "打开此运行以确认周期报告将使用的文章。报告尚未生成。", + failedMeasurement: "打开此运行查看失败原因。请管理员恢复测量,然后重新运行。", + failedTopicLineage: "打开此运行查看失败原因。请管理员恢复主题谱系分析,然后重新运行。", + failedLineage: "打开此运行查看失败原因,然后从当前快照重试重建。", + failedReport: "打开此运行查看失败原因,然后从当前快照重新生成周期报告。", + running: "此运行正在进行。请刷新以查看结果。", + cancelledLineage: "此运行已取消。请从当前快照请求新的谱系重建。", + cancelledMeasurement: "此运行已取消。请管理员恢复测量,并从当前快照提交新的运行。", + cancelledTopicLineage: "此运行已取消。请管理员恢复主题谱系分析,并从当前快照提交新的运行。", + cancelledReport: "此运行已取消。请从当前快照重新生成周期报告。", + emptyMeasurement: "此快照中没有可测量的文章。请打开较晚的运行,或请管理员创建更新的快照。", + emptyTopicLineage: "此快照中没有可用于主题谱系分析的文章。请打开较晚的运行,或请管理员创建更新的快照。", + emptyLineage: "此快照中没有可重建的文章。请打开较晚的运行,或请管理员创建更新的快照。", + emptyReport: "此快照中没有可用于周期报告的文章。请打开较晚的运行,或请管理员创建更新的快照。", + corpusFailedMeasurement: "这些文章已在此快照中选为测量对象。请管理员恢复测量,然后重新运行。", + corpusSucceededMeasurement: "这些文章已在此运行中完成测量。", + corpusPendingMeasurement: "此运行完成后将测量这些文章。", + corpusCancelledMeasurement: "这些文章原本将被测量。运行在生成校准结果前已取消。", + corpusAttachedMeasurement: "这些文章已附加到此测量运行。", + corpusFailedTopicLineage: "这些文章已在此快照中选为主题谱系分析对象。请管理员恢复分析,然后重新运行。", + corpusSucceededTopicLineage: "这些文章在此运行中构成了主题谱系。", + corpusPendingTopicLineage: "此运行完成后,这些文章将构成主题谱系。", + corpusCancelledTopicLineage: "这些文章原本将构成主题谱系。运行在生成校准后的主题结果前已取消。", + corpusAttachedTopicLineage: "这些文章已附加到此主题谱系运行。", + }, + ja: { + pendingLineage: "この実行を開いてから系譜の再構成を開始してください。再構成はまだ始まっていません。", + pendingMeasurement: "この実行を開いて測定する投稿を確認してください。測定はまだ始まっておらず、校正済みの結果ではありません。", + pendingTopicLineage: "この実行を開いてトピック系譜を構成する投稿を確認してください。分析はまだ始まっておらず、校正済みのトピック結果ではありません。", + pendingReport: "この実行を開いて期間レポートに使用する投稿を確認してください。レポートはまだ作成されていません。", + failedMeasurement: "この実行を開いて失敗理由を確認してください。管理者に測定の復旧を依頼してから再実行してください。", + failedTopicLineage: "この実行を開いて失敗理由を確認してください。管理者にトピック系譜分析の復旧を依頼してから再実行してください。", + failedLineage: "この実行を開いて失敗理由を確認し、現在のスナップショットから再構成を再試行してください。", + failedReport: "この実行を開いて失敗理由を確認し、現在のスナップショットから期間レポートを再作成してください。", + running: "この実行は進行中です。結果を確認するには更新してください。", + cancelledLineage: "この実行はキャンセルされました。現在のスナップショットから新しい系譜再構成を依頼してください。", + cancelledMeasurement: "この実行はキャンセルされました。管理者に測定の復旧を依頼し、現在のスナップショットから新しい実行を送信してください。", + cancelledTopicLineage: "この実行はキャンセルされました。管理者にトピック系譜分析の復旧を依頼し、現在のスナップショットから新しい実行を送信してください。", + cancelledReport: "この実行はキャンセルされました。現在のスナップショットから期間レポートを再作成してください。", + emptyMeasurement: "このスナップショットには測定できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", + emptyTopicLineage: "このスナップショットにはトピック系譜を分析できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", + emptyLineage: "このスナップショットには再構成できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", + emptyReport: "このスナップショットには期間レポートで使用できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", + corpusFailedMeasurement: "これらの投稿は、このスナップショットで測定対象に選ばれました。管理者に測定の復旧を依頼してから再実行してください。", + corpusSucceededMeasurement: "これらの投稿はこの実行で測定されました。", + corpusPendingMeasurement: "この実行が完了すると、これらの投稿が測定されます。", + corpusCancelledMeasurement: "これらの投稿は測定される予定でした。校正済みの結果が作成される前に実行がキャンセルされました。", + corpusAttachedMeasurement: "これらの投稿はこの測定実行に関連付けられています。", + corpusFailedTopicLineage: "これらの投稿は、このスナップショットでトピック系譜分析の対象に選ばれました。管理者に分析の復旧を依頼してから再実行してください。", + corpusSucceededTopicLineage: "これらの投稿はこの実行でトピック系譜を構成しました。", + corpusPendingTopicLineage: "この実行が完了すると、これらの投稿がトピック系譜を構成します。", + corpusCancelledTopicLineage: "これらの投稿はトピック系譜を構成する予定でした。校正済みのトピック結果が作成される前に実行がキャンセルされました。", + corpusAttachedTopicLineage: "これらの投稿はこのトピック系譜実行に関連付けられています。", + }, + vi: { + pendingLineage: "Mở lượt chạy này rồi bắt đầu tái dựng phả hệ. Việc tái dựng chưa bắt đầu.", + pendingMeasurement: "Mở lượt chạy này để xác nhận các bài viết sẽ được đo. Việc đo chưa bắt đầu và đây chưa phải là kết quả đã hiệu chuẩn.", + pendingTopicLineage: "Mở lượt chạy này để xác nhận các bài viết sẽ tạo thành phả hệ chủ đề. Phân tích chưa bắt đầu và đây chưa phải là kết quả chủ đề đã hiệu chuẩn.", + pendingReport: "Mở lượt chạy này để xác nhận các bài viết mà báo cáo kỳ sẽ sử dụng. Báo cáo chưa được tạo.", + failedMeasurement: "Mở lượt chạy này để xem lý do thất bại. Hãy yêu cầu quản trị viên khôi phục việc đo rồi chạy lại.", + failedTopicLineage: "Mở lượt chạy này để xem lý do thất bại. Hãy yêu cầu quản trị viên khôi phục phân tích phả hệ chủ đề rồi chạy lại.", + failedLineage: "Mở lượt chạy này để xem lý do thất bại, rồi thử tái dựng lại từ ảnh chụp hiện tại.", + failedReport: "Mở lượt chạy này để xem lý do thất bại, rồi tạo lại báo cáo kỳ từ ảnh chụp hiện tại.", + running: "Lượt chạy này đang thực hiện. Hãy làm mới để kiểm tra kết quả.", + cancelledLineage: "Lượt chạy này đã bị hủy. Hãy yêu cầu tái dựng phả hệ mới từ ảnh chụp hiện tại.", + cancelledMeasurement: "Lượt chạy này đã bị hủy. Hãy yêu cầu quản trị viên khôi phục việc đo và gửi lượt chạy mới từ ảnh chụp hiện tại.", + cancelledTopicLineage: "Lượt chạy này đã bị hủy. Hãy yêu cầu quản trị viên khôi phục phân tích phả hệ chủ đề và gửi lượt chạy mới từ ảnh chụp hiện tại.", + cancelledReport: "Lượt chạy này đã bị hủy. Hãy tạo lại báo cáo kỳ từ ảnh chụp hiện tại.", + emptyMeasurement: "Không có bài viết để đo trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", + emptyTopicLineage: "Không có bài viết để phân tích phả hệ chủ đề trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", + emptyLineage: "Không có bài viết để tái dựng trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", + emptyReport: "Không có bài viết cho báo cáo kỳ trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", + corpusFailedMeasurement: "Các bài viết này đã được chọn để đo trong ảnh chụp này. Hãy yêu cầu quản trị viên khôi phục việc đo rồi chạy lại.", + corpusSucceededMeasurement: "Các bài viết này đã được đo trong lượt chạy này.", + corpusPendingMeasurement: "Các bài viết này sẽ được đo khi lượt chạy hoàn tất.", + corpusCancelledMeasurement: "Các bài viết này lẽ ra sẽ được đo. Lượt chạy đã bị hủy trước khi tạo kết quả đã hiệu chuẩn.", + corpusAttachedMeasurement: "Các bài viết này được đính kèm với lượt chạy đo này.", + corpusFailedTopicLineage: "Các bài viết này đã được chọn để phân tích phả hệ chủ đề trong ảnh chụp này. Hãy yêu cầu quản trị viên khôi phục phân tích rồi chạy lại.", + corpusSucceededTopicLineage: "Các bài viết này đã tạo thành phả hệ chủ đề trong lượt chạy này.", + corpusPendingTopicLineage: "Các bài viết này sẽ tạo thành phả hệ chủ đề khi lượt chạy hoàn tất.", + corpusCancelledTopicLineage: "Các bài viết này lẽ ra sẽ tạo thành phả hệ chủ đề. Lượt chạy đã bị hủy trước khi tạo kết quả chủ đề đã hiệu chuẩn.", + corpusAttachedTopicLineage: "Các bài viết này được đính kèm với lượt chạy phả hệ chủ đề này.", + }, +}; + +export const ANALYSIS_RUN_COPY_KEYS = Object.keys( + ENGLISH_ANALYSIS_RUN_COPY, +) as AnalysisRunCopyKey[]; + +/** Return analysis-run guidance in the active product locale. */ +export function analysisRunText(key: AnalysisRunCopyKey): string { + return ANALYSIS_RUN_COPY[getLocale()][key]; +} From ea85595b67e11f7ba56d2c137c8341d6c662d7e8 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 13:12:58 +0900 Subject: [PATCH 122/238] docs(gaps): refresh exact PR queue --- docs/product-technical-gap-baseline.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index cdc50b33b..107db947e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 12:49 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 13:12 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, @@ -85,29 +85,34 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #689 | `81d85a02` | accepted measurement-owner release pin restacked on current #640; hosted checks and independent review pending | -| #688 | `dd65e92e` | automatic related-source evidence lookup restacked on current #640; newly analyzed project evidence now durably requeues completed sibling analyses with missing facts, and the current head is UNSTABLE with hosted checks pending | -| #687 | `827978a5` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | -| #686 | `c056dad2` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved, ranking guidance has desktop/mobile Storybook screenshot evidence, and hosted checks remain pending | +| #690 | `244efc6b` | analysis-run next actions, empty-snapshot states, and selected-post guidance localized across five product locales; Korean desktop/mobile Storybook screenshots retained; stacked on #667 with hosted checks pending | +| #689 | `3197954d` | accepted measurement-owner release pin contains current #640 after #687 merged; hosted checks and review pending | +| #688 | `a7cda9b3` | automatic related-source lookup contains current #640; project evidence requeues completed siblings with missing facts without failing already-persisted primary evidence; hosted checks and review pending | +| #686 | `fbca05d9` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved, ranking guidance has desktop/mobile Storybook screenshot evidence, and hosted checks remain pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `147f208e` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; unexpected verification failures degrade to unavailable, and embedding work is performed before the pool is acquired; hosted checks requeued | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `793931a6` | baseline refresh plus repeated-turn conversation-key repair, stale-history response fencing, and legacy ontology identifier separation; current head has no unresolved review threads, while hosted checks and independent approval remain pending | +| #667 | `2a2ec9cf` | baseline refresh plus repeated-turn conversation-key repair, stale-history response fencing, and legacy ontology identifier separation; current head has no unresolved review threads, while hosted checks and independent approval remain pending | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head local ontology/migration/docstring checks pass (100 tests) and frontend ontology/token/i18n checks pass (88 tests); hosted checks are terminal successful except queued OpenCode review, and independent review remains required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `eaec942f` | dashboard ranking and topic-influence stack now localizes evidence-rank labels, uses one topic-journey vocabulary, and makes the PostgreSQL tuning command contract explicit while retaining migration replay safety, id-only Ask citations, and the not-applicable topic state; focused UI and tuning-plan regressions passed, while exact-head hosted checks and independent review remain required | +| #640 | `9d4210c0` | dashboard ranking/topic-influence stack now includes merged #687's bounded semantic backfill operator; current protected-main candidate checks and independent review remain pending | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | | #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | -The exact-head check-run scan at 12:49 KST found no `failure`, `cancelled`, or +PR #687 exact head `827978a5` completed both hosted test jobs with no unresolved +review thread and merged into its non-default stack base as merge commit +`9d4210c04fb0aeec17e885bed097f400c7018269`. This is stack integration +evidence only; it is not protected-`main` delivery. + +The exact-head check-run scan at 13:12 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 19 current heads. Several heads, including -PR #667, #672, and #686 after their repair pushes, are still queued and therefore have +PR #640, #667, #686, #688, #689, and #690 after their repair or restack pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. No row above is merge evidence. Immediately before any lifecycle action, From 2e8578dbe93d835a88e76d0b0972ba39f44a5887 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 13:17:37 +0900 Subject: [PATCH 123/238] docs(gaps): record semantic window repair --- docs/product-technical-gap-baseline.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 15fa241ee..d0f6127eb 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 12:49 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 13:16 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, @@ -85,27 +85,27 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #689 | `81d85a02` | accepted measurement-owner release pin restacked on current #640; hosted checks and independent review pending | -| #688 | `dd65e92e` | automatic related-source evidence lookup restacked on current #640; newly analyzed project evidence now durably requeues completed sibling analyses with missing facts, and the current head is UNSTABLE with hosted checks pending | -| #687 | `827978a5` | bounded semantic backfill jobs stacked on #640; UNSTABLE with hosted checks and stack-base delivery pending | -| #686 | `c056dad2` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved, ranking guidance has desktop/mobile Storybook screenshot evidence, and hosted checks remain pending | +| #690 | `ea85595b` | five-locale analysis-run guidance and desktop/mobile Storybook evidence stacked on #667; hosted checks and parent delivery pending | +| #689 | `3197954d` | accepted measurement-owner release pin restacked on current #640; hosted checks and independent review pending | +| #688 | `5b874f4d` | automatic related-source evidence lookup now fingerprints the exact authorized evidence window so an unchanged sibling is re-analyzed when new project evidence arrives; all review threads are resolved, 1,435 full-suite tests passed before the concurrent rebase and 61 affected tests passed after it, while hosted checks and #640 delivery remain pending | +| #686 | `fbca05d9` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved, ranking guidance has desktop/mobile Storybook screenshot evidence, and hosted checks remain pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `147f208e` | persisted semantic-evidence nomination for Global Ask with ADR renumbering; unexpected verification failures degrade to unavailable, and embedding work is performed before the pool is acquired; hosted checks requeued | | #668 | `e452bf38` | evidence-bound project history projection with ADR renumbering, request guards, source-code/time-basis display repair, and theme-token timeline styling; BLOCKED with review required | -| #667 | `793931a6` | baseline refresh plus repeated-turn conversation-key repair, stale-history response fencing, and legacy ontology identifier separation; current head has no unresolved review threads, while hosted checks and independent approval remain pending | +| #667 | `2a2ec9cf` | baseline refresh plus repeated-turn conversation-key repair, stale-history response fencing, legacy ontology identifier separation, and an explicit analysis-run localization gap; current head has no unresolved review threads, while hosted checks and independent approval remain pending | | #663 | `f616887a` | project ontology traversal, cutoff-snapshot project focus, bounded MCP admission, and migration-fixture/worker startup repair; exact-head local ontology/migration/docstring checks pass (100 tests) and frontend ontology/token/i18n checks pass (88 tests); hosted checks are terminal successful except queued OpenCode review, and independent review remains required | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | -| #640 | `eaec942f` | dashboard ranking and topic-influence stack now localizes evidence-rank labels, uses one topic-journey vocabulary, and makes the PostgreSQL tuning command contract explicit while retaining migration replay safety, id-only Ask citations, and the not-applicable topic state; focused UI and tuning-plan regressions passed, while exact-head hosted checks and independent review remain required | +| #640 | `9d4210c0` | dashboard ranking and topic-influence stack now includes bounded semantic backfill jobs, localizes evidence-rank labels, uses one topic-journey vocabulary, and makes the PostgreSQL tuning command contract explicit while retaining migration replay safety, id-only Ask citations, and the not-applicable topic state; exact-head hosted checks and independent review remain required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | | #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | -The exact-head check-run scan at 12:49 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 13:16 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 19 current heads. Several heads, including PR #667, #672, and #686 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -433,7 +433,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 12:49 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 13:16 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, two independent exact-head approvals including last-push approval, protected squash-merge SHA | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -541,7 +541,8 @@ review latency are never blockers — keep working while they settle. .github#1263, and land the atomic hourly LineageWeave caller in .github#1288 after its current-head independent approval and checks complete. 2. Process the current section 1 inventory in ascending PR order after dependency review. #677 is merged into the non-default baseline branch and - must be retargeted to `main` after #667; #687 and #688 depend on #640. No + must be retargeted to `main` after #667; #688 and #689 depend on #640, while + #690 depends on #667. No child head may substitute for protected delivery of its base. Merge only after each exact head shows terminal green required checks plus current-head independent approval. From 7fc59bc3de8d9153a7b6b6408898efba21361905 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 13:19:58 +0900 Subject: [PATCH 124/238] fix: keep analysis responsibility in product copy --- frontend/src/AnalysisRunGuidance.stories.tsx | 2 +- frontend/src/App.test.tsx | 8 +-- frontend/src/App.tsx | 4 +- frontend/src/analysisRunI18n.ts | 60 ++++++++++---------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/src/AnalysisRunGuidance.stories.tsx b/frontend/src/AnalysisRunGuidance.stories.tsx index 4a8a91403..4cb9705c6 100644 --- a/frontend/src/AnalysisRunGuidance.stories.tsx +++ b/frontend/src/AnalysisRunGuidance.stories.tsx @@ -59,7 +59,7 @@ export const StatusAndCorpusMatrix: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await expect(canvas.getByText("관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", { exact: false })).toBeVisible(); - await expect(canvas.getByText("이 실행이 끝나면 이 글들이 토픽 계보를 구성합니다.")).toBeVisible(); + await expect(canvas.getByText("이 실행이 끝나면 LineageWeave가 이 글들을 토픽 계보로 구성합니다.")).toBeVisible(); }, }; diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 76e787529..22cb30356 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -3800,13 +3800,13 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("These posts will be measured when this run finishes."), + await screen.findByText("LineageWeave will measure these posts when this run finishes."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); expect(screen.queryByText(/this TEPP run measured/i)).not.toBeInTheDocument(); expect(screen.queryByText(/Reconstruction has not started yet/)).not.toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Start reconstruction" })).not.toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Start TEPP measurement" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Start measurement" })).toBeInTheDocument(); }); it("starts a pending TEPP run through tepp_client and does not invent a theta", async () => { @@ -3818,7 +3818,7 @@ describe("App, authenticated", () => { name: "Open analysis run: TEPP measurement · Pending · Demo Corp", }), ); - await userEvent.click(screen.getByRole("button", { name: "Start TEPP measurement" })); + await userEvent.click(screen.getByRole("button", { name: "Start measurement" })); expect( await screen.findByRole("heading", { name: "TEPP measurement · Failed · Demo Corp" }), ).toBeInTheDocument(); @@ -3864,7 +3864,7 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("These posts were measured in this run."), + await screen.findByText("LineageWeave measured these posts in this run."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 84ccc3d60..36b28f812 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3025,7 +3025,7 @@ function analysisRunCanStart(run: AnalysisRun): boolean { function analysisRunStartLabel(run: AnalysisRun): string { if (run.run_kind_code === "analysis_run_tepp") { - return "Start TEPP measurement"; + return "Start measurement"; } if (run.run_kind_code === "analysis_run_topic_lineage") { return "Start topic lineage"; @@ -3317,7 +3317,7 @@ function AnalysisRunsPanel({ > {starting ? selected.run_kind_code === "analysis_run_tepp" - ? "Submitting the TEPP request..." + ? "Starting measurement..." : selected.run_kind_code === "analysis_run_topic_lineage" ? "Submitting the topic-lineage request..." : "Reconstructing the cutoff bag..." diff --git a/frontend/src/analysisRunI18n.ts b/frontend/src/analysisRunI18n.ts index efd99c9c1..812ccb4b1 100644 --- a/frontend/src/analysisRunI18n.ts +++ b/frontend/src/analysisRunI18n.ts @@ -4,9 +4,9 @@ const ENGLISH_ANALYSIS_RUN_COPY = { pendingLineage: "Open this run, then start reconstruction. Reconstruction has not started yet.", pendingMeasurement: - "Open this run to confirm which posts will be measured. Measurement has not started yet — this is not a calibrated result.", + "Open this run to confirm which posts LineageWeave will measure. Measurement has not started yet — this is not a calibrated result.", pendingTopicLineage: - "Open this run to confirm which posts will form the topic lineage. Analysis has not started yet — this is not a calibrated topic result.", + "Open this run to confirm which posts LineageWeave will organize into topic lineage. Analysis has not started yet — this is not a calibrated topic result.", pendingReport: "Open this run to confirm which posts the period report will use. The report has not been built yet.", failedMeasurement: @@ -36,16 +36,16 @@ const ENGLISH_ANALYSIS_RUN_COPY = { "No posts were available at this snapshot for the period report. Open a later run, or ask an administrator to capture a newer snapshot.", corpusFailedMeasurement: "These posts were selected for measurement at this snapshot. Ask an administrator to restore measurement, then run it again.", - corpusSucceededMeasurement: "These posts were measured in this run.", - corpusPendingMeasurement: "These posts will be measured when this run finishes.", + corpusSucceededMeasurement: "LineageWeave measured these posts in this run.", + corpusPendingMeasurement: "LineageWeave will measure these posts when this run finishes.", corpusCancelledMeasurement: "These posts would have been measured. The run was cancelled before a calibrated result was created.", corpusAttachedMeasurement: "These posts are attached to this measurement run.", corpusFailedTopicLineage: "These posts were selected for topic-lineage analysis at this snapshot. Ask an administrator to restore analysis, then run it again.", - corpusSucceededTopicLineage: "These posts formed the topic lineage in this run.", + corpusSucceededTopicLineage: "LineageWeave organized these posts into topic lineage in this run.", corpusPendingTopicLineage: - "These posts will form the topic lineage when this run finishes.", + "LineageWeave will organize these posts into topic lineage when this run finishes.", corpusCancelledTopicLineage: "These posts would have formed the topic lineage. The run was cancelled before a calibrated topic result was created.", corpusAttachedTopicLineage: "These posts are attached to this topic-lineage run.", @@ -60,8 +60,8 @@ const ANALYSIS_RUN_COPY: Record< en: ENGLISH_ANALYSIS_RUN_COPY, ko: { pendingLineage: "이 실행을 연 다음 계보 재구성을 시작하세요. 재구성은 아직 시작되지 않았습니다.", - pendingMeasurement: "이 실행을 열어 측정할 글을 확인하세요. 측정은 아직 시작되지 않았으며, 보정된 결과가 아닙니다.", - pendingTopicLineage: "이 실행을 열어 토픽 계보를 구성할 글을 확인하세요. 분석은 아직 시작되지 않았으며, 보정된 토픽 결과가 아닙니다.", + pendingMeasurement: "이 실행을 열어 LineageWeave가 측정할 글을 확인하세요. 측정은 아직 시작되지 않았으며, 보정된 결과가 아닙니다.", + pendingTopicLineage: "이 실행을 열어 LineageWeave가 토픽 계보로 구성할 글을 확인하세요. 분석은 아직 시작되지 않았으며, 보정된 토픽 결과가 아닙니다.", pendingReport: "이 실행을 열어 기간 보고서에 사용할 글을 확인하세요. 보고서는 아직 생성되지 않았습니다.", failedMeasurement: "이 실행을 열어 실패 이유를 확인하세요. 관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", failedTopicLineage: "이 실행을 열어 실패 이유를 확인하세요. 관리자에게 토픽 계보 분석 복구를 요청한 다음 다시 실행하세요.", @@ -77,20 +77,20 @@ const ANALYSIS_RUN_COPY: Record< emptyLineage: "이 스냅샷에는 재구성할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", emptyReport: "이 스냅샷에는 기간 보고서에 사용할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", corpusFailedMeasurement: "이 글들은 이 스냅샷에서 측정 대상으로 선택되었습니다. 관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", - corpusSucceededMeasurement: "이 실행에서 이 글들을 측정했습니다.", - corpusPendingMeasurement: "이 실행이 끝나면 이 글들을 측정합니다.", + corpusSucceededMeasurement: "LineageWeave가 이 실행에서 이 글들을 측정했습니다.", + corpusPendingMeasurement: "이 실행이 끝나면 LineageWeave가 이 글들을 측정합니다.", corpusCancelledMeasurement: "이 글들은 측정될 예정이었습니다. 보정된 결과가 생성되기 전에 실행이 취소되었습니다.", corpusAttachedMeasurement: "이 글들은 이 측정 실행에 연결되어 있습니다.", corpusFailedTopicLineage: "이 글들은 이 스냅샷에서 토픽 계보 분석 대상으로 선택되었습니다. 관리자에게 분석 복구를 요청한 다음 다시 실행하세요.", - corpusSucceededTopicLineage: "이 실행에서 이 글들이 토픽 계보를 구성했습니다.", - corpusPendingTopicLineage: "이 실행이 끝나면 이 글들이 토픽 계보를 구성합니다.", + corpusSucceededTopicLineage: "LineageWeave가 이 실행에서 이 글들을 토픽 계보로 구성했습니다.", + corpusPendingTopicLineage: "이 실행이 끝나면 LineageWeave가 이 글들을 토픽 계보로 구성합니다.", corpusCancelledTopicLineage: "이 글들은 토픽 계보를 구성할 예정이었습니다. 보정된 토픽 결과가 생성되기 전에 실행이 취소되었습니다.", corpusAttachedTopicLineage: "이 글들은 이 토픽 계보 실행에 연결되어 있습니다.", }, zh: { pendingLineage: "打开此运行,然后开始重建。重建尚未开始。", - pendingMeasurement: "打开此运行以确认要测量的文章。测量尚未开始,这不是校准结果。", - pendingTopicLineage: "打开此运行以确认将构成主题谱系的文章。分析尚未开始,这不是校准后的主题结果。", + pendingMeasurement: "打开此运行以确认 LineageWeave 将测量的文章。测量尚未开始,这不是校准结果。", + pendingTopicLineage: "打开此运行以确认 LineageWeave 将整理为主题谱系的文章。分析尚未开始,这不是校准后的主题结果。", pendingReport: "打开此运行以确认周期报告将使用的文章。报告尚未生成。", failedMeasurement: "打开此运行查看失败原因。请管理员恢复测量,然后重新运行。", failedTopicLineage: "打开此运行查看失败原因。请管理员恢复主题谱系分析,然后重新运行。", @@ -106,20 +106,20 @@ const ANALYSIS_RUN_COPY: Record< emptyLineage: "此快照中没有可重建的文章。请打开较晚的运行,或请管理员创建更新的快照。", emptyReport: "此快照中没有可用于周期报告的文章。请打开较晚的运行,或请管理员创建更新的快照。", corpusFailedMeasurement: "这些文章已在此快照中选为测量对象。请管理员恢复测量,然后重新运行。", - corpusSucceededMeasurement: "这些文章已在此运行中完成测量。", - corpusPendingMeasurement: "此运行完成后将测量这些文章。", + corpusSucceededMeasurement: "LineageWeave 已在此运行中测量这些文章。", + corpusPendingMeasurement: "此运行完成后,LineageWeave 将测量这些文章。", corpusCancelledMeasurement: "这些文章原本将被测量。运行在生成校准结果前已取消。", corpusAttachedMeasurement: "这些文章已附加到此测量运行。", corpusFailedTopicLineage: "这些文章已在此快照中选为主题谱系分析对象。请管理员恢复分析,然后重新运行。", - corpusSucceededTopicLineage: "这些文章在此运行中构成了主题谱系。", - corpusPendingTopicLineage: "此运行完成后,这些文章将构成主题谱系。", + corpusSucceededTopicLineage: "LineageWeave 已在此运行中将这些文章整理为主题谱系。", + corpusPendingTopicLineage: "此运行完成后,LineageWeave 将把这些文章整理为主题谱系。", corpusCancelledTopicLineage: "这些文章原本将构成主题谱系。运行在生成校准后的主题结果前已取消。", corpusAttachedTopicLineage: "这些文章已附加到此主题谱系运行。", }, ja: { pendingLineage: "この実行を開いてから系譜の再構成を開始してください。再構成はまだ始まっていません。", - pendingMeasurement: "この実行を開いて測定する投稿を確認してください。測定はまだ始まっておらず、校正済みの結果ではありません。", - pendingTopicLineage: "この実行を開いてトピック系譜を構成する投稿を確認してください。分析はまだ始まっておらず、校正済みのトピック結果ではありません。", + pendingMeasurement: "この実行を開いて LineageWeave が測定する投稿を確認してください。測定はまだ始まっておらず、校正済みの結果ではありません。", + pendingTopicLineage: "この実行を開いて LineageWeave がトピック系譜にまとめる投稿を確認してください。分析はまだ始まっておらず、校正済みのトピック結果ではありません。", pendingReport: "この実行を開いて期間レポートに使用する投稿を確認してください。レポートはまだ作成されていません。", failedMeasurement: "この実行を開いて失敗理由を確認してください。管理者に測定の復旧を依頼してから再実行してください。", failedTopicLineage: "この実行を開いて失敗理由を確認してください。管理者にトピック系譜分析の復旧を依頼してから再実行してください。", @@ -135,20 +135,20 @@ const ANALYSIS_RUN_COPY: Record< emptyLineage: "このスナップショットには再構成できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", emptyReport: "このスナップショットには期間レポートで使用できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", corpusFailedMeasurement: "これらの投稿は、このスナップショットで測定対象に選ばれました。管理者に測定の復旧を依頼してから再実行してください。", - corpusSucceededMeasurement: "これらの投稿はこの実行で測定されました。", - corpusPendingMeasurement: "この実行が完了すると、これらの投稿が測定されます。", + corpusSucceededMeasurement: "LineageWeave がこの実行でこれらの投稿を測定しました。", + corpusPendingMeasurement: "この実行が完了すると、LineageWeave がこれらの投稿を測定します。", corpusCancelledMeasurement: "これらの投稿は測定される予定でした。校正済みの結果が作成される前に実行がキャンセルされました。", corpusAttachedMeasurement: "これらの投稿はこの測定実行に関連付けられています。", corpusFailedTopicLineage: "これらの投稿は、このスナップショットでトピック系譜分析の対象に選ばれました。管理者に分析の復旧を依頼してから再実行してください。", - corpusSucceededTopicLineage: "これらの投稿はこの実行でトピック系譜を構成しました。", - corpusPendingTopicLineage: "この実行が完了すると、これらの投稿がトピック系譜を構成します。", + corpusSucceededTopicLineage: "LineageWeave がこの実行でこれらの投稿をトピック系譜にまとめました。", + corpusPendingTopicLineage: "この実行が完了すると、LineageWeave がこれらの投稿をトピック系譜にまとめます。", corpusCancelledTopicLineage: "これらの投稿はトピック系譜を構成する予定でした。校正済みのトピック結果が作成される前に実行がキャンセルされました。", corpusAttachedTopicLineage: "これらの投稿はこのトピック系譜実行に関連付けられています。", }, vi: { pendingLineage: "Mở lượt chạy này rồi bắt đầu tái dựng phả hệ. Việc tái dựng chưa bắt đầu.", - pendingMeasurement: "Mở lượt chạy này để xác nhận các bài viết sẽ được đo. Việc đo chưa bắt đầu và đây chưa phải là kết quả đã hiệu chuẩn.", - pendingTopicLineage: "Mở lượt chạy này để xác nhận các bài viết sẽ tạo thành phả hệ chủ đề. Phân tích chưa bắt đầu và đây chưa phải là kết quả chủ đề đã hiệu chuẩn.", + pendingMeasurement: "Mở lượt chạy này để xác nhận các bài viết LineageWeave sẽ đo. Việc đo chưa bắt đầu và đây chưa phải là kết quả đã hiệu chuẩn.", + pendingTopicLineage: "Mở lượt chạy này để xác nhận các bài viết LineageWeave sẽ sắp xếp thành phả hệ chủ đề. Phân tích chưa bắt đầu và đây chưa phải là kết quả chủ đề đã hiệu chuẩn.", pendingReport: "Mở lượt chạy này để xác nhận các bài viết mà báo cáo kỳ sẽ sử dụng. Báo cáo chưa được tạo.", failedMeasurement: "Mở lượt chạy này để xem lý do thất bại. Hãy yêu cầu quản trị viên khôi phục việc đo rồi chạy lại.", failedTopicLineage: "Mở lượt chạy này để xem lý do thất bại. Hãy yêu cầu quản trị viên khôi phục phân tích phả hệ chủ đề rồi chạy lại.", @@ -164,13 +164,13 @@ const ANALYSIS_RUN_COPY: Record< emptyLineage: "Không có bài viết để tái dựng trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", emptyReport: "Không có bài viết cho báo cáo kỳ trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", corpusFailedMeasurement: "Các bài viết này đã được chọn để đo trong ảnh chụp này. Hãy yêu cầu quản trị viên khôi phục việc đo rồi chạy lại.", - corpusSucceededMeasurement: "Các bài viết này đã được đo trong lượt chạy này.", - corpusPendingMeasurement: "Các bài viết này sẽ được đo khi lượt chạy hoàn tất.", + corpusSucceededMeasurement: "LineageWeave đã đo các bài viết này trong lượt chạy này.", + corpusPendingMeasurement: "LineageWeave sẽ đo các bài viết này khi lượt chạy hoàn tất.", corpusCancelledMeasurement: "Các bài viết này lẽ ra sẽ được đo. Lượt chạy đã bị hủy trước khi tạo kết quả đã hiệu chuẩn.", corpusAttachedMeasurement: "Các bài viết này được đính kèm với lượt chạy đo này.", corpusFailedTopicLineage: "Các bài viết này đã được chọn để phân tích phả hệ chủ đề trong ảnh chụp này. Hãy yêu cầu quản trị viên khôi phục phân tích rồi chạy lại.", - corpusSucceededTopicLineage: "Các bài viết này đã tạo thành phả hệ chủ đề trong lượt chạy này.", - corpusPendingTopicLineage: "Các bài viết này sẽ tạo thành phả hệ chủ đề khi lượt chạy hoàn tất.", + corpusSucceededTopicLineage: "LineageWeave đã sắp xếp các bài viết này thành phả hệ chủ đề trong lượt chạy này.", + corpusPendingTopicLineage: "LineageWeave sẽ sắp xếp các bài viết này thành phả hệ chủ đề khi lượt chạy hoàn tất.", corpusCancelledTopicLineage: "Các bài viết này lẽ ra sẽ tạo thành phả hệ chủ đề. Lượt chạy đã bị hủy trước khi tạo kết quả chủ đề đã hiệu chuẩn.", corpusAttachedTopicLineage: "Các bài viết này được đính kèm với lượt chạy phả hệ chủ đề này.", }, From bb4edabd78eae358d79a87788e5f1b5aee90561d Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 13:19:58 +0900 Subject: [PATCH 125/238] fix(ask): lock evidence before citation persistence --- backend/app/post_ask_history.py | 35 ++++++++++++--------------------- tests/test_post_ask_history.py | 26 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 116cffc87..d89b69bdc 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -278,31 +278,28 @@ async def fetch_conversation( } -async def _ensure_citations_visible( +async def _ensure_sources_visible( conn: asyncpg.Connection, - conversation_id: UUID, - turn_ordinal: int, - cited_post_count: int, + source_post_ids: list[str], can_see_post: Callable[[asyncpg.Record], bool], ) -> None: - """Lock and re-authorize new citations before their transaction commits.""" + """Lock and re-authorize every source before dependent rows are inserted.""" rows = await conn.fetch( f""" - select relation.cited_post_id::text as post_id, - post.post_title, post.visibility_code, post.corporate_entity_id, + select post.post_id::text as post_id, post.post_title, + post.visibility_code, post.corporate_entity_id, post.process_unit_id, post.author_account_id, post.source_detail_state_code - from post_ask_turn_citation relation - join source_post post on post.post_id = relation.cited_post_id - where relation.post_ask_session_id = $1 - and relation.turn_ordinal = $2 + from source_post post + where post.post_id = any($1::uuid[]) and ({SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')}) for share of post """, - conversation_id, - turn_ordinal, + source_post_ids, ) - if len(rows) != cited_post_count or any(not can_see_post(row) for row in rows): + if len(rows) != len(source_post_ids) or any( + not can_see_post(row) for row in rows + ): raise PostAskEvidenceChanged @@ -324,6 +321,8 @@ async def persist_turn( dict.fromkeys(str(post_id_value) for post_id_value in cited_post_ids if str(post_id_value) in source_set) ) async with conn.transaction(): + if can_see_post is not None: + await _ensure_sources_visible(conn, source_ids, can_see_post) if conversation_id is None: conversation_id = uuid4() await conn.execute( @@ -397,13 +396,5 @@ async def persist_turn( "update post_ask_session set updated_at = now() where post_ask_session_id = $1", conversation_id, ) - if can_see_post is not None: - await _ensure_citations_visible( - conn, - conversation_id, - ordinal, - len(cited_ids), - can_see_post, - ) assert conversation_id is not None return conversation_id diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py index c15ef4993..ce426abfe 100644 --- a/tests/test_post_ask_history.py +++ b/tests/test_post_ask_history.py @@ -279,3 +279,29 @@ def test_persist_turn_aborts_when_a_citation_loses_authorization() -> None: "post.process_unit_id" in query and "for share of post" in query.lower() for query, _ in connection.calls ) + + +def test_persist_turn_rejects_deleted_source_before_foreign_key_insert() -> None: + """A source deleted mid-request becomes evidence-changed, never a raw FK error.""" + connection = _Connection([]) + + with pytest.raises(PostAskEvidenceChanged): + asyncio.run( + persist_turn( + connection, + "account-1", + "post-1", + None, + "What changed?", + "A complete answer.", + ["post-1", "post-2"], + ["post-2"], + can_see_post=lambda _row: True, + ) + ) + + assert not any( + "insert into post_ask_turn_source" in query + or "insert into post_ask_turn_citation" in query + for query, _ in connection.calls + ) From b4b030112c16cc15e977f69abb1e5a93e0c7f9cb Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 13:21:44 +0900 Subject: [PATCH 126/238] fix: remove duplicate measurement handoff copy --- frontend/src/App.test.tsx | 5 ----- frontend/src/App.tsx | 16 ---------------- 2 files changed, 21 deletions(-) diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 22cb30356..6da159253 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -3840,11 +3840,6 @@ describe("App, authenticated", () => { name: "Open analysis run: TEPP measurement · Failed · Demo Corp", }), ); - expect( - await screen.findByText( - "Ask an administrator to enable measurement, then retry from this failed run.", - ), - ).toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Request a new TEPP measurement" })).not.toBeInTheDocument(); expect(screen.queryByRole("heading", { name: "TEPP measurement · Pending · Demo Corp" })).not.toBeInTheDocument(); expect( diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 36b28f812..37ece825e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3033,15 +3033,6 @@ function analysisRunStartLabel(run: AnalysisRun): string { return "Start reconstruction"; } -/** Failed TEPP/topic-lineage is terminal. Create cannot invent a Pending row. */ -function analysisRunCanRequestTeppRetry(run: AnalysisRun): boolean { - return ( - (run.run_kind_code === "analysis_run_tepp" || - run.run_kind_code === "analysis_run_topic_lineage") && - run.status_code === "analysis_status_failed" - ); -} - const REPORT_PERIOD_KEY = /^\d{4}-W\d{2}$/; /** @@ -3324,13 +3315,6 @@ function AnalysisRunsPanel({ : analysisRunStartLabel(selected)} )} - {analysisRunCanRequestTeppRetry(selected) && ( -

- {selected.run_kind_code === "analysis_run_topic_lineage" - ? "Ask an administrator to enable topic-lineage analysis, then retry from this failed run." - : "Ask an administrator to enable measurement, then retry from this failed run."} -

- )} {analysisRunReportPeriod(selected) && onSelectReportPeriod && ( + + ))} + + + ); +} + +const meta = { + title: "Workspace/AnalysisRunGuidance", + component: AnalysisRunGuidanceInventory, + parameters: { layout: "padded" }, + beforeEach: () => { + const previous = getLocale(); + setLocale("ko"); + return () => setLocale(previous); + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const StatusAndCorpusMatrix: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText("관리자에게 측정 복구를 요청한 다음 다시 실행하세요.", { exact: false })).toBeVisible(); + await expect(canvas.getByText("이 실행이 끝나면 LineageWeave가 이 글들을 토픽 계보로 구성합니다.")).toBeVisible(); + }, +}; + +export const Phone: Story = { + ...StatusAndCorpusMatrix, + parameters: { viewport: { defaultViewport: "mobile1" } }, +}; diff --git a/frontend/src/App.css b/frontend/src/App.css index 4fc37055c..6e1d7a0f6 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -941,6 +941,11 @@ gap: 0.75rem; } +.analysis-run-item .post-meta { + overflow-wrap: anywhere; + word-break: keep-all; +} + .analysis-run-item.has-document-count.has-next-action { grid-template-columns: minmax(12rem, 1fr) auto minmax(18rem, 2fr); } diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 67d7c59af..6da159253 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -3276,7 +3276,7 @@ describe("App, authenticated", () => { expect(list).toHaveTextContent("TEPP measurement · Failed · Demo Corp"); expect(list).toHaveTextContent("Period report · Succeeded · Demo Corp"); expect(list).toHaveTextContent( - "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again.", + "Open this run to see why it failed. Ask an administrator to restore measurement, then run it again.", ); expect(list).toHaveTextContent("3 documents"); expect(list).not.toHaveTextContent("postgresql://"); @@ -3374,7 +3374,7 @@ describe("App, authenticated", () => { ).toBeInTheDocument(); const teppHistory = screen.getByRole("list", { name: "Analysis run status history" }); expect(teppHistory).toHaveTextContent("Failed 2026-01-12 12:37 · tepp_not_available"); - expect(screen.getByText(/cutoff corpus TEPP would measure/i)).toBeInTheDocument(); + expect(screen.getByText(/selected for measurement at this snapshot/i)).toBeInTheDocument(); expect(teppHistory).not.toHaveTextContent("Succeeded"); }); @@ -3430,11 +3430,11 @@ describe("App, authenticated", () => { ["analysis_run_lineage", "Request a new lineage reconstruction from a current snapshot."], [ "analysis_run_tepp", - "Ask an administrator to enable measurement and submit a new run from a current snapshot.", + "Ask an administrator to restore measurement and submit a new run from a current snapshot.", ], [ "analysis_run_topic_lineage", - "Ask an administrator to enable topic-lineage analysis and submit a new run from a current snapshot.", + "Ask an administrator to restore topic-lineage analysis and submit a new run from a current snapshot.", ], ["analysis_run_report", "Rebuild the period report from a current snapshot."], ] satisfies [AnalysisRunKindCode, string][])( @@ -3453,6 +3453,16 @@ describe("App, authenticated", () => { }, ); + it("shows analysis-run next actions in the selected locale", async () => { + setLocale("ko"); + stubBackend({ cancelledRunKind: "analysis_run_lineage" }); + render(); + + expect(await screen.findByText( + "이 실행은 취소되었습니다. 현재 스냅샷에서 새 계보 재구성을 요청하세요.", + )).toBeInTheDocument(); + }); + it("tells a running lineage run how to check for results", async () => { stubBackend({ runningLineageRun: true }); render(); @@ -3486,7 +3496,7 @@ describe("App, authenticated", () => { ); expect(lineageButton).not.toHaveTextContent("measurement service"); expect(teppButton).toHaveTextContent( - "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again.", + "Open this run to see why it failed. Ask an administrator to restore measurement, then run it again.", ); expect(teppButton).not.toHaveTextContent("reconstruction"); }); @@ -3775,7 +3785,7 @@ describe("App, authenticated", () => { ).not.toBeInTheDocument(); expect( await screen.findByText( - "No posts were available at this cutoff for the period report. Open a later run, or ask an administrator to capture a newer snapshot.", + "No posts were available at this snapshot for the period report. Open a later run, or ask an administrator to capture a newer snapshot.", ), ).toBeInTheDocument(); }); @@ -3790,13 +3800,13 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("These posts are the cutoff corpus TEPP will measure once this run finishes."), + await screen.findByText("LineageWeave will measure these posts when this run finishes."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); expect(screen.queryByText(/this TEPP run measured/i)).not.toBeInTheDocument(); expect(screen.queryByText(/Reconstruction has not started yet/)).not.toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Start reconstruction" })).not.toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Start TEPP measurement" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Start measurement" })).toBeInTheDocument(); }); it("starts a pending TEPP run through tepp_client and does not invent a theta", async () => { @@ -3808,7 +3818,7 @@ describe("App, authenticated", () => { name: "Open analysis run: TEPP measurement · Pending · Demo Corp", }), ); - await userEvent.click(screen.getByRole("button", { name: "Start TEPP measurement" })); + await userEvent.click(screen.getByRole("button", { name: "Start measurement" })); expect( await screen.findByRole("heading", { name: "TEPP measurement · Failed · Demo Corp" }), ).toBeInTheDocument(); @@ -3830,11 +3840,6 @@ describe("App, authenticated", () => { name: "Open analysis run: TEPP measurement · Failed · Demo Corp", }), ); - expect( - await screen.findByText( - "Ask an administrator to enable measurement, then retry from this failed run.", - ), - ).toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Request a new TEPP measurement" })).not.toBeInTheDocument(); expect(screen.queryByRole("heading", { name: "TEPP measurement · Pending · Demo Corp" })).not.toBeInTheDocument(); expect( @@ -3854,7 +3859,7 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("These posts are the cutoff corpus this TEPP run measured."), + await screen.findByText("LineageWeave measured these posts in this run."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6e860896f..37ece825e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,6 +2,7 @@ import { AdminPanel } from "./components/AdminPanel"; import { LeftoverPairList } from "./components/LeftoverPairList"; import { WorkspaceCalendar } from "./components/WorkspaceCalendar"; import { focusedGraphMustReset } from "./focusedGraphSelection"; +import { analysisRunText } from "./analysisRunI18n"; import { useCallback, useEffect, useEffectEvent, useRef, useState, type ReactNode } from "react"; import { useAuth } from "react-oidc-context"; @@ -2794,13 +2795,13 @@ function analysisRunNextAction(run: AnalysisRun): string | null { case "analysis_status_pending": switch (run.run_kind_code) { case "analysis_run_lineage": - return "Open this run, then start reconstruction. Reconstruction has not started yet."; + return analysisRunText("pendingLineage"); case "analysis_run_tepp": - return "Open this run to confirm which posts TEPP will measure. Measurement has not started yet — this is not a calibrated result."; + return analysisRunText("pendingMeasurement"); case "analysis_run_topic_lineage": - return "Open this run to confirm which posts TEPP will thread into topic lineage. Topic-lineage analysis has not started yet — this is not a calibrated topic result."; + return analysisRunText("pendingTopicLineage"); case "analysis_run_report": - return "Open this run to confirm which posts the period report will use. The report has not been built yet."; + return analysisRunText("pendingReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; @@ -2809,30 +2810,30 @@ function analysisRunNextAction(run: AnalysisRun): string | null { case "analysis_status_failed": switch (run.run_kind_code) { case "analysis_run_tepp": - return "Open this run to see why it failed. Ask an administrator to enable measurement, then run it again."; + return analysisRunText("failedMeasurement"); case "analysis_run_topic_lineage": - return "Open this run to see why it failed. Ask an administrator to enable topic-lineage analysis, then run it again."; + return analysisRunText("failedTopicLineage"); case "analysis_run_lineage": - return "Open this run to see why it failed, then retry reconstruction from a current snapshot."; + return analysisRunText("failedLineage"); case "analysis_run_report": - return "Open this run to see why it failed, then rebuild the period report from a current snapshot."; + return analysisRunText("failedReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; } } case "analysis_status_running": - return "This run is in progress. Refresh it to check for results."; + return analysisRunText("running"); case "analysis_status_cancelled": switch (run.run_kind_code) { case "analysis_run_lineage": - return "This run was cancelled. Request a new lineage reconstruction from a current snapshot."; + return analysisRunText("cancelledLineage"); case "analysis_run_tepp": - return "This run was cancelled. Ask an administrator to enable measurement and submit a new run from a current snapshot."; + return analysisRunText("cancelledMeasurement"); case "analysis_run_topic_lineage": - return "This run was cancelled. Ask an administrator to enable topic-lineage analysis and submit a new run from a current snapshot."; + return analysisRunText("cancelledTopicLineage"); case "analysis_run_report": - return "This run was cancelled. Rebuild the period report from a current snapshot."; + return analysisRunText("cancelledReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; @@ -2854,25 +2855,13 @@ function analysisRunNextAction(run: AnalysisRun): string | null { function analysisRunEmptyPostsHint(run: AnalysisRun): string { switch (run.run_kind_code) { case "analysis_run_tepp": - return ( - "No posts were available at this cutoff for TEPP to measure. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyMeasurement"); case "analysis_run_topic_lineage": - return ( - "No posts were available at this cutoff for topic-lineage analysis. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyTopicLineage"); case "analysis_run_lineage": - return ( - "No posts were available at this cutoff for reconstruction. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyLineage"); case "analysis_run_report": - return ( - "No posts were available at this cutoff for the period report. " + - "Open a later run, or ask an administrator to capture a newer snapshot." - ); + return analysisRunText("emptyReport"); default: { const unexpected: never = run.run_kind_code; return unexpected; @@ -2889,28 +2878,28 @@ function analysisRunEmptyPostsHint(run: AnalysisRun): string { function analysisRunCorpusHint(run: AnalysisRun): string | null { const isTopicLineage = run.run_kind_code === "analysis_run_topic_lineage"; if (run.run_kind_code !== "analysis_run_tepp" && !isTopicLineage) return null; - const service = isTopicLineage ? "topic-lineage" : "TEPP"; - const result = isTopicLineage ? "a topic-identity result" : "a calibrated result"; - const verb = isTopicLineage ? "thread" : "measure"; - const verbPast = isTopicLineage ? "threaded" : "measured"; switch (run.status_code) { case "analysis_status_failed": - return ( - `These posts are the cutoff corpus ${service} would ${verb}. Connect a TEPP ` + - `transport, then re-run, to replace Failed with ${result}.` + return analysisRunText( + isTopicLineage ? "corpusFailedTopicLineage" : "corpusFailedMeasurement", ); case "analysis_status_succeeded": - return `These posts are the cutoff corpus this ${service} run ${verbPast}.`; + return analysisRunText( + isTopicLineage ? "corpusSucceededTopicLineage" : "corpusSucceededMeasurement", + ); case "analysis_status_pending": case "analysis_status_running": - return `These posts are the cutoff corpus ${service} will ${verb} once this run finishes.`; + return analysisRunText( + isTopicLineage ? "corpusPendingTopicLineage" : "corpusPendingMeasurement", + ); case "analysis_status_cancelled": - return ( - `These posts are the cutoff corpus this ${service} run would have ${verbPast}. ` + - `The run was cancelled before ${result}.` + return analysisRunText( + isTopicLineage ? "corpusCancelledTopicLineage" : "corpusCancelledMeasurement", ); case null: - return `These posts are the cutoff corpus attached to this ${service} run.`; + return analysisRunText( + isTopicLineage ? "corpusAttachedTopicLineage" : "corpusAttachedMeasurement", + ); default: { const unexpected: never = run.status_code; return unexpected; @@ -3036,7 +3025,7 @@ function analysisRunCanStart(run: AnalysisRun): boolean { function analysisRunStartLabel(run: AnalysisRun): string { if (run.run_kind_code === "analysis_run_tepp") { - return "Start TEPP measurement"; + return "Start measurement"; } if (run.run_kind_code === "analysis_run_topic_lineage") { return "Start topic lineage"; @@ -3044,15 +3033,6 @@ function analysisRunStartLabel(run: AnalysisRun): string { return "Start reconstruction"; } -/** Failed TEPP/topic-lineage is terminal. Create cannot invent a Pending row. */ -function analysisRunCanRequestTeppRetry(run: AnalysisRun): boolean { - return ( - (run.run_kind_code === "analysis_run_tepp" || - run.run_kind_code === "analysis_run_topic_lineage") && - run.status_code === "analysis_status_failed" - ); -} - const REPORT_PERIOD_KEY = /^\d{4}-W\d{2}$/; /** @@ -3328,20 +3308,13 @@ function AnalysisRunsPanel({ > {starting ? selected.run_kind_code === "analysis_run_tepp" - ? "Submitting the TEPP request..." + ? "Starting measurement..." : selected.run_kind_code === "analysis_run_topic_lineage" ? "Submitting the topic-lineage request..." : "Reconstructing the cutoff bag..." : analysisRunStartLabel(selected)} )} - {analysisRunCanRequestTeppRetry(selected) && ( -

- {selected.run_kind_code === "analysis_run_topic_lineage" - ? "Ask an administrator to enable topic-lineage analysis, then retry from this failed run." - : "Ask an administrator to enable measurement, then retry from this failed run."} -

- )} {analysisRunReportPeriod(selected) && onSelectReportPeriod && ( )} + {analysisRunCanRetryMeasurement(selected) && ( + + )} {analysisRunReportPeriod(selected) && onSelectReportPeriod && ( diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index ac1c3199b..47de97d73 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -124,6 +124,39 @@ describe("ChatPanel conversation history", () => { expect(screen.getByRole("option", { name: "Older question (1)" })).toBeInTheDocument(); }); + it("discards a paginated conversation response after moving to another post", async () => { + let resolveOldPage!: (response: Response) => void; + const oldPage = new Promise((resolve) => { resolveOldPage = resolve; }); + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { + const url = input instanceof Request ? input.url : String(input); + if (url.includes("post-1/chat/conversations?")) return oldPage; + if (url.endsWith("post-1/chat/conversations")) { + return jsonResponse({ + conversations: [], + next_cursor: { updated_at: "2026-08-26T00:00:00Z", conversation_id: "conversation-old" }, + }); + } + if (url.endsWith("post-2/chat/conversations")) { + return jsonResponse({ + conversations: [{ conversation_id: "conversation-new", title: "Current post", updated_at: "2026-08-26T00:00:00Z", turn_count: 1 }], + next_cursor: null, + }); + } + return jsonResponse({ post_id: url.includes("post-2") ? "post-2" : "post-1", exchanges: [] }); + })); + + const view = render(); + await userEvent.click(await screen.findByRole("button", { name: "Load more" })); + view.rerender(); + expect(await screen.findByRole("option", { name: "Current post (1)" })).toBeInTheDocument(); + resolveOldPage(jsonResponse({ + conversations: [{ conversation_id: "conversation-old", title: "Previous post", updated_at: "2026-08-25T00:00:00Z", turn_count: 1 }], + next_cursor: null, + })); + + await waitFor(() => expect(screen.queryByRole("option", { name: "Previous post (1)" })).toBeNull()); + }); + it("reopens an owned conversation and returns to the seeded new-conversation state", async () => { vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : String(input); From 03c4cffb45e8e4c818a9c0d182564edfb58c7911 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:19:05 +0900 Subject: [PATCH 158/238] docs(gaps): remove closed unmerged delivery claim --- docs/product-technical-gap-baseline.md | 37 ++++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b7be0b4f6..adf92d171 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 15:08 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 15:14 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 19 open PRs and 10 open issues. The exact-head +At this snapshot there were 18 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 15:08 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 15:14 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, @@ -78,7 +78,7 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 19 open PRs and 10 +at this refresh. The live queue contains 18 open PRs and 10 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. @@ -88,12 +88,11 @@ context only. | #694 | `814b1f76` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | | #693 | `8fa7e9bf` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | | #692 | `f20c0af6` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; the authorized API projection independently checks every evidence post so a visible mention cannot disclose a cross-entity private source. It remains stacked on #693; parent reconciliation, retargeting, exact-head checks, and independent review are required | -| #686 | `fbca05d9` | customer-facing copy boundary audit removes implementation labels while retaining Event Lineage distinction and localized actions; current review threads are resolved, ranking guidance has desktop/mobile Storybook screenshot evidence, and hosted checks remain pending | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | `56dc4097` | baseline/conversation repairs contain merged #691 retry semantics and map evidence drift during recovered Ask persistence to the explicit unavailable response instead of an internal error. Review threads are resolved; hosted checks and independent approval remain pending. This row records the branch parent observed immediately before this snapshot-only documentation commit | +| #667 | `19422ba5` | baseline/conversation repairs contain merged #691 retry semantics, map recovered-Ask evidence drift to an explicit unavailable response, and invalidate conversation pagination generations when the post or access token changes so stale pages cannot contaminate a new post. Frontend 405 tests and lint pass; hosted checks and independent approval remain pending | | #663 | `ee795ac0` | project ontology traversal, cutoff-snapshot focus, bounded MCP admission, and migration-fixture/worker startup repair; its new ADRs use unique 0230/0231 identities, KG edge creation obeys the knowledge cutoff, and sealed `snapshot_at` now bounds authorizing focus evidence for every ontology node type rather than Projects alone (32 focused ontology tests pass); hosted checks and independent review requeued | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -114,9 +113,13 @@ and `60b4c6004739a05e63edae8ff160758f8e665919`. These are stack-integration evidence only; they are not protected-`main` delivery. Their acceptance now travels with the two parent heads above. -The exact-head check-run scan at 15:08 KST found no `failure`, `cancelled`, or -`timed_out` conclusions on the 19 current heads. Several heads, including -PR #667, #672, and #686 after their repair pushes, are still queued and therefore have +PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not +protected-main delivery and any still-required behavior must travel through an +open current-main candidate rather than relying on that closed head. + +The exact-head check-run scan at 15:14 KST found no `failure`, `cancelled`, or +`timed_out` conclusions on the 18 current heads. Several heads, including +PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. No row above is merge evidence. Immediately before any lifecycle action, @@ -135,7 +138,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 19 open PRs. The +to divergent filenames across the 18 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -144,11 +147,11 @@ and 2.22.0 on #679. Release-version and duplicated-delivery overlaps still require ordered parent landing, child retargeting, and exact-head revalidation; identifier collision is no longer the blocker. -PR #680 and #686 independently edit the same ranking, ontology, and locale -surfaces, and neither exact head contains the other. Land #686 first because it -contains the repository-wide customer-copy boundary audit and rendered -desktop/mobile evidence; then rebase #680 and retain only behavior not already -covered, so a later merge cannot restore implementation-facing copy. +PR #680 and closed-unmerged #686 independently edited the same ranking, +ontology, and locale surfaces. Before #680 can land, compare it with #686 and +port only still-required customer actions and rendered evidence into the open +current-main candidate; the closed head is not delivery evidence and must not +be used to restore implementation-facing copy. The hosted Full test for PR #632 at superseded head `cad4debf` failed only in the real-PostgreSQL semantic-nomination test with `InvalidPasswordError`; the @@ -450,7 +453,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 15:08 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:14 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -492,7 +495,7 @@ before a commercial release claim. Figma File ID `1Su3lDRmiZdcUs47t1QwIX`. | Style Selection | Korean UI standards merged (#347) | Tokenized light/dark; Anti-Slop-UI density; no decorative noise | | Layout & Responsive | Desktop popup shell; this candidate stacks analysis-run caption, document count, and next action at 390px and retains explicit grid columns at 1440px | Complete 402px-class phone acceptance for remaining panels; stacked GNB; readable DAG | | Typography & Color | Badge tokens extracted | Contrast on badges, links, error/status; no raw hex in components | -| Localization | Shared and ontology customer actions are checked across English, Korean, Chinese, Japanese, and Vietnamese on #686. The #667 candidate now includes five-locale analysis-run guidance, completeness tests, and desktop/mobile Storybook evidence without exposing implementation ownership; neither candidate is protected-main delivery | Land #686 and #667 through their exact-head protected gates, then repeat authenticated locale switching and assistive-technology acceptance on the release head before claiming locale-complete operations UX | +| Localization | Closed-unmerged #686 contains a five-locale customer-copy audit but is not delivery evidence. The open #667 candidate includes five-locale analysis-run guidance, completeness tests, and desktop/mobile Storybook evidence without exposing implementation ownership | Port any still-required #686 behavior into an open current-main candidate, land it and #667 through exact-head protected gates, then repeat authenticated locale switching and assistive-technology acceptance on the release head | | Animation | Minimal | Reduced-motion; no blocking animation on evidence open | | Forms & Feedback | Login, Ask, tickets, admin brand; this candidate gives all four Cancelled analysis kinds an evidence-safe next action | Inline validation and unavailable-vs-failed acceptance across remaining workflows | | Navigation Patterns | Board / customers / calendar / Ask / admin | Deep-link post + OIDC return URL (#426); bookmarkable Ask | From 886a0c6f3e15b0dc04247523fa83ef1ca547785a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 23:24:25 -0700 Subject: [PATCH 159/238] docs(architecture): define accelerator service boundary (#695) Co-authored-by: Codex --- ARCHITECTURE.md | 7 ++ ...37-accelerator-runtime-service-boundary.md | 94 +++++++++++++++++++ docs/adr/README.md | 1 + docs/product-technical-gap-baseline.md | 1 + 4 files changed, 103 insertions(+) create mode 100644 docs/adr/0237-accelerator-runtime-service-boundary.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 399894584..1365a2ea2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -25,6 +25,13 @@ recovery/equivalence checks; affected product paths fail closed during each cutover rather than substituting a local estimate. See `docs/doctoring/python-mathematical-compute-boundary-audit.md`. +ADR 0237 also keeps accelerator deployment outside this repository. MLX runs +as a native Apple-silicon inference service behind contextual-orchestrator; +CUDA or OpenCL profiles belong to the TEPP, fast-mlsirm, RankWeave, or +inference service that owns the computation. LineageWeave Compose therefore +does not reserve devices or mount host drivers. Its provider-neutral connectors +consume versioned results and fail closed when an owning service is unavailable. + ## Data flow ```mermaid diff --git a/docs/adr/0237-accelerator-runtime-service-boundary.md b/docs/adr/0237-accelerator-runtime-service-boundary.md new file mode 100644 index 000000000..6b34281a2 --- /dev/null +++ b/docs/adr/0237-accelerator-runtime-service-boundary.md @@ -0,0 +1,94 @@ +# ADR 0237 — Accelerator runtimes stay behind owning service contracts + +**Decision status:** Accepted +**Date:** 2026-08-26 +**Related:** ADR 0076, ADR 0083, ADR 0208 + +## Context + +LineageWeave runs with Docker Compose on Linux, macOS, and Windows hosts, but +does not own model inference or scientific computation. Adding MLX, CUDA, or +OpenCL devices to its backend would duplicate upstream capability selection, +couple the evidence API to host drivers, and make CPU-only installations less +portable. + +The accelerator mechanisms are platform-specific. MLX targets Apple silicon's +unified CPU/GPU memory. Docker Compose can reserve an NVIDIA GPU only when the +host and daemon expose it, while the NVIDIA Container Toolkit injects host +devices and driver mounts into a Linux container. OpenCL discovers vendor +implementations through an installable-client-driver loader, so an image alone +cannot prove that a compatible device and vendor driver are present. + +## Decision + +1. LineageWeave owns no MLX, CUDA, OpenCL, GPU, or scientific CPU runtime. + Its backend and frontend remain portable consumers of authenticated, + versioned service contracts. +2. LLM, VISION, and embedding acceleration belongs to + contextual-orchestrator or a provider-neutral inference service registered + behind it. On Apple silicon, an MLX process runs natively as such a service; + LineageWeave does not pass Metal devices into its Linux VM or encode an MLX + URL, model, port, or chat template. +3. TEPP, fast-mlsirm, and RankWeave own their construct-specific Rust compute. + An owner may publish separate CPU and accelerator deployment profiles: + deterministic multithreaded CPU is the portable required path; CUDA uses an + explicit Compose GPU reservation plus a compatible host driver/toolkit; + OpenCL uses an explicitly mounted device and matching vendor ICD. These + profiles are not added to LineageWeave Compose. +4. LineageWeave connectors accept only the owner's provider-neutral envelope. + Persisted evidence records the owner, contract/model version, input/output + digest, execution-device class reported by the owner, convergence or + completion state, and uncertainty where the construct requires it. A device + label is provenance, not a quality score. +5. Missing devices, drivers, ICDs, or owner services fail at the owning service + boundary. LineageWeave shows unavailable/failed status and the next valid + action; it never retries on a guessed backend, computes a Python substitute, + or claims GPU execution from configuration alone. + +```mermaid +flowchart LR + LW[LineageWeave API and UI] -->|provider-neutral contract| CO[contextual-orchestrator] + LW -->|measurement contract| M[TEPP / fast-mlsirm / RankWeave service] + CO --> N[Native MLX service on Apple silicon] + CO --> P[Remote or container inference provider] + M --> C[Deterministic multithreaded CPU] + M --> G[Owner CUDA or OpenCL profile] +``` + +## Considered alternatives + +- **Add accelerator profiles to LineageWeave Compose.** Rejected because this + repository does not own the computation and cannot validate host drivers for + another service's algorithm. +- **Run every accelerator natively.** Rejected because CUDA containers are a + supported owner deployment when their host prerequisites are explicit. +- **Use CPU fallback inside LineageWeave.** Rejected because it would reproduce + the formula on the wrong side of the contract. + +## Consequences and acceptance + +- LineageWeave Compose remains CPU-portable and contains no device reservation. +- Owners bear additional deployment and recovery-test work for every advertised + execution profile. +- An integration is accepted only when the owning repository proves the same + versioned synthetic input on deterministic CPU and each advertised + accelerator, reports bounded numerical tolerance and device provenance, and + LineageWeave proves malformed, mismatched, and unavailable envelopes fail + closed without exposing implementation details in customer copy. +- Native MLX availability is verified at contextual-orchestrator's provider + boundary; CUDA/OpenCL availability is verified in the compute owner's health + and conformance evidence. A Compose declaration by itself is insufficient. + +## References (APA 7th) + +Docker, Inc. (2026). *Run Docker Compose services with GPU access*. +https://docs.docker.com/compose/how-tos/gpu-support/ + +Khronos Group. (2026). *OpenCL registry*. +https://registry.khronos.org/OpenCL/ + +MLX Contributors. (2026). *Unified memory*. MLX documentation. +https://ml-explore.github.io/mlx/build/html/usage/unified_memory.html + +NVIDIA Corporation. (2026). *NVIDIA Container Toolkit architecture overview*. +https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/arch-overview.html diff --git a/docs/adr/README.md b/docs/adr/README.md index 039a349f6..275f6d706 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -23,6 +23,7 @@ decision from them. | Evidence operations Dashboard (`/`) | [0206](0206-evidence-operations-dashboard.md) | | [`temporal-topic-context-influence-research.md`](../temporal-topic-context-influence-research.md) | [0210](0210-temporal-topic-context-influence-dashboard.md) | | [`python-mathematical-compute-boundary-audit.md`](../doctoring/python-mathematical-compute-boundary-audit.md) | [0208](0208-externalize-local-mathematical-compute.md) | +| Accelerator deployment boundary | [0237](0237-accelerator-runtime-service-boundary.md), [0076](0076-paper-grounded-model-policy.md), [0208](0208-externalize-local-mathematical-compute.md) | [0011](0011-prov-o-standard-relations.md) and [0065](0065-prov-o-provenance-boundary.md) cite the dated W3C PROV-O and PROV-DM Recommendations (https://www.w3.org/TR/2013/REC-prov-o-20130430/ and https://www.w3.org/TR/2013/REC-prov-dm-20130430/). diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index adf92d171..119799174 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -477,6 +477,7 @@ for wholesale replay from #490. | Frontend delivery performance | A current production build succeeds but emits Vite's >500 kB chunk warning (`539.27 kB` minified); raising the warning limit would conceal rather than reduce delivery cost | Measure module contribution on an exact head, split one real route/surface boundary with native dynamic import, then prove the warning is absent and loading/error states remain accessible | | External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | +| Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 now defines MLX as a native orchestrator-side service and CUDA/OpenCL/CPU profiles as compute-owner deployments, so LineageWeave Compose remains device-neutral | Each owner must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX availability through its provider-neutral health/contract boundary. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when the owner is unavailable | | Product contract authority | This branch recreates the first LineageWeave PRD after superseded #613 closed without merge and records an exact-case ecosystem authority register; TEPP, fast-mlsirm, keyverse, and ThreadWeave have standalone PRDs, while contextual-orchestrator, RankWeave, DiskSage, and wardnet currently rely on product-planning/architecture documents and naruon has only a scoped Topic Intelligence PRD | Land the LineageWeave PRD, keep ADRs normative, and add standalone PRDs in each owning repository before making cross-product release claims beyond its documented boundary | | Release quality | Protected merges #660 and #659 are represented by `main@494b54e2`; the #660 stacked tree passed the complete Python suite (1,352 passed, 17 skipped) before protected delivery. Frontend/Storybook, security, browser, and authorized-runtime evidence remain separate gaps | Repository-wide coverage, frontend/Storybook, security, browser, and authorized-runtime evidence on one exact head | | PII | Masking would paralyze the product; ADR 0001 forbids identifying artifacts in git | ABAC + authorized runtime; synthetic fixtures in git; no mask-in-place that drops names the operator must read | From b96a9bf6879e38eacf2436c0017730036db61911 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 25 Aug 2026 23:27:59 -0700 Subject: [PATCH 160/238] docs(architecture): correct RankWeave runtime ownership (#696) Co-authored-by: Codex --- ARCHITECTURE.md | 9 ++--- ...37-accelerator-runtime-service-boundary.md | 34 +++++++++++-------- docs/product-technical-gap-baseline.md | 2 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 1365a2ea2..e83f7d9ba 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -27,10 +27,11 @@ cutover rather than substituting a local estimate. See ADR 0237 also keeps accelerator deployment outside this repository. MLX runs as a native Apple-silicon inference service behind contextual-orchestrator; -CUDA or OpenCL profiles belong to the TEPP, fast-mlsirm, RankWeave, or -inference service that owns the computation. LineageWeave Compose therefore -does not reserve devices or mount host drivers. Its provider-neutral connectors -consume versioned results and fail closed when an owning service is unavailable. +scientific CPU/CUDA/OpenCL profiles belong to TEPP or fast-mlsirm. RankWeave +remains the dependency-free Python retrieval-fusion/evaluation owner behind its +published contract. LineageWeave Compose therefore does not reserve devices or +mount host drivers; its provider-neutral connectors consume versioned results +and fail closed when an owning service is unavailable. ## Data flow diff --git a/docs/adr/0237-accelerator-runtime-service-boundary.md b/docs/adr/0237-accelerator-runtime-service-boundary.md index 6b34281a2..621a61382 100644 --- a/docs/adr/0237-accelerator-runtime-service-boundary.md +++ b/docs/adr/0237-accelerator-runtime-service-boundary.md @@ -29,12 +29,15 @@ cannot prove that a compatible device and vendor driver are present. behind it. On Apple silicon, an MLX process runs natively as such a service; LineageWeave does not pass Metal devices into its Linux VM or encode an MLX URL, model, port, or chat template. -3. TEPP, fast-mlsirm, and RankWeave own their construct-specific Rust compute. - An owner may publish separate CPU and accelerator deployment profiles: - deterministic multithreaded CPU is the portable required path; CUDA uses an - explicit Compose GPU reservation plus a compatible host driver/toolkit; - OpenCL uses an explicitly mounted device and matching vendor ICD. These - profiles are not added to LineageWeave Compose. +3. TEPP and fast-mlsirm own their construct-specific scientific and + psychometric Rust cores. Their compute services may publish separate CPU and + accelerator deployment profiles: deterministic multithreaded CPU is the + portable required path; CUDA uses an explicit Compose GPU reservation plus + a compatible host driver/toolkit; OpenCL uses an explicitly mounted device + and matching vendor ICD. RankWeave remains the dependency-free Python owner + of retrieval fusion and evaluation behind its published contract; this ADR + neither changes its implementation language nor transfers psychometric + ownership to it. None of these profiles are added to LineageWeave Compose. 4. LineageWeave connectors accept only the owner's provider-neutral envelope. Persisted evidence records the owner, contract/model version, input/output digest, execution-device class reported by the owner, convergence or @@ -48,7 +51,8 @@ cannot prove that a compatible device and vendor driver are present. ```mermaid flowchart LR LW[LineageWeave API and UI] -->|provider-neutral contract| CO[contextual-orchestrator] - LW -->|measurement contract| M[TEPP / fast-mlsirm / RankWeave service] + LW -->|measurement contract| M[TEPP / fast-mlsirm service] + LW -->|retrieval-fusion contract| R[RankWeave] CO --> N[Native MLX service on Apple silicon] CO --> P[Remote or container inference provider] M --> C[Deterministic multithreaded CPU] @@ -68,13 +72,15 @@ flowchart LR ## Consequences and acceptance - LineageWeave Compose remains CPU-portable and contains no device reservation. -- Owners bear additional deployment and recovery-test work for every advertised - execution profile. -- An integration is accepted only when the owning repository proves the same - versioned synthetic input on deterministic CPU and each advertised - accelerator, reports bounded numerical tolerance and device provenance, and - LineageWeave proves malformed, mismatched, and unavailable envelopes fail - closed without exposing implementation details in customer copy. +- TEPP and fast-mlsirm bear deployment and recovery-test work for every + advertised scientific-compute profile. RankWeave retains its own retrieval + fusion/evaluation conformance contract. +- A scientific-compute integration is accepted only when its owning repository + proves the same versioned synthetic input on deterministic CPU and each + advertised accelerator, reports bounded numerical tolerance and device + provenance, and LineageWeave proves malformed, mismatched, and unavailable + envelopes fail closed without exposing implementation details in customer + copy. - Native MLX availability is verified at contextual-orchestrator's provider boundary; CUDA/OpenCL availability is verified in the compute owner's health and conformance evidence. A Compose declaration by itself is insufficient. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 119799174..1595f153b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -477,7 +477,7 @@ for wholesale replay from #490. | Frontend delivery performance | A current production build succeeds but emits Vite's >500 kB chunk warning (`539.27 kB` minified); raising the warning limit would conceal rather than reduce delivery cost | Measure module contribution on an exact head, split one real route/surface boundary with native dynamic import, then prove the warning is absent and loading/error states remain accessible | | External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | -| Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 now defines MLX as a native orchestrator-side service and CUDA/OpenCL/CPU profiles as compute-owner deployments, so LineageWeave Compose remains device-neutral | Each owner must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX availability through its provider-neutral health/contract boundary. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when the owner is unavailable | +| Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 now defines MLX as a native orchestrator-side service and TEPP/fast-mlsirm CUDA/OpenCL/CPU profiles as scientific-compute-owner deployments, so LineageWeave Compose remains device-neutral. RankWeave remains the dependency-free Python retrieval-fusion/evaluation owner behind its published contract | TEPP and fast-mlsirm must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX availability through its provider-neutral health/contract boundary. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when the owner is unavailable | | Product contract authority | This branch recreates the first LineageWeave PRD after superseded #613 closed without merge and records an exact-case ecosystem authority register; TEPP, fast-mlsirm, keyverse, and ThreadWeave have standalone PRDs, while contextual-orchestrator, RankWeave, DiskSage, and wardnet currently rely on product-planning/architecture documents and naruon has only a scoped Topic Intelligence PRD | Land the LineageWeave PRD, keep ADRs normative, and add standalone PRDs in each owning repository before making cross-product release claims beyond its documented boundary | | Release quality | Protected merges #660 and #659 are represented by `main@494b54e2`; the #660 stacked tree passed the complete Python suite (1,352 passed, 17 skipped) before protected delivery. Frontend/Storybook, security, browser, and authorized-runtime evidence remain separate gaps | Repository-wide coverage, frontend/Storybook, security, browser, and authorized-runtime evidence on one exact head | | PII | Masking would paralyze the product; ADR 0001 forbids identifying artifacts in git | ABAC + authorized runtime; synthetic fixtures in git; no mask-in-place that drops names the operator must read | From ec7fca7eb2557d7b1629cd2df4b2de3babfd652a Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:29:32 +0900 Subject: [PATCH 161/238] docs(gaps): record accelerator ownership boundary --- docs/product-technical-gap-baseline.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 1595f153b..1a767da5a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 15:14 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 15:29 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 15:14 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 15:29 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, @@ -86,13 +86,13 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #694 | `814b1f76` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `8fa7e9bf` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | -| #692 | `f20c0af6` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; the authorized API projection independently checks every evidence post so a visible mention cannot disclose a cross-entity private source. It remains stacked on #693; parent reconciliation, retargeting, exact-head checks, and independent review are required | +| #693 | `7e292a7d` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | +| #692 | `afcb7317` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; the authorized API projection independently checks every evidence post so a visible mention cannot disclose a cross-entity private source. It remains stacked on #693; parent reconciliation, retargeting, exact-head checks, and independent review are required | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | `19422ba5` | baseline/conversation repairs contain merged #691 retry semantics, map recovered-Ask evidence drift to an explicit unavailable response, and invalidate conversation pagination generations when the post or access token changes so stale pages cannot contaminate a new post. Frontend 405 tests and lint pass; hosted checks and independent approval remain pending | +| #667 | `b96a9bf6` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, and now include ADR 0237's accelerator ownership boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, frontend 405 tests, and lint pass; hosted checks and independent approval remain pending | | #663 | `ee795ac0` | project ontology traversal, cutoff-snapshot focus, bounded MCP admission, and migration-fixture/worker startup repair; its new ADRs use unique 0230/0231 identities, KG edge creation obeys the knowledge cutoff, and sealed `snapshot_at` now bounds authorizing focus evidence for every ontology node type rather than Projects alone (32 focused ontology tests pass); hosted checks and independent review requeued | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -117,7 +117,7 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 15:14 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 15:29 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 18 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -453,7 +453,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:14 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:29 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 07a41cd7b4a43dcdec351ee3fd7594077b3898a4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:30:31 +0900 Subject: [PATCH 162/238] docs(architecture): cover Podman and Colima accelerators --- ARCHITECTURE.md | 8 +++++--- docs/adr/0237-accelerator-runtime-service-boundary.md | 10 ++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index e83f7d9ba..fcfcc4157 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -20,9 +20,11 @@ authorization, provenance persistence, and UI projection only. The current Python IRT/report, residual-map, similarity, graph-ranking, and fusion paths are explicitly inventoried migration debt rather than evidence that this repository owns their mathematics. They move by construct to TEPP, -fast-mlsirm, or RankWeave after versioned Rust CPU/GPU owner contracts pass -recovery/equivalence checks; affected product paths fail closed during each -cutover rather than substituting a local estimate. See +fast-mlsirm, or RankWeave after each owner's versioned contract passes +recovery/equivalence checks; TEPP and fast-mlsirm own Rust scientific compute, +while RankWeave owns its existing retrieval and comparison implementation. +Affected product paths fail closed during each cutover rather than substituting +a local estimate. See `docs/doctoring/python-mathematical-compute-boundary-audit.md`. ADR 0237 also keeps accelerator deployment outside this repository. MLX runs diff --git a/docs/adr/0237-accelerator-runtime-service-boundary.md b/docs/adr/0237-accelerator-runtime-service-boundary.md index 621a61382..86f266eb0 100644 --- a/docs/adr/0237-accelerator-runtime-service-boundary.md +++ b/docs/adr/0237-accelerator-runtime-service-boundary.md @@ -38,6 +38,10 @@ cannot prove that a compatible device and vendor driver are present. of retrieval fusion and evaluation behind its published contract; this ADR neither changes its implementation language nor transfers psychometric ownership to it. None of these profiles are added to LineageWeave Compose. + Podman owners request GPUs through supported GPU/CDI device contracts. A + Colima `krunkit` model runner is likewise an inference-owner deployment on + supported Apple-silicon hosts, not a reason to expose a device or model + selector in LineageWeave. 4. LineageWeave connectors accept only the owner's provider-neutral envelope. Persisted evidence records the owner, contract/model version, input/output digest, execution-device class reported by the owner, convergence or @@ -98,3 +102,9 @@ https://ml-explore.github.io/mlx/build/html/usage/unified_memory.html NVIDIA Corporation. (2026). *NVIDIA Container Toolkit architecture overview*. https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/arch-overview.html + +Podman Contributors. (2026). *podman-pod-create*. +https://docs.podman.io/en/latest/markdown/podman-pod-create.1.html + +Suzuki, A. (2026). *Colima: Container runtimes on macOS (and Linux) with +minimal setup*. GitHub. https://github.com/abiosoft/colima From 0905fa91ec227cf54e9470ccf7bd96208341315b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:33:51 +0900 Subject: [PATCH 163/238] docs(gaps): record source-bound product evidence --- docs/product-technical-gap-baseline.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 1a767da5a..605667f86 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 15:29 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 15:38 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 15:29 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 15:38 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, @@ -86,13 +86,13 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #694 | `814b1f76` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `7e292a7d` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | -| #692 | `afcb7317` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; the authorized API projection independently checks every evidence post so a visible mention cannot disclose a cross-entity private source. It remains stacked on #693; parent reconciliation, retargeting, exact-head checks, and independent review are required | +| #693 | `f8d1a7d5` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | +| #692 | `ccc9c27d` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | | #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | `b96a9bf6` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, and now include ADR 0237's accelerator ownership boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, frontend 405 tests, and lint pass; hosted checks and independent approval remain pending | +| #667 | `07a41cd7` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, and include ADR 0237's Docker/Podman/Colima accelerator boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, frontend 405 tests, and lint pass; hosted checks and independent approval remain pending | | #663 | `ee795ac0` | project ontology traversal, cutoff-snapshot focus, bounded MCP admission, and migration-fixture/worker startup repair; its new ADRs use unique 0230/0231 identities, KG edge creation obeys the knowledge cutoff, and sealed `snapshot_at` now bounds authorizing focus evidence for every ontology node type rather than Projects alone (32 focused ontology tests pass); hosted checks and independent review requeued | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -117,7 +117,7 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 15:29 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 15:38 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 18 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -453,7 +453,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:29 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:38 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 625495f75331c5d7964b2c9f40e3765827f94213 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:40:23 +0900 Subject: [PATCH 164/238] docs(architecture): cite Colima maintainers accurately --- docs/adr/0237-accelerator-runtime-service-boundary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/adr/0237-accelerator-runtime-service-boundary.md b/docs/adr/0237-accelerator-runtime-service-boundary.md index 86f266eb0..bda90751b 100644 --- a/docs/adr/0237-accelerator-runtime-service-boundary.md +++ b/docs/adr/0237-accelerator-runtime-service-boundary.md @@ -106,5 +106,5 @@ https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/arch-ov Podman Contributors. (2026). *podman-pod-create*. https://docs.podman.io/en/latest/markdown/podman-pod-create.1.html -Suzuki, A. (2026). *Colima: Container runtimes on macOS (and Linux) with +Colima Contributors. (2026). *Colima: Container runtimes on macOS (and Linux) with minimal setup*. GitHub. https://github.com/abiosoft/colima From 5a5fc289a5ee504c90bbdf7214cee18a69fb5f4a Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:41:48 +0900 Subject: [PATCH 165/238] docs(gaps): refresh central hourly loop evidence --- docs/product-technical-gap-baseline.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 605667f86..c159fe493 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 15:38 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 15:49 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 15:38 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 15:49 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, @@ -117,7 +117,7 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 15:38 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 15:49 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 18 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -285,7 +285,7 @@ requires the ADR 0001 incident process and security/privacy-owner coordination; never force-push or delete evidence ad hoc. The repository-owned hourly commercialization loop and the central thin GitHub -Actions caller ContextualWisdomLab/.github#1288 (current head `a11a2e53`, minute +Actions caller ContextualWisdomLab/.github#1288 (current head `428e31a0`, minute 4, `pr-review-fix-scheduler.yml`) both target this repository. The central candidate now reaches model execution through a pinned contextual-orchestrator sidecar and exposes only its loopback gateway contract to OpenCode. PR #1259 is the @@ -453,7 +453,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:38 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:49 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -515,7 +515,7 @@ of leverage; open connector PRs there when the defect is upstream: 6. **ThreadWeave** — tree assembly. 7. **Naruon** — calendar projection delivered through merged #355/closed #336; email/project lineage projection remains open as #338. 8. **DiskSage / wardnet** — storage and network policy as needed. -9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1288, current head `a11a2e53`). Its candidate routes provider work through a pinned contextual-orchestrator sidecar, exposes only the loopback gateway contract to OpenCode, and preserves the existing review/OIDC mutation credentials; 97 focused workflow/security tests and actionlint pass, while exact-head hosted checks and independent re-review remain pending. If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. +9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1288, current head `428e31a0`). Its current-main reconciliation preserves the pinned contextual-orchestrator sidecar, loopback gateway contract, provider-key isolation, and existing review/OIDC mutation credentials; 180 focused tests and actionlint pass, while exact-head hosted checks and independent re-review remain pending. If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. ## 8. Public ontology publication boundary From ad25b8076c414babb89582c951ba259ff6e29702 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 15:45:13 +0900 Subject: [PATCH 166/238] fix(chat): align source eligibility reauthorization --- backend/app/post_chat_ingestion.py | 10 ++++++---- tests/test_post_chat_ingestion.py | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/app/post_chat_ingestion.py b/backend/app/post_chat_ingestion.py index 4ca9e2f2d..913013a22 100644 --- a/backend/app/post_chat_ingestion.py +++ b/backend/app/post_chat_ingestion.py @@ -305,13 +305,14 @@ async def gather_chat_sources( if vision_client is None: vision_client = NullImageContentClient() - this_post = await conn.fetchrow( + this_post = await conn.fetchrow( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli "select post_id, post_title, post_body, source_system_code, source_record_key, " "source_author_code, source_author_name, source_company_code, source_company_name, " "source_process_unit_code, source_process_unit_name, " "source_sales_pool_code, source_sales_pool_name, " "source_customer_code, source_customer_name, source_project_code, " - "source_project_name from source_post where post_id = $1", + "source_project_name from source_post where post_id = $1 and " + f"{SOURCE_POST_ELIGIBILITY_SQL.format(alias='source_post')}", post_id, ) if this_post is None: @@ -339,14 +340,15 @@ async def gather_chat_sources( if not candidate_ids: return sources - rows = await conn.fetch( + rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli "select post_id, post_title, post_body, visibility_code, corporate_entity_id, process_unit_id, " "source_system_code, source_record_key, source_author_code, source_author_name, " "source_company_code, source_company_name, source_process_unit_code, " "source_process_unit_name, source_sales_pool_code, source_sales_pool_name, " "source_customer_code, source_customer_name, " "source_project_code, source_project_name " - "from source_post where post_id = any($1::uuid[]) " + "from source_post where post_id = any($1::uuid[]) and " + f"{SOURCE_POST_ELIGIBILITY_SQL.format(alias='source_post')} " "order by array_position($1::uuid[], post_id) limit $2", candidate_ids, _POST_CHAT_CANDIDATE_LIMIT, diff --git a/tests/test_post_chat_ingestion.py b/tests/test_post_chat_ingestion.py index 6626d85ac..81da79895 100644 --- a/tests/test_post_chat_ingestion.py +++ b/tests/test_post_chat_ingestion.py @@ -202,6 +202,8 @@ async def fetch(self, query: str, *args: object): expected_candidates = [*sorted(direct_ids), *sorted(indirect_ids)][:32] assert conn.candidate_ids == expected_candidates assert "array_position" in conn.candidate_query + assert "source_draft_code" in conn.candidate_query + assert "source_deleted_flag" in conn.candidate_query assert [source.post_id for source in sources] == [root_id, *expected_candidates[:7]] assert len(sources) == 8 From 6f3e179be588d7cbec772e8cea1bd353001fee7b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:08:45 +0900 Subject: [PATCH 167/238] fix(security): document bounded eligibility SQL --- backend/app/post_ask_history.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index b5f041e72..007a09e04 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -284,7 +284,9 @@ async def _ensure_sources_visible( can_see_post: Callable[[asyncpg.Record], bool], ) -> None: """Lock and re-authorize every source before dependent rows are inserted.""" - rows = await conn.fetch( + # Safe SQL: the only interpolation is the repository-owned eligibility + # expression; every request value remains an asyncpg parameter. + rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli f""" select post.post_id::text as post_id, post.post_title, post.visibility_code, post.corporate_entity_id, From 45eaeaa8984a6d955c6aacdf47fa1aaaa5693b70 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:13:30 +0900 Subject: [PATCH 168/238] docs(gaps): refresh semantic PR exact heads --- docs/product-technical-gap-baseline.md | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c159fe493..71d57cfe9 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 18 open PRs and 10 open issues. The exact-head +At this snapshot there were 20 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 15:49 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 16:12 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, @@ -78,25 +78,27 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 18 open PRs and 10 +at this refresh. The live queue contains 20 open PRs and 10 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 | | ---: | --- | --- | -| #694 | `814b1f76` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `f8d1a7d5` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | -| #692 | `ccc9c27d` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | -| #680 | `5c246a54` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | -| #679 | `29aa69dd` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and aggregate-status guidance repair; BLOCKED with exact-head checks and independent review required | +| #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | +| #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | +| #694 | `296cbae6` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | +| #693 | `999063d2` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | +| #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | +| #680 | `b6c8c46d` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | +| #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | `07a41cd7` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, and include ADR 0237's Docker/Podman/Colima accelerator boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, frontend 405 tests, and lint pass; hosted checks and independent approval remain pending | +| #667 | `6f3e179b` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, apply the shared source-eligibility boundary to chat evidence, and include ADR 0237's Docker/Podman/Colima accelerator boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, focused backend/frontend tests, and lint pass; hosted checks and independent approval remain pending | | #663 | `ee795ac0` | project ontology traversal, cutoff-snapshot focus, bounded MCP admission, and migration-fixture/worker startup repair; its new ADRs use unique 0230/0231 identities, KG edge creation obeys the knowledge cutoff, and sealed `snapshot_at` now bounds authorizing focus evidence for every ontology node type rather than Projects alone (32 focused ontology tests pass); hosted checks and independent review requeued | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | -| #644 | `ed8d97f3` | native-surface code splitting; BLOCKED with review required | +| #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | | #640 | `19c9c9e4` | dashboard ranking and topic-influence stack now includes bounded semantic backfill jobs, evidence-window fingerprint invalidation for automatic related-source analysis, accepted measurement-owner release pins, localized evidence-rank labels, one topic-journey vocabulary, migration replay safety, id-only Ask citations, and the not-applicable topic state; redundant test lambdas were removed without changing behavior, while exact-head hosted checks and independent review remain required | | #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | @@ -117,8 +119,8 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 15:49 KST found no `failure`, `cancelled`, or -`timed_out` conclusions on the 18 current heads. Several heads, including +The exact-head check-run scan at 16:12 KST found no `failure`, `cancelled`, or +`timed_out` conclusions on the 20 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -138,7 +140,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 18 open PRs. The +to divergent filenames across the 20 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed From 6de0e34d1004cfd25bf69b1fcd1acc074af2bbb4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:15:35 +0900 Subject: [PATCH 169/238] docs(gaps): reconcile delivered acceptance gaps --- docs/product-technical-gap-baseline.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 71d57cfe9..5da5ea9d3 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 15:49 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 16:12 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -455,7 +455,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 15:49 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty PRs remain open at the 16:12 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -465,6 +465,7 @@ for wholesale replay from #490. | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | +| Product hierarchy and voice exploration | PR #692 carries an evidence-bound product group/model/variant/trade-item catalog, and #694 carries overlapping voice classifications with source eligibility, ABAC, and original evidence preserved; both remain stacked candidates rather than protected delivery | Land the ordered parent stack, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | | Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | @@ -472,11 +473,11 @@ for wholesale replay from #490. | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | -| Asynchronous authorization | Protected `main` rebuilds Global Ask worker scope after the bearer token leaves the request; #468 now persists exact Keyverse organization/process-unit scope in 3NF child tables and intersects it with current affiliations | Land #468 through the protected gate; prove a second affiliation and a revoked process unit cannot widen delayed-job evidence | +| Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | -| Accessibility and responsive UX | #602 delivered base post-detail modal semantics; #605 adds selected-post refocus, collapsed/hidden/inert/CSS-invisible focus exclusion across both modal types, readable evidence separators, focused tests, and desktop/mobile Storybook screenshots | Land #605 through the protected gate, then complete screen-reader and authenticated Playwright acceptance on the exact release head | +| Accessibility and responsive UX | Protected-main #602 and #605 deliver modal semantics, selected-post refocus, collapsed/hidden/inert/CSS-invisible focus exclusion, readable evidence separators, focused tests, and desktop/mobile Storybook screenshots | Complete screen-reader and authenticated Playwright acceptance on the exact release head | | Design tokens and repeated objects | Token extraction started; sanitized Figma Event Lineage desktop/mobile frames exist, while other repeated product surfaces remain incomplete | Tokens in CSS + Storybook stories for board, popup, DAG, Ask, calendar, forms, charts; same-viewport Figma/runtime visual comparison before release | -| Frontend delivery performance | A current production build succeeds but emits Vite's >500 kB chunk warning (`539.27 kB` minified); raising the warning limit would conceal rather than reduce delivery cost | Measure module contribution on an exact head, split one real route/surface boundary with native dynamic import, then prove the warning is absent and loading/error states remain accessible | +| Frontend delivery performance | PR #644 exact head `f11e77d1` splits the real conditional workspace surfaces with native dynamic imports; 105 focused tests and the production build pass without the former large-chunk warning | Land #644 through protected gates, then repeat loading/error accessibility and bundle evidence on the exact release head | | External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | | Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 now defines MLX as a native orchestrator-side service and TEPP/fast-mlsirm CUDA/OpenCL/CPU profiles as scientific-compute-owner deployments, so LineageWeave Compose remains device-neutral. RankWeave remains the dependency-free Python retrieval-fusion/evaluation owner behind its published contract | TEPP and fast-mlsirm must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX availability through its provider-neutral health/contract boundary. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when the owner is unavailable | From adad5be02885467581951de70ac1d30b193604be Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:24:24 +0900 Subject: [PATCH 170/238] docs(gaps): record current customer-copy evidence --- docs/product-technical-gap-baseline.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5da5ea9d3..b7e617afe 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 16:12 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 16:27 KST. Protected `main` is > `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 16:12 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 16:27 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, @@ -90,11 +90,11 @@ context only. | #694 | `296cbae6` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | | #693 | `999063d2` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | | #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | -| #680 | `b6c8c46d` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | +| #680 | `cc2b7182` | customer-facing ranking and related-concept copy now removes the remaining rendered internal ontology label while preserving the Event Lineage distinction. Focused 75-test i18n/component regression, lint, Storybook build, and synthetic 1440×1000 / 390×844 visual audits pass; fresh exact-head hosted checks and independent review are required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | `6f3e179b` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, apply the shared source-eligibility boundary to chat evidence, and include ADR 0237's Docker/Podman/Colima accelerator boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, focused backend/frontend tests, and lint pass; hosted checks and independent approval remain pending | +| #667 | parent `6de0e34d` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination from contaminating a new post, applies the shared source-eligibility boundary to chat evidence, and includes ADR 0237's Docker/Podman/Colima accelerator boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene, focused backend/frontend tests, and lint pass; hosted checks and independent approval remain pending | | #663 | `ee795ac0` | project ontology traversal, cutoff-snapshot focus, bounded MCP admission, and migration-fixture/worker startup repair; its new ADRs use unique 0230/0231 identities, KG edge creation obeys the knowledge cutoff, and sealed `snapshot_at` now bounds authorizing focus evidence for every ontology node type rather than Projects alone (32 focused ontology tests pass); hosted checks and independent review requeued | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | @@ -119,7 +119,7 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 16:12 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 16:27 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 20 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. From a76dae3bb16179dd6007521b95405c6221849a54 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:24:53 +0900 Subject: [PATCH 171/238] docs(gaps): record protected ontology delivery and math debt --- docs/product-technical-gap-baseline.md | 33 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5da5ea9d3..6fafb1503 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,7 +1,7 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 16:12 KST. Protected `main` is -> `494b54e2245040bcf02b45376f221c37cd437e76`. This local branch is not +> Dashboard delivery snapshot: 2026-08-26 16:24 KST. Protected `main` is +> `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`. This local branch is not > protected-main release evidence. ## Operations Dashboard PRD/TRD traceability @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 20 open PRs and 10 open issues. The exact-head +At this snapshot there were 19 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 16:12 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 16:24 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, @@ -77,8 +77,8 @@ lifecycle claim. ## 1. Exact-head and governance evidence -The protected default branch is `494b54e2245040bcf02b45376f221c37cd437e76` -at this refresh. The live queue contains 20 open PRs and 10 +The protected default branch is `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f` +at this refresh. The live queue contains 19 open PRs and 10 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. @@ -87,15 +87,14 @@ context only. | ---: | --- | --- | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | -| #694 | `296cbae6` | preserves overlapping voice classifications and authorized aggregate filters; the repaired stack aligns source eligibility/ABAC and period semantics, rejects NULL model receipts in replay-safe schema upgrades, omits the unrelated panel from external-only views, and replaces implementation-boundary labels with localized next-action copy. Focused backend/frontend, lint/build/Storybook, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `999063d2` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition preserves exact orchestrator/measurement dependencies, rejects oversized backfill units explicitly, has no unresolved review thread, and remains stacked directly on #640 pending protected parent delivery | +| #694 | `3f35e69e` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | +| #693 | `a3cd34c4` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, and requeues successful records whose operations evidence is missing. It remains stacked directly on #640 pending protected parent delivery | | #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | | #680 | `b6c8c46d` | customer-facing ranking copy with localized retry/search guidance and source-record detail copy corrected; BLOCKED with exact-head checks and independent review required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | | #667 | `6f3e179b` | baseline/conversation repairs contain merged #691 retry semantics, prevent stale conversation pagination from contaminating a new post, apply the shared source-eligibility boundary to chat evidence, and include ADR 0237's Docker/Podman/Colima accelerator boundary: MLX stays behind contextual-orchestrator, scientific Rust CPU/CUDA/OpenCL stays with TEPP/fast-mlsirm, and RankWeave remains the Python retrieval-fusion/evaluation contract owner. Documentation hygiene, focused backend/frontend tests, and lint pass; hosted checks and independent approval remain pending | -| #663 | `ee795ac0` | project ontology traversal, cutoff-snapshot focus, bounded MCP admission, and migration-fixture/worker startup repair; its new ADRs use unique 0230/0231 identities, KG edge creation obeys the knowledge cutoff, and sealed `snapshot_at` now bounds authorizing focus evidence for every ontology node type rather than Projects alone (32 focused ontology tests pass); hosted checks and independent review requeued | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | @@ -115,12 +114,18 @@ and `60b4c6004739a05e63edae8ff160758f8e665919`. These are stack-integration evidence only; they are not protected-`main` delivery. Their acceptance now travels with the two parent heads above. +PR #663 merged to protected `main` as merge commit +`faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`; its project-ontology traversal, +cutoff-snapshot authorization, bounded MCP admission, and caller-parsed +semantic-unit seam are therefore protected delivery. This does not by itself +ship a Naruon conversation-turn producer contract. + PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 16:12 KST found no `failure`, `cancelled`, or -`timed_out` conclusions on the 20 current heads. Several heads, including +The exact-head check-run scan at 16:20 KST found no `failure`, `cancelled`, or +`timed_out` conclusions on the 19 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -140,7 +145,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 20 open PRs. The +to divergent filenames across the 19 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -455,7 +460,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@494b54e2` includes the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty PRs remain open at the 16:12 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@faff7a32` includes #663's project-ontology and caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 16:24 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -464,6 +469,7 @@ for wholesale replay from #490. | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. An older-image local observation found repeated post-filter queries while `/api/posts` exceeded 30 seconds; ADR 0212 combines two authorized filter-option queries into one round trip without narrowing ABAC-visible options. PR #629 exact head `48496ff6` moves Global Ask question embedding before `pool.acquire()`, validates a finite non-zero embedding envelope, and has terminal successful hosted checks with no unresolved review thread; protected delivery remains blocked on independent review. These observations are not exact-head capacity evidence or a product guarantee | Land #629 through the protected gate, rebuild its merge head as an application image, run `make load-http` with declared environment concurrency/window, retain raw distributions and resource configuration, and compare the post-list database plan and latency with ADR 0212; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | +| Source conversation-turn ingestion | PRD FR-4 and ADR 0062 require ordered sender/receiver turns, but `chunk_by_conversation_turn()` has no production caller. PR #663 adds a caller-parsed semantic-unit seam without a versioned Naruon contract; Ask conversation history and ThreadWeave message threading are separate graphs | Stack a bounded, versioned LineageWeave semantic-unit request contract on #663 and a Naruon consumer contract that supplies authorized RFC/JMAP-derived `conversation_turn` units with opaque speaker evidence. Prove ordering, fail-closed validation, ABAC non-disclosure, idempotent replay, semantic-only turn retrieval and citation, and no body-pattern speaker inference | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Product hierarchy and voice exploration | PR #692 carries an evidence-bound product group/model/variant/trade-item catalog, and #694 carries overlapping voice classifications with source eligibility, ABAC, and original evidence preserved; both remain stacked candidates rather than protected delivery | Land the ordered parent stack, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | @@ -472,6 +478,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm and PR #697 deletes unused cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen; no accepted Rust graph/retrieval owner contract exists yet | Extend the owning repositories with versioned Rust artifacts rather than reproducing formulas locally: fast-mlsirm must return the complete period-report and anchored-weight artifacts; RankWeave must return graph-ranking and fusion contribution artifacts. Then replace each active LineageWeave path with validation, persistence, and projection only, with CPU/GPU parity and true-parameter recovery evidence | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | From 83f5b15af1d011a657cfebb57a76e43744d93b9b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:31:51 +0900 Subject: [PATCH 172/238] style(docs): repair protected merge whitespace --- docs/adr/0218-current-contract-mcp-global-ask.md | 1 - docs/adr/0222-project-nodes-in-ontology-neighborhood.md | 6 +++--- docs/adr/0230-pnpm-build-script-allowlist.md | 2 +- docs/adr/0231-external-lineage-arithmetic-authority.md | 2 +- docs/doctoring/MCP_GLOBAL_ASK_REFERENCES.md | 1 - tests/test_frontend_container_install_policy.py | 1 - 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/adr/0218-current-contract-mcp-global-ask.md b/docs/adr/0218-current-contract-mcp-global-ask.md index 2b2e15f60..624f2d87f 100644 --- a/docs/adr/0218-current-contract-mcp-global-ask.md +++ b/docs/adr/0218-current-contract-mcp-global-ask.md @@ -87,4 +87,3 @@ https://doi.org/10.17487/RFC9700 Model Context Protocol. (2025). *Transports: Streamable HTTP* (Specification 2025-06-18). https://modelcontextprotocol.io/specification/2025-06-18/basic/transports - diff --git a/docs/adr/0222-project-nodes-in-ontology-neighborhood.md b/docs/adr/0222-project-nodes-in-ontology-neighborhood.md index 900b76e8e..597bf06da 100644 --- a/docs/adr/0222-project-nodes-in-ontology-neighborhood.md +++ b/docs/adr/0222-project-nodes-in-ontology-neighborhood.md @@ -1,8 +1,8 @@ # ADR 0222: Project nodes in the ontology neighborhood -**Status:** Accepted -**Date:** 2026-08-26 -**Extends:** [ADR 0036](0036-semantic-project-and-keyman-evidence.md), [ADR 0184](0184-ontology-provenance-explorer.md) +**Status:** Accepted +**Date:** 2026-08-26 +**Extends:** [ADR 0036](0036-semantic-project-and-keyman-evidence.md), [ADR 0184](0184-ontology-provenance-explorer.md) **Figma:** File ID `1Su3lDRmiZdcUs47t1QwIX` ## Context diff --git a/docs/adr/0230-pnpm-build-script-allowlist.md b/docs/adr/0230-pnpm-build-script-allowlist.md index 8433fb4e6..97d84ef18 100644 --- a/docs/adr/0230-pnpm-build-script-allowlist.md +++ b/docs/adr/0230-pnpm-build-script-allowlist.md @@ -1,6 +1,6 @@ # ADR 0230: pnpm build-script allowlist -**Status:** Accepted +**Status:** Accepted **Date:** 2026-08-26 ## Context diff --git a/docs/adr/0231-external-lineage-arithmetic-authority.md b/docs/adr/0231-external-lineage-arithmetic-authority.md index c520cbeb5..6eb20c793 100644 --- a/docs/adr/0231-external-lineage-arithmetic-authority.md +++ b/docs/adr/0231-external-lineage-arithmetic-authority.md @@ -1,6 +1,6 @@ # ADR 0231: External lineage arithmetic authority -**Status:** Accepted +**Status:** Accepted **Date:** 2026-08-26 ## Context diff --git a/docs/doctoring/MCP_GLOBAL_ASK_REFERENCES.md b/docs/doctoring/MCP_GLOBAL_ASK_REFERENCES.md index 9d51e8408..f3f1084b6 100644 --- a/docs/doctoring/MCP_GLOBAL_ASK_REFERENCES.md +++ b/docs/doctoring/MCP_GLOBAL_ASK_REFERENCES.md @@ -28,4 +28,3 @@ https://doi.org/10.17487/RFC9700 Model Context Protocol. (2025). *Transports: Streamable HTTP* (Specification 2025-06-18). https://modelcontextprotocol.io/specification/2025-06-18/basic/transports - diff --git a/tests/test_frontend_container_install_policy.py b/tests/test_frontend_container_install_policy.py index 980d595b1..dacae246c 100644 --- a/tests/test_frontend_container_install_policy.py +++ b/tests/test_frontend_container_install_policy.py @@ -11,4 +11,3 @@ def test_frontend_container_copies_the_single_build_script_policy() -> None: assert workspace == "allowBuilds:\n esbuild: true\n" assert "COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./" in dockerfile - From 8a341ba485386236769bd50e0ae20416bc476e7c Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:37:28 +0900 Subject: [PATCH 173/238] fix: fence post conversation requests --- frontend/src/App.tsx | 3 +- frontend/src/ChatPanel.test.tsx | 76 +++++++++++++++++++++++++++++++++ tests/test_post_ask_history.py | 29 +++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 75bb2f6d3..6fc01ff7a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -293,10 +293,12 @@ export function ChatPanel({ const [evidencePostId, setEvidencePostId] = useState(null); const [seededOnly, setSeededOnly] = useState(false); const conversationListRequest = useRef(0); + const conversationRequest = useRef(0); useEffect(() => { let active = true; ++conversationListRequest.current; + ++conversationRequest.current; setExchanges([]); setSeededExchanges([]); setConversations([]); @@ -327,7 +329,6 @@ export function ChatPanel({ return () => { active = false; }; }, [postId, accessToken]); - const conversationRequest = useRef(0); async function selectConversation(nextId: string) { const requestId = ++conversationRequest.current; setHistoryError(null); diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 47de97d73..c093c9d71 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -157,6 +157,82 @@ describe("ChatPanel conversation history", () => { await waitFor(() => expect(screen.queryByRole("option", { name: "Previous post (1)" })).toBeNull()); }); + it("discards a selected conversation response after moving to another post", async () => { + let resolveOldConversation!: (response: Response) => void; + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { + const url = input instanceof Request ? input.url : String(input); + if (url.endsWith("post-1/chat/conversations/conversation-old")) { + return new Promise((resolve) => { resolveOldConversation = resolve; }); + } + if (url.endsWith("post-1/chat/conversations")) { + return jsonResponse({ + conversations: [{ conversation_id: "conversation-old", title: "Previous post", updated_at: "2026-08-25T00:00:00Z", turn_count: 1 }], + next_cursor: null, + }); + } + if (url.endsWith("post-2/chat/conversations")) { + return jsonResponse({ conversations: [], next_cursor: null }); + } + return jsonResponse({ post_id: url.includes("post-2") ? "post-2" : "post-1", exchanges: [] }); + })); + + const view = render(); + await userEvent.selectOptions(await screen.findByLabelText("Conversation history"), "conversation-old"); + view.rerender(); + resolveOldConversation(jsonResponse({ + conversation_id: "conversation-old", + title: "Previous post", + older_cursor: null, + exchanges: [{ turn_id: "turn-old", question_text: "Old?", answer_text: "Stale selected answer", cited_post_ids: [] }], + })); + + await waitFor(() => expect(screen.queryByText("Stale selected answer")).toBeNull()); + expect(screen.getByLabelText("Conversation history")).toHaveValue(""); + }); + + it("discards an earlier-page response after moving to another post", async () => { + let resolveOlder!: (response: Response) => void; + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { + const url = input instanceof Request ? input.url : String(input); + if (url.endsWith("post-1/chat/conversations/conversation-old?before_turn=2")) { + return new Promise((resolve) => { resolveOlder = resolve; }); + } + if (url.endsWith("post-1/chat/conversations/conversation-old")) { + return jsonResponse({ + conversation_id: "conversation-old", + title: "Previous post", + older_cursor: "2", + exchanges: [{ turn_id: "turn-current", question_text: "Current?", answer_text: "Current old-post answer", cited_post_ids: [] }], + }); + } + if (url.endsWith("post-1/chat/conversations")) { + return jsonResponse({ + conversations: [{ conversation_id: "conversation-old", title: "Previous post", updated_at: "2026-08-25T00:00:00Z", turn_count: 2 }], + next_cursor: null, + }); + } + if (url.endsWith("post-2/chat/conversations")) { + return jsonResponse({ conversations: [], next_cursor: null }); + } + return jsonResponse({ post_id: url.includes("post-2") ? "post-2" : "post-1", exchanges: [] }); + })); + + const view = render(); + await userEvent.selectOptions(await screen.findByLabelText("Conversation history"), "conversation-old"); + await screen.findByText("Current old-post answer"); + await userEvent.click(screen.getByRole("button", { name: "Load earlier messages" })); + view.rerender(); + resolveOlder(jsonResponse({ + conversation_id: "conversation-old", + title: "Previous post", + older_cursor: null, + exchanges: [{ turn_id: "turn-earlier", question_text: "Earlier?", answer_text: "Stale earlier-page answer", cited_post_ids: [] }], + })); + + await waitFor(() => expect(screen.queryByText("Stale earlier-page answer")).toBeNull()); + expect(screen.queryByText("Current old-post answer")).toBeNull(); + }); + it("reopens an owned conversation and returns to the seeded new-conversation state", async () => { vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : String(input); diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py index 7bd16c768..fa168bb08 100644 --- a/tests/test_post_ask_history.py +++ b/tests/test_post_ask_history.py @@ -277,6 +277,35 @@ async def fetchrow(self, query: str, *arguments: object) -> None: assert not any("insert into post_ask_turn" in query for query, _ in connection.calls) +def test_persist_turn_locks_existing_session_before_allocating_ordinal() -> None: + """Every existing-session append is serialized before choosing its ordinal.""" + connection = _Connection() + + asyncio.run( + persist_turn( + connection, + "account-1", + "post-1", + UUID("00000000-0000-0000-0000-000000000005"), + "What changed?", + "An answer.", + ["post-1"], + [], + ) + ) + + statements = [query for query, _arguments in connection.calls] + lock_index = next( + index for index, query in enumerate(statements) + if "from post_ask_session" in query and "for update" in query + ) + ordinal_index = next( + index for index, query in enumerate(statements) + if "coalesce(max(turn_ordinal)" in query + ) + assert lock_index < ordinal_index + + def test_persist_post_ask_turn_starts_a_new_conversation_if_a_confirmed_one_is_deleted( monkeypatch: pytest.MonkeyPatch, ) -> None: From c2f0e8756caf90dab7207e98461204bcc5a701dd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:44:12 +0900 Subject: [PATCH 174/238] docs(gaps): record exact-head load evidence --- docs/product-technical-gap-baseline.md | 27 +++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e2ec1e8d5..02d6b584e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,7 +1,7 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 16:27 KST. Protected `main` is -> `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`. This local branch is not +> Dashboard delivery snapshot: 2026-08-26 16:42 KST. Protected `main` is +> `ff7431bd1851c03e737808d22c6a2d43968582f9`. This local branch is not > protected-main release evidence. ## Operations Dashboard PRD/TRD traceability @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 19 open PRs and 10 open issues. The exact-head +At this snapshot there were 17 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 16:27 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 16:42 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, @@ -77,8 +77,8 @@ lifecycle claim. ## 1. Exact-head and governance evidence -The protected default branch is `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f` -at this refresh. The live queue contains 19 open PRs and 10 +The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` +at this refresh. The live queue contains 17 open PRs and 10 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. @@ -87,8 +87,8 @@ context only. | ---: | --- | --- | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | -| #694 | `3f35e69e` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `a3cd34c4` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, and requeues successful records whose operations evidence is missing. It remains stacked directly on #640 pending protected parent delivery | +| #694 | `d903f7d0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | +| #693 | `cdd499b1` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, and requeues successful records whose operations evidence is missing. It remains stacked directly on #640 pending protected parent delivery | | #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | | #680 | `cc2b7182` | customer-facing ranking and related-concept copy now removes the remaining rendered internal ontology label while preserving the Event Lineage distinction. Focused 75-test i18n/component regression, lint, Storybook build, and synthetic 1440×1000 / 390×844 visual audits pass; fresh exact-head hosted checks and independent review are required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | @@ -100,9 +100,8 @@ context only. | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | | #640 | `19c9c9e4` | dashboard ranking and topic-influence stack now includes bounded semantic backfill jobs, evidence-window fingerprint invalidation for automatic related-source analysis, accepted measurement-owner release pins, localized evidence-rank labels, one topic-journey vocabulary, migration replay safety, id-only Ask citations, and the not-applicable topic state; redundant test lambdas were removed without changing behavior, while exact-head hosted checks and independent review remain required | -| #639 | `8da485d3` | running-action/config repair; BLOCKED with review required | +| #639 | `f6c8c93f` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. Its exact-head Compose image proves the pnpm `allowBuilds` input repair and a regression locks the seed command; fresh hosted checks and independent review remain required | | #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | -| #631 | `e6b4f0c4` | ADR decomposition documentation; BLOCKED with review required | | #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge @@ -124,8 +123,8 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 16:27 KST found no `failure`, `cancelled`, or -`timed_out` conclusions on the 19 current heads. Several heads, including +The exact-head check-run scan at 16:42 KST found no `failure`, `cancelled`, or +`timed_out` conclusions on the 17 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -460,13 +459,13 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@faff7a32` includes #663's project-ontology and caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 16:27 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 16:42 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | -| Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. An older-image local observation found repeated post-filter queries while `/api/posts` exceeded 30 seconds; ADR 0212 combines two authorized filter-option queries into one round trip without narrowing ABAC-visible options. PR #629 exact head `48496ff6` moves Global Ask question embedding before `pool.acquire()`, validates a finite non-zero embedding envelope, and has terminal successful hosted checks with no unresolved review thread; protected delivery remains blocked on independent review. These observations are not exact-head capacity evidence or a product guarantee | Land #629 through the protected gate, rebuild its merge head as an application image, run `make load-http` with declared environment concurrency/window, retain raw distributions and resource configuration, and compare the post-list database plan and latency with ADR 0212; set no SLO until representative capacity evidence is approved | +| Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. On PR #639 exact head `f6c8c93f`, a local 4-VU/30-second synthetic authenticated run completed 4,650 iterations (152.21/s), 13,952 requests (456.71/s), and zero failed requests. Ask enqueue was 74.90 ms; Ask polling p95 was 29.94 ms; combined post/lineage reads were 23.22 ms average and 40.88 ms p95. The one Ask job settled `succeeded`. A mid-run sample observed backend CPU 98.03%, PostgreSQL CPU 107.59%, Valkey 1.90% with zero rejected connections/evictions, and orchestrator 0.47%; PostgreSQL showed no lock wait. This names CPU pressure at the application/database boundary but does not establish a latency bottleneck, capacity limit, or SLO. The first PR #629 image build also reproduced the pnpm 11 ignored-build failure; PR #639's workspace-policy copy fixes that owned Compose contract and now locks the seed extras in regression. PR #629 exact head `48496ff6` still moves Global Ask question embedding before `pool.acquire()` and remains blocked on independent review | Land #639 and #629 through their protected gates, repeat this declared workload on their merge heads with endpoint-separated trends and repeated resource samples, then increase concurrency only until an observed latency/error knee identifies a bottleneck. Retain raw distributions and resource configuration; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Source conversation-turn ingestion | PRD FR-4 and ADR 0062 require ordered sender/receiver turns, but `chunk_by_conversation_turn()` has no production caller. Protected #663 supplies the caller-parsed semantic-unit seam without a versioned Naruon contract; Ask conversation history and ThreadWeave message threading are separate graphs | Add a bounded, versioned LineageWeave semantic-unit request contract on protected main and a Naruon consumer contract that supplies authorized RFC/JMAP-derived `conversation_turn` units with opaque speaker evidence. Prove ordering, fail-closed validation, ABAC non-disclosure, idempotent replay, semantic-only turn retrieval and citation, and no body-pattern speaker inference | From 7e23a186099ff42fc01ae86318e94a6abdf238c5 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:47:08 +0900 Subject: [PATCH 175/238] docs(gaps): refresh merge-forward head evidence --- docs/product-technical-gap-baseline.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 02d6b584e..2bad24ada 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 16:42 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 16:48 KST. Protected `main` is > `ff7431bd1851c03e737808d22c6a2d43968582f9`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 16:42 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 16:48 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, @@ -90,11 +90,11 @@ context only. | #694 | `d903f7d0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | | #693 | `cdd499b1` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, and requeues successful records whose operations evidence is missing. It remains stacked directly on #640 pending protected parent delivery | | #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | -| #680 | `cc2b7182` | customer-facing ranking and related-concept copy now removes the remaining rendered internal ontology label while preserving the Event Lineage distinction. Focused 75-test i18n/component regression, lint, Storybook build, and synthetic 1440×1000 / 390×844 visual audits pass; fresh exact-head hosted checks and independent review are required | +| #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | | #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | | #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | parent `adad5be0` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination from contaminating a new post, applies the shared source-eligibility boundary to chat evidence, merge-forwards protected #663, and includes ADR 0237's Docker/Podman/Colima accelerator boundary. The row records the remote parent observed immediately before this documentation merge because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused semantic tests pass; hosted checks and independent approval remain pending | +| #667 | parent `c2f0e875` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination from contaminating a new post, applies the shared source-eligibility boundary to chat evidence, merge-forwards protected #663, and includes ADR 0237's Docker/Podman/Colima accelerator boundary. The row records the remote parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused semantic tests pass; hosted checks and independent approval remain pending | | #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | @@ -123,7 +123,7 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 16:42 KST found no `failure`, `cancelled`, or +The exact-head check-run scan at 16:48 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 17 current heads. Several heads, including PR #667 and #672 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. @@ -459,7 +459,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 16:42 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 0bc2bc6adb0ccfceb037cea76e00c344ad685fb3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:49:03 +0900 Subject: [PATCH 176/238] docs(gaps): track source turn contract candidate --- docs/product-technical-gap-baseline.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 2bad24ada..2169595d8 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 17 open PRs and 10 open issues. The exact-head +At this snapshot there were 18 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,13 +78,14 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 17 open PRs and 10 +at this refresh. The live queue contains 18 open PRs and 10 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 | | ---: | --- | --- | +| #700 | `0b04fe73` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | | #694 | `d903f7d0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | @@ -125,7 +126,7 @@ open current-main candidate rather than relying on that closed head. The exact-head check-run scan at 16:48 KST found no `failure`, `cancelled`, or `timed_out` conclusions on the 17 current heads. Several heads, including -PR #667 and #672 after their repair pushes, are still queued and therefore have +PR #667, #672, and #700 after their repair pushes, are still queued and therefore have no terminal gate evidence; review approval is also independently required. No row above is merge evidence. Immediately before any lifecycle action, @@ -144,7 +145,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 19 open PRs. The +to divergent filenames across the 18 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -459,7 +460,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -468,7 +469,7 @@ for wholesale replay from #490. | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. On PR #639 exact head `f6c8c93f`, a local 4-VU/30-second synthetic authenticated run completed 4,650 iterations (152.21/s), 13,952 requests (456.71/s), and zero failed requests. Ask enqueue was 74.90 ms; Ask polling p95 was 29.94 ms; combined post/lineage reads were 23.22 ms average and 40.88 ms p95. The one Ask job settled `succeeded`. A mid-run sample observed backend CPU 98.03%, PostgreSQL CPU 107.59%, Valkey 1.90% with zero rejected connections/evictions, and orchestrator 0.47%; PostgreSQL showed no lock wait. This names CPU pressure at the application/database boundary but does not establish a latency bottleneck, capacity limit, or SLO. The first PR #629 image build also reproduced the pnpm 11 ignored-build failure; PR #639's workspace-policy copy fixes that owned Compose contract and now locks the seed extras in regression. PR #629 exact head `48496ff6` still moves Global Ask question embedding before `pool.acquire()` and remains blocked on independent review | Land #639 and #629 through their protected gates, repeat this declared workload on their merge heads with endpoint-separated trends and repeated resource samples, then increase concurrency only until an observed latency/error knee identifies a bottleneck. Retain raw distributions and resource configuration; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | -| Source conversation-turn ingestion | PRD FR-4 and ADR 0062 require ordered sender/receiver turns, but `chunk_by_conversation_turn()` has no production caller. Protected #663 supplies the caller-parsed semantic-unit seam without a versioned Naruon contract; Ask conversation history and ThreadWeave message threading are separate graphs | Add a bounded, versioned LineageWeave semantic-unit request contract on protected main and a Naruon consumer contract that supplies authorized RFC/JMAP-derived `conversation_turn` units with opaque speaker evidence. Prove ordering, fail-closed validation, ABAC non-disclosure, idempotent replay, semantic-only turn retrieval and citation, and no body-pattern speaker inference | +| Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish its immutable contract fixture, and add a Naruon consumer that supplies authorized RFC/JMAP-derived turns. Prove ABAC non-disclosure, semantic-only turn retrieval and exact-unit citation, and absence of cross-graph inference on released heads | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Product hierarchy and voice exploration | PR #692 carries an evidence-bound product group/model/variant/trade-item catalog, and #694 carries overlapping voice classifications with source eligibility, ABAC, and original evidence preserved; both remain stacked candidates rather than protected delivery | Land the ordered parent stack, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | From ad3c5933e3da3d1672c70a7363bf0f711def0daa Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:51:30 +0900 Subject: [PATCH 177/238] docs(gaps): refresh conversation contract head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 2169595d8..0d4afd7f3 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,7 +85,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #700 | `0b04fe73` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | +| #700 | `fe1836f5` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | | #694 | `d903f7d0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | From 776e636a586c128e88492dbf338f4c5989cbb1b0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 16:55:03 +0900 Subject: [PATCH 178/238] docs(gaps): record migration fixture repair --- docs/product-technical-gap-baseline.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 0d4afd7f3..8c2fb0fba 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 18 open PRs and 10 open issues. The exact-head +At this snapshot there were 19 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,13 +78,14 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 18 open PRs and 10 +at this refresh. The live queue contains 19 open PRs and 10 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 | | ---: | --- | --- | +| #701 | `5eae0e05` | repairs the backend integration fixture so PostgreSQL concurrent-index migrations execute with the same per-statement autocommit boundary as production `psql`; no migration is skipped or suppressed. The formerly failing fixture and 38 schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `fe1836f5` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | @@ -145,7 +146,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 18 open PRs. The +to divergent filenames across the 19 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -460,7 +461,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Eighteen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From cb3ebfcc7ef9c78b3396ce5fa797098248d6e45b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:04:52 +0900 Subject: [PATCH 179/238] docs(gaps): refresh review repair heads --- 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 8c2fb0fba..7454318eb 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,8 +85,8 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #701 | `5eae0e05` | repairs the backend integration fixture so PostgreSQL concurrent-index migrations execute with the same per-statement autocommit boundary as production `psql`; no migration is skipped or suppressed. The formerly failing fixture and 38 schema/replay/backend checks pass; protected hosted checks and independent review remain required | -| #700 | `fe1836f5` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | +| #701 | `8ab3d653` | repairs both integration fixtures so PostgreSQL concurrent-index migrations execute with the same per-statement autocommit boundary as production `psql`, without manufacturing empty trailing statements; no migration is skipped or suppressed. The formerly failing fixture and 38 schema/replay/backend checks pass; protected hosted checks and independent review remain required | +| #700 | `80f86da1` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body image/style metadata or trigger unused vision work. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | | #694 | `d903f7d0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | From 9f185711f0ba5cf3a67687e3a7750e6bab9a62bd Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:07:32 +0900 Subject: [PATCH 180/238] fix: replace recovered conversation transcript --- frontend/src/App.tsx | 10 +++++--- frontend/src/ChatPanel.test.tsx | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6fc01ff7a..c316e30e7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -358,11 +358,13 @@ export function ChatPanel({ async function handleAsk(asked = question) { if (!asked.trim()) return; - const startsConversation = conversationId === null; + const requestedConversationId = conversationId; setLoading(true); setError(null); try { - const result = await askPostChat(accessToken, postId, asked, conversationId); + const result = await askPostChat(accessToken, postId, asked, requestedConversationId); + const startsConversation = requestedConversationId === null + || (result.conversation_id !== undefined && result.conversation_id !== requestedConversationId); setAnswer(result); if (result.conversation_id) { setConversationId(result.conversation_id); @@ -373,7 +375,9 @@ export function ChatPanel({ updated_at: new Date().toISOString(), turn_count: (current.find((row) => row.conversation_id === result.conversation_id)?.turn_count ?? 0) + 1, }, - ...current.filter((row) => row.conversation_id !== result.conversation_id), + ...current.filter((row) => + row.conversation_id !== result.conversation_id + && row.conversation_id !== requestedConversationId), ]); } setExchanges((prev) => { diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index c093c9d71..903d317e2 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -83,6 +83,47 @@ describe("ChatPanel conversation history", () => { expect(screen.queryByText("Demo answer")).toBeNull(); }); + it("replaces a deleted conversation transcript when recovery creates a new one", async () => { + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { + const url = input instanceof Request ? input.url : String(input); + if (url.endsWith("/chat") && init?.method === "POST") { + return jsonResponse({ + answer_text: "Recovered answer", + cited_post_ids: [], + cited_posts: [], + conversation_id: "conversation-new", + }); + } + if (url.endsWith("/chat/conversations/conversation-deleted")) { + return jsonResponse({ + conversation_id: "conversation-deleted", + title: "Deleted conversation", + older_cursor: null, + exchanges: [{ turn_id: "turn-old", question_text: "Old?", answer_text: "Deleted transcript", cited_post_ids: [] }], + }); + } + if (url.endsWith("/chat/conversations")) { + return jsonResponse({ + conversations: [{ conversation_id: "conversation-deleted", title: "Deleted conversation", updated_at: "2026-08-26T00:00:00Z", turn_count: 1 }], + next_cursor: null, + }); + } + return jsonResponse({ post_id: "post-1", exchanges: [] }); + })); + + render(); + const history = await screen.findByLabelText("Conversation history"); + await userEvent.selectOptions(history, "conversation-deleted"); + await screen.findByText("Deleted transcript"); + await userEvent.type(screen.getByPlaceholderText("What happened between these events?"), "Recover this"); + await userEvent.click(screen.getByRole("button", { name: "Ask" })); + + expect(await screen.findByText("Recovered answer")).toBeInTheDocument(); + expect(screen.queryByText("Deleted transcript")).toBeNull(); + expect(history).toHaveValue("conversation-new"); + expect(screen.queryByRole("option", { name: /Deleted conversation/ })).toBeNull(); + }); + it("does not duplicate an answered conversation when loading another page", async () => { vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { const url = input instanceof Request ? input.url : String(input); From c263cab71ec9bc0b4a24cc7aad5d8bc336b88f68 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:20:34 +0900 Subject: [PATCH 181/238] docs(gaps): sync exact review repair heads --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 7454318eb..9ece702f4 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,12 +85,12 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #701 | `8ab3d653` | repairs both integration fixtures so PostgreSQL concurrent-index migrations execute with the same per-statement autocommit boundary as production `psql`, without manufacturing empty trailing statements; no migration is skipped or suppressed. The formerly failing fixture and 38 schema/replay/backend checks pass; protected hosted checks and independent review remain required | +| #701 | `67510e76` | repairs both integration fixtures so PostgreSQL concurrent-index migrations execute with the same per-statement autocommit boundary as production `psql`; the controlled migration now has a tested one-statement-per-terminator contract, and no migration is skipped or suppressed. The formerly failing fixture and 38 schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `80f86da1` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body image/style metadata or trigger unused vision work. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | | #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | -| #694 | `d903f7d0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, and the replay-safe schema permits only one open assertion per post, status, and concept. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `cdd499b1` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, and requeues successful records whose operations evidence is missing. It remains stacked directly on #640 pending protected parent delivery | +| #694 | `faadbae0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, concurrent loading uses one live region, and synthetic-only Demo identities cannot enter a real-source denominator. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | +| #693 | `c747fcfa` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, requeues stale source-hash analysis, and pins the two-poll orchestrator cadence in regression. It remains stacked directly on #640 pending protected parent delivery | | #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | | #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | From d6971d079aef6152bce8b1ad4f5208093134712b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:21:53 +0900 Subject: [PATCH 182/238] fix: reject partial conversation cursors --- backend/app/post_ask_history.py | 2 ++ tests/test_post_ask_history.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 007a09e04..5a13b3197 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -59,6 +59,8 @@ async def list_conversations( before_conversation_id: UUID | None = None, ) -> dict[str, Any]: """Return this account's conversations on ``post_id``, newest first.""" + if (before_updated_at is None) != (before_conversation_id is None): + raise ValueError("before_updated_at and before_conversation_id must be provided together") rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli """ select session.post_ask_session_id, diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py index fa168bb08..75a0a2400 100644 --- a/tests/test_post_ask_history.py +++ b/tests/test_post_ask_history.py @@ -104,6 +104,34 @@ def test_list_conversations_binds_account_post_and_cursor() -> None: assert result["conversations"][0]["conversation_id"] == "00000000-0000-0000-0000-000000000001" +@pytest.mark.parametrize( + ("before_updated_at", "before_conversation_id"), + [ + (datetime(2026, 1, 3, tzinfo=UTC), None), + (None, UUID("00000000-0000-0000-0000-000000000003")), + ], +) +def test_list_conversations_rejects_a_partial_cursor( + before_updated_at: datetime | None, + before_conversation_id: UUID | None, +) -> None: + """Direct callers cannot silently turn a partial cursor into page one.""" + connection = _Connection() + + with pytest.raises(ValueError, match="must be provided together"): + asyncio.run( + list_conversations( + connection, + "account-1", + "post-1", + before_updated_at=before_updated_at, + before_conversation_id=before_conversation_id, + ) + ) + + assert connection.calls == [] + + def test_conversation_exists_requires_account_and_post() -> None: """A conversation id from another post or account must not match.""" connection = _Connection() From 60a79253ed6a3c105eccfc3769150e1cbf30de1f Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:31:29 +0900 Subject: [PATCH 183/238] docs(gaps): reconcile stacked merges and exact heads --- docs/product-technical-gap-baseline.md | 36 ++++++++++++++------------ 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 9ece702f4..62daa875e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 19 open PRs and 10 open issues. The exact-head +At this snapshot there were 17 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,27 +78,24 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 19 open PRs and 10 +at this refresh. The live queue contains 17 open PRs and 10 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 | | ---: | --- | --- | -| #701 | `67510e76` | repairs both integration fixtures so PostgreSQL concurrent-index migrations execute with the same per-statement autocommit boundary as production `psql`; the controlled migration now has a tested one-statement-per-terminator contract, and no migration is skipped or suppressed. The formerly failing fixture and 38 schema/replay/backend checks pass; protected hosted checks and independent review remain required | -| #700 | `80f86da1` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body image/style metadata or trigger unused vision work. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #699 | `2fc467c6` | audits the dashboard stack against the Rust ownership boundary: TEPP and fast-mlsirm are the accepted scientific-compute owners, RankWeave remains the current Python retrieval contract, and no future Rust vector/graph scoring owner is invented. It is stacked on #694 pending parent delivery, hosted checks, and independent review | -| #697 | `4003ed27` | deletes unused Python vector helpers without inventing a replacement. The active Global Ask vector arithmetic remains explicit migration debt until an accepted Rust retrieval-scoring owner contract exists; it is stacked on #692 pending parent delivery, hosted checks, and independent review | -| #694 | `faadbae0` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, concurrent loading uses one live region, and synthetic-only Demo identities cannot enter a real-source denominator. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #692, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `c747fcfa` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, requeues stale source-hash analysis, and pins the two-poll orchestrator cadence in regression. It remains stacked directly on #640 pending protected parent delivery | -| #692 | `583059ed` | adds an evidence-bound product group/model/variant/trade-item ontology and normalized semantic catalog; each evidence post is independently authorized, malformed optional-orchestrator responses fail without escaping the optional channel, and evidence spans/digests bind to original source text rather than an augmented prompt. Focused tests pass; it remains stacked on #693 pending retargeting, hosted checks, and independent review | +| #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | +| #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | +| #694 | `85fe98da` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, concurrent loading uses one live region, and synthetic-only Demo identities cannot enter a real-source denominator. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #693's product-catalog composition, so parent delivery, retargeting, fresh hosted checks, and independent review are required | +| #693 | `ae129154` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, reclaims stale source-hash product analysis, and pins gateway authentication/cadence in regression. It remains stacked directly on #640 pending protected parent delivery | | #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | -| #672 | `748944ad` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; empty-citation public egress now fails closed, the no-public-claims state is buyer-visible, and the opt-in regression distinguishes successful from failed settlement. Review threads are resolved; hosted checks and independent review remain required | -| #668 | `dd7bd3f0` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | parent `c2f0e875` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination from contaminating a new post, applies the shared source-eligibility boundary to chat evidence, merge-forwards protected #663, and includes ADR 0237's Docker/Podman/Colima accelerator boundary. The row records the remote parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused semantic tests pass; hosted checks and independent approval remain pending | -| #658 | `f497a6e8` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | -| #657 | `709df1b9` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | +| #672 | `3f76c189` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence, removes duplicate embedding work, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | +| #668 | `d74139d2` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | +| #667 | parent `d6971d07` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, and includes ADR 0237's accelerator boundary. The row records the remote parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused tests pass; hosted checks and independent approval remain pending | +| #658 | `500a541b` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | +| #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | | #643 | `3453ab08` | accessible status notices; BLOCKED with review required | | #640 | `19c9c9e4` | dashboard ranking and topic-influence stack now includes bounded semantic backfill jobs, evidence-window fingerprint invalidation for automatic related-source analysis, accepted measurement-owner release pins, localized evidence-rank labels, one topic-journey vocabulary, migration replay safety, id-only Ask citations, and the not-applicable topic state; redundant test lambdas were removed without changing behavior, while exact-head hosted checks and independent review remain required | @@ -115,6 +112,13 @@ and `60b4c6004739a05e63edae8ff160758f8e665919`. These are stack-integration evidence only; they are not protected-`main` delivery. Their acceptance now travels with the two parent heads above. +PRs #692 and #697 merged into the non-default #693 composition as +`cdd499b161053a9c5439181e8f39e1baa80e68c0` and +`dc3ebb6911187637cf85fcbcc036cf39e571aaec`. PR #699 merged into the +non-default #694 composition as `d47aae9f77a3f71c7f91929cb258f6e73d1f6d40`. +Their product-catalog, Python-arithmetic deletion, and Rust-ownership audit +evidence now travels with those open parents; none is protected-main delivery. + PR #663 merged to protected `main` as merge commit `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`; its project-ontology traversal, cutoff-snapshot authorization, bounded MCP admission, and caller-parsed @@ -146,7 +150,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 19 open PRs. The +to divergent filenames across the 17 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -461,7 +465,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Nineteen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From f0314cc39d624bfd0c9ef45d8d353f95d1c12edc Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:36:08 +0900 Subject: [PATCH 184/238] docs(gaps): refresh owner-boundary exact heads --- docs/product-technical-gap-baseline.md | 59 +++++++++++++++++--------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 62daa875e..345f2a389 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 16:48 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 17:34 KST. Protected `main` is > `ff7431bd1851c03e737808d22c6a2d43968582f9`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 16:48 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 17:34 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, @@ -93,7 +93,7 @@ context only. | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | | #672 | `3f76c189` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence, removes duplicate embedding work, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | | #668 | `d74139d2` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | parent `d6971d07` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, and includes ADR 0237's accelerator boundary. The row records the remote parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused tests pass; hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `897b88e2` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and is merged forward to protected `main@ff7431bd`. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused tests must pass again on the resulting head; hosted checks and independent approval remain pending | | #658 | `500a541b` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | @@ -129,10 +129,28 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 16:48 KST found no `failure`, `cancelled`, or -`timed_out` conclusions on the 17 current heads. Several heads, including -PR #667, #672, and #700 after their repair pushes, are still queued and therefore have -no terminal gate evidence; review approval is also independently required. +The exact-head check-run scan at 17:34 KST found one failure on #679 and no +terminal gate evidence for several queued heads, including #667, #672, #700, +and #701. The failed check needs root-cause repair on its exact head; queued +checks and bot success statuses are not merge evidence. Independent approval +is also required. + +### Ecosystem owner-boundary evidence + +- `ContextualWisdomLab/contextual-orchestrator` PR #857 exact head + `4dcf952a` owns provider-backed embedding discovery, selection, execution, + durable batching, session propagation, and Rust token/vector arithmetic. + Its required hosted checks were queued at this snapshot. LineageWeave may + request embeddings and preserve an orchestrator-returned session model pin; + it must not configure `LLM_GATEWAY_EMBEDDING_MODEL`, infer a provider from a + model name, or present #857 as delivered before its protected merge. +- `ContextualWisdomLab/RankWeave` PR #41 exact head `8e75aa11` contains the + proposed Rust calculation core and a rebased semantic-unit ranking commit. + Stacked PR #48 exact head `f3cd7ed7` contains the same feature intent on a + divergent sibling commit and targets #41's branch. Both heads had queued + hosted checks and no protected-main merge evidence. Reconcile them to one + reviewed exact-head lineage before consumption; neither candidate permits + LineageWeave to retain Python vector arithmetic. No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head @@ -465,7 +483,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 16:48 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, one independent approval under active ruleset `18156473`, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 17:34 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -476,14 +494,14 @@ for wholesale replay from #490. | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish its immutable contract fixture, and add a Naruon consumer that supplies authorized RFC/JMAP-derived turns. Prove ABAC non-disclosure, semantic-only turn retrieval and exact-unit citation, and absence of cross-graph inference on released heads | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | -| Product hierarchy and voice exploration | PR #692 carries an evidence-bound product group/model/variant/trade-item catalog, and #694 carries overlapping voice classifications with source eligibility, ABAC, and original evidence preserved; both remain stacked candidates rather than protected delivery | Land the ordered parent stack, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | +| Product hierarchy and voice exploration | PR #692 merged only into the non-default #693 composition, which carries its evidence-bound product group/model/variant/trade-item catalog. Stacked #694 carries overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. Neither open parent is protected delivery | Land #693 and then #694 through their ordered protected gates, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | | Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm and PR #697 deletes unused cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 proposes the relation-safe, content-addressed Rust period artifact on #1417 without copying the unsupported weighted calibration score; no accepted Rust graph/retrieval owner contract exists yet | Land and implement fast-mlsirm #1417/#1436 with formal distinguishability and recovery evidence, then replace the period path with validation/persistence/projection only. Separately extend RankWeave with graph-ranking and fusion contribution artifacts before deleting those active LineageWeave paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 proposes the relation-safe, content-addressed Rust period artifact on #1417. RankWeave #41 (`8e75aa11`) proposes the shared Rust/PyO3 calculation boundary; stacked #48 (`f3cd7ed7`) proposes deterministic semantic-unit cosine ranking with winning-unit evidence and no local model/provider/weight selection. The sibling feature commits currently diverge and all required hosted gates remain queued, so none is protected delivery | Reconcile RankWeave #41/#48 to one reviewed stack and land the Rust owner contract before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | @@ -492,7 +510,7 @@ for wholesale replay from #490. | Frontend delivery performance | PR #644 exact head `f11e77d1` splits the real conditional workspace surfaces with native dynamic imports; 105 focused tests and the production build pass without the former large-chunk warning | Land #644 through protected gates, then repeat loading/error accessibility and bundle evidence on the exact release head | | External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | -| Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 now defines MLX as a native orchestrator-side service and TEPP/fast-mlsirm CUDA/OpenCL/CPU profiles as scientific-compute-owner deployments, so LineageWeave Compose remains device-neutral. RankWeave remains the dependency-free Python retrieval-fusion/evaluation owner behind its published contract | TEPP and fast-mlsirm must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX availability through its provider-neutral health/contract boundary. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when the owner is unavailable | +| Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 defines MLX as a native orchestrator-side service and TEPP/fast-mlsirm CUDA/OpenCL/CPU profiles as scientific-compute-owner deployments, so LineageWeave Compose remains device-neutral. contextual-orchestrator #857 proposes its Rust token/vector boundary, while RankWeave #41/#48 propose the Rust retrieval calculation boundary; all remain candidates until protected delivery | TEPP and fast-mlsirm must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX and embedding capability through its provider-neutral health/contract boundary; RankWeave must publish its reviewed Rust artifact. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when an owner is unavailable | | Product contract authority | This branch recreates the first LineageWeave PRD after superseded #613 closed without merge and records an exact-case ecosystem authority register; TEPP, fast-mlsirm, keyverse, and ThreadWeave have standalone PRDs, while contextual-orchestrator, RankWeave, DiskSage, and wardnet currently rely on product-planning/architecture documents and naruon has only a scoped Topic Intelligence PRD | Land the LineageWeave PRD, keep ADRs normative, and add standalone PRDs in each owning repository before making cross-product release claims beyond its documented boundary | | Release quality | Protected merges #660 and #659 are represented by `main@494b54e2`; the #660 stacked tree passed the complete Python suite (1,352 passed, 17 skipped) before protected delivery. Frontend/Storybook, security, browser, and authorized-runtime evidence remain separate gaps | Repository-wide coverage, frontend/Storybook, security, browser, and authorized-runtime evidence on one exact head | | PII | Masking would paralyze the product; ADR 0001 forbids identifying artifacts in git | ABAC + authorized runtime; synthetic fixtures in git; no mask-in-place that drops names the operator must read | @@ -579,25 +597,26 @@ review latency are never blockers — keep working while they settle. 1. Revalidate Strix after protected ContextualWisdomLab/.github#1320, reconcile .github#1263, and land the atomic hourly LineageWeave caller in .github#1288 after its current-head independent approval and checks complete. 2. Process the current section 1 inventory in ascending PR order after - dependency review. #677 is merged into the non-default baseline branch and - must be retargeted to `main` after #667. The completed #688/#689/#690 stack - integrations now travel only through parent PRs #640 and #667. No - child head may substitute for protected delivery of its base. + dependency review. #677, #688, #689, #690, #692, #697, and #699 are already + merged only into non-default parent branches; their acceptance travels + through #667, #640, #693, or #694 as recorded in section 1. Land #693 before + #694. No child head or non-default merge may substitute for protected + delivery of its base. Merge only after each exact head shows terminal green required checks plus current-head independent approval. 3. After the queue drains, resume user-visible gaps from §5 in leverage order: Event Lineage evidence (merged #387; historical issue #274), Naruon calendar (#355), and authenticated operations/ontology publication acceptance. -5. Rename remaining `[Buyer Gap]` issue titles to neutral product-object +4. Rename remaining `[Buyer Gap]` issue titles to neutral product-object naming per repository convention (no "Buyer" for internal objects). -6. Keep psychometric tests as true-parameter recovery (RMSE); never fixture +5. Keep psychometric tests as true-parameter recovery (RMSE); never fixture tautologies, invented theta, or hand-authored numeric weights. Remove weights from tests that do not exercise fusion; fusion tests must consume provenance-bearing fast-mlsirm estimates over synthetic fixtures. -7. Run frontend lint/test/build/Storybook, backend tests, and authenticated +6. Run frontend lint/test/build/Storybook, backend tests, and authenticated browser/accessibility checks on the exact candidate release head. -8. Fix only evidence-backed failures and repeat the protected merge gate. -9. Refresh this file each loop with the exact queue state. +7. Fix only evidence-backed failures and repeat the protected merge gate. +8. Refresh this file each loop with the exact queue state. ## 11. Spec pointers (derive, do not fork) From 32179e76a16270a3b6e4afdfe5e281ec08f1863b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:38:59 +0900 Subject: [PATCH 185/238] docs(gaps): compose current owner stacks --- docs/product-technical-gap-baseline.md | 41 +++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 345f2a389..490eeea42 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 17 open PRs and 10 open issues. The exact-head +At this snapshot there were 16 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 17:34 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 17:36 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, @@ -78,7 +78,7 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 17 open PRs and 10 +at this refresh. The live queue contains 16 open PRs and 10 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. @@ -87,8 +87,7 @@ context only. | ---: | --- | --- | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #694 | `85fe98da` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, concurrent loading uses one live region, and synthetic-only Demo identities cannot enter a real-source denominator. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #693's product-catalog composition, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `ae129154` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, reclaims stale source-hash product analysis, and pins gateway authentication/cadence in regression. It remains stacked directly on #640 pending protected parent delivery | +| #693 | `0feb7f72` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640. PR #694 is now composed into this head, preserving overlapping voice classifications, authorized aggregates, one concurrent-loading live region, synthetic-row exclusion, and the customer-visible evidence/actions. The composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, reclaims stale source-hash product analysis, and pins gateway authentication/cadence in regression. It remains stacked directly on #640 pending protected parent delivery; fresh exact-head checks are queued | | #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | | #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | | #672 | `3f76c189` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence, removes duplicate embedding work, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | @@ -112,12 +111,13 @@ and `60b4c6004739a05e63edae8ff160758f8e665919`. These are stack-integration evidence only; they are not protected-`main` delivery. Their acceptance now travels with the two parent heads above. -PRs #692 and #697 merged into the non-default #693 composition as +PRs #692, #697, and #694 merged into the non-default #693 composition as `cdd499b161053a9c5439181e8f39e1baa80e68c0` and -`dc3ebb6911187637cf85fcbcc036cf39e571aaec`. PR #699 merged into the -non-default #694 composition as `d47aae9f77a3f71c7f91929cb258f6e73d1f6d40`. -Their product-catalog, Python-arithmetic deletion, and Rust-ownership audit -evidence now travels with those open parents; none is protected-main delivery. +`dc3ebb6911187637cf85fcbcc036cf39e571aaec`, then protected-stack merge +`0feb7f72cc34fbd23e8f1bd6355c9a5ee49ded89`. PR #699 had already merged into +#694 as `d47aae9f77a3f71c7f91929cb258f6e73d1f6d40`. Their product-catalog, +voice exploration, Python-arithmetic deletion, and Rust-ownership audit +evidence now travels with open parent #693; none is protected-main delivery. PR #663 merged to protected `main` as merge commit `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`; its project-ontology traversal, @@ -145,12 +145,12 @@ is also required. it must not configure `LLM_GATEWAY_EMBEDDING_MODEL`, infer a provider from a model name, or present #857 as delivered before its protected merge. - `ContextualWisdomLab/RankWeave` PR #41 exact head `8e75aa11` contains the - proposed Rust calculation core and a rebased semantic-unit ranking commit. - Stacked PR #48 exact head `f3cd7ed7` contains the same feature intent on a - divergent sibling commit and targets #41's branch. Both heads had queued - hosted checks and no protected-main merge evidence. Reconcile them to one - reviewed exact-head lineage before consumption; neither candidate permits - LineageWeave to retain Python vector arithmetic. + proposed Rust calculation core and the semantic-unit ranking feature merged + from stacked PR #48 (`f3cd7ed7`). PR #48 is therefore stack-integration + evidence only; #41's new exact head has queued hosted checks and no + protected-main merge evidence. LineageWeave may consume the owner contract + only after that composed head passes its protected gate; it may not retain + Python vector arithmetic. No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head @@ -494,14 +494,14 @@ for wholesale replay from #490. | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish its immutable contract fixture, and add a Naruon consumer that supplies authorized RFC/JMAP-derived turns. Prove ABAC non-disclosure, semantic-only turn retrieval and exact-unit citation, and absence of cross-graph inference on released heads | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | -| Product hierarchy and voice exploration | PR #692 merged only into the non-default #693 composition, which carries its evidence-bound product group/model/variant/trade-item catalog. Stacked #694 carries overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. Neither open parent is protected delivery | Land #693 and then #694 through their ordered protected gates, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | +| Product hierarchy and voice exploration | PRs #692 and #694 are now composed into non-default parent #693, which carries the evidence-bound product group/model/variant/trade-item catalog plus overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. The open parent is not protected delivery | Land #693 through its ordered parent gate, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | | Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 proposes the relation-safe, content-addressed Rust period artifact on #1417. RankWeave #41 (`8e75aa11`) proposes the shared Rust/PyO3 calculation boundary; stacked #48 (`f3cd7ed7`) proposes deterministic semantic-unit cosine ranking with winning-unit evidence and no local model/provider/weight selection. The sibling feature commits currently diverge and all required hosted gates remain queued, so none is protected delivery | Reconcile RankWeave #41/#48 to one reviewed stack and land the Rust owner contract before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 proposes the relation-safe, content-addressed Rust period artifact on #1417. RankWeave #41 (`8e75aa11`) now composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | @@ -597,10 +597,9 @@ review latency are never blockers — keep working while they settle. 1. Revalidate Strix after protected ContextualWisdomLab/.github#1320, reconcile .github#1263, and land the atomic hourly LineageWeave caller in .github#1288 after its current-head independent approval and checks complete. 2. Process the current section 1 inventory in ascending PR order after - dependency review. #677, #688, #689, #690, #692, #697, and #699 are already + dependency review. #677, #688, #689, #690, #692, #694, #697, and #699 are already merged only into non-default parent branches; their acceptance travels - through #667, #640, #693, or #694 as recorded in section 1. Land #693 before - #694. No child head or non-default merge may substitute for protected + through #667, #640, or #693 as recorded in section 1. No child head or non-default merge may substitute for protected delivery of its base. Merge only after each exact head shows terminal green required checks plus current-head independent approval. From 06068637cb4048ca58f4f52b2c4a26ac64224689 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:39:17 +0900 Subject: [PATCH 186/238] docs(gaps): reconcile review repairs and voice stack --- docs/product-technical-gap-baseline.md | 43 +++++++++++++------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 345f2a389..55e235659 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 17 open PRs and 10 open issues. The exact-head +At this snapshot there were 16 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,7 +78,7 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 17 open PRs and 10 +at this refresh. The live queue contains 16 open PRs and 10 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. @@ -87,20 +87,19 @@ context only. | ---: | --- | --- | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #694 | `85fe98da` | preserves overlapping voice classifications and authorized aggregate filters; voice evidence and next actions remain visible when the surrounding Dashboard is pending or failed, concurrent loading uses one live region, and synthetic-only Demo identities cannot enter a real-source denominator. Focused backend/frontend, lint/build/Storybook, PostgreSQL constraint, and 1280×720 visual checks pass. It remains stacked on #693's product-catalog composition, so parent delivery, retargeting, fresh hosted checks, and independent review are required | -| #693 | `ae129154` | restores the missing review/delivery parent for durable semantic embedding and operations-worker changes accumulated after #688 merged into #640; current composition leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, reclaims stale source-hash product analysis, and pins gateway authentication/cadence in regression. It remains stacked directly on #640 pending protected parent delivery | +| #693 | `c4db9437` | restores the missing review/delivery parent for durable semantic embedding, product/voice semantics, and operations-worker changes accumulated after #688/#692/#694 merged into its composition; current code leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, reclaims stale source-hash product analysis, and pins gateway authentication/cadence in regression. It remains stacked directly on #640 pending protected parent delivery | | #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | -| #679 | `5601fea8` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields; BLOCKED with exact-head checks and independent review required | +| #679 | `fdcc7e15` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields. Its stale internal-implementation failure-copy assertions now match the customer-action contract; focused diagnostics/queue tests pass, while fresh exact-head checks and independent review remain required | | #672 | `3f76c189` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence, removes duplicate embedding work, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | -| #668 | `d74139d2` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, and localizes both action and loading guidance in all supported locales. Focused i18n regression and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `897b88e2` | this refresh branch contains merged #691 retry semantics, prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and is merged forward to protected `main@ff7431bd`. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Documentation hygiene and focused tests must pass again on the resulting head; hosted checks and independent approval remain pending | -| #658 | `500a541b` | evidence-honest Global Ask cutoff with robust revision timestamps; BLOCKED with review required | +| #668 | `afb7a19b` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | +| #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #658 | `02bb612a` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state, aligns blank/live guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | -| #643 | `3453ab08` | accessible status notices; BLOCKED with review required | +| #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `19c9c9e4` | dashboard ranking and topic-influence stack now includes bounded semantic backfill jobs, evidence-window fingerprint invalidation for automatic related-source analysis, accepted measurement-owner release pins, localized evidence-rank labels, one topic-journey vocabulary, migration replay safety, id-only Ask citations, and the not-applicable topic state; redundant test lambdas were removed without changing behavior, while exact-head hosted checks and independent review remain required | | #639 | `f6c8c93f` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. Its exact-head Compose image proves the pnpm `allowBuilds` input repair and a regression locks the seed command; fresh hosted checks and independent review remain required | -| #632 | `811026cc` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | +| #632 | `c3c04c49` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | | #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge @@ -115,9 +114,11 @@ delivery. Their acceptance now travels with the two parent heads above. PRs #692 and #697 merged into the non-default #693 composition as `cdd499b161053a9c5439181e8f39e1baa80e68c0` and `dc3ebb6911187637cf85fcbcc036cf39e571aaec`. PR #699 merged into the -non-default #694 composition as `d47aae9f77a3f71c7f91929cb258f6e73d1f6d40`. -Their product-catalog, Python-arithmetic deletion, and Rust-ownership audit -evidence now travels with those open parents; none is protected-main delivery. +non-default #694 composition as `d47aae9f77a3f71c7f91929cb258f6e73d1f6d40`; +#694 then merged into the non-default #693 composition as +`0feb7f72cc34fbd23e8f1bd6355c9a5ee49ded89`. Their product-catalog, +voice taxonomy, Python-arithmetic deletion, and Rust-ownership audit evidence +now travels with open parent #693; none is protected-main delivery. PR #663 merged to protected `main` as merge commit `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`; its project-ontology traversal, @@ -129,11 +130,11 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 17:34 KST found one failure on #679 and no -terminal gate evidence for several queued heads, including #667, #672, #700, -and #701. The failed check needs root-cause repair on its exact head; queued -checks and bot success statuses are not merge evidence. Independent approval -is also required. +The exact-head check-run scan at 17:34 KST found #679's former test failure was +repaired on its new head; no failed conclusion transfers to that head. Several +heads, including #667, #672, #700, and #701, still lack terminal gate evidence. +Queued checks and bot success statuses are not merge evidence, and independent +approval is also required. ### Ecosystem owner-boundary evidence @@ -168,7 +169,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 17 open PRs. The +to divergent filenames across the 16 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -483,7 +484,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 17:34 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Sixteen PRs remain open at the 17:34 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -494,7 +495,7 @@ for wholesale replay from #490. | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish its immutable contract fixture, and add a Naruon consumer that supplies authorized RFC/JMAP-derived turns. Prove ABAC non-disclosure, semantic-only turn retrieval and exact-unit citation, and absence of cross-graph inference on released heads | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | -| Product hierarchy and voice exploration | PR #692 merged only into the non-default #693 composition, which carries its evidence-bound product group/model/variant/trade-item catalog. Stacked #694 carries overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. Neither open parent is protected delivery | Land #693 and then #694 through their ordered protected gates, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | +| Product hierarchy and voice exploration | PRs #692 and #694 merged only into the non-default #693 composition, which now carries the evidence-bound product hierarchy and overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. The open parent is not protected delivery | Land #693 through its protected gate, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | | Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | From fccd5678754edf25373a7e60286d3c55da549665 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:53:44 +0900 Subject: [PATCH 187/238] docs(gaps): reconcile current review and stack heads --- docs/product-technical-gap-baseline.md | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b919dcb14..a0a55c346 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 16 open PRs and 10 open issues. The exact-head +At this snapshot there were 15 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,7 +78,7 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 16 open PRs and 10 +at this refresh. The live queue contains 15 open PRs and 10 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. @@ -87,20 +87,19 @@ context only. | ---: | --- | --- | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #693 | `c4db9437` | restores the missing review/delivery parent for durable semantic embedding, product/voice semantics, and operations-worker changes accumulated after #688/#692/#694 merged into its composition; current code leaves token splitting with the orchestrator's Rust owner, reports event-loop progress instead of PID existence, reclaims stale source-hash product analysis, and pins gateway authentication/cadence in regression. It remains stacked directly on #640 pending protected parent delivery | | #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | -| #679 | `fdcc7e15` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, aggregate-status guidance repair, and rollback protection for truth-owned fields. Its stale internal-implementation failure-copy assertions now match the customer-action contract; focused diagnostics/queue tests pass, while fresh exact-head checks and independent review remain required | -| #672 | `3f76c189` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence, removes duplicate embedding work, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | -| #668 | `afb7a19b` | evidence-bound project history orders by recorded event time, guarantees one deterministic shortest path per predecessor, suppresses false direct handovers across truncated gaps, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | +| #679 | `20faa941` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance renders once, and uncorroborated unavailable/NEI candidates cannot appear as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | +| #672 | `5d2626bb` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | +| #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | | #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | -| #658 | `02bb612a` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state, aligns blank/live guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | +| #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `19c9c9e4` | dashboard ranking and topic-influence stack now includes bounded semantic backfill jobs, evidence-window fingerprint invalidation for automatic related-source analysis, accepted measurement-owner release pins, localized evidence-rank labels, one topic-journey vocabulary, migration replay safety, id-only Ask citations, and the not-applicable topic state; redundant test lambdas were removed without changing behavior, while exact-head hosted checks and independent review remain required | +| #640 | `7adb7a4a` | dashboard ranking and topic-influence stack now includes merged #693: bounded semantic backfill, product/voice semantics, source-hash reclamation, evidence-window invalidation, accepted measurement-owner pins, one topic-journey vocabulary, migration replay safety, and id-only Ask citations. This is non-default stack integration; exact-head hosted checks and independent review remain required | | #639 | `f6c8c93f` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. Its exact-head Compose image proves the pnpm `allowBuilds` input repair and a regression locks the seed command; fresh hosted checks and independent review remain required | -| #632 | `c3c04c49` | graph-fact provenance repair with current baseline evidence; BLOCKED with hosted checks queued and review required | -| #629 | `48496ff6` | provider-work release, bounded reads, and UUID tie-break ordering; BLOCKED with review required | +| #632 | `e93d8140` | graph-fact provenance repair now also restores the token-backed Ask form layout and removes a duplicate Storybook ontology table split; frontend lint and 390 tests pass, while hosted checks and independent review remain required | +| #629 | `b2bc72c1` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, and persist each completed result before a later provider failure; focused tests pass, while hosted checks and independent review remain required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge commits `9d4210c04fb0aeec17e885bed097f400c7018269`, @@ -118,7 +117,8 @@ non-default #694 composition as `d47aae9f77a3f71c7f91929cb258f6e73d1f6d40`; #694 then merged into the non-default #693 composition as `0feb7f72cc34fbd23e8f1bd6355c9a5ee49ded89`. Their product-catalog, voice taxonomy, Python-arithmetic deletion, and Rust-ownership audit evidence -now travels with open parent #693; none is protected-main delivery. +traveled with #693 and now travels with open parent #640 after #693 merged +there as `7adb7a4a9712f2f56a7291d437225a1227debbf8`; none is protected-main delivery. PR #663 merged to protected `main` as merge commit `faff7a32cf9b3c81fefa2814b6f30a0a3ba4e58f`; its project-ontology traversal, @@ -169,7 +169,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 16 open PRs. The +to divergent filenames across the 15 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -484,7 +484,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Sixteen PRs remain open at the 17:34 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Fifteen PRs remain open at the 17:34 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -495,7 +495,7 @@ for wholesale replay from #490. | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | | Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish its immutable contract fixture, and add a Naruon consumer that supplies authorized RFC/JMAP-derived turns. Prove ABAC non-disclosure, semantic-only turn retrieval and exact-unit citation, and absence of cross-graph inference on released heads | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | -| Product hierarchy and voice exploration | PRs #692 and #694 merged only into the non-default #693 composition, which now carries the evidence-bound product hierarchy and overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. The open parent is not protected delivery | Land #693 through its protected gate, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | +| Product hierarchy and voice exploration | PRs #692 and #694 merged into #693, then #693 merged only into non-default parent #640. That stack carries the evidence-bound product hierarchy and overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. The open parent is not protected delivery | Land #640 through its protected gate, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | | Source-code lookup UX | Source state/detail codes remain evidence-bearing machine values and current detail presentation is dense | Catalog-backed display labels with raw-code provenance, compact 5W1H/source-detail hierarchy, keyboard access, and no unsupported customer/project binding | | Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | From aea7deb20f644ca9e1116a0024789f2476c5177d Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 17:58:49 +0900 Subject: [PATCH 188/238] docs(gaps): refresh exact-head queue evidence --- docs/product-technical-gap-baseline.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a0a55c346..bb5a33d36 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 17:34 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 17:56 KST. Protected `main` is > `ff7431bd1851c03e737808d22c6a2d43968582f9`. This local branch is not > protected-main release evidence. @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 17:36 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 17:56 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, @@ -89,7 +89,7 @@ context only. | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | | #679 | `20faa941` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance renders once, and uncorroborated unavailable/NEI candidates cannot appear as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | -| #672 | `5d2626bb` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Review threads are resolved; hosted checks and independent review remain required | +| #672 | `b464e883` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | | #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | @@ -98,8 +98,8 @@ context only. | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `7adb7a4a` | dashboard ranking and topic-influence stack now includes merged #693: bounded semantic backfill, product/voice semantics, source-hash reclamation, evidence-window invalidation, accepted measurement-owner pins, one topic-journey vocabulary, migration replay safety, and id-only Ask citations. This is non-default stack integration; exact-head hosted checks and independent review remain required | | #639 | `f6c8c93f` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. Its exact-head Compose image proves the pnpm `allowBuilds` input repair and a regression locks the seed command; fresh hosted checks and independent review remain required | -| #632 | `e93d8140` | graph-fact provenance repair now also restores the token-backed Ask form layout and removes a duplicate Storybook ontology table split; frontend lint and 390 tests pass, while hosted checks and independent review remain required | -| #629 | `b2bc72c1` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, and persist each completed result before a later provider failure; focused tests pass, while hosted checks and independent review remain required | +| #632 | `4f1dfd01` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Hosted checks and independent review remain required | +| #629 | `c00b571c` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge commits `9d4210c04fb0aeec17e885bed097f400c7018269`, @@ -130,7 +130,7 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 17:34 KST found #679's former test failure was +The exact-head check-run scan at 17:56 KST found #679's former test failure was repaired on its new head; no failed conclusion transfers to that head. Several heads, including #667, #672, #700, and #701, still lack terminal gate evidence. Queued checks and bot success statuses are not merge evidence, and independent @@ -484,7 +484,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Fifteen PRs remain open at the 17:34 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Fifteen PRs remain open at the 17:56 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 060f9e354c1dd13940d381f026592b80295cebe8 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:03:37 +0900 Subject: [PATCH 189/238] docs(gaps): refresh exact PR heads --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index bb5a33d36..dff26d2a5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -87,9 +87,9 @@ context only. | ---: | --- | --- | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #680 | `95f8feee` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | -| #679 | `20faa941` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance renders once, and uncorroborated unavailable/NEI candidates cannot appear as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | -| #672 | `b464e883` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | +| #680 | `6a9a3dec` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | +| #679 | `7dfff363` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance renders once, and uncorroborated unavailable/NEI candidates cannot appear as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | +| #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | | #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | From 6adf1e3cb9749f6cfe62dde4fb632982fa886782 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:07:02 +0900 Subject: [PATCH 190/238] docs(gaps): record PR 639 merge repair --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index dff26d2a5..be2d7a003 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -97,7 +97,7 @@ context only. | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `7adb7a4a` | dashboard ranking and topic-influence stack now includes merged #693: bounded semantic backfill, product/voice semantics, source-hash reclamation, evidence-window invalidation, accepted measurement-owner pins, one topic-journey vocabulary, migration replay safety, and id-only Ask citations. This is non-default stack integration; exact-head hosted checks and independent review remain required | -| #639 | `f6c8c93f` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. Its exact-head Compose image proves the pnpm `allowBuilds` input repair and a regression locks the seed command; fresh hosted checks and independent review remain required | +| #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | | #632 | `4f1dfd01` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Hosted checks and independent review remain required | | #629 | `c00b571c` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | From 50703c15ab3f93d43f21ac0fcafc205a61de32ea Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:07:38 +0900 Subject: [PATCH 191/238] docs(gaps): refresh graph provenance head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index be2d7a003..5ceebe671 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -98,7 +98,7 @@ context only. | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `7adb7a4a` | dashboard ranking and topic-influence stack now includes merged #693: bounded semantic backfill, product/voice semantics, source-hash reclamation, evidence-window invalidation, accepted measurement-owner pins, one topic-journey vocabulary, migration replay safety, and id-only Ask citations. This is non-default stack integration; exact-head hosted checks and independent review remain required | | #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | -| #632 | `4f1dfd01` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Hosted checks and independent review remain required | +| #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `c00b571c` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge From 14d6df29991bc8c6f164899529f5c526f20764f6 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:16:05 +0900 Subject: [PATCH 192/238] docs(gaps): refresh repaired PR heads --- 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 5ceebe671..83cf6fcba 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -87,7 +87,7 @@ context only. | ---: | --- | --- | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #680 | `6a9a3dec` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. The merge-forward head passes 77 focused i18n/component tests and lint; fresh exact-head hosted checks and independent review are required | +| #680 | `cd2cfb81` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source guidance and recommendation-versus-ranking labels now agree across locales; lint and 64 i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `7dfff363` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance renders once, and uncorroborated unavailable/NEI candidates cannot appear as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | @@ -99,7 +99,7 @@ context only. | #640 | `7adb7a4a` | dashboard ranking and topic-influence stack now includes merged #693: bounded semantic backfill, product/voice semantics, source-hash reclamation, evidence-window invalidation, accepted measurement-owner pins, one topic-journey vocabulary, migration replay safety, and id-only Ask citations. This is non-default stack integration; exact-head hosted checks and independent review remain required | | #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | -| #629 | `c00b571c` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | +| #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge commits `9d4210c04fb0aeec17e885bed097f400c7018269`, From 55ef163376dd355848ae554bdbfe4f6933511d74 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:25:28 +0900 Subject: [PATCH 193/238] docs(gaps): record scheduler and broken stack head --- docs/product-technical-gap-baseline.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 83cf6fcba..d7b08e61a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -96,7 +96,7 @@ context only. | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `7adb7a4a` | dashboard ranking and topic-influence stack now includes merged #693: bounded semantic backfill, product/voice semantics, source-hash reclamation, evidence-window invalidation, accepted measurement-owner pins, one topic-journey vocabulary, migration replay safety, and id-only Ask citations. This is non-default stack integration; exact-head hosted checks and independent review remain required | +| #640 | `93c5b6f6` | dashboard ranking and topic-influence stack was merged with current main, but the merge resolution dropped required Ask imports/provenance fields and mixed worker, MCP, cutoff, verification, and timeline contracts; focused pytest cannot collect. Auto-merge is disabled until those exact-head regressions are repaired and the composed contracts are retested | | #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -316,10 +316,11 @@ requires the ADR 0001 incident process and security/privacy-owner coordination; never force-push or delete evidence ad hoc. The repository-owned hourly commercialization loop and the central thin GitHub -Actions caller ContextualWisdomLab/.github#1288 (current head `428e31a0`, minute +Actions caller ContextualWisdomLab/.github#1288 (current head `c78ae017`, minute 4, `pr-review-fix-scheduler.yml`) both target this repository. The central candidate now reaches model execution through a pinned contextual-orchestrator -sidecar and exposes only its loopback gateway contract to OpenCode. PR #1259 is the +sidecar, exposes only its loopback gateway contract to OpenCode, and requires +customer next-action copy without rendered implementation boundaries. PR #1259 is the closed predecessor and must not be treated as current scheduler evidence. Do not add a LineageWeave-local duplicate workflow. ContextualWisdomLab/.github#1258 merged at exact head `897819c4` to repair the pnpm/coverage-evidence workflow; @@ -502,7 +503,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 proposes the relation-safe, content-addressed Rust period artifact on #1417. RankWeave #41 (`8e75aa11`) now composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 exact head `517e0f28` proposes the relation-safe, content-addressed Rust period artifact on #1417 and remains Draft until its enumerated recovery evidence exists. RankWeave #41 (`8e75aa11`) now composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | @@ -549,7 +550,7 @@ of leverage; open connector PRs there when the defect is upstream: 6. **ThreadWeave** — tree assembly. 7. **Naruon** — calendar projection delivered through merged #355/closed #336; email/project lineage projection remains open as #338. 8. **DiskSage / wardnet** — storage and network policy as needed. -9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1288, current head `428e31a0`). Its current-main reconciliation preserves the pinned contextual-orchestrator sidecar, loopback gateway contract, provider-key isolation, and existing review/OIDC mutation credentials; 180 focused tests and actionlint pass, while exact-head hosted checks and independent re-review remain pending. If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. +9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1288, current head `c78ae017`). Its current-main reconciliation preserves the pinned contextual-orchestrator sidecar, loopback gateway contract, provider-key isolation, existing review/OIDC mutation credentials, and the action-oriented customer-copy rule; 67 focused central tests pass, while exact-head hosted checks and independent re-review remain pending. If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. ## 8. Public ontology publication boundary From 8707db56edf3b385094594839ff4d165be976e42 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:26:23 +0900 Subject: [PATCH 194/238] docs(gaps): refresh customer-copy repair heads --- 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 d7b08e61a..6d3c45088 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -87,8 +87,8 @@ context only. | ---: | --- | --- | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | -| #680 | `cd2cfb81` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source guidance and recommendation-versus-ranking labels now agree across locales; lint and 64 i18n checks pass. Fresh exact-head hosted checks and independent review are required | -| #679 | `7dfff363` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance renders once, and uncorroborated unavailable/NEI candidates cannot appear as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | +| #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | +| #679 | `077b8be7` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | | #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | From 93e45baa83432db3ec1e852263d6858e65ce2da0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:28:57 +0900 Subject: [PATCH 195/238] docs(gaps): record frontend split reconciliation --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6d3c45088..b85f2610d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -94,7 +94,7 @@ context only. | #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | -| #644 | `f11e77d1` | native-surface code splitting; BLOCKED with review required | +| #644 | `b116128e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `93c5b6f6` | dashboard ranking and topic-influence stack was merged with current main, but the merge resolution dropped required Ask imports/provenance fields and mixed worker, MCP, cutoff, verification, and timeline contracts; focused pytest cannot collect. Auto-merge is disabled until those exact-head regressions are repaired and the composed contracts are retested | | #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | From 760dffa80e4689b4f94169b994b2613a925b512c Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:36:06 +0900 Subject: [PATCH 196/238] docs(gaps): add source coverage and stack evidence --- docs/product-technical-gap-baseline.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b85f2610d..5b47c3188 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,7 +61,7 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 15 open PRs and 10 open issues. The exact-head +At this snapshot there were 16 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, @@ -78,13 +78,14 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 15 open PRs and 10 +at this refresh. The live queue contains 16 open PRs and 10 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 | | ---: | --- | --- | +| #702 | `766568b0` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and records only aggregate coverage evidence. Eighty-five focused import/audit/ontology checks pass; the authenticated aggregate audit reports no fully covered record rather than substituting titles or claiming failed provider windows. Protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | @@ -96,7 +97,7 @@ context only. | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `b116128e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `93c5b6f6` | dashboard ranking and topic-influence stack was merged with current main, but the merge resolution dropped required Ask imports/provenance fields and mixed worker, MCP, cutoff, verification, and timeline contracts; focused pytest cannot collect. Auto-merge is disabled until those exact-head regressions are repaired and the composed contracts are retested | +| #640 | `ca3b9e79` | dashboard ranking and topic-influence stack was merged with current main. A concurrent repair restored the core Ask evidence/status contract and test import, but exact-head audit still finds missing ontology imports and packaged-Turtle parity, fixture transaction semantics, MCP Compose profile, cutoff/public-verification rendering, and service imports. Auto-merge is disabled until those regressions are repaired and the composed contracts are retested | | #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | From 715632dea9fd93bb938cc099b2f3f798e358f7b4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:42:03 +0900 Subject: [PATCH 197/238] docs(gaps): record repaired dashboard stack --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5b47c3188..04ee12c4e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -97,7 +97,7 @@ context only. | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `b116128e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `ca3b9e79` | dashboard ranking and topic-influence stack was merged with current main. A concurrent repair restored the core Ask evidence/status contract and test import, but exact-head audit still finds missing ontology imports and packaged-Turtle parity, fixture transaction semantics, MCP Compose profile, cutoff/public-verification rendering, and service imports. Auto-merge is disabled until those regressions are repaired and the composed contracts are retested | +| #640 | `4c6fca15` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and cutoff/public-verification and retained-revision evidence in the current timeline UI. Backend/Ask/schema/ontology/Compose/k6 checks pass 104 with 2 skipped; frontend lint and 414 tests plus Compose validation pass. Exact-head hosted checks and independent review remain required | | #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | From 76969f3806566431b7815e0989306858b8285aa8 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:45:09 +0900 Subject: [PATCH 198/238] docs(gaps): refresh reconciled stack heads --- 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 04ee12c4e..b077cc217 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -95,10 +95,10 @@ context only. | #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | -| #644 | `b116128e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | +| #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `4c6fca15` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and cutoff/public-verification and retained-revision evidence in the current timeline UI. Backend/Ask/schema/ontology/Compose/k6 checks pass 104 with 2 skipped; frontend lint and 414 tests plus Compose validation pass. Exact-head hosted checks and independent review remain required | -| #639 | `fac30fc4` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; 16 focused checks pass. Fresh exact-head hosted checks and independent review remain required | +| #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | From 3e432b4137bb2a07e2721ac58484b1e53a8a0b29 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 18:51:58 +0900 Subject: [PATCH 199/238] docs(gap): refresh exact-head owner evidence --- docs/product-technical-gap-baseline.md | 45 +++++++++++++++----------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b077cc217..6aed20ec5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,6 @@ # Product & Technical Gap Baseline -> Dashboard delivery snapshot: 2026-08-26 17:56 KST. Protected `main` is +> Dashboard delivery snapshot: 2026-08-26 18:51 KST. Protected `main` is > `ff7431bd1851c03e737808d22c6a2d43968582f9`. This local branch is not > protected-main release evidence. @@ -16,7 +16,7 @@ | Natural-language Ask with evidence, report, alert, MCP | Persisted semantic-unit embeddings plus versioned delivery/resource contract | Candidate implementation uses whole-question embedding retrieval with no lexical fallback; authenticated runtime acceptance pending | | Per-post Ask continuity | ADR 0235; account/post-scoped normalized sessions and current-authorization citation projection | PR #677 merged into the non-default baseline branch as `80c59672`; retarget to `main` and revalidate after protected parent delivery | | Similar VOC, customer cohort, prior action | Persisted repeat-issue candidate semantics plus orchestrator pair adjudication and extractive evidence | Candidate live post endpoint and post-detail UI implemented; authenticated runtime acceptance pending | -| TEPP independent Event Lineage anchor | Accepted, persisted TEPP criterion bound to exact snapshot/cutoff before fast-mlsirm activation | Consumer PR #606 is on protected main; TEPP producer PR #237 remains open, so no end-to-end accepted artifact is release evidence yet | +| TEPP independent Event Lineage anchor | Accepted, persisted TEPP criterion bound to exact snapshot/cutoff before fast-mlsirm activation | Consumer PR #606 and TEPP contract PR #237 are on their protected main branches; #237 intentionally publishes the fail-closed wire contract without an estimator, so no emitted, digest-bound terminal artifact is release evidence yet | | Temporal Lineage topics and multilevel important posts | ADR 0210; TEPP posterior topic/plausible-value contract followed by fast-mlsirm observed-information case-deletion influence | Product/technical contract is protected on `main`; neither required Rust CPU/GPU producer envelope is shipped, so the Dashboard surface remains unavailable (ADR 0208: no local Python substitute) | ### Technical contract and flow @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 17:56 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 18:51 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, @@ -85,19 +85,19 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #702 | `766568b0` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and records only aggregate coverage evidence. Eighty-five focused import/audit/ontology checks pass; the authenticated aggregate audit reports no fully covered record rather than substituting titles or claiming failed provider windows. Protected hosted checks and independent review remain required | +| #702 | `e04249e7` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, records only aggregate coverage evidence, and makes SHACL validation independent of a developer checkout path. Eighty-five focused import/audit/ontology checks pass; the authenticated aggregate audit reports no fully covered record rather than substituting titles or claiming failed provider windows. Protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | -| #679 | `077b8be7` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | +| #679 | `866c46d0` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance remains present on plain answers, renders once, prevents uncorroborated unavailable/NEI candidates from appearing as external evidence, and removes unused implementation-facing verification copy. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `f0314cc3` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `76969f38` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `4c6fca15` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and cutoff/public-verification and retained-revision evidence in the current timeline UI. Backend/Ask/schema/ontology/Compose/k6 checks pass 104 with 2 skipped; frontend lint and 414 tests plus Compose validation pass. Exact-head hosted checks and independent review remain required | +| #640 | `d784135a` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and cutoff/public-verification and retained-revision evidence in the current timeline UI. Backend/Ask/schema/ontology/Compose/k6 checks pass 104 with 2 skipped; frontend lint and 414 tests plus Compose validation pass. Exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -131,28 +131,37 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 17:56 KST found #679's former test failure was -repaired on its new head; no failed conclusion transfers to that head. Several -heads, including #667, #672, #700, and #701, still lack terminal gate evidence. -Queued checks and bot success statuses are not merge evidence, and independent -approval is also required. +The exact-head check-run scan at 18:51 KST found no failed conclusion on any +current head. Every head still had queued or in-progress gates; #702 had one +unresolved review threads while the other fifteen had none. No current head +had an exact-head independent approval. Queued checks and bot success statuses +are not merge evidence. ### Ecosystem owner-boundary evidence - `ContextualWisdomLab/contextual-orchestrator` PR #857 exact head - `4dcf952a` owns provider-backed embedding discovery, selection, execution, + `dc5ed7a1` owns provider-backed embedding discovery, selection, execution, durable batching, session propagation, and Rust token/vector arithmetic. Its required hosted checks were queued at this snapshot. LineageWeave may request embeddings and preserve an orchestrator-returned session model pin; it must not configure `LLM_GATEWAY_EMBEDDING_MODEL`, infer a provider from a model name, or present #857 as delivered before its protected merge. -- `ContextualWisdomLab/RankWeave` PR #41 exact head `8e75aa11` contains the +- `ContextualWisdomLab/RankWeave` PR #41 exact head `e95ed46f` contains the proposed Rust calculation core and the semantic-unit ranking feature merged from stacked PR #48 (`f3cd7ed7`). PR #48 is therefore stack-integration evidence only; #41's new exact head has queued hosted checks and no protected-main merge evidence. LineageWeave may consume the owner contract only after that composed head passes its protected gate; it may not retain Python vector arithmetic. +- `ContextualWisdomLab/fast-mlsirm` draft PR #1436 exact head `517e0f28` + specifies the Rust-owned, content-addressed polytomous period artifact on + non-default parent #1417. Its queued owner checks and missing enumerated + recovery evidence make it proposal evidence only, not a consumable artifact. +- `ContextualWisdomLab/TEPP` PR #237 merged to protected `main` as + `eec86be724e9131ecfe8f152db0f7728af68017f`. It publishes the fail-closed + lineage-criterion anchor wire contract but explicitly does not implement the + estimator; LineageWeave must keep weights unavailable until TEPP emits the + digest-bound terminal artifact. No row above is merge evidence. Immediately before any lifecycle action, re-fetch the head, unresolved threads, formal reviews, rulesets, and same-head @@ -170,7 +179,7 @@ ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 15 open PRs. The +to divergent filenames across the 16 open PRs. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed @@ -486,7 +495,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Fifteen PRs remain open at the 17:56 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Sixteen PRs remain open at the 18:51 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -503,8 +512,8 @@ for wholesale replay from #490. | Calendar / Naruon | #355 and closed issue #336 delivered the consumer projection and v2.17.0 operator wiring without forwarding the end-user token. Cross-repository email/project lineage issue #338 remains open; producer/consumer runtime fixtures are not protected release evidence | Verify observed events against the published schema without invented events; keep commitments available when the channel is unwired | | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | -| Scientific measurement | Durable accepted TEPP receipts and LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer are protected; TEPP #237 remains open, so no registered producer artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Land TEPP #237 through its protected gate, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 exact head `517e0f28` proposes the relation-safe, content-addressed Rust period artifact on #1417 and remains Draft until its enumerated recovery evidence exists. RankWeave #41 (`8e75aa11`) now composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Scientific measurement | Durable accepted TEPP receipts, LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer, and TEPP #237's criterion-anchor wire contract are protected. #237 intentionally does not implement the estimator, so no emitted digest-bound terminal artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Implement and verify the TEPP estimator behind the protected #237 contract, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 exact head `517e0f28` proposes the relation-safe, content-addressed Rust period artifact on #1417 and remains Draft until its enumerated recovery evidence exists. RankWeave #41 (`e95ed46f`) now composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | From cac8bf05ed157d0be4cc11e278496d335cc36fc7 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:04:31 +0900 Subject: [PATCH 200/238] docs(gaps): bind semantic coverage evidence --- docs/product-technical-gap-baseline.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6aed20ec5..24c834c7b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,19 +85,19 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #702 | `e04249e7` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, records only aggregate coverage evidence, and makes SHACL validation independent of a developer checkout path. Eighty-five focused import/audit/ontology checks pass; the authenticated aggregate audit reports no fully covered record rather than substituting titles or claiming failed provider windows. Protected hosted checks and independent review remain required | +| #702 | `b439c8e2` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. Protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `866c46d0` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance remains present on plain answers, renders once, prevents uncorroborated unavailable/NEI candidates from appearing as external evidence, and removes unused implementation-facing verification copy. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `76969f38` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `3e432b41` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `d784135a` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and cutoff/public-verification and retained-revision evidence in the current timeline UI. Backend/Ask/schema/ontology/Compose/k6 checks pass 104 with 2 skipped; frontend lint and 414 tests plus Compose validation pass. Exact-head hosted checks and independent review remain required | +| #640 | `c15b2ec4` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Focused authorization checks pass; exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -501,10 +501,11 @@ for wholesale replay from #490. | 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 | +| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered selected-unit membership is bound to the caller's probability strata and the digest-bound fast-mlsirm Rust sample-size artifact; any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. The observed 80-record deterministic window proves pipeline cardinality only, so corpus inference is unavailable | Produce the independently versioned Rust owner artifact and caller manifest with population/frame size, known inclusion probabilities, frame and membership digests, prior-evidence reference, and retained-failure declaration. Retry failed selected members in place; emit a non-identifying coverage aggregate only after every declared member succeeds | | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. On PR #639 exact head `f6c8c93f`, a local 4-VU/30-second synthetic authenticated run completed 4,650 iterations (152.21/s), 13,952 requests (456.71/s), and zero failed requests. Ask enqueue was 74.90 ms; Ask polling p95 was 29.94 ms; combined post/lineage reads were 23.22 ms average and 40.88 ms p95. The one Ask job settled `succeeded`. A mid-run sample observed backend CPU 98.03%, PostgreSQL CPU 107.59%, Valkey 1.90% with zero rejected connections/evictions, and orchestrator 0.47%; PostgreSQL showed no lock wait. This names CPU pressure at the application/database boundary but does not establish a latency bottleneck, capacity limit, or SLO. The first PR #629 image build also reproduced the pnpm 11 ignored-build failure; PR #639's workspace-policy copy fixes that owned Compose contract and now locks the seed extras in regression. PR #629 exact head `48496ff6` still moves Global Ask question embedding before `pool.acquire()` and remains blocked on independent review | Land #639 and #629 through their protected gates, repeat this declared workload on their merge heads with endpoint-separated trends and repeated resource samples, then increase concurrency only until an observed latency/error knee identifies a bottleneck. Retain raw distributions and resource configuration; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | -| Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish its immutable contract fixture, and add a Naruon consumer that supplies authorized RFC/JMAP-derived turns. Prove ABAC non-disclosure, semantic-only turn retrieval and exact-unit citation, and absence of cross-graph inference on released heads | +| Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. The reference is write-only: repository search finds it in import/chunk/persistence paths but no authorized read projection or API response, so a user cannot yet open the exact source evidence behind a cited turn. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, then define an ADR-governed read contract that returns or resolves the opaque reference only for an authorized semantic unit and guides the user to open its source evidence. Publish the immutable producer fixture, add a Naruon RFC/JMAP-derived consumer, and prove ABAC non-disclosure, exact-unit citation, safe source resolution, and absence of cross-graph inference on released heads | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Product hierarchy and voice exploration | PRs #692 and #694 merged into #693, then #693 merged only into non-default parent #640. That stack carries the evidence-bound product hierarchy and overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. The open parent is not protected delivery | Land #640 through its protected gate, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | From 1e180c5e3305e343d2c7a65db428815747c1abbb Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:20:36 +0900 Subject: [PATCH 201/238] docs(gaps): refresh repaired PR heads --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 24c834c7b..b2a5e199a 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -87,13 +87,13 @@ context only. | ---: | --- | --- | | #702 | `b439c8e2` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. Protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | -| #700 | `28f7ec9d` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | +| #700 | `495b4504` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | -| #679 | `866c46d0` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. Customer guidance remains present on plain answers, renders once, prevents uncorroborated unavailable/NEI candidates from appearing as external evidence, and removes unused implementation-facing verification copy. Backend/frontend/lint checks pass locally; fresh exact-head checks and independent review remain required | +| #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | | #667 | pre-documentation parent `3e432b41` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | -| #658 | `6813894e` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. Backend/frontend/lint/build checks pass locally; exact-head hosted checks and independent review remain required | +| #658 | `95708d59` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head also restores the exact documented missing-cover contract after the hosted full-suite regression exposed it. Focused revision tests pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | From 6e362f9dc1c2054f4b73e34575ad3b517edd3ddb Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:23:14 +0900 Subject: [PATCH 202/238] fix(chat): fence delayed answers by post --- docs/product-technical-gap-baseline.md | 4 ++-- frontend/src/App.tsx | 8 ++++++- frontend/src/ChatPanel.test.tsx | 31 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b2a5e199a..4a186bfcb 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -92,12 +92,12 @@ context only. | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `3e432b41` | this refresh branch prevents stale conversation pagination/recovery from contaminating a replacement conversation, enforces both-or-neither cursor validation, applies the shared source-eligibility boundary, includes ADR 0237's accelerator boundary, and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `1e180c5e` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `95708d59` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head also restores the exact documented missing-cover contract after the hosted full-suite regression exposed it. Focused revision tests pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `c15b2ec4` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Focused authorization checks pass; exact-head hosted checks and independent review remain required | +| #640 | `26bfea65` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head also gives the source-preserving voice taxonomy a collision-free ADR/migration identity. Focused authorization checks pass; exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c316e30e7..7bdcef955 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -294,11 +294,13 @@ export function ChatPanel({ const [seededOnly, setSeededOnly] = useState(false); const conversationListRequest = useRef(0); const conversationRequest = useRef(0); + const askRequest = useRef(0); useEffect(() => { let active = true; ++conversationListRequest.current; ++conversationRequest.current; + ++askRequest.current; setExchanges([]); setSeededExchanges([]); setConversations([]); @@ -308,6 +310,7 @@ export function ChatPanel({ setConversationOlderCursor(null); setAnswer(null); setError(null); + setLoading(false); setSeededOnly(false); setEvidencePostId(null); fetchPostChat(accessToken, postId) @@ -358,11 +361,13 @@ export function ChatPanel({ async function handleAsk(asked = question) { if (!asked.trim()) return; + const requestId = ++askRequest.current; const requestedConversationId = conversationId; setLoading(true); setError(null); try { const result = await askPostChat(accessToken, postId, asked, requestedConversationId); + if (requestId !== askRequest.current) return; const startsConversation = requestedConversationId === null || (result.conversation_id !== undefined && result.conversation_id !== requestedConversationId); setAnswer(result); @@ -390,12 +395,13 @@ export function ChatPanel({ return startsConversation ? [next] : [...prev, next]; }); } catch (err) { + if (requestId !== askRequest.current) return; setError(orchestratorUnavailableMessage(err, "Chat")); if (err instanceof BackendError && err.status === 503) { setSeededOnly(true); } } finally { - setLoading(false); + if (requestId === askRequest.current) setLoading(false); } } diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 903d317e2..68c0fc92c 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -231,6 +231,37 @@ describe("ChatPanel conversation history", () => { expect(screen.getByLabelText("Conversation history")).toHaveValue(""); }); + it("discards an answer response after moving to another post", async () => { + let resolveOldAnswer!: (response: Response) => void; + vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => { + const url = input instanceof Request ? input.url : String(input); + if (url.endsWith("post-1/chat") && init?.method === "POST") { + return new Promise((resolve) => { resolveOldAnswer = resolve; }); + } + if (url.endsWith("/chat/conversations")) { + return jsonResponse({ conversations: [], next_cursor: null }); + } + return jsonResponse({ post_id: url.includes("post-2") ? "post-2" : "post-1", exchanges: [] }); + })); + + const view = render(); + await userEvent.type( + await screen.findByPlaceholderText("What happened between these events?"), + "Old post question", + ); + await userEvent.click(screen.getByRole("button", { name: "Ask" })); + view.rerender(); + resolveOldAnswer(jsonResponse({ + answer_text: "Stale old-post answer", + cited_post_ids: [], + cited_posts: [], + conversation_id: "old-post-conversation", + })); + + await waitFor(() => expect(screen.queryByText("Stale old-post answer")).toBeNull()); + expect(screen.getByRole("button", { name: "Ask" })).toBeEnabled(); + }); + it("discards an earlier-page response after moving to another post", async () => { let resolveOlder!: (response: Response) => void; vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { From 1754b2c2fa670bb47b050f2ff78e3dc01a6467d3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:26:19 +0900 Subject: [PATCH 203/238] docs(gaps): refresh chat review heads --- 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 4a186bfcb..48a627a87 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -92,8 +92,8 @@ context only. | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `1e180c5e` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | -| #658 | `95708d59` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head also restores the exact documented missing-cover contract after the hosted full-suite regression exposed it. Focused revision tests pass locally; exact-head hosted checks and independent review remain required | +| #667 | pre-documentation parent `6e362f9d` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #658 | `0ae09b83` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract after the hosted full-suite regression and renders the unavailable cutoff title through the active locale instead of exposing the backend placeholder. Focused revision/frontend tests and lint pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | From 657dda0d03b39f417a09f07f9a94da1b61989218 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:34:10 +0900 Subject: [PATCH 204/238] docs(gaps): sync worker and Rust owner evidence --- docs/product-technical-gap-baseline.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 48a627a87..8411754ae 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -92,12 +92,12 @@ context only. | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `6e362f9d` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `1754b2c2` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `0ae09b83` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract after the hosted full-suite regression and renders the unavailable cutoff title through the active locale instead of exposing the backend placeholder. Focused revision/frontend tests and lint pass locally; exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `26bfea65` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head also gives the source-preserving voice taxonomy a collision-free ADR/migration identity. Focused authorization checks pass; exact-head hosted checks and independent review remain required | +| #640 | `58659cbd` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head gives the source-preserving voice taxonomy a collision-free ADR/migration identity and makes canonical API startup depend on the progress-healthy durable worker without moving queue consumers back into the API process. Thirteen focused ownership/Compose/health/documentation checks pass; exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -153,10 +153,13 @@ are not merge evidence. protected-main merge evidence. LineageWeave may consume the owner contract only after that composed head passes its protected gate; it may not retain Python vector arithmetic. -- `ContextualWisdomLab/fast-mlsirm` draft PR #1436 exact head `517e0f28` - specifies the Rust-owned, content-addressed polytomous period artifact on - non-default parent #1417. Its queued owner checks and missing enumerated - recovery evidence make it proposal evidence only, not a consumable artifact. +- `ContextualWisdomLab/fast-mlsirm` draft PR #1445 exact head `a0131c02` + supplies current owner evidence for the Rust-owned, content-addressed + polytomous period artifact: four Rust-core tests, seven Python-boundary tests, + and 25 documentation/governance tests pass alongside `cargo check`, wheel + build, and Ruff. The PR remains Draft with hosted checks queued, so this is + owner-candidate evidence rather than a protected released artifact; corpus + inference remains unavailable until that artifact passes its protected gate. - `ContextualWisdomLab/TEPP` PR #237 merged to protected `main` as `eec86be724e9131ecfe8f152db0f7728af68017f`. It publishes the fail-closed lineage-criterion anchor wire contract but explicitly does not implement the @@ -514,7 +517,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts, LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer, and TEPP #237's criterion-anchor wire contract are protected. #237 intentionally does not implement the estimator, so no emitted digest-bound terminal artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Implement and verify the TEPP estimator behind the protected #237 contract, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1436 exact head `517e0f28` proposes the relation-safe, content-addressed Rust period artifact on #1417 and remains Draft until its enumerated recovery evidence exists. RankWeave #41 (`e95ed46f`) now composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1417/#1436 before replacing period arithmetic. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm Draft #1445 exact head `a0131c02` supplies four Rust-core, seven Python-boundary, and 25 documentation/governance passing tests plus `cargo check`, wheel-build, and Ruff evidence for its relation-safe content-addressed owner artifact, but queued hosted checks and Draft status make it unavailable for corpus inference. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 through its protected gate before replacing period arithmetic or claiming corpus inference. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | From b4bfb70ffee5addb73bae4dd84cea4717e84eebe Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:50:07 +0900 Subject: [PATCH 205/238] docs(gaps): sync protected queue exact heads --- docs/product-technical-gap-baseline.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 8411754ae..4c4d549d3 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,19 +85,20 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #702 | `b439c8e2` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. Protected hosted checks and independent review remain required | +| #702 | `e8fd06cc` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head removes evidence-length heuristics and refreshes this evidence ledger; protected hosted checks, three informational review threads, and independent review remain open | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `495b4504` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | | #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `1754b2c2` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | -| #658 | `0ae09b83` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract after the hosted full-suite regression and renders the unavailable cutoff title through the active locale instead of exposing the backend placeholder. Focused revision/frontend tests and lint pass locally; exact-head hosted checks and independent review remain required | +| #667 | pre-documentation parent `657dda0d` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `58659cbd` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head gives the source-preserving voice taxonomy a collision-free ADR/migration identity and makes canonical API startup depend on the progress-healthy durable worker without moving queue consumers back into the API process. Thirteen focused ownership/Compose/health/documentation checks pass; exact-head hosted checks and independent review remain required | +| #640 | `0b906a95` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head keeps the durable worker as the owner while health-gating canonical API startup and adds structured operations-case validation evidence; exact-head hosted checks and independent review remain required | +| #703 | `ff536af9` | stacked on #640, preserves bounded post-content failure provenance without copying provider payloads or source content, requires structured operations-case responses, records validation codes through the worker-owned durable ledger, and binds incomplete-evidence failures to the content-persistence stage and existing post session. The current #640 parent is merged normally into the child. Ninety-two focused worker, schema, Compose, migration, and documentation tests pass; review threads are resolved and auto-merge is requested, while protected hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | From 958eb2af3641aae2e47248f9a849e852ff80db5e Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 19:52:35 +0900 Subject: [PATCH 206/238] docs(gaps): record merged provenance child --- 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 4c4d549d3..2f5e18984 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -97,8 +97,8 @@ context only. | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `0b906a95` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head keeps the durable worker as the owner while health-gating canonical API startup and adds structured operations-case validation evidence; exact-head hosted checks and independent review remain required | -| #703 | `ff536af9` | stacked on #640, preserves bounded post-content failure provenance without copying provider payloads or source content, requires structured operations-case responses, records validation codes through the worker-owned durable ledger, and binds incomplete-evidence failures to the content-persistence stage and existing post session. The current #640 parent is merged normally into the child. Ninety-two focused worker, schema, Compose, migration, and documentation tests pass; review threads are resolved and auto-merge is requested, while protected hosted checks and independent review remain required | +| #640 | `b08c4f05` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head keeps the durable worker as the owner while health-gating canonical API startup, adds structured operations-case validation evidence, and binds incomplete-evidence failures to the content-persistence stage and existing post session. Twenty-seven focused worker tests pass; exact-head hosted checks and independent review remain required | +| #703 | merged into #640 as `4ecb4983` | preserves bounded post-content failure provenance without copying provider payloads or source content. The merged exact head passed 131 focused worker, HTTP, schema, Compose, migration, and documentation tests. A post-merge review found missing stage/session binding on incomplete evidence; the correction is carried by current parent #640 rather than by later commits on the already-merged source branch | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | From bdc3b0be03dbad52e926d4ddc0b44253de9ea828 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:06:20 +0900 Subject: [PATCH 207/238] docs(gaps): sync semantic exact-head evidence --- docs/product-technical-gap-baseline.md | 39 +++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 2f5e18984..0d793bf6b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 16 open PRs and 10 open issues. The exact-head +At this snapshot there were 17 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 18:51 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 20:05 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, @@ -78,29 +78,29 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 16 open PRs and 10 +at this refresh. The live queue contains 17 open PRs and 10 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 | | ---: | --- | --- | -| #702 | `e8fd06cc` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head removes evidence-length heuristics and refreshes this evidence ledger; protected hosted checks, three informational review threads, and independent review remain open | +| #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | +| #702 | `51331843` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, and assigns union-free ADR 0240/0241/0242; protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `495b4504` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | -| #672 | `f78f036c` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. Hosted checks and independent review remain required | -| #668 | `f9c4bd65` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. Focused documentation/project-history and existing desktop/mobile screenshot evidence pass; hosted checks and independent review remain required | -| #667 | pre-documentation parent `657dda0d` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | +| #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | +| #667 | pre-documentation parent `958eb2af` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `b08c4f05` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head keeps the durable worker as the owner while health-gating canonical API startup, adds structured operations-case validation evidence, and binds incomplete-evidence failures to the content-persistence stage and existing post session. Twenty-seven focused worker tests pass; exact-head hosted checks and independent review remain required | -| #703 | merged into #640 as `4ecb4983` | preserves bounded post-content failure provenance without copying provider payloads or source content. The merged exact head passed 131 focused worker, HTTP, schema, Compose, migration, and documentation tests. A post-merge review found missing stage/session binding on incomplete evidence; the correction is carried by current parent #640 rather than by later commits on the already-merged source branch | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | -| #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures now execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass. Hosted checks and independent review remain required | +| #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. The exact head currently has a failed Strix conclusion and pending test/security coverage, so root-cause review and exact-head revalidation remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge @@ -132,11 +132,12 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 18:51 KST found no failed conclusion on any -current head. Every head still had queued or in-progress gates; #702 had one -unresolved review threads while the other fifteen had none. No current head -had an exact-head independent approval. Queued checks and bot success statuses -are not merge evidence. +The exact-head check-run scan at 20:05 KST found a failed Strix conclusion on +#632. Every head still had queued or in-progress gates; +#702 and #704 had zero unresolved review threads after evidence replies and +repairs. No current head had an exact-head independent approval. Queued checks +and bot success statuses are not merge evidence, and #632 requires root-cause +repair rather than a rerun-only or bypass response. ### Ecosystem owner-boundary evidence @@ -182,15 +183,19 @@ ontology publication decision now uses ADR 0236, leaving #679's public-claim ADR 0229 unambiguous. #672's Semantic Ask migrations now use 0225/0226, separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR 0224 and 0225 collisions are resolved on #663 by unique ADR 0230/0231 -identities. A current-head inventory found no ADR or migration number assigned -to divergent filenames across the 16 open PRs. The +identities. A current-head inventory confirms that #702's semantic-coverage +decisions moved to ADR 0240/0241/0242 and #704's external-lineage decision +moved to ADR 0239. #668's evidence-bound project-history projection moved from +the remaining shared 0232 identifier to ADR 0243, leaving #640's +source-preserving voice semantic taxonomy as the sole 0232 decision. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed `pyproject.toml` versions are 2.18.0 on #632/#640/#663, 2.19.0 on #643, and 2.22.0 on #679. Release-version and duplicated-delivery overlaps still require ordered parent landing, child retargeting, and exact-head -revalidation; identifier collision is no longer the blocker. +revalidation; ADR identifier collision is no longer the blocker at this +snapshot. PR #680 and closed-unmerged #686 independently edited the same ranking, ontology, and locale surfaces. Before #680 can land, compare it with #686 and From 2bc24dd72261f70414f7eed31a11f18acc6075d5 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:07:38 +0900 Subject: [PATCH 208/238] docs(gaps): record open-head identifier audit --- docs/product-technical-gap-baseline.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 0d793bf6b..964a92c29 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -88,7 +88,7 @@ context only. | #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | | #702 | `51331843` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, and assigns union-free ADR 0240/0241/0242; protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | -| #700 | `495b4504` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. Focused import/persistence/chunking/docstring/documentation tests and Ruff pass; protected hosted checks and independent review remain required | +| #700 | `273678ce` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change to union-free migration 0233 and applies that migration in the real-PostgreSQL fixture; 42 focused replay, schema, and documentation tests pass. Protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | @@ -188,6 +188,11 @@ decisions moved to ADR 0240/0241/0242 and #704's external-lineage decision moved to ADR 0239. #668's evidence-bound project-history projection moved from the remaining shared 0232 identifier to ADR 0243, leaving #640's source-preserving voice semantic taxonomy as the sole 0232 decision. The +open-head migration union found one distinct-name collision at 0230: #640's +voice semantic taxonomy and #700's conversation-turn evidence. #700 now owns +union-free migration 0233, preserving #640's accepted 0230 identity; focused +replay against real PostgreSQL confirms the renamed migration is applied. +The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather than a semantic divergence. Release metadata also diverges: the observed From ee361ced9095b44679cf93868007529bbe36e1ba Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:11:32 +0900 Subject: [PATCH 209/238] docs(gaps): refresh owner and Strix evidence --- docs/product-technical-gap-baseline.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 964a92c29..3917874c5 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -100,7 +100,7 @@ context only. | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `b08c4f05` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head keeps the durable worker as the owner while health-gating canonical API startup, adds structured operations-case validation evidence, and binds incomplete-evidence failures to the content-persistence stage and existing post session. Twenty-seven focused worker tests pass; exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | -| #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. The exact head currently has a failed Strix conclusion and pending test/security coverage, so root-cause review and exact-head revalidation remain required | +| #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | PRs #687, #688, and #689 merged into the non-default #640 stack as merge @@ -132,12 +132,12 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 20:05 KST found a failed Strix conclusion on -#632. Every head still had queued or in-progress gates; -#702 and #704 had zero unresolved review threads after evidence replies and -repairs. No current head had an exact-head independent approval. Queued checks -and bot success statuses are not merge evidence, and #632 requires root-cause -repair rather than a rerun-only or bypass response. +The exact-head check-run scan at 20:10 KST found no terminal failure on an open +head, but every head still had queued or in-progress gates. #632's previously +failed Strix run has a normal rerun accepted with HTTP 201 and its replacement +job is queued; that transport acknowledgement is not completed scan evidence. +No current head had an exact-head independent approval. Queued checks and bot +success statuses are not merge evidence. ### Ecosystem owner-boundary evidence @@ -155,11 +155,13 @@ repair rather than a rerun-only or bypass response. protected-main merge evidence. LineageWeave may consume the owner contract only after that composed head passes its protected gate; it may not retain Python vector arithmetic. -- `ContextualWisdomLab/fast-mlsirm` draft PR #1445 exact head `a0131c02` +- `ContextualWisdomLab/fast-mlsirm` draft PR #1445 exact head `74f7c902` supplies current owner evidence for the Rust-owned, content-addressed polytomous period artifact: four Rust-core tests, seven Python-boundary tests, and 25 documentation/governance tests pass alongside `cargo check`, wheel - build, and Ruff. The PR remains Draft with hosted checks queued, so this is + build, and Ruff. The head advance changes only governed changelog evidence; + it does not add released runtime or corpus evidence. The PR remains Draft + with hosted checks queued and zero unresolved threads, so this is owner-candidate evidence rather than a protected released artifact; corpus inference remains unavailable until that artifact passes its protected gate. - `ContextualWisdomLab/TEPP` PR #237 merged to protected `main` as @@ -528,7 +530,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts, LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer, and TEPP #237's criterion-anchor wire contract are protected. #237 intentionally does not implement the estimator, so no emitted digest-bound terminal artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Implement and verify the TEPP estimator behind the protected #237 contract, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm Draft #1445 exact head `a0131c02` supplies four Rust-core, seven Python-boundary, and 25 documentation/governance passing tests plus `cargo check`, wheel-build, and Ruff evidence for its relation-safe content-addressed owner artifact, but queued hosted checks and Draft status make it unavailable for corpus inference. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 through its protected gate before replacing period arithmetic or claiming corpus inference. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm Draft #1445 exact head `74f7c902` supplies four Rust-core, seven Python-boundary, and 25 documentation/governance passing tests plus `cargo check`, wheel-build, and Ruff evidence for its relation-safe content-addressed owner artifact; its latest change is governed changelog evidence only, and queued hosted checks plus Draft status make it unavailable for corpus inference. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 through its protected gate before replacing period arithmetic or claiming corpus inference. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | From 76a15aba6426c71e7c560c910f28d783d6f917df Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:26:44 +0900 Subject: [PATCH 210/238] fix(chat): keep saved turns out of demo seed view --- docs/product-technical-gap-baseline.md | 30 +++++++++++++------------- frontend/src/App.tsx | 17 ++++++++------- frontend/src/ChatPanel.test.tsx | 1 + 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 3917874c5..6fb0a9061 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -482,29 +482,29 @@ this file per §3.5 of the prior snapshot). | #280 | Full project-lifecycle history and handover intervals | Tracked with issue #284; no active delivery PR confirmed | | #284 | Authoritative lifecycle ingestion and idempotent reconciliation | No active delivery PR confirmed | | #338 | Evidence-bounded email/project lineage contract for Naruon consumption | No active delivery PR; #355 is merged historical consumer work | -| #611 | Decompose unshipped ADR 0133–0137 acceptance evidence from PR #490 | Decomposition is stacked in #667's non-default branch; no separate open delivery PR | +| #611 | Reconcile historical ADR 0133–0137 proposals from closed PR #490 with current product authority | #667 records the current-main evidence and removes ADR 0137's unauthorized duplicate identity scope | ### 4.1 ADR 0133–0137 current-main decomposition Closed PR #490 is recoverable source evidence, not delivery evidence. The matrix below compares its five decisions with protected -`main@494b54e2245040bcf02b45376f221c37cd437e76`; it does not transfer #490's -reviews, checks, or 321-file tree. Repository searches exclude this baseline -itself, so an identifier count of zero is evidence that the named contract is -absent from the protected source tree, not evidence that a similarly named -feature is equivalent. +`main@ff7431bd1851c03e737808d22c6a2d43968582f9`; it does not transfer #490's +reviews, checks, or 321-file tree. Current accepted ADRs and the PRD determine +whether a historical proposal is delivered, still pending, superseded, or +outside LineageWeave's product authority. | Decision | Protected-main evidence | Classification | Focused acceptance before delivery | | --- | --- | --- | --- | -| ADR 0133 — source-reference research | No `source_reference_research` persistence, post-admin action, or reader contract exists. The existing relation-verification client verifies an already extracted organization and is not the cited-resource discovery workflow | Missing | Add the ADR first, then one bounded SearXNG → contextual-orchestrator judgment slice with public-host/redirect rejection, normalized provenance, synthetic SSRF tests, and no entity binding from a search hit alone | -| ADR 0134 — token-backed exception messages | Protected main has no shared `StatusNotice`; #643 (`3453ab08`) is the active current-main implementation candidate | In progress, not protected delivery | Land #643 only after exact-head checks and independent approval; then migrate remaining raw/color-only exception surfaces with Storybook unavailable/retry scenes | -| ADR 0135 — analysis-kind exact next actions | Protected main has no `analysisRunGuidance`; merged stack #669 (`21bb799c`) is included in #667's non-default branch with cancelled-run guidance and responsive layout | In progress, not protected delivery | Land #667 with exact-head UI tests and desktop/mobile screenshot evidence; follow with the remaining kind × status Storybook interaction matrix without inventing TEPP or report actions | -| ADR 0136 — per-post Ask history | No `post_ask_session` or `post_ask_turn` schema/API exists on protected main | Missing | Add the ADR and normalized account + post scoped tables, hot-post-safe index, batched visibility reauthorization, list/select/new UI, cross-account/post rejection tests, and citation-revocation evidence | -| ADR 0137 — cross-post customer identity | No `customer_identity_judgment`, `customer_identity_binding`, or `corporate_entity_name_history` schema exists on protected main | Missing | Add the ADR before implementation; retain `(source_system_code, source_customer_code)` identity, require multiple eligible posts and external cited corroboration, persist abstention/tie states, and consume owning-library judgment evidence without local scoring | - -The next implementation order is ADR 0134/#643 and the stacked ADR 0135 work because -their focused current-base heads already exist. ADR 0133, ADR 0136, and ADR -0137 must each start from a new ADR-first current-main PR; none is authorized +| ADR 0133 — source-reference research | Superseded by accepted ADR 0215 and PRD FR-5A; protected-main deliveries #641 and #682 provide the opt-in, bounded SearXNG and contextual-orchestrator verification boundary | Delivered under current authority | Keep internal evidence, public citations, unavailable states, and entity-binding authority separate; do not recreate the closed branch's parallel schema | +| ADR 0134 — token-backed exception messages | #643 is the active shared `StatusNotice` implementation candidate | In progress, not protected delivery | Land #643 only after exact-head checks and independent approval; then audit remaining raw/color-only exception surfaces with Storybook unavailable/retry scenes | +| ADR 0135 — analysis-kind exact next actions | #639 restores the current run-action contract and #667 carries cancelled-run guidance and responsive layout | In progress, not protected delivery | Land each exact-head candidate through protected gates, then test the remaining kind × status interaction matrix without inventing TEPP or report actions | +| ADR 0136 — per-post Ask history | #667 implements accepted ADR 0235's normalized account-and-post-scoped conversation history, authorization rechecks, pagination, and saved/new UI | In progress, not protected delivery | Land #667 with exact-head backend/frontend checks and independent approval; retain citation-revocation and cross-account/post denial evidence | +| ADR 0137 — cross-post customer identity | PRD FR-7 assigns identity to Keyverse; a LineageWeave-owned customer identity judgment/binding store would duplicate that authority | Not an authorized product gap | Keep identity at the Keyverse boundary and remove the closed branch proposal from the implementation queue | + +The remaining delivery order is ADR 0134/#643, ADR 0135/#639 plus #667 guidance, +and ADR 0136/#667 because their focused current-base heads already exist. ADR +0133 is delivered under ADR 0215, while ADR 0137 is outside LineageWeave's +identity authority; neither starts a new implementation PR. None is protected for wholesale replay from #490. ## 5. Open product and technical gaps diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7bdcef955..ae91cd74e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -410,19 +410,20 @@ export function ChatPanel({ const firstCitedTitle = exchanges[0]?.cited_posts?.[0]?.post_title ?? (firstCitedPostId ? firstCitedPostId.slice(0, 8) : null); - const landedEvidencePostId = nameFirstAsk ? (evidencePostId ?? firstCitedPostId) : null; + const showNamedSeed = Boolean(nameFirstAsk && conversationId === null && exchanges[0]); + const landedEvidencePostId = showNamedSeed ? (evidencePostId ?? firstCitedPostId) : null; return (

{t("Ask about this lineage")}

- {nameFirstAsk && exchanges[0] ? ( + {showNamedSeed ? (

{firstAskNextAction(exchanges[0].question_text)}

) : null} - {nameFirstAsk && exchanges[0] ? ( + {showNamedSeed ? (

{exchanges[0].question_text}

{exchanges[0].answer_text}

@@ -436,12 +437,12 @@ export function ChatPanel({ />
) : null} - {nameFirstAsk && firstCitedTitle ? ( + {showNamedSeed && firstCitedTitle ? (

{firstCitedNextAction(firstCitedTitle)}

) : null} - {nameFirstAsk && landedEvidencePostId ? ( + {showNamedSeed && landedEvidencePostId ? ( ) : null} - {nameFirstAsk && firstCitedTitle && landedEvidencePostId ? ( + {showNamedSeed && firstCitedTitle && landedEvidencePostId ? (

{landedEvidenceNextAction(firstCitedTitle)}

@@ -538,7 +539,7 @@ export function ChatPanel({ className="chat-suggestion-chip" aria-label={tf("Ask seeded question: {question}", { question: exchange.question_text })} aria-current={ - nameFirstAsk && index === 0 + showNamedSeed && index === 0 ? "true" : undefined } @@ -555,7 +556,7 @@ export function ChatPanel({ )} {error &&

{error}

} {exchanges - .slice(nameFirstAsk ? 1 : 0) + .slice(showNamedSeed ? 1 : 0) .map((exchange, index) => (

{exchange.question_text}

diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 68c0fc92c..90ad89f39 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -45,6 +45,7 @@ describe("ChatPanel conversation history", () => { expect(await screen.findAllByText("First answer")).toHaveLength(1); expect(screen.getByText("Second answer")).toBeInTheDocument(); + expect(screen.queryByLabelText("Ask seed next action")).not.toBeInTheDocument(); expect(screen.getAllByRole("button", { name: "Ask seeded question: What changed?" })).toHaveLength(2); }); From f1502eba1b7d7f9c56c495c89f6ff8dacdadbdfa Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:28:32 +0900 Subject: [PATCH 211/238] docs(gaps): sync semantic and migration stack heads --- docs/product-technical-gap-baseline.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6fb0a9061..5451cf477 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -86,19 +86,19 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | | #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | -| #702 | `51331843` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, and assigns union-free ADR 0240/0241/0242; protected hosted checks and independent review remain required | +| #702 | `896430ed` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, assigns union-free ADR 0240/0241/0242, and preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | -| #700 | `273678ce` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change to union-free migration 0233 and applies that migration in the real-PostgreSQL fixture; 42 focused replay, schema, and documentation tests pass. Protected hosted checks and independent review remain required | +| #700 | `84551cf9` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233 and applies that migration in the real-PostgreSQL fixture; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `958eb2af` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `76a15aba` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `b08c4f05` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. The current head keeps the durable worker as the owner while health-gating canonical API startup, adds structured operations-case validation evidence, and binds incomplete-evidence failures to the content-persistence stage and existing post session. Twenty-seven focused worker tests pass; exact-head hosted checks and independent review remain required | +| #640 | `6b9b84ee` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Merged child #706 keeps the durable worker as the owner, records bounded structured validation evidence through union-free migration 0234, and pins the reviewed structured-failover runtime; the child passed 64 focused migration, documentation, operations-case, and worker tests before its normal merge. Exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -194,6 +194,11 @@ open-head migration union found one distinct-name collision at 0230: #640's voice semantic taxonomy and #700's conversation-turn evidence. #700 now owns union-free migration 0233, preserving #640's accepted 0230 identity; focused replay against real PostgreSQL confirms the renamed migration is applied. +Merged child #706 originally reused 0233 for post-content validation; it moved +that distinct schema contract to union-free migration 0234 before normal merge +into #640. PR #705 merged its replay guard into the non-default historical +`fix/ask-auto-source-composer` branch as `db181493`; it is stack-integration +evidence only and does not by itself deliver the optimization on #640 or main. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather From fccaef21eaa7ac07c6732b6d5d815d6183b8e485 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:32:43 +0900 Subject: [PATCH 212/238] docs(gaps): sync current semantic and live stack evidence --- docs/product-technical-gap-baseline.md | 30 +++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5451cf477..7e2fb14b6 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -88,17 +88,17 @@ context only. | #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | | #702 | `896430ed` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, assigns union-free ADR 0240/0241/0242, and preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | -| #700 | `84551cf9` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233 and applies that migration in the real-PostgreSQL fixture; protected hosted checks and independent review remain required | +| #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `76a15aba` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `f1502eba` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `6b9b84ee` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Merged child #706 keeps the durable worker as the owner, records bounded structured validation evidence through union-free migration 0234, and pins the reviewed structured-failover runtime; the child passed 64 focused migration, documentation, operations-case, and worker tests before its normal merge. Exact-head hosted checks and independent review remain required | +| #640 | `cb086313` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Merged child #706 keeps the durable worker as the owner, records bounded structured validation evidence through union-free migration 0234, and pins the reviewed structured-failover runtime; merged child #707 forwards #705's atomic, advisory-locked voice-backfill completion guard from the stale historical stack into live #640. Exact-head hosted checks and independent review remain required | | #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -132,12 +132,16 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 20:10 KST found no terminal failure on an open -head, but every head still had queued or in-progress gates. #632's previously -failed Strix run has a normal rerun accepted with HTTP 201 and its replacement -job is queued; that transport acknowledgement is not completed scan evidence. -No current head had an exact-head independent approval. Queued checks and bot -success statuses are not merge evidence. +The exact-head check-run scan at 20:30 KST found Strix failures on #629, #643, +#644, #657, and #680. Sampled exact-head logs show a shared provider/transport +failure: NVIDIA attempts returned unavailable or rate-limit responses and the +OpenAI fallback sent function tools plus reasoning effort through Chat +Completions, which that model rejects. This is central Strix routing/protocol +debt rather than five independent source defects; normal reruns cannot become +passing evidence until the owning workflow repairs capability translation. +Every open head still had queued or in-progress gates and no exact-head +independent approval. Queued checks and bot success statuses are not merge +evidence. ### Ecosystem owner-boundary evidence @@ -196,9 +200,11 @@ union-free migration 0233, preserving #640's accepted 0230 identity; focused replay against real PostgreSQL confirms the renamed migration is applied. Merged child #706 originally reused 0233 for post-content validation; it moved that distinct schema contract to union-free migration 0234 before normal merge -into #640. PR #705 merged its replay guard into the non-default historical -`fix/ask-auto-source-composer` branch as `db181493`; it is stack-integration -evidence only and does not by itself deliver the optimization on #640 or main. +into #640. PR #705 first merged its replay guard into the non-default historical +`fix/ask-auto-source-composer` branch as `db181493`; that merge alone was only +stack-integration evidence. Merged child #707 then forwarded the same guarded +contract into live parent #640 as `cb086313`, so #640 now carries it while main +still does not. The `0212_global_ask_knowledge_cutoff.sql` blobs in PR #658 and #663 are byte-identical, so that overlap is duplicated delivery rather From ffde4b3a2bfd4c72536216c78d2adddbd3bf2222 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 20:47:15 +0900 Subject: [PATCH 213/238] docs: refresh exact protected evidence --- docs/product-technical-gap-baseline.md | 66 +++++++++----------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 7e2fb14b6..9b90d3bca 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 20:05 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 20:44 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, @@ -93,7 +93,7 @@ context only. | #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `f1502eba` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `fccaef21` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | @@ -132,16 +132,11 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 20:30 KST found Strix failures on #629, #643, -#644, #657, and #680. Sampled exact-head logs show a shared provider/transport -failure: NVIDIA attempts returned unavailable or rate-limit responses and the -OpenAI fallback sent function tools plus reasoning effort through Chat -Completions, which that model rejects. This is central Strix routing/protocol -debt rather than five independent source defects; normal reruns cannot become -passing evidence until the owning workflow repairs capability translation. -Every open head still had queued or in-progress gates and no exact-head -independent approval. Queued checks and bot success statuses are not merge -evidence. +The exact-head check-run scan at 20:44 KST found Strix failures on #629, #639, +#643, #644, #657, #680, and #701; #639 also had a terminal Full test suite +failure. All 17 open PRs had zero unresolved review threads, but every head +still had queued or in-progress gates and lacked exact-head independent +approval. Queued checks and bot success statuses are not merge evidence. ### Ecosystem owner-boundary evidence @@ -268,36 +263,21 @@ regression is part of the current candidate and is not delivery evidence yet. Three systemic gates currently dominate the queue: -1. **Strix visibility lookup failure (org control plane).** PR #600 exact head - `7580bdc9` failed before scanning because the required-workflow token could - not resolve this public repository after six API retries. The root repair is - ContextualWisdomLab/.github#1320 at `3b9b2380`: ordinary PR, push, and - schedule runs use trusted event visibility; cross-repository dispatch keeps - authoritative public/private/internal visibility; private and internal - repositories remain on private-capable providers. The exact head also - composes the executable fallback contract and classifies bounded NVIDIA - `ServiceUnavailableError` overload evidence as retryable across configured - distinct models without weakening exhaustion or vulnerability fail-close. - A hosted fallback then completed with zero vulnerabilities but was rejected - because the generic warning gate treated Strix's fallback-model banner and - a Hugging Face unauthenticated-download notice as provider failures. The - current head removes only those two exact scanner notices before the - existing general warning and explicit 429/provider failure checks. The - current head also clears a foreign NVIDIA/OpenRouter endpoint before a - direct-OpenAI fallback while retaining an explicitly configured - direct-OpenAI primary endpoint. The prior full quick-gate harness, overload - path, 12 visibility-contract tests, and the focused cross-provider endpoint - contract passed; exact-head hosted revalidation remains pending. It is blocked on - hosted exact-head gates and independent review, so no repaired - protected-main Strix runtime evidence exists yet. -2. **Strix provider unavailability (org control plane).** The central required - Strix scan on .github#1320 failed when NVIDIA returned `Service temporarily - overloaded`; the gate correctly failed closed but did not try its configured - distinct fallbacks because the service-unavailable classifier excluded the - NVIDIA provider. Exact head `3b9b2380` composes that execution repair and the - two exact non-fatal scanner-notice exclusions while keeping - incomplete exhaustion non-passing. This is still an unmerged control-plane - proposal, not protected-main or downstream runtime evidence. +1. **Strix visibility and fallback repair (org control plane).** + ContextualWisdomLab/.github#1320 merged to protected `main` as + `d2c554dbbc04854db6215970fabb70cef1ceb690`; its former candidate head is no + longer open-PR evidence. Current follow-up #1350 is open at exact head + `7e44aa17`, with zero unresolved threads and no terminal failed checks, but + its required hosted checks are queued and it has no formal independent + approval. It changes the owned Strix fallback contract and focused + regression only. Until #1350 passes its protected gate and downstream scans + succeed, the seven current LineageWeave Strix failures remain unresolved + control-plane evidence rather than seven proven source defects. +2. **Exact-head hosted evidence.** #1350's local verification and mergeable + state do not prove the central workflow repair. A terminal successful + protected merge and subsequent successful LineageWeave scans are still + required; incomplete provider exhaustion and vulnerability findings remain + non-passing. 3. **Current-head independent approval.** The org merge scheduler requires `reviewDecision == APPROVED` plus complete Strix evidence on the exact head. Bot review evidence regenerates per push, so any repair push resets @@ -522,7 +502,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Sixteen PRs remain open at the 18:51 KST snapshot; every candidate still requires exact-head checks, unresolved-thread review, and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 20:44 KST snapshot; every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From c7ec2b1ef024bbcd0f013ecb70ac45860ce2d2e7 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 21:02:23 +0900 Subject: [PATCH 214/238] docs(gaps): refresh exact delivery evidence --- docs/product-technical-gap-baseline.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 7e2fb14b6..25f66b302 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 20:05 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 20:48 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, @@ -99,7 +99,7 @@ context only. | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | | #640 | `cb086313` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Merged child #706 keeps the durable worker as the owner, records bounded structured validation evidence through union-free migration 0234, and pins the reviewed structured-failover runtime; merged child #707 forwards #705's atomic, advisory-locked voice-backfill completion guard from the stale historical stack into live #640. Exact-head hosted checks and independent review remain required | -| #639 | `f1d7aaaa` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The current-main merge preserves both host-artifact exclusions and both frontend container contract tests; fresh exact-head hosted checks and independent review remain required | +| #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -548,10 +548,10 @@ for wholesale replay from #490. | Accessibility and responsive UX | Protected-main #602 and #605 deliver modal semantics, selected-post refocus, collapsed/hidden/inert/CSS-invisible focus exclusion, readable evidence separators, focused tests, and desktop/mobile Storybook screenshots | Complete screen-reader and authenticated Playwright acceptance on the exact release head | | Design tokens and repeated objects | Token extraction started; sanitized Figma Event Lineage desktop/mobile frames exist, while other repeated product surfaces remain incomplete | Tokens in CSS + Storybook stories for board, popup, DAG, Ask, calendar, forms, charts; same-viewport Figma/runtime visual comparison before release | | Frontend delivery performance | PR #644 exact head `f11e77d1` splits the real conditional workspace surfaces with native dynamic imports; 105 focused tests and the production build pass without the former large-chunk warning | Land #644 through protected gates, then repeat loading/error accessibility and bundle evidence on the exact release head | -| External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, DiskSage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | +| External integrations | Search, Zotero, calendar, Keyverse, orchestrator, RankWeave, ThreadWeave, TEPP, disksage, wardnet | Provider conformance, failure/reconciliation behavior, and provenance-bearing integration evidence | | MSA / modular reuse | LineageWeave must run standalone and as a consumer of org packages | Do not reimplement RankWeave/TEPP/orchestrator/ThreadWeave/Keyverse; fix upstream and PR there | | Accelerator runtime ownership | ADR 0076/0208 already prohibit local model and mathematical ownership; ADR 0237 defines MLX as a native orchestrator-side service and TEPP/fast-mlsirm CUDA/OpenCL/CPU profiles as scientific-compute-owner deployments, so LineageWeave Compose remains device-neutral. contextual-orchestrator #857 proposes its Rust token/vector boundary, while RankWeave #41/#48 propose the Rust retrieval calculation boundary; all remain candidates until protected delivery | TEPP and fast-mlsirm must publish deterministic CPU recovery plus conformance evidence for every advertised CUDA/OpenCL profile; contextual-orchestrator must prove native MLX and embedding capability through its provider-neutral health/contract boundary; RankWeave must publish its reviewed Rust artifact. LineageWeave accepts only versioned, provenance-bearing envelopes and fails closed when an owner is unavailable | -| Product contract authority | This branch recreates the first LineageWeave PRD after superseded #613 closed without merge and records an exact-case ecosystem authority register; TEPP, fast-mlsirm, keyverse, and ThreadWeave have standalone PRDs, while contextual-orchestrator, RankWeave, DiskSage, and wardnet currently rely on product-planning/architecture documents and naruon has only a scoped Topic Intelligence PRD | Land the LineageWeave PRD, keep ADRs normative, and add standalone PRDs in each owning repository before making cross-product release claims beyond its documented boundary | +| Product contract authority | This branch recreates the first LineageWeave PRD after superseded #613 closed without merge and records an exact-case ecosystem authority register; TEPP, fast-mlsirm, keyverse, and ThreadWeave have standalone PRDs, while contextual-orchestrator, RankWeave, disksage, and wardnet currently rely on product-planning/architecture documents and naruon has only a scoped Topic Intelligence PRD | Land the LineageWeave PRD, keep ADRs normative, and add standalone PRDs in each owning repository before making cross-product release claims beyond its documented boundary | | Release quality | Protected merges #660 and #659 are represented by `main@494b54e2`; the #660 stacked tree passed the complete Python suite (1,352 passed, 17 skipped) before protected delivery. Frontend/Storybook, security, browser, and authorized-runtime evidence remain separate gaps | Repository-wide coverage, frontend/Storybook, security, browser, and authorized-runtime evidence on one exact head | | PII | Masking would paralyze the product; ADR 0001 forbids identifying artifacts in git | ABAC + authorized runtime; synthetic fixtures in git; no mask-in-place that drops names the operator must read | | Database | PostgreSQL, 3NF, snake_case ≥ two words, hot-partition and lock policy | No file DBs; read/write split if lock management fails; whitelist every migration | @@ -587,7 +587,7 @@ of leverage; open connector PRs there when the defect is upstream: 5. **fast-mlsirm** — GRM/GPCM/CAT/FIPC recovery tests (#451–#454) must stay true-parameter RMSE. 6. **ThreadWeave** — tree assembly. 7. **Naruon** — calendar projection delivered through merged #355/closed #336; email/project lineage projection remains open as #338. -8. **DiskSage / wardnet** — storage and network policy as needed. +8. **disksage / wardnet** — storage and network policy as needed. 9. **ContextualWisdomLab/.github** — required review workflows (OpenCode, Strix, Noema) and the LineageWeave hourly caller (#1288, current head `c78ae017`). Its current-main reconciliation preserves the pinned contextual-orchestrator sidecar, loopback gateway contract, provider-key isolation, existing review/OIDC mutation credentials, and the action-oriented customer-copy rule; 67 focused central tests pass, while exact-head hosted checks and independent re-review remain pending. If stacked PRs miss central review or coverage-evidence fails on pnpm 9 (`--trust-lockfile` is pnpm 11.3) or a missing Vitest coverage provider, fix the org workflow (#1258), not a local bypass. ## 8. Public ontology publication boundary From 497e817a3e68e7669faffd363926210c2b3f7942 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 21:16:57 +0900 Subject: [PATCH 215/238] docs(gaps): track current queue and security repair --- docs/product-technical-gap-baseline.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 12dbe4ade..1b0f81efd 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 17 open PRs and 10 open issues. The exact-head +At this snapshot there were 18 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 20:48 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 21:12 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, @@ -78,19 +78,20 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 17 open PRs and 10 +at this refresh. The live queue contains 18 open PRs and 10 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 | | ---: | --- | --- | +| #708 | `813f8d46` | stacked on #640 and repairs the operations-response schema/prompt contract. It must not merge into the non-default parent: land #640 through protected `main`, retarget #708 to `main`, and collect fresh exact-head checks and independent review | | #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | -| #702 | `896430ed` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, assigns union-free ADR 0240/0241/0242, and preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | +| #702 | `ebb1dfa8` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, assigns union-free ADR 0240/0241/0242, and preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | -| #679 | `e26a7208` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. Customer guidance remains present on plain answers, renders once, and prevents uncorroborated unavailable/NEI candidates from appearing as external evidence. Focused backend/frontend/lint checks pass locally; fresh exact-head hosted checks and independent review remain required | +| #679 | `d5220bcb` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. It also materializes the bounded eligibility fragment into one static query before `asyncpg` execution, repairing the exact-head Semgrep SQL-construction finding without a suppression; 18 focused queue/docstring tests pass locally. Fresh hosted checks and independent review remain required, with normal auto-merge enabled | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | | #667 | pre-documentation parent `fccaef21` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | From 26836cb017886f7a6d7e7a3f3c990685338ae0b3 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 21:22:34 +0900 Subject: [PATCH 216/238] fix(chat): keep saved citation evidence reachable --- frontend/src/App.tsx | 2 +- frontend/src/ChatPanel.test.tsx | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ae91cd74e..672161d25 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -578,7 +578,7 @@ export function ChatPanel({ />
)} - {!nameFirstAsk && evidencePostId ? ( + {!showNamedSeed && evidencePostId ? ( { title: "Repeated question", older_cursor: null, exchanges: [ - { turn_id: "turn-1", question_text: "What changed?", answer_text: "First answer", cited_post_ids: [] }, + { + turn_id: "turn-1", + question_text: "What changed?", + answer_text: "First answer", + cited_post_ids: ["evidence-post"], + cited_posts: [{ post_id: "evidence-post", post_title: "Saved evidence" }], + }, { turn_id: "turn-2", question_text: "What changed?", answer_text: "Second answer", cited_post_ids: [] }, ], }); } + if (url.endsWith("/api/posts/evidence-post")) { + return jsonResponse({ + post_id: "evidence-post", + post_title: "Saved evidence", + post_body: "Evidence from the saved conversation.", + }); + } if (url.endsWith("/chat/conversations")) { return jsonResponse({ conversations: [{ conversation_id: "conversation-1", title: "Repeated question", updated_at: "2026-08-26T00:00:00Z", turn_count: 2 }], @@ -47,6 +60,10 @@ describe("ChatPanel conversation history", () => { expect(screen.getByText("Second answer")).toBeInTheDocument(); expect(screen.queryByLabelText("Ask seed next action")).not.toBeInTheDocument(); expect(screen.getAllByRole("button", { name: "Ask seeded question: What changed?" })).toHaveLength(2); + await userEvent.click(screen.getByRole("button", { name: "Open evidence: Saved evidence" })); + expect(await screen.findByRole("complementary", { name: "Evidence" })).toHaveTextContent( + "Evidence from the saved conversation.", + ); }); it("replaces demo cache rows when the first saved turn starts", async () => { From 50711ffc040a25fb256f7ba09dc250ad56642a51 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 21:27:04 +0900 Subject: [PATCH 217/238] test(storybook): cover saved citation evidence --- frontend/src/ChatPanel.stories.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/frontend/src/ChatPanel.stories.tsx b/frontend/src/ChatPanel.stories.tsx index 395a324dd..7089027f1 100644 --- a/frontend/src/ChatPanel.stories.tsx +++ b/frontend/src/ChatPanel.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; +import { expect, userEvent, within } from "storybook/test"; import { ChatPanel } from "./App"; type Fixture = "empty" | "saved"; @@ -45,6 +46,13 @@ function installFixture(fixture: Fixture) { : [], }); } + if (url.endsWith("/api/posts/post-2")) { + return jsonResponse({ + post_id: "post-2", + post_title: "Linked source post", + post_body: "Evidence from the saved conversation.", + }); + } return jsonResponse({ post_id: "post-1", exchanges: [ @@ -80,10 +88,22 @@ export const SeededDump: Story = { }; export const SavedHistory: Story = { + args: { nameFirstAsk: true }, render(args) { installFixture("saved"); return ; }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.selectOptions( + await canvas.findByLabelText("Conversation history"), + "conversation-post-1", + ); + await userEvent.click(await canvas.findByRole("button", { name: "Open evidence: Linked source post" })); + await expect(await canvas.findByRole("complementary", { name: "Evidence" })).toHaveTextContent( + "Evidence from the saved conversation.", + ); + }, }; export const Phone: Story = { From 4855c38084beef16ec7e5ebfd502aed17f5a85b0 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 26 Aug 2026 21:28:52 +0900 Subject: [PATCH 218/238] docs: refresh current queue evidence --- docs/product-technical-gap-baseline.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 1b0f81efd..e88b1b899 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 21:12 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-26 21:27 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, @@ -85,21 +85,21 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #708 | `813f8d46` | stacked on #640 and repairs the operations-response schema/prompt contract. It must not merge into the non-default parent: land #640 through protected `main`, retarget #708 to `main`, and collect fresh exact-head checks and independent review | +| #709 | `3157645a` | publishes ADR 0232's 24-concept DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights. Its 103 focused ontology, publication, and documentation checks pass locally; protected hosted checks and independent review remain required | | #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | -| #702 | `ebb1dfa8` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token to a stratum and to the digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. The observed 80-record deterministic-window run is pipeline acceptance only, not corpus inference, and corpus coverage therefore remains unavailable. The current head aligns Unicode body-availability semantics across RDF and SHACL, uses the internal orchestrator credential boundary, validates declared stratum cardinality without taking over Rust-owned sample arithmetic, assigns union-free ADR 0240/0241/0242, and preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | +| #702 | `ebb1dfa8` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token, stratum, caller hash, and digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. For `N = 43,814`, a valid simple random sample of `n = 80` would have an approximately `±10.95%` 95% margin of error at `p = .5` after finite-population correction. The observed 80-record deterministic window is not that probability sample, so corpus inference remains unavailable until a verifiable fast-mlsirm artifact and bound caller manifest exist. The current head preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | -| #680 | `ff4d9eaf` | customer-facing ranking and related-concept copy removes the remaining rendered internal ontology label while preserving the Event Lineage distinction and protected-main's Project node additions. Orphaned-source and unavailable-ranking guidance now direct the reader to the valid workspace-admin action across locales; lint and 159 App/i18n checks pass. Fresh exact-head hosted checks and independent review are required | +| #680 | `6013821a` | replaces rendered implementation-boundary language across source, project, summary, search, customer, analysis-run, and empty-board states with the next valid customer action. The exact-head authenticated synthetic 1280×720 audit confirmed the empty-board guidance and absence of a developer command; focused empty-board and 64 i18n completeness checks, lint, production build, and diff check passed locally. Fresh exact-head hosted checks and independent review are required | | #679 | `d5220bcb` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. It also materializes the bounded eligibility fragment into one static query before `asyncpg` execution, repairing the exact-head Semgrep SQL-construction finding without a suppression; 18 focused queue/docstring tests pass locally. Fresh hosted checks and independent review remain required, with normal auto-merge enabled | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `fccaef21` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `014db02e` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `cb086313` | dashboard ranking and topic-influence stack now preserves Ask service imports and evidence contracts, restores the shared `source_post_visible` authorization dependency used by post reads, retains ontology imports and packaged-Turtle parity, transactional schema fixtures, the backend-worker plus MCP Compose profile, and one cutoff/public-verification and retained-revision presentation in the current timeline UI. Merged child #706 keeps the durable worker as the owner, records bounded structured validation evidence through union-free migration 0234, and pins the reviewed structured-failover runtime; merged child #707 forwards #705's atomic, advisory-locked voice-backfill completion guard from the stale historical stack into live #640. Exact-head hosted checks and independent review remain required | +| #640 | `78f9e5b1` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. The current head also carries the composed operations-response contract while retaining distinct Event and post counts and chronological project journeys. Exact-head hosted checks and independent review remain required | | #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -133,11 +133,11 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 20:44 KST found Strix failures on #629, #639, -#643, #644, #657, #680, and #701; #639 also had a terminal Full test suite -failure. All 17 open PRs had zero unresolved review threads, but every head -still had queued or in-progress gates and lacked exact-head independent -approval. Queued checks and bot success statuses are not merge evidence. +The exact-head check-run scan at 21:27 KST found Strix failures on #629, #643, +#644, and #658. Review-thread inspection found one unresolved thread on #709 +and two on #679; the other 16 open heads had zero. Every head still had queued +or in-progress gates and lacked exact-head independent approval. Queued checks +and bot success statuses are not merge evidence. ### Ecosystem owner-boundary evidence @@ -509,7 +509,7 @@ for wholesale replay from #490. | 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 | -| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered selected-unit membership is bound to the caller's probability strata and the digest-bound fast-mlsirm Rust sample-size artifact; any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. The observed 80-record deterministic window proves pipeline cardinality only, so corpus inference is unavailable | Produce the independently versioned Rust owner artifact and caller manifest with population/frame size, known inclusion probabilities, frame and membership digests, prior-evidence reference, and retained-failure declaration. Retry failed selected members in place; emit a non-identifying coverage aggregate only after every declared member succeeds | +| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered membership is bound to caller hashes, probability strata, and a digest-bound fast-mlsirm Rust artifact; any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. For `N = 43,814`, `n = 80` implies approximately `±10.95%` at 95% under `p = .5` only for a valid simple random sample. The observed deterministic window proves pipeline cardinality only, so corpus inference is unavailable until the independently verifiable owner artifact and caller manifest exist | Produce the independently versioned Rust owner artifact and caller manifest with population/frame size, known inclusion probabilities, frame and membership digests, prior-evidence reference, and retained-failure declaration. Retry failed selected members in place; emit a non-identifying coverage aggregate only after every declared member succeeds | | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. On PR #639 exact head `f6c8c93f`, a local 4-VU/30-second synthetic authenticated run completed 4,650 iterations (152.21/s), 13,952 requests (456.71/s), and zero failed requests. Ask enqueue was 74.90 ms; Ask polling p95 was 29.94 ms; combined post/lineage reads were 23.22 ms average and 40.88 ms p95. The one Ask job settled `succeeded`. A mid-run sample observed backend CPU 98.03%, PostgreSQL CPU 107.59%, Valkey 1.90% with zero rejected connections/evictions, and orchestrator 0.47%; PostgreSQL showed no lock wait. This names CPU pressure at the application/database boundary but does not establish a latency bottleneck, capacity limit, or SLO. The first PR #629 image build also reproduced the pnpm 11 ignored-build failure; PR #639's workspace-policy copy fixes that owned Compose contract and now locks the seed extras in regression. PR #629 exact head `48496ff6` still moves Global Ask question embedding before `pool.acquire()` and remains blocked on independent review | Land #639 and #629 through their protected gates, repeat this declared workload on their merge heads with endpoint-separated trends and repeated resource samples, then increase concurrency only until an observed latency/error knee identifies a bottleneck. Retain raw distributions and resource configuration; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | From c2d11a8a6df32b40e3c8e66aa8a930fc6a71c244 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 01:17:25 +0900 Subject: [PATCH 219/238] docs: refresh exact-head product gap baseline --- docs/product-technical-gap-baseline.md | 81 ++++++++++++++++---------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e88b1b899..f46cae2e2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 18 open PRs and 10 open issues. The exact-head +At this snapshot there were 22 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-26 21:27 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 00:46 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, @@ -78,28 +78,32 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 18 open PRs and 10 +at this refresh. The live queue contains 22 open PRs and 10 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 | | ---: | --- | --- | -| #709 | `3157645a` | publishes ADR 0232's 24-concept DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights. Its 103 focused ontology, publication, and documentation checks pass locally; protected hosted checks and independent review remain required | -| #704 | `6fcf03df` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head also converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500; all review threads are resolved, while protected hosted checks and independent review remain required | -| #702 | `ebb1dfa8` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and fails closed unless a caller-supplied probability-sample manifest binds every selected opaque membership token, stratum, caller hash, and digest-bound Rust owner artifact. Provider/transport/item failures remain in the declared denominator and invalidate the whole sample; failed members cannot be dropped or replaced. For `N = 43,814`, a valid simple random sample of `n = 80` would have an approximately `±10.95%` 95% margin of error at `p = .5` after finite-population correction. The observed 80-record deterministic window is not that probability sample, so corpus inference remains unavailable until a verifiable fast-mlsirm artifact and bound caller manifest exist. The current head preserves authoritative bodies during metadata-only refresh; protected hosted checks and independent review remain required | +| #714 | `5f294c72` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current head resolves the cross-PR identities as unique ADR 0247 and replay-safe migration 0236, requires explicit positive resource budgets, keeps private posts out of egress and activity publication, and replaces implementation-boundary copy with the next evidence action. Forty focused backend checks, 393 frontend checks, lint, Storybook build, and synthetic desktop/mobile screenshot inspection pass locally; all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #713 | `fea73e19` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed six unsupported named-organization `rel_*` projections rather than mirroring post classifications into entity facts, added the missing boundary test, and aligned changelog vocabulary; 99 focused checks pass and review threads are resolved. Parent #640 now carries the same twelve-code post contract while preserving the independently governed six organization-relationship codes; both still require protected gates | +| #711 | `33fd146e` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. Upstream #882 merged only into the still-open, conflicting #857 stack and its commit is not contained by contextual-orchestrator protected `main`; ADR 0070 therefore forbids repinning or treating it as validated delivery. The existing pinned image remains healthy in a fixed-name Compose smoke, six documentation checks pass, the P1 dependency review remains intentionally unresolved, and auto-merge correctly stays disabled | +| #710 | `8df04b68` | records the worker-function delivery gap against #709 and reconciles its own 20-PR historical snapshot count. It remains documentation candidate evidence until protected delivery; exact-head hosted checks and independent review remain required | +| #709 | `ec9a1353` | publishes ADR 0232's 24-concept DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level DOT-to-O*NET/Fleishman crosswalk. The current head preserves the complete ordered DOT Appendix B definitions, canonical `Signaling` spelling, SKOS definitions, deterministic publication rendering, and full taxonomy digest, and removes all unused imports and redundant `range` starts identified by exact-head static analysis. Eighty-three focused ontology/publication checks and Ruff pass locally; protected hosted checks and independent review remain required | +| #704 | `027323cf` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500 and removes a duplicate module alias from its focused test boundary. Sixteen adjudication-client checks pass locally and all review threads are resolved; protected hosted checks and independent review remain required | +| #702 | `5de66ab9` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The manifest binds selected opaque membership tokens, strata, exact inclusion-probability numerator/denominator pairs, frame hashes, and a selection digest; Rust artifact v2 binds those exact `(n_h, N_h)` ratios with population, confidence, margin, finite-population correction, allocation, and content hashes. Provider/transport/item failures remain in the denominator and invalidate the sample. For `N = 43,814`, `n = 80` is only a pilot with approximately `±10.95%` 95% margin at `p = .5`; corpus inference remains explicitly unavailable until a separate terminal Rust estimator/variance/interval artifact exists. Thirty-six focused audit/documentation/docstring checks and Ruff pass locally, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | -| #680 | `6013821a` | replaces rendered implementation-boundary language across source, project, summary, search, customer, analysis-run, and empty-board states with the next valid customer action. The exact-head authenticated synthetic 1280×720 audit confirmed the empty-board guidance and absence of a developer command; focused empty-board and 64 i18n completeness checks, lint, production build, and diff check passed locally. Fresh exact-head hosted checks and independent review are required | -| #679 | `d5220bcb` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and locks translated next-action and migration contracts. It also materializes the bounded eligibility fragment into one static query before `asyncpg` execution, repairing the exact-head Semgrep SQL-construction finding without a suppression; 18 focused queue/docstring tests pass locally. Fresh hosted checks and independent review remain required, with normal auto-merge enabled | +| #680 | `bebab3d6` | replaces rendered implementation-boundary language across source, project, summary, search, customer, analysis-run, and empty-board states with the next valid customer action. The exact-head authenticated synthetic 1280×720 audit confirmed the empty-board guidance and absence of a developer command; 39 focused backend checks, five focused UI checks, 64 i18n checks, lint, and production build passed locally. The follow-up review confirmed the customer-action wording is consistent and all threads are resolved; fresh exact-head hosted checks and independent review are required | +| #679 | `13ecf41d` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and excludes claims and sources created after a cutoff. The Semgrep finding is narrowly suppressed at the audited `asyncpg` call because the statement is assembled only from repository-owned constant fragments and its sole runtime value remains parameter `$1`; 58 focused Ask/claim/schema checks pass. Normal auto-merge is enabled, while fresh exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `014db02e` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The row records the parent observed immediately before this documentation commit because a commit cannot contain its own SHA; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `4855c380` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. This parent also records the 18-PR exact-head queue before the present evidence correction; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `78f9e5b1` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. The current head also carries the composed operations-response contract while retaining distinct Event and post counts and chronological project journeys. Exact-head hosted checks and independent review remain required | +| #640 | `fa9f0aeb` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. The current head composes latest #713 as an ancestor and updates ADR 0244, migration 0230 replay/trigger/backfill, SHACL, ontology mirrors, PRD, and tests to accept all twelve post codes while retaining the independently governed six post-by-organization relationship codes; a post voice never assigns a relationship to every named organization. Ninety-one focused, two live PostgreSQL, and eight documentation/docstring checks pass; exact-head hosted checks and independent review remain required | | #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -113,6 +117,12 @@ and `60b4c6004739a05e63edae8ff160758f8e665919`. These are stack-integration evidence only; they are not protected-`main` delivery. Their acceptance now travels with the two parent heads above. +PR #712 merged into the non-default #702 stack as `78a144107`; it freezes +LineageWeave-local scoring and entity-resolution arithmetic behind ADR 0245 +without inventing a replacement. The whitespace repair for that carried ADR +is present on the current #702 head. This is stack-integration evidence only, +not protected-`main` delivery. + PRs #692, #697, and #694 merged into the non-default #693 composition as `cdd499b161053a9c5439181e8f39e1baa80e68c0` and `dc3ebb6911187637cf85fcbcc036cf39e571aaec`. PR #699 merged into the @@ -133,11 +143,15 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 21:27 KST found Strix failures on #629, #643, -#644, and #658. Review-thread inspection found one unresolved thread on #709 -and two on #679; the other 16 open heads had zero. Every head still had queued -or in-progress gates and lacked exact-head independent approval. Queued checks -and bot success statuses are not merge evidence. +The exact-head check-run scan at 00:46 KST found 21 of 22 heads with a terminal +failure and 12 with a queued or in-progress check. Strix accounted for 20 +failed heads; three heads had full-suite failures, three had multi-language +Semgrep failures, and one had a Semgrep OSS failure. Fourteen unresolved +threads were distributed across five heads at the scan boundary; subsequent +#714 repair resolved its current threads and started fresh exact-head checks. +All 22 heads lacked formal approval, so no candidate is protected delivery. +Queued checks, `MERGEABLE`, auto-merge, and bot success statuses are not merge +evidence. ### Ecosystem owner-boundary evidence @@ -155,15 +169,16 @@ and bot success statuses are not merge evidence. protected-main merge evidence. LineageWeave may consume the owner contract only after that composed head passes its protected gate; it may not retain Python vector arithmetic. -- `ContextualWisdomLab/fast-mlsirm` draft PR #1445 exact head `74f7c902` - supplies current owner evidence for the Rust-owned, content-addressed - polytomous period artifact: four Rust-core tests, seven Python-boundary tests, - and 25 documentation/governance tests pass alongside `cargo check`, wheel - build, and Ruff. The head advance changes only governed changelog evidence; - it does not add released runtime or corpus evidence. The PR remains Draft - with hosted checks queued and zero unresolved threads, so this is - owner-candidate evidence rather than a protected released artifact; corpus - inference remains unavailable until that artifact passes its protected gate. +- `ContextualWisdomLab/fast-mlsirm` PR #1445 exact head `e2e86a7d` + supplies the Rust-owned finite-population proportion design artifact consumed + by #702: source and algorithm identities, population, confidence, margin, + expected proportion, uncorrected and corrected sample sizes, allocation, + ordered strata, exact `(n_h, N_h)` inclusion ratios, and + input/output/artifact hashes. The ratios are bound through Rust, PyO3, + Python, output hashing, and artifact hashing. Five Rust and eleven PyO3 + checks pass with `cargo check`, Ruff, and lock verification. The PR is ready + and auto-merge is enabled, but hosted checks and independent approval remain + pending; it is owner-candidate evidence, not protected release evidence. - `ContextualWisdomLab/TEPP` PR #237 merged to protected `main` as `eec86be724e9131ecfe8f152db0f7728af68017f`. It publishes the fail-closed lineage-criterion anchor wire contract but explicitly does not implement the @@ -188,8 +203,12 @@ separate from #640's 0211/0222 and #679's 0224. The former #640/#663 ADR identities. A current-head inventory confirms that #702's semantic-coverage decisions moved to ADR 0240/0241/0242 and #704's external-lineage decision moved to ADR 0239. #668's evidence-bound project-history projection moved from -the remaining shared 0232 identifier to ADR 0243, leaving #640's -source-preserving voice semantic taxonomy as the sole 0232 decision. The +the remaining shared 0232 identifier to ADR 0243, and #640's +source-preserving voice semantic taxonomy now owns ADR 0244. That leaves +#709's worker-function taxonomy as the sole ADR 0232 decision. #713's expanded +post-voice taxonomy now owns union-free ADR 0246 and migration 0235; #640 +composes the same post vocabulary without fabricating organization +relationships. The open-head migration union found one distinct-name collision at 0230: #640's voice semantic taxonomy and #700's conversation-turn evidence. #700 now owns union-free migration 0233, preserving #640's accepted 0230 identity; focused @@ -268,7 +287,7 @@ Three systemic gates currently dominate the queue: ContextualWisdomLab/.github#1320 merged to protected `main` as `d2c554dbbc04854db6215970fabb70cef1ceb690`; its former candidate head is no longer open-PR evidence. Current follow-up #1350 is open at exact head - `7e44aa17`, with zero unresolved threads and no terminal failed checks, but + `045f1789`, with zero unresolved threads and no terminal failed checks, but its required hosted checks are queued and it has no formal independent approval. It changes the owned Strix fallback contract and focused regression only. Until #1350 passes its protected gate and downstream scans @@ -503,17 +522,17 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Seventeen PRs remain open at the 20:44 KST snapshot; every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent and last-push approvals, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty-two PRs remain open at the 00:46 KST snapshot; twenty-one target `main` and #711 targets #640. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | -| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered membership is bound to caller hashes, probability strata, and a digest-bound fast-mlsirm Rust artifact; any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. For `N = 43,814`, `n = 80` implies approximately `±10.95%` at 95% under `p = .5` only for a valid simple random sample. The observed deterministic window proves pipeline cardinality only, so corpus inference is unavailable until the independently verifiable owner artifact and caller manifest exist | Produce the independently versioned Rust owner artifact and caller manifest with population/frame size, known inclusion probabilities, frame and membership digests, prior-evidence reference, and retained-failure declaration. Retry failed selected members in place; emit a non-identifying coverage aggregate only after every declared member succeeds | +| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered opaque membership is bound to probability strata, frame hashes, a selection digest, and exact inclusion numerator/denominator pairs that equal fast-mlsirm's Rust-attested `(n_h, N_h)` ratios. Any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. For `N = 43,814`, `n = 80` implies approximately `±10.95%` at 95% under `p = .5` only for a valid simple random sample. The current Rust artifact proves design arithmetic and exact inclusion ratios, not the achieved estimator, variance, or interval. Corpus inference therefore remains unavailable | Land fast-mlsirm #1445 and #702 through their protected gates. Then execute the complete declared probability sample without replacement of failures and produce a separate terminal Rust artifact for the estimand, estimator, variance, and achieved interval. Commit only the non-identifying aggregate after every selected member succeeds | | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. On PR #639 exact head `f6c8c93f`, a local 4-VU/30-second synthetic authenticated run completed 4,650 iterations (152.21/s), 13,952 requests (456.71/s), and zero failed requests. Ask enqueue was 74.90 ms; Ask polling p95 was 29.94 ms; combined post/lineage reads were 23.22 ms average and 40.88 ms p95. The one Ask job settled `succeeded`. A mid-run sample observed backend CPU 98.03%, PostgreSQL CPU 107.59%, Valkey 1.90% with zero rejected connections/evictions, and orchestrator 0.47%; PostgreSQL showed no lock wait. This names CPU pressure at the application/database boundary but does not establish a latency bottleneck, capacity limit, or SLO. The first PR #629 image build also reproduced the pnpm 11 ignored-build failure; PR #639's workspace-policy copy fixes that owned Compose contract and now locks the seed extras in regression. PR #629 exact head `48496ff6` still moves Global Ask question embedding before `pool.acquire()` and remains blocked on independent review | Land #639 and #629 through their protected gates, repeat this declared workload on their merge heads with endpoint-separated trends and repeated resource samples, then increase concurrency only until an observed latency/error knee identifies a bottleneck. Retain raw distributions and resource configuration; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | -| Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. The reference is write-only: repository search finds it in import/chunk/persistence paths but no authorized read projection or API response, so a user cannot yet open the exact source evidence behind a cited turn. It is a current-main candidate, not protected delivery; Naruon producer consumption, authorized semantic-only retrieval/citation, and runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, then define an ADR-governed read contract that returns or resolves the opaque reference only for an authorized semantic unit and guides the user to open its source evidence. Publish the immutable producer fixture, add a Naruon RFC/JMAP-derived consumer, and prove ABAC non-disclosure, exact-unit citation, safe source resolution, and absence of cross-graph inference on released heads | +| Source conversation-turn ingestion | PR #700 adds ADR 0238's bounded versioned PostgreSQL-import envelope, whole-result preflight, ordered turn persistence, and opaque caller evidence references without body-pattern speaker inference. The opaque adapter locator stays private, while an eligible live Global Ask citation can return the typed `open_cited_content_unit(post_id, unit_index)` action after source eligibility and caller authorization succeed. That action opens the already-authorized product unit without revealing or resolving the adapter locator. It is a current-main candidate, not protected delivery; Naruon producer consumption, direct source-system resolution, and released-head runtime ABAC evidence remain absent. Ask conversation history and ThreadWeave message threading remain separate graphs | Land #700 through the protected gate, publish the immutable producer fixture, add a Naruon RFC/JMAP-derived consumer, and prove ABAC non-disclosure, exact-unit citation and navigation, and absence of cross-graph inference on released heads. Add a direct source-system resolver only after a separate authorization and audit ADR defines it | | Event and project semantics | Multi-project mentions, project-bound actions, 5W1H, requester/processor, and semantic relations exist in ADR 0036/0052/0100/0111/0129 and active stacks | Aggregate authenticated evidence must show distinct projects and events, explicit requester/processor and real R&R, normalized relative time, and product/entity relations without promoting attendance or co-occurrence | | Product hierarchy and voice exploration | PRs #692 and #694 merged into #693, then #693 merged only into non-default parent #640. That stack carries the evidence-bound product hierarchy and overlapping voice classifications with source eligibility, ABAC, original evidence, and synthetic-row exclusion from real-source summaries. The open parent is not protected delivery | Land #640 through its protected gate, then prove through authenticated aggregate API and rendered acceptance that authorized users can navigate product hierarchy and overlapping voice classes without exposing hidden evidence or implementation ownership | | Knowledge Graph readability | PR #659 is protected-main delivery in `main@494b54e2`: ontology node types use semantic-family light/dark tokens while shape and text remain non-color channels; exact-value tables retain full labels | Complete authenticated rendered acceptance for light/dark contrast, keyboard graph navigation, full labels, and evidence tables | @@ -522,7 +541,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts, LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer, and TEPP #237's criterion-anchor wire contract are protected. #237 intentionally does not implement the estimator, so no emitted digest-bound terminal artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Implement and verify the TEPP estimator behind the protected #237 contract, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm Draft #1445 exact head `74f7c902` supplies four Rust-core, seven Python-boundary, and 25 documentation/governance passing tests plus `cargo check`, wheel-build, and Ruff evidence for its relation-safe content-addressed owner artifact; its latest change is governed changelog evidence only, and queued hosted checks plus Draft status make it unavailable for corpus inference. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 through its protected gate before replacing period arithmetic or claiming corpus inference. Add graph-ranking and fusion-contribution Rust artifacts at the owning boundary before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1445 exact head `e2e86a7d` now supplies a content-addressed Rust finite-population proportion design artifact with exact `(n_h, N_h)` ratios bound through Rust, PyO3/Python, output hash, and artifact hash; #702 exact head `5de66ab9` only replays and binds that owner output. Neither is protected delivery, and no terminal estimator/variance/interval artifact exists. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 and #702 before corpus inference. Add graph-ranking, fusion-contribution, and estimator/variance/interval Rust artifacts at their owning boundaries before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | From 360d62acb2306647aabde81d3e0373929babe1a3 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 01:18:25 +0900 Subject: [PATCH 220/238] docs: sync repaired research head --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index f46cae2e2..49460c941 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -85,7 +85,7 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #714 | `5f294c72` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current head resolves the cross-PR identities as unique ADR 0247 and replay-safe migration 0236, requires explicit positive resource budgets, keeps private posts out of egress and activity publication, and replaces implementation-boundary copy with the next evidence action. Forty focused backend checks, 393 frontend checks, lint, Storybook build, and synthetic desktop/mobile screenshot inspection pass locally; all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #714 | `aa93318f` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current head resolves the cross-PR identities as unique ADR 0247 and replay-safe migration 0236, requires explicit positive resource budgets, keeps private posts out of egress and activity publication, retains determinate citations when a later lead fails, and replaces implementation-boundary copy with the next evidence action. Forty-seven focused backend checks, 393 frontend checks, lint, Storybook build, and synthetic desktop/mobile screenshot inspection pass locally; all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #713 | `fea73e19` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed six unsupported named-organization `rel_*` projections rather than mirroring post classifications into entity facts, added the missing boundary test, and aligned changelog vocabulary; 99 focused checks pass and review threads are resolved. Parent #640 now carries the same twelve-code post contract while preserving the independently governed six organization-relationship codes; both still require protected gates | | #711 | `33fd146e` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. Upstream #882 merged only into the still-open, conflicting #857 stack and its commit is not contained by contextual-orchestrator protected `main`; ADR 0070 therefore forbids repinning or treating it as validated delivery. The existing pinned image remains healthy in a fixed-name Compose smoke, six documentation checks pass, the P1 dependency review remains intentionally unresolved, and auto-merge correctly stays disabled | | #710 | `8df04b68` | records the worker-function delivery gap against #709 and reconciles its own 20-PR historical snapshot count. It remains documentation candidate evidence until protected delivery; exact-head hosted checks and independent review remain required | From d8cf63b061cd02b8f1b1ef4c8a4811e823628a49 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 01:50:38 +0900 Subject: [PATCH 221/238] fix(ui): retain measurement retry identity per run --- .../adr/0235-post-ask-conversation-history.md | 3 ++ docs/product-technical-gap-baseline.md | 54 ++++++++++--------- frontend/src/App.test.tsx | 25 ++++----- frontend/src/App.tsx | 20 +++---- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/docs/adr/0235-post-ask-conversation-history.md b/docs/adr/0235-post-ask-conversation-history.md index c75a6519d..eeda9c01b 100644 --- a/docs/adr/0235-post-ask-conversation-history.md +++ b/docs/adr/0235-post-ask-conversation-history.md @@ -51,6 +51,9 @@ orchestrator is off. Account history is additional, not a replacement. UUID, and cannot load a conversation against a different post id. * Revoked post visibility removes that post's citation projection; the stored answer remains account-owned transcript data. +* Hard deletion is a separate data-erasure boundary and cascades the post's + conversations. Callers must use visibility revocation, not hard deletion, + when the source record must remain retained but inaccessible. * TEPP topic modeling of how many posts can connect, and how many lineages form under temporal precedence, remains deferred. * Reauthorization for a conversation's turns is batched diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 49460c941..bae2109ab 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 22 open PRs and 10 open issues. The exact-head +At this snapshot there were 28 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 00:46 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 01:40 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, @@ -78,32 +78,38 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 22 open PRs and 10 +at this refresh. The live queue contains 28 open PRs and 10 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 | | ---: | --- | --- | -| #714 | `aa93318f` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current head resolves the cross-PR identities as unique ADR 0247 and replay-safe migration 0236, requires explicit positive resource budgets, keeps private posts out of egress and activity publication, retains determinate citations when a later lead fails, and replaces implementation-boundary copy with the next evidence action. Forty-seven focused backend checks, 393 frontend checks, lint, Storybook build, and synthetic desktop/mobile screenshot inspection pass locally; all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | -| #713 | `fea73e19` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed six unsupported named-organization `rel_*` projections rather than mirroring post classifications into entity facts, added the missing boundary test, and aligned changelog vocabulary; 99 focused checks pass and review threads are resolved. Parent #640 now carries the same twelve-code post contract while preserving the independently governed six organization-relationship codes; both still require protected gates | -| #711 | `33fd146e` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. Upstream #882 merged only into the still-open, conflicting #857 stack and its commit is not contained by contextual-orchestrator protected `main`; ADR 0070 therefore forbids repinning or treating it as validated delivery. The existing pinned image remains healthy in a fixed-name Compose smoke, six documentation checks pass, the P1 dependency review remains intentionally unresolved, and auto-merge correctly stays disabled | -| #710 | `8df04b68` | records the worker-function delivery gap against #709 and reconciles its own 20-PR historical snapshot count. It remains documentation candidate evidence until protected delivery; exact-head hosted checks and independent review remain required | -| #709 | `ec9a1353` | publishes ADR 0232's 24-concept DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level DOT-to-O*NET/Fleishman crosswalk. The current head preserves the complete ordered DOT Appendix B definitions, canonical `Signaling` spelling, SKOS definitions, deterministic publication rendering, and full taxonomy digest, and removes all unused imports and redundant `range` starts identified by exact-head static analysis. Eighty-three focused ontology/publication checks and Ruff pass locally; protected hosted checks and independent review remain required | -| #704 | `027323cf` | publishes the bounded external-lineage contract with union-free ADR 0239, fail-closed structured adjudication, and exact same-group inference eligibility for the weights-unavailable disclosure. The current head converts malformed adjudication output into the governed provider-failure boundary instead of leaking a raw 500 and removes a duplicate module alias from its focused test boundary. Sixteen adjudication-client checks pass locally and all review threads are resolved; protected hosted checks and independent review remain required | -| #702 | `5de66ab9` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The manifest binds selected opaque membership tokens, strata, exact inclusion-probability numerator/denominator pairs, frame hashes, and a selection digest; Rust artifact v2 binds those exact `(n_h, N_h)` ratios with population, confidence, margin, finite-population correction, allocation, and content hashes. Provider/transport/item failures remain in the denominator and invalidate the sample. For `N = 43,814`, `n = 80` is only a pilot with approximately `±10.95%` 95% margin at `p = .5`; corpus inference remains explicitly unavailable until a separate terminal Rust estimator/variance/interval artifact exists. Thirty-six focused audit/documentation/docstring checks and Ruff pass locally, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #721 | `e12533e2` | stacked occupational-construct persistence candidate. Its recorded base OID does not match current parent #718, it has three unresolved threads, auto-merge is disabled, and it cannot inherit parent checks or review evidence | +| #720 | `dda0531d` | cancels stale test runs after PR closure; normal auto-merge is enabled, but independent review remains required before protected delivery | +| #719 | `2a353d8d` | stacked on #718 and extends the occupational ontology. One review thread remains unresolved and auto-merge is disabled pending parent delivery | +| #718 | `6c49b3df` | stacked on #709 and adds evidence-bound occupational constructs. One review thread remains unresolved and auto-merge is disabled pending parent delivery | +| #717 | `0a8ce31f` | stacked on #713 and persists evidence-bearing Voice-of-X combinations. Three review threads and a pending external review remain; auto-merge is disabled pending parent delivery | +| #716 | `bee26e53` | stacked on #711 and prioritizes the evidence-bound operations backfill. Two review threads remain unresolved and auto-merge is disabled pending both parent heads | +| #714 | `f92bc988` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates a malformed URL port instead of aborting all research, preserves customer next actions, and retains synthetic desktop/mobile evidence. Exact-head hosted checks plus independent review remain required | +| #713 | `cc3dfc14` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed unsupported named-organization projections, and preserves the independently governed organization-relationship vocabulary. Exact-head hosted checks and independent review remain required | +| #711 | `8902e37f` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. One review thread and the full suite remain pending, while auto-merge correctly stays disabled until its parent and dependency contract are delivered | +| #710 | `47dbd335` | records the worker-function delivery gap against #709. One review thread remains unresolved; exact-head hosted checks and independent review remain required | +| #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | +| #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | +| #702 | `7de6af0c` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The manifest binds selected opaque membership tokens, strata, exact inclusion-probability numerator/denominator pairs, frame hashes, and a selection digest; Rust artifact v2 binds those exact `(n_h, N_h)` ratios with population, confidence, margin, finite-population correction, allocation, and content hashes. Provider/transport/item failures remain in the denominator and invalidate the sample. For `N = 43,814`, `n = 80` is only a pilot with approximately `±10.95%` 95% margin at `p = .5`; corpus inference remains explicitly unavailable until a separate terminal Rust estimator/variance/interval artifact exists. Thirty-six focused audit/documentation/docstring checks and Ruff pass locally, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | -| #680 | `bebab3d6` | replaces rendered implementation-boundary language across source, project, summary, search, customer, analysis-run, and empty-board states with the next valid customer action. The exact-head authenticated synthetic 1280×720 audit confirmed the empty-board guidance and absence of a developer command; 39 focused backend checks, five focused UI checks, 64 i18n checks, lint, and production build passed locally. The follow-up review confirmed the customer-action wording is consistent and all threads are resolved; fresh exact-head hosted checks and independent review are required | -| #679 | `13ecf41d` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head reuses the shared source-publication eligibility boundary, validates claim/truth lookup categories, revokes egress after visibility becomes non-public, and excludes claims and sources created after a cutoff. The Semgrep finding is narrowly suppressed at the audited `asyncpg` call because the statement is assembled only from repository-owned constant fragments and its sole runtime value remains parameter `$1`; 58 focused Ask/claim/schema checks pass. Normal auto-merge is enabled, while fresh exact-head hosted checks and independent review remain required | +| #680 | `876129e5` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The follow-up fixes the Vietnamese action-label mismatch and adds four-locale containment coverage; 68 i18n checks and lint pass, all threads are resolved, and hosted checks plus independent review remain required | +| #679 | `01cb291f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and wraps claim/evidence rows at desktop and mobile widths. A Storybook interaction test, 167 focused tests, lint, build, and committed synthetic desktop/mobile screenshots verify the state; all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `4855c380` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. This parent also records the 18-PR exact-head queue before the present evidence correction; re-fetch the resulting PR head for lifecycle use. Hosted checks and independent approval remain pending | +| #667 | pre-documentation parent `360d62ac` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The current repair retains one retry key per failed measurement run across run switches and records hard deletion as an intentional erasure boundary distinct from visibility revocation. Focused interaction tests, lint, production build, and documentation checks pass; re-fetch the resulting PR head for lifecycle use | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | -| #643 | `42ba340e` | accessible status notices; BLOCKED with review required | -| #640 | `fa9f0aeb` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. The current head composes latest #713 as an ancestor and updates ADR 0244, migration 0230 replay/trigger/backfill, SHACL, ontology mirrors, PRD, and tests to accept all twelve post codes while retaining the independently governed six post-by-organization relationship codes; a post voice never assigns a relationship to every named organization. Ninety-one focused, two live PostgreSQL, and eight documentation/docstring checks pass; exact-head hosted checks and independent review remain required | +| #643 | `8767de1b` | accessible status notices; hosted checks and independent review remain required | +| #640 | `5594029c` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. The current head composes latest #713 as an ancestor while retaining the independently governed post-by-organization relationship vocabulary; exact-head hosted checks and independent review remain required | | #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -143,13 +149,11 @@ PR #686 was closed without merge at `fbca05d9`; its customer-copy work is not protected-main delivery and any still-required behavior must travel through an open current-main candidate rather than relying on that closed head. -The exact-head check-run scan at 00:46 KST found 21 of 22 heads with a terminal -failure and 12 with a queued or in-progress check. Strix accounted for 20 -failed heads; three heads had full-suite failures, three had multi-language -Semgrep failures, and one had a Semgrep OSS failure. Fourteen unresolved -threads were distributed across five heads at the scan boundary; subsequent -#714 repair resolved its current threads and started fresh exact-head checks. -All 22 heads lacked formal approval, so no candidate is protected delivery. +The exact-head scan at 01:40 KST found 12 of 28 heads with a terminal failure, +nine with a queued or in-progress context, and nine with unresolved review +threads. Twenty-one heads had normal squash auto-merge enabled; all seven +stacked children correctly remained off. All 28 heads lacked a qualifying +independent exact-head approval, so no candidate is protected delivery. Queued checks, `MERGEABLE`, auto-merge, and bot success statuses are not merge evidence. @@ -522,13 +526,13 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty-two PRs remain open at the 00:46 KST snapshot; twenty-one target `main` and #711 targets #640. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty-eight PRs remain open at the 01:40 KST snapshot: twenty-one target `main` and seven form four explicit stacks. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | -| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered opaque membership is bound to probability strata, frame hashes, a selection digest, and exact inclusion numerator/denominator pairs that equal fast-mlsirm's Rust-attested `(n_h, N_h)` ratios. Any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. For `N = 43,814`, `n = 80` implies approximately `±10.95%` at 95% under `p = .5` only for a valid simple random sample. The current Rust artifact proves design arithmetic and exact inclusion ratios, not the achieved estimator, variance, or interval. Corpus inference therefore remains unavailable | Land fast-mlsirm #1445 and #702 through their protected gates. Then execute the complete declared probability sample without replacement of failures and produce a separate terminal Rust artifact for the estimand, estimator, variance, and achieved interval. Commit only the non-identifying aggregate after every selected member succeeds | +| Corpus semantic-coverage inference | #702 accepts a declared sample only when ordered opaque membership is bound to probability strata, frame hashes, a selection digest, and exact inclusion numerator/denominator pairs that equal fast-mlsirm's Rust-attested `(n_h, N_h)` ratios. Any provider, transport, trace, parse, or item failure stays in the denominator and invalidates the complete sample. The existing five-time-stratum × 100-record diagnostic was not probability-selected and therefore supports pipeline diagnosis only, not corpus prevalence. For `N = 43,814`, a valid simple random `n = 80` implies approximately `±10.95%`, while `n = 500` would imply approximately `±4.36%`, at 95% under `p = .5`; those intervals do not attach to the current diagnostic. The current Rust artifact proves design arithmetic and exact inclusion ratios, not the achieved estimator, variance, design effect, or interval. Corpus inference therefore remains unavailable | Land fast-mlsirm #1445 and #702 through their protected gates. Then execute the complete declared probability sample without replacement of failures and produce a separate terminal Rust artifact for the estimand, estimator, variance, design effect, and achieved interval. Commit only the non-identifying aggregate after every selected member succeeds | | Concurrent web responsiveness | ADR 0204 releases pooled transactions during provider work, and the synthetic Compose boundary has an authenticated k6 E2E harness for Ask enqueue, concurrent reads, and job polling. On PR #639 exact head `f6c8c93f`, a local 4-VU/30-second synthetic authenticated run completed 4,650 iterations (152.21/s), 13,952 requests (456.71/s), and zero failed requests. Ask enqueue was 74.90 ms; Ask polling p95 was 29.94 ms; combined post/lineage reads were 23.22 ms average and 40.88 ms p95. The one Ask job settled `succeeded`. A mid-run sample observed backend CPU 98.03%, PostgreSQL CPU 107.59%, Valkey 1.90% with zero rejected connections/evictions, and orchestrator 0.47%; PostgreSQL showed no lock wait. This names CPU pressure at the application/database boundary but does not establish a latency bottleneck, capacity limit, or SLO. The first PR #629 image build also reproduced the pnpm 11 ignored-build failure; PR #639's workspace-policy copy fixes that owned Compose contract and now locks the seed extras in regression. PR #629 exact head `48496ff6` still moves Global Ask question embedding before `pool.acquire()` and remains blocked on independent review | Land #639 and #629 through their protected gates, repeat this declared workload on their merge heads with endpoint-separated trends and repeated resource samples, then increase concurrency only until an observed latency/error knee identifies a bottleneck. Retain raw distributions and resource configuration; set no SLO until representative capacity evidence is approved | | Image understanding | Region, OCR, and description work exists across active heads (#405, #419), but current runtime acceptance has not yet proved table-image structure, complete region coverage, or summary/image readiness together | Orchestrator-backed rendered workflow, original/derived asset provenance, region-before-OCR processing, and honest unsupported states; reconcile ADR 0052's image-bearing summary readiness with ADR 0098 before changing sequencing | | Semantic source rendering | ADR 0223 and migration 0221 were first delivered via #664/#660 and remain on protected `main@494b54e2`; persisted paragraph, list, table, MathML formula, and caller-parsed conversation-turn kinds remain explicit and image regions remain ordered normalized children | Prove an authorized semantic-only query retrieves each persisted unit kind and gather authenticated browser evidence that nesting, continuation alignment, formula units, and image regions retain source order | @@ -541,7 +545,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts, LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer, and TEPP #237's criterion-anchor wire contract are protected. #237 intentionally does not implement the estimator, so no emitted digest-bound terminal artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Implement and verify the TEPP estimator behind the protected #237 contract, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1445 exact head `e2e86a7d` now supplies a content-addressed Rust finite-population proportion design artifact with exact `(n_h, N_h)` ratios bound through Rust, PyO3/Python, output hash, and artifact hash; #702 exact head `5de66ab9` only replays and binds that owner output. Neither is protected delivery, and no terminal estimator/variance/interval artifact exists. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 and #702 before corpus inference. Add graph-ranking, fusion-contribution, and estimator/variance/interval Rust artifacts at their owning boundaries before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1445 exact head `e2e86a7d` now supplies a content-addressed Rust finite-population proportion design artifact with exact `(n_h, N_h)` ratios bound through Rust, PyO3/Python, output hash, and artifact hash; #702 exact head `7de6af0c` only replays and binds that owner output. Neither is protected delivery, and no terminal estimator/variance/interval artifact exists. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 and #702 before corpus inference. Add graph-ranking, fusion-contribution, and estimator/variance/interval Rust artifacts at their owning boundaries before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 341cbd7cf..cd1f9e4e7 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -3994,7 +3994,7 @@ describe("App, authenticated", () => { expect(createBodies[1].idempotency_key).not.toBe(createBodies[0].idempotency_key); }); - it("scopes an interrupted measurement retry key to its source run", async () => { + it("retains each interrupted measurement retry key across run switches", async () => { const fetchMock = stubBackend({ failMeasurementStartOnce: true, secondFailedTeppRun: true, @@ -4010,20 +4010,20 @@ describe("App, authenticated", () => { await waitFor(() => expect(screen.getByRole("button", { name: "Retry measurement" })).toBeEnabled(), ); - await userEvent.click(screen.getByRole("button", { name: "Retry measurement" })); - await waitFor(() => - expect( - fetchMock.mock.calls.filter((call) => - String(call[0]).endsWith("/api/analysis-runs/run-demo-tepp-retry/start"), - ), - ).toHaveLength(2), - ); await userEvent.click( screen.getByRole("button", { name: "Open analysis run: TEPP measurement · Failed · Other Demo Corp", }), ); await userEvent.click(screen.getByRole("button", { name: "Retry measurement" })); + const originalRun = screen + .getAllByRole("button", { + name: "Open analysis run: TEPP measurement · Failed · Demo Corp", + }) + .find((button) => button.textContent?.includes("3 documents")); + expect(originalRun).toBeDefined(); + await userEvent.click(originalRun!); + await userEvent.click(screen.getByRole("button", { name: "Retry measurement" })); const retries = fetchMock.mock.calls .filter( @@ -4032,9 +4032,10 @@ describe("App, authenticated", () => { .map((call) => JSON.parse(String(call[1]?.body))); expect(retries).toHaveLength(3); expect(retries[0].corporate_entity_id).toBe("corp-demo"); - expect(retries[1].idempotency_key).toBe(retries[0].idempotency_key); - expect(retries[2].corporate_entity_id).toBe("corp-other"); - expect(retries[2].idempotency_key).not.toBe(retries[0].idempotency_key); + expect(retries[1].corporate_entity_id).toBe("corp-other"); + expect(retries[1].idempotency_key).not.toBe(retries[0].idempotency_key); + expect(retries[2].corporate_entity_id).toBe("corp-demo"); + expect(retries[2].idempotency_key).toBe(retries[0].idempotency_key); }); it("does not tell a succeeded TEPP run to replace Failed", async () => { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 672161d25..80fc59859 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3162,10 +3162,7 @@ function AnalysisRunsPanel({ const [starting, setStarting] = useState(false); const [selectedEntityId, setSelectedEntityId] = useState(""); const lineageRequestKeyRef = useRef(null); - const measurementRetryKeyRef = useRef<{ - sourceRunId: string; - idempotencyKey: string; - } | null>(null); + const measurementRetryKeyRef = useRef(new Map()); const entitiesReady = corporateEntities !== null && entitiesLoadError === null; const requestLabel = requesting ? "Recording the run..." @@ -3249,13 +3246,12 @@ function AnalysisRunsPanel({ if (!selected || !analysisRunCanRetryMeasurement(selected)) return; setError(null); setStarting(true); - if (measurementRetryKeyRef.current?.sourceRunId !== selected.analysis_run_id) { - measurementRetryKeyRef.current = { - sourceRunId: selected.analysis_run_id, - idempotencyKey: crypto.randomUUID(), - }; + const sourceRunId = selected.analysis_run_id; + let idempotencyKey = measurementRetryKeyRef.current.get(sourceRunId); + if (!idempotencyKey) { + idempotencyKey = crypto.randomUUID(); + measurementRetryKeyRef.current.set(sourceRunId, idempotencyKey); } - const idempotencyKey = measurementRetryKeyRef.current.idempotencyKey; try { const created = await createAnalysisRun(accessToken, { run_kind_code: selected.run_kind_code, @@ -3266,10 +3262,10 @@ function AnalysisRunsPanel({ const listed = await fetchAnalysisRuns(accessToken); setRuns(listed.analysis_runs); setSelected(started); - measurementRetryKeyRef.current = null; + measurementRetryKeyRef.current.delete(sourceRunId); } catch (err) { if (err instanceof BackendError && err.status === 409) { - measurementRetryKeyRef.current = null; + measurementRetryKeyRef.current.delete(sourceRunId); } setError(err instanceof BackendError ? err.message : String(err)); } finally { From 964479b955b4b03cfb3f5880097c054892bd2757 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 01:59:11 +0900 Subject: [PATCH 222/238] docs: refresh exact-head product gap evidence --- docs/product-technical-gap-baseline.md | 42 +++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index bae2109ab..daceb1ef2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 28 open PRs and 10 open issues. The exact-head +At this snapshot there were 29 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 01:40 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 01:56 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, @@ -78,20 +78,21 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 28 open PRs and 10 +at this refresh. The live queue contains 29 open PRs and 10 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 | | ---: | --- | --- | -| #721 | `e12533e2` | stacked occupational-construct persistence candidate. Its recorded base OID does not match current parent #718, it has three unresolved threads, auto-merge is disabled, and it cannot inherit parent checks or review evidence | +| #723 | `e2cbca8e` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The ancestry is valid, eight focused catalog/schema/docstring checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #721 | `9214c50f` | stacked occupational-construct persistence candidate. The current head synchronizes its parent and removes the duplicate construct-detail field; lint and production build pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #720 | `dda0531d` | cancels stale test runs after PR closure; normal auto-merge is enabled, but independent review remains required before protected delivery | -| #719 | `2a353d8d` | stacked on #718 and extends the occupational ontology. One review thread remains unresolved and auto-merge is disabled pending parent delivery | -| #718 | `6c49b3df` | stacked on #709 and adds evidence-bound occupational constructs. One review thread remains unresolved and auto-merge is disabled pending parent delivery | -| #717 | `0a8ce31f` | stacked on #713 and persists evidence-bearing Voice-of-X combinations. Three review threads and a pending external review remain; auto-merge is disabled pending parent delivery | -| #716 | `bee26e53` | stacked on #711 and prioritizes the evidence-bound operations backfill. Two review threads remain unresolved and auto-merge is disabled pending both parent heads | -| #714 | `f92bc988` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates a malformed URL port instead of aborting all research, preserves customer next actions, and retains synthetic desktop/mobile evidence. Exact-head hosted checks plus independent review remain required | +| #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #717 | `684df3d8` | stacked on #713 and persists evidence-bearing Voice-of-X combinations. The current head preserves combined-voice cutoff semantics, client filtering, localization, and historical primary `recorded_at`; backend and targeted UI checks plus lint pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #716 | `239b6bab` | stacked on #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. Two informational threads still require correlated-subquery `EXPLAIN` evidence and tier-eligibility confirmation; auto-merge remains disabled pending both parent heads | +| #714 | `53a4b8b5` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates a malformed URL port, discards late responses after post switches, blocks private-post execution, and rejects NAT64, 6to4, and Teredo transition addresses before connection while preserving native public IPv6. Thirty-nine backend and two UI checks plus lint pass; all threads are resolved, auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #713 | `cc3dfc14` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed unsupported named-organization projections, and preserves the independently governed organization-relationship vocabulary. Exact-head hosted checks and independent review remain required | | #711 | `8902e37f` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. One review thread and the full suite remain pending, while auto-merge correctly stays disabled until its parent and dependency contract are delivered | | #710 | `47dbd335` | records the worker-function delivery gap against #709. One review thread remains unresolved; exact-head hosted checks and independent review remain required | @@ -109,7 +110,7 @@ context only. | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `8767de1b` | accessible status notices; hosted checks and independent review remain required | -| #640 | `5594029c` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. The current head composes latest #713 as an ancestor while retaining the independently governed post-by-organization relationship vocabulary; exact-head hosted checks and independent review remain required | +| #640 | `c142c4ea` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. PR #722 merged normally into this non-default parent to restore the dedicated Ask worker's semantic-query and public-verification factories plus the production-equivalent concurrent-migration fixture path; this is stack integration, not protected delivery. Exact-head hosted checks and independent review remain required | | #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -129,6 +130,12 @@ without inventing a replacement. The whitespace repair for that carried ADR is present on the current #702 head. This is stack-integration evidence only, not protected-`main` delivery. +PR #722 merged normally into non-default parent #640 as `c142c4ea`; it restores +the dedicated Ask worker's semantic-query and opt-in public-verification +factories and the production-equivalent concurrent-migration fixture path. +This is stack-integration evidence only and cannot substitute for #640's +protected-`main` delivery. + PRs #692, #697, and #694 merged into the non-default #693 composition as `cdd499b161053a9c5439181e8f39e1baa80e68c0` and `dc3ebb6911187637cf85fcbcc036cf39e571aaec`. PR #699 merged into the @@ -151,9 +158,10 @@ open current-main candidate rather than relying on that closed head. The exact-head scan at 01:40 KST found 12 of 28 heads with a terminal failure, nine with a queued or in-progress context, and nine with unresolved review -threads. Twenty-one heads had normal squash auto-merge enabled; all seven -stacked children correctly remained off. All 28 heads lacked a qualifying -independent exact-head approval, so no candidate is protected delivery. +threads. The 01:56 follow-up contained 29 open heads after #723 opened; 22 +targeted `main` with normal auto-merge and seven stacked children correctly +remained off. No current head had a qualifying independent exact-head approval, +so no candidate is protected delivery. Queued checks, `MERGEABLE`, auto-merge, and bot success statuses are not merge evidence. @@ -367,6 +375,12 @@ not add a LineageWeave-local duplicate workflow. ContextualWisdomLab/.github#125 merged at exact head `897819c4` to repair the pnpm/coverage-evidence workflow; newly created exact PR heads must still prove the runtime behavior because merged workflow source alone is not check evidence. +The local `com.contextualwisdomlab.lineageweave-hourly` launchd registration +was live-audited at this snapshot with a 3,600-second interval, 16 recorded +runs, and last exit code 0; its output log contains completed queue/repair +iterations. Registration and prior successful exits do not prove the next run +or transfer protected-head evidence, so every invocation still re-reads live +PR state. Figma design-system boundary (ADR 0002): File ID `1Su3lDRmiZdcUs47t1QwIX`. The sanitized file now contains synthetic Event Lineage desktop (`5:14`) and @@ -526,7 +540,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty-eight PRs remain open at the 01:40 KST snapshot: twenty-one target `main` and seven form four explicit stacks. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty-nine PRs remain open at the 01:56 KST snapshot: twenty-two target `main` and seven form four explicit stacks. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 85c2b1554d41b9931a18e5073dc7db10ce3c7b3e Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 02:07:06 +0900 Subject: [PATCH 223/238] docs: refresh ontology queue evidence --- docs/product-technical-gap-baseline.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index daceb1ef2..f2c87d69d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 29 open PRs and 10 open issues. The exact-head +At this snapshot there were 30 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 01:56 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 02:06 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, @@ -78,27 +78,28 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 29 open PRs and 10 +at this refresh. The live queue contains 30 open PRs and 10 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 | | ---: | --- | --- | -| #723 | `e2cbca8e` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The ancestry is valid, eight focused catalog/schema/docstring checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #724 | `e4599dc5` | stacked on #723 and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. One hundred ten focused ontology/publication/docstring checks pass; CodeRabbit is successful, Devin remains pending, and auto-merge remains disabled pending parent delivery | +| #723 | `30ddc8fd` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The current repair normalizes whitespace-only descriptions to unavailable rather than publishing empty literals. Seven focused catalog/docstring checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #721 | `9214c50f` | stacked occupational-construct persistence candidate. The current head synchronizes its parent and removes the duplicate construct-detail field; lint and production build pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #720 | `dda0531d` | cancels stale test runs after PR closure; normal auto-merge is enabled, but independent review remains required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `684df3d8` | stacked on #713 and persists evidence-bearing Voice-of-X combinations. The current head preserves combined-voice cutoff semantics, client filtering, localization, and historical primary `recorded_at`; backend and targeted UI checks plus lint pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #716 | `239b6bab` | stacked on #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. Two informational threads still require correlated-subquery `EXPLAIN` evidence and tier-eligibility confirmation; auto-merge remains disabled pending both parent heads | -| #714 | `53a4b8b5` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates a malformed URL port, discards late responses after post switches, blocks private-post execution, and rejects NAT64, 6to4, and Teredo transition addresses before connection while preserving native public IPv6. Thirty-nine backend and two UI checks plus lint pass; all threads are resolved, auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #717 | `90b3999c` | stacked on #713 and persists evidence-bearing Voice-of-X combinations. Concurrent follow-ups completed all Voice labels and retain authorized imported voices across ontology cutoffs while preserving combined-voice cutoff semantics, client filtering, and historical primary `recorded_at`. Nineteen focused backend/schema checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #716 | `239b6bab` | stacked on #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. Thirty focused queue/runtime checks pass and two informational review threads are resolved. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 is still absent, so its performance thread honestly remains unresolved; auto-merge remains disabled pending parent delivery and that evidence | +| #714 | `98149723` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates malformed ports, discards late responses after post switches, blocks private-post execution, rejects transition addresses, and retries a separately verified public IPv4 address when the first verified IPv6 connection fails; policy/content rejection remains immediate. Forty focused checks pass, all threads are resolved, auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #713 | `cc3dfc14` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed unsupported named-organization projections, and preserves the independently governed organization-relationship vocabulary. Exact-head hosted checks and independent review remain required | | #711 | `8902e37f` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. One review thread and the full suite remain pending, while auto-merge correctly stays disabled until its parent and dependency contract are delivered | | #710 | `47dbd335` | records the worker-function delivery gap against #709. One review thread remains unresolved; exact-head hosted checks and independent review remain required | | #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | | #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | -| #702 | `7de6af0c` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The manifest binds selected opaque membership tokens, strata, exact inclusion-probability numerator/denominator pairs, frame hashes, and a selection digest; Rust artifact v2 binds those exact `(n_h, N_h)` ratios with population, confidence, margin, finite-population correction, allocation, and content hashes. Provider/transport/item failures remain in the denominator and invalidate the sample. For `N = 43,814`, `n = 80` is only a pilot with approximately `±10.95%` 95% margin at `p = .5`; corpus inference remains explicitly unavailable until a separate terminal Rust estimator/variance/interval artifact exists. Thirty-six focused audit/documentation/docstring checks and Ruff pass locally, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #702 | `039b7425` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The manifest binds selected opaque membership tokens, strata, exact inclusion-probability numerator/denominator pairs, frame hashes, and a selection digest; Rust artifact v2 binds those exact `(n_h, N_h)` ratios with population, confidence, margin, finite-population correction, allocation, and content hashes. Provider/transport/item failures remain in the denominator and invalidate the sample. For `N = 43,814`, `n = 80` is only a pilot with approximately `±10.95%` 95% margin at `p = .5`; corpus inference remains explicitly unavailable until a separate terminal Rust estimator/variance/interval artifact exists. The exact head adds documentation-only whitespace cleanup after the verified design repair; focused checks and Ruff pass locally, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `876129e5` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The follow-up fixes the Vietnamese action-label mismatch and adds four-locale containment coverage; 68 i18n checks and lint pass, all threads are resolved, and hosted checks plus independent review remain required | @@ -540,7 +541,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Twenty-nine PRs remain open at the 01:56 KST snapshot: twenty-two target `main` and seven form four explicit stacks. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Thirty PRs remain open at the 02:06 KST snapshot: twenty-two target `main` and eight form four explicit stacks. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 2525244bdae2338c14181e67b089a7a47459e62c Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 02:09:57 +0900 Subject: [PATCH 224/238] fix(ui): clear Ask draft when changing posts --- frontend/src/App.tsx | 1 + frontend/src/ChatPanel.test.tsx | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 80fc59859..ea1ef3712 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -301,6 +301,7 @@ export function ChatPanel({ ++conversationListRequest.current; ++conversationRequest.current; ++askRequest.current; + setQuestion(""); setExchanges([]); setSeededExchanges([]); setConversations([]); diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 4116f9e11..2495f5baa 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -237,6 +237,10 @@ describe("ChatPanel conversation history", () => { const view = render(); await userEvent.selectOptions(await screen.findByLabelText("Conversation history"), "conversation-old"); + await userEvent.type( + screen.getByPlaceholderText("What happened between these events?"), + "Question for the previous post", + ); view.rerender(); resolveOldConversation(jsonResponse({ conversation_id: "conversation-old", @@ -247,6 +251,7 @@ describe("ChatPanel conversation history", () => { await waitFor(() => expect(screen.queryByText("Stale selected answer")).toBeNull()); expect(screen.getByLabelText("Conversation history")).toHaveValue(""); + expect(screen.getByPlaceholderText("What happened between these events?")).toHaveValue(""); }); it("discards an answer response after moving to another post", async () => { @@ -277,7 +282,8 @@ describe("ChatPanel conversation history", () => { })); await waitFor(() => expect(screen.queryByText("Stale old-post answer")).toBeNull()); - expect(screen.getByRole("button", { name: "Ask" })).toBeEnabled(); + expect(screen.getByPlaceholderText("What happened between these events?")).toHaveValue(""); + expect(screen.getByRole("button", { name: "Ask" })).toBeDisabled(); }); it("discards an earlier-page response after moving to another post", async () => { From 4d5eb5a4657a9142881e42618302a67ebf952997 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 02:41:51 +0900 Subject: [PATCH 225/238] docs: reconcile semantic stack evidence --- docs/product-technical-gap-baseline.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index f2c87d69d..52c2f4728 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 30 open PRs and 10 open issues. The exact-head +At this snapshot there were 32 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 02:06 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 02:40 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, @@ -78,40 +78,42 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 30 open PRs and 10 +at this refresh. The live queue contains 32 open PRs and 10 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 | | ---: | --- | --- | -| #724 | `e4599dc5` | stacked on #723 and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. One hundred ten focused ontology/publication/docstring checks pass; CodeRabbit is successful, Devin remains pending, and auto-merge remains disabled pending parent delivery | +| #726 | `00e7a6fb` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. A valid empty result remains distinct from unavailable analysis; no crosswalk, score, weight, similarity, or person-trait inference is added. The branch preserves a concurrent requeue-migration repair and uses unique ADR 0253; focused extraction/schema/worker/docs checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #725 | `74c8eb73` | stacked on #640 and records non-identifying worker memory/PostgreSQL evidence without proposing arbitrary headroom, limits, or tuning values. The current repair discovers exited containers, retains Docker terminal state, keeps unavailable post-exit cgroup readings null, bounds pre-exit peak evidence, classifies OOM only from Docker/kernel evidence, leaves uncorroborated exit 137 unattributed, and rejects missing required event keys. Nineteen focused tests pass with 100% changed-script statement coverage; all threads are resolved and auto-merge remains disabled pending parent delivery | +| #724 | `96bd422d` | targets the occupational-taxonomy stack and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. The branch now uses unique ADR 0252; one hundred ten focused ontology/publication/docstring checks plus direct renumber contracts pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #723 | `30ddc8fd` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The current repair normalizes whitespace-only descriptions to unavailable rather than publishing empty literals. Seven focused catalog/docstring checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #721 | `9214c50f` | stacked occupational-construct persistence candidate. The current head synchronizes its parent and removes the duplicate construct-detail field; lint and production build pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #720 | `dda0531d` | cancels stale test runs after PR closure; normal auto-merge is enabled, but independent review remains required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `90b3999c` | stacked on #713 and persists evidence-bearing Voice-of-X combinations. Concurrent follow-ups completed all Voice labels and retain authorized imported voices across ontology cutoffs while preserving combined-voice cutoff semantics, client filtering, and historical primary `recorded_at`. Nineteen focused backend/schema checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #716 | `239b6bab` | stacked on #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. Thirty focused queue/runtime checks pass and two informational review threads are resolved. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 is still absent, so its performance thread honestly remains unresolved; auto-merge remains disabled pending parent delivery and that evidence | +| #717 | `e3ecb3b2` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Concurrent follow-ups completed all Voice labels, retain authorized imported voices across ontology cutoffs, and add evidence assignments while preserving combined-voice cutoff semantics, client filtering, and historical primary `recorded_at`. The branch reserves unique ADR 0251; focused backend/schema checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #716 | `55655681` | stacked on #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. It preserves the concurrent runtime-endpoint/readiness repairs and synchronizes the current parent without force. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 is still absent, so its performance thread honestly remains unresolved; auto-merge remains disabled pending parent delivery and that evidence | | #714 | `98149723` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates malformed ports, discards late responses after post switches, blocks private-post execution, rejects transition addresses, and retries a separately verified public IPv4 address when the first verified IPv6 connection fails; policy/content rejection remains immediate. Forty focused checks pass, all threads are resolved, auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #713 | `cc3dfc14` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed unsupported named-organization projections, and preserves the independently governed organization-relationship vocabulary. Exact-head hosted checks and independent review remain required | -| #711 | `8902e37f` | stacked on #640 rather than `main`; pins a candidate contextual-orchestrator structured-workflow revision. One review thread and the full suite remain pending, while auto-merge correctly stays disabled until its parent and dependency contract are delivered | +| #711 | `8fa6688f` | stacked on #640 rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. Its runtime-evidence thread stays unresolved and auto-merge correctly remains disabled pending protected upstream delivery and canonical runtime proof | | #710 | `47dbd335` | records the worker-function delivery gap against #709. One review thread remains unresolved; exact-head hosted checks and independent review remain required | | #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | | #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | -| #702 | `039b7425` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The manifest binds selected opaque membership tokens, strata, exact inclusion-probability numerator/denominator pairs, frame hashes, and a selection digest; Rust artifact v2 binds those exact `(n_h, N_h)` ratios with population, confidence, margin, finite-population correction, allocation, and content hashes. Provider/transport/item failures remain in the denominator and invalidate the sample. For `N = 43,814`, `n = 80` is only a pilot with approximately `±10.95%` 95% margin at `p = .5`; corpus inference remains explicitly unavailable until a separate terminal Rust estimator/variance/interval artifact exists. The exact head adds documentation-only whitespace cleanup after the verified design repair; focused checks and Ruff pass locally, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #702 | `eda7083b` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The current 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The full 43,814-row replay records zero nonblank bodies and separates fourteen deployed PROV-O tables from the still-missing linkage of 3,190 evidence edges; a missing PROV support profile now fails closed instead of producing an environment-dependent term set. Twenty-nine focused audit/docstring/hygiene checks pass, all threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `876129e5` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The follow-up fixes the Vietnamese action-label mismatch and adds four-locale containment coverage; 68 i18n checks and lint pass, all threads are resolved, and hosted checks plus independent review remain required | | #679 | `01cb291f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and wraps claim/evidence rows at desktop and mobile widths. A Storybook interaction test, 167 focused tests, lint, build, and committed synthetic desktop/mobile screenshots verify the state; all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `360d62ac` | this refresh branch prevents stale conversation pagination, recovery, and delayed answers from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. The current repair retains one retry key per failed measurement run across run switches and records hard deletion as an intentional erasure boundary distinct from visibility revocation. Focused interaction tests, lint, production build, and documentation checks pass; re-fetch the resulting PR head for lifecycle use | +| #667 | pre-documentation parent `2525244b` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches and records hard deletion as an intentional erasure boundary distinct from visibility revocation. Focused interaction tests, lint, production build, and documentation checks pass; re-fetch the resulting PR head for lifecycle use | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `8767de1b` | accessible status notices; hosted checks and independent review remain required | -| #640 | `c142c4ea` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. PR #722 merged normally into this non-default parent to restore the dedicated Ask worker's semantic-query and public-verification factories plus the production-equivalent concurrent-migration fixture path; this is stack integration, not protected delivery. Exact-head hosted checks and independent review remain required | +| #640 | `353dfd01` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. PR #727 merged normally into this non-default parent after replacing two remaining general-reader implementation-boundary messages with locale-aware evidence actions; backend/i18n/rendered tests, lint/build/Storybook, and exact-head desktop/mobile inspection pass. This remains stack integration, not protected delivery; exact-head hosted checks and independent review remain required | | #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -541,7 +543,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Thirty PRs remain open at the 02:06 KST snapshot: twenty-two target `main` and eight form four explicit stacks. Every candidate still requires exact-head checks and independent approval before merge | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Thirty-two PRs remain open at the 02:40 KST snapshot: twenty-two target `main` and ten target non-default stack branches. Every candidate still requires exact-head checks and independent approval before protected delivery | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | From 37c5c7ac4e2d4c4b35f4a84dfc723991ca763b3b Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 02:46:29 +0900 Subject: [PATCH 226/238] fix(ui): serialize conversation loading and Ask --- frontend/src/App.tsx | 17 ++++++++++++++--- frontend/src/ChatPanel.test.tsx | 4 +++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index ea1ef3712..dbeb77ca6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -290,6 +290,7 @@ export function ChatPanel({ const [answer, setAnswer] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); + const [conversationLoading, setConversationLoading] = useState(false); const [evidencePostId, setEvidencePostId] = useState(null); const [seededOnly, setSeededOnly] = useState(false); const conversationListRequest = useRef(0); @@ -312,6 +313,7 @@ export function ChatPanel({ setAnswer(null); setError(null); setLoading(false); + setConversationLoading(false); setSeededOnly(false); setEvidencePostId(null); fetchPostChat(accessToken, postId) @@ -335,6 +337,7 @@ export function ChatPanel({ async function selectConversation(nextId: string) { const requestId = ++conversationRequest.current; + setConversationLoading(true); setHistoryError(null); setAnswer(null); try { @@ -346,11 +349,14 @@ export function ChatPanel({ } catch { if (requestId !== conversationRequest.current) return; setHistoryError(t("Conversation history could not be loaded. Start a new conversation or try again later.")); + } finally { + if (requestId === conversationRequest.current) setConversationLoading(false); } } function startNewConversation() { ++conversationRequest.current; + setConversationLoading(false); setConversationId(null); setConversationOlderCursor(null); setExchanges(seededExchanges); @@ -361,7 +367,7 @@ export function ChatPanel({ } async function handleAsk(asked = question) { - if (!asked.trim()) return; + if (!asked.trim() || conversationLoading) return; const requestId = ++askRequest.current; const requestedConversationId = conversationId; setLoading(true); @@ -413,6 +419,7 @@ export function ChatPanel({ (firstCitedPostId ? firstCitedPostId.slice(0, 8) : null); const showNamedSeed = Boolean(nameFirstAsk && conversationId === null && exchanges[0]); const landedEvidencePostId = showNamedSeed ? (evidencePostId ?? firstCitedPostId) : null; + const chatBusy = loading || conversationLoading; return (
@@ -496,6 +503,7 @@ export function ChatPanel({ {conversationId && conversationOlderCursor ? ( + }} disabled={chatBusy}>{t("Load earlier messages")} ) : null} {historyError ?

{historyError}

: null} {!seededOnly && ( @@ -518,11 +528,12 @@ export function ChatPanel({ setQuestion(event.target.value)} onKeyDown={(event) => event.key === "Enter" && handleAsk()} placeholder={t("What happened between these events?")} /> -
diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index 2495f5baa..ade858572 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -236,11 +236,13 @@ describe("ChatPanel conversation history", () => { })); const view = render(); - await userEvent.selectOptions(await screen.findByLabelText("Conversation history"), "conversation-old"); await userEvent.type( screen.getByPlaceholderText("What happened between these events?"), "Question for the previous post", ); + await userEvent.selectOptions(await screen.findByLabelText("Conversation history"), "conversation-old"); + expect(screen.getByPlaceholderText("What happened between these events?")).toBeDisabled(); + expect(screen.getByRole("button", { name: "Ask" })).toBeDisabled(); view.rerender(); resolveOldConversation(jsonResponse({ conversation_id: "conversation-old", From bc399e894ae2fabf26aad174e41c77b83356a21b Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 02:39:52 +0900 Subject: [PATCH 227/238] fix(ui): remove remaining internal customer copy --- backend/app/global_ask_queue.py | 4 ++-- frontend/src/App.test.tsx | 10 ++++++++++ frontend/src/App.tsx | 2 +- frontend/src/i18n.test.ts | 2 ++ frontend/src/i18n.ts | 16 ++++++++-------- tests/test_global_ask_queue.py | 23 +++++++++++++++++++++++ 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/backend/app/global_ask_queue.py b/backend/app/global_ask_queue.py index 9bffd8502..9e8430ddd 100644 --- a/backend/app/global_ask_queue.py +++ b/backend/app/global_ask_queue.py @@ -168,8 +168,8 @@ def _verification_next_action(status_code: str) -> str: return { VERIFICATION_SKIPPED: "Enable public verification to check eligible public claims.", - VERIFICATION_UNAVAILABLE: "Configure public search and contextual-orchestrator, then retry.", - VERIFICATION_NO_PUBLIC_CLAIMS: "Inspect the internal cited posts; no public claim was eligible.", + VERIFICATION_UNAVAILABLE: "Ask a workspace administrator to enable public verification, then retry.", + VERIFICATION_NO_PUBLIC_CLAIMS: "Inspect the authorized cited posts and their evidence.", VERIFICATION_COMPLETED: "Inspect public evidence separately before any governed graph review.", CLAIM_NOT_ENOUGH_INFORMATION: "Collect stronger authoritative evidence before accepting the claim.", }.get(status_code, "Inspect the authorized cited posts and their evidence.") diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index cd1f9e4e7..ef1d783e8 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1758,6 +1758,7 @@ describe("App, authenticated", () => { relationship_label: "Voice of Customer", verification_status_code: "verify_pending", verification_evidence_url: null, + verification_evidence_post_id: "post-1", corporate_entity_id: "corp-1", ...demoOrgAlias, }, @@ -3057,6 +3058,15 @@ describe("App, authenticated", () => { expect(screen.queryByRole("button", { name: "Counterparty org: Northridge Grid" })).not.toBeInTheDocument(); }); + it("opens a counterparty supporting post without exposing its storage boundary", async () => { + stubBackend(); + render(); + await userEvent.click(await screen.findByRole("button", { name: "View post: Public post" })); + + expect(await screen.findByRole("button", { name: "Open supporting post" })).toBeInTheDocument(); + expect(screen.queryByText(/internal evidence/i)).not.toBeInTheDocument(); + }); + it("links a verification badge only for http(s) evidence URLs", async () => { stubBackend({ verificationEvidenceUrl: "https://example.test/searxng?q=Northridge" }); render(); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index dbeb77ca6..4334db94e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1714,7 +1714,7 @@ function CounterpartyPanel({ className="keyman-select" onClick={() => onSelectPost(c.verification_evidence_post_id!)} > - View internal evidence + {t("Open supporting post")} ) : null} diff --git a/frontend/src/i18n.test.ts b/frontend/src/i18n.test.ts index ae085d010..afd047874 100644 --- a/frontend/src/i18n.test.ts +++ b/frontend/src/i18n.test.ts @@ -80,6 +80,8 @@ describe("i18n", () => { "Open this observed occurrence. It is not a LineageWeave commitment.", "Collect stronger authoritative evidence before accepting the claim.", "Inspect the authorized cited posts and their evidence.", + "Ask a workspace administrator to enable public verification, then retry.", + "Open supporting post", "Review unavailable historical channels before relying on this cutoff answer.", "Compare these cutoff-grounded citations with live evidence next.", ] as const; diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index a219024dd..57fe26d6e 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -189,8 +189,8 @@ const TRANSLATIONS: Partial>> = { "Conflicts with public evidence": "공개 근거와 충돌합니다", "Not enough public information": "공개 정보가 충분하지 않습니다", "Enable public verification to check eligible public claims.": "검증 가능한 공개 주장을 확인하려면 공개 자료 검증을 켜세요.", - "Configure public search and contextual-orchestrator, then retry.": "공개 검색과 contextual-orchestrator를 구성한 후 다시 시도하세요.", - "Inspect the internal cited posts; no public claim was eligible.": "검증 가능한 공개 주장이 없으므로 내부 인용 글을 확인하세요.", + "Ask a workspace administrator to enable public verification, then retry.": "작업 공간 관리자에게 공개 자료 검증을 켜 달라고 요청한 후 다시 시도하세요.", + "Open supporting post": "근거 글 열기", "Inspect public evidence separately before any governed graph review.": "거버넌스 그래프 검토 전에 공개 근거를 별도로 확인하세요.", "Collect stronger authoritative evidence before accepting the claim.": "주장을 받아들이기 전에 더 강한 권위 있는 근거를 확보하세요.", "Inspect the authorized cited posts and their evidence.": "권한이 있는 인용 글과 근거를 확인하세요.", @@ -721,8 +721,8 @@ const TRANSLATIONS: Partial>> = { "Conflicts with public evidence": "与公开证据冲突", "Not enough public information": "公开信息不足", "Enable public verification to check eligible public claims.": "启用公开资料核验以检查符合条件的声明。", - "Configure public search and contextual-orchestrator, then retry.": "配置公开搜索和 contextual-orchestrator 后重试。", - "Inspect the internal cited posts; no public claim was eligible.": "没有符合条件的公开声明,请检查内部引用文章。", + "Ask a workspace administrator to enable public verification, then retry.": "请联系工作区管理员启用公开资料核验,然后重试。", + "Open supporting post": "打开支持性帖子", "Inspect public evidence separately before any governed graph review.": "在治理图谱审查前单独检查公开证据。", "Collect stronger authoritative evidence before accepting the claim.": "接受该声明前,请收集更有力的权威证据。", "Inspect the authorized cited posts and their evidence.": "检查已获授权的引用文章及其证据。", @@ -1269,8 +1269,8 @@ const TRANSLATIONS: Partial>> = { "Conflicts with public evidence": "公開証拠と矛盾しています", "Not enough public information": "公開情報が不十分です", "Enable public verification to check eligible public claims.": "対象となる主張を確認するには公開検証を有効にしてください。", - "Configure public search and contextual-orchestrator, then retry.": "公開検索と contextual-orchestrator を設定して再試行してください。", - "Inspect the internal cited posts; no public claim was eligible.": "対象となる公開主張がないため、内部の引用投稿を確認してください。", + "Ask a workspace administrator to enable public verification, then retry.": "ワークスペース管理者に公開情報の検証を有効にするよう依頼してから、再試行してください。", + "Open supporting post": "根拠となる投稿を開く", "Inspect public evidence separately before any governed graph review.": "管理対象グラフをレビューする前に公開証拠を別途確認してください。", "Collect stronger authoritative evidence before accepting the claim.": "主張を受け入れる前に、より強い権威ある証拠を集めてください。", "Inspect the authorized cited posts and their evidence.": "許可された引用投稿とその証拠を確認してください。", @@ -1796,8 +1796,8 @@ const TRANSLATIONS: Partial>> = { "Conflicts with public evidence": "Mâu thuẫn với bằng chứng công khai", "Not enough public information": "Không đủ thông tin công khai", "Enable public verification to check eligible public claims.": "Bật xác minh công khai để kiểm tra các tuyên bố đủ điều kiện.", - "Configure public search and contextual-orchestrator, then retry.": "Cấu hình tìm kiếm công khai và contextual-orchestrator rồi thử lại.", - "Inspect the internal cited posts; no public claim was eligible.": "Không có tuyên bố công khai đủ điều kiện; hãy xem các bài viết nội bộ được trích dẫn.", + "Ask a workspace administrator to enable public verification, then retry.": "Hãy yêu cầu quản trị viên không gian làm việc bật xác minh công khai, rồi thử lại.", + "Open supporting post": "Mở bài viết làm bằng chứng", "Inspect public evidence separately before any governed graph review.": "Kiểm tra riêng bằng chứng công khai trước khi rà soát đồ thị được quản trị.", "Collect stronger authoritative evidence before accepting the claim.": "Thu thập bằng chứng có thẩm quyền mạnh hơn trước khi chấp nhận tuyên bố.", "Inspect the authorized cited posts and their evidence.": "Kiểm tra các bài viết được trích dẫn đã cấp quyền và bằng chứng của chúng.", diff --git a/tests/test_global_ask_queue.py b/tests/test_global_ask_queue.py index fed1b90d7..d272ddd8e 100644 --- a/tests/test_global_ask_queue.py +++ b/tests/test_global_ask_queue.py @@ -111,6 +111,29 @@ def test_public_verification_requires_public_capability_and_internal_citation() assert client.calls == 0 +def test_no_public_claim_next_action_opens_authorized_evidence() -> None: + """Customer copy names the evidence action, not an internal boundary.""" + + next_action = global_ask_queue._verification_next_action( + cv.VERIFICATION_NO_PUBLIC_CLAIMS + ) + + assert next_action == "Inspect the authorized cited posts and their evidence." + assert "internal" not in next_action.lower() + + +def test_unavailable_public_verification_guides_the_reader_without_service_names() -> None: + """Unavailable verification names the customer action, not its providers.""" + + next_action = global_ask_queue._verification_next_action( + cv.VERIFICATION_UNAVAILABLE + ) + + assert next_action == ( + "Ask a workspace administrator to enable public verification, then retry." + ) + assert "orchestrator" not in next_action.lower() + def test_public_verification_keeps_external_urls_out_of_internal_citations() -> None: """A verified URL remains external evidence, never a cited post id.""" From f1e71d5933934db11cdc4444649208fbea955ea3 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 04:34:47 +0900 Subject: [PATCH 228/238] fix(ui): replace implementation details with next actions --- backend/app/analysis_run_start.py | 12 ++-- backend/app/global_ask_queue.py | 25 ++++---- backend/app/main.py | 58 +++++++++---------- backend/tests/test_api.py | 7 ++- docs/product-technical-gap-baseline.md | 54 +++++++++-------- docs/storybook-inventory.md | 7 ++- frontend/src/AnalysisRunGuidance.stories.tsx | 2 +- frontend/src/App.test.tsx | 47 +++++++++++---- frontend/src/App.tsx | 6 +- frontend/src/ChatPanel.stories.tsx | 31 +++++++++- frontend/src/analysisRunI18n.ts | 20 +++---- frontend/src/i18n.test.ts | 2 +- frontend/src/i18n.ts | 32 ++++++---- tests/test_analysis_run_start.py | 23 ++++++++ .../test_frontend_container_install_policy.py | 22 ++++++- tests/test_global_ask_queue.py | 8 +-- tests/test_server_diagnostics.py | 8 +-- 17 files changed, 238 insertions(+), 126 deletions(-) diff --git a/backend/app/analysis_run_start.py b/backend/app/analysis_run_start.py index c08810078..8fd22e907 100644 --- a/backend/app/analysis_run_start.py +++ b/backend/app/analysis_run_start.py @@ -954,9 +954,9 @@ async def _claim_delivery_plan( if weights is None: raise AnalysisRunStartError( 503, - "Channel weights are not estimated yet for this run's active " - f"channels ({', '.join(sorted(active_channels))}). Run " - "scripts/estimate_channel_weights.py, then start this run again.", + "Lineage calibration evidence is unavailable for this run. Ask " + "your workspace administrator to complete calibration, then start " + "this run again.", ) return _DeliveryPlan( _LINEAGE_KIND, @@ -986,9 +986,9 @@ def _execute_delivery_plan( except _AdjudicationProviderError as exc: raise AnalysisRunStartError( 503, - "The adjudication provider failed mid-reconstruction; nothing " - "was persisted. Check the contextual-orchestrator transport, " - "then start this run again.", + "Lineage reconstruction is temporarily unavailable. No result " + "was saved. Start this run again in a moment; if this continues, " + "contact your workspace administrator.", ) from exc return _DeliveryOutcome(plan.work_kind_code, plan.started_at, tuple(edges)) diff --git a/backend/app/global_ask_queue.py b/backend/app/global_ask_queue.py index 9e8430ddd..5be5ab924 100644 --- a/backend/app/global_ask_queue.py +++ b/backend/app/global_ask_queue.py @@ -76,6 +76,10 @@ # trimmed stream) and are republished by the worker's recovery sweep. _REPUBLISH_AFTER_SECONDS = 60 _RECOVERY_INTERVAL_SECONDS = 30.0 +_ASK_RETRY_MESSAGE = ( + "Ask Agent is unavailable. Retry in a moment. If this continues, " + "contact your workspace administrator." +) # Hard ceiling on one job's answer computation. Without it a hung # orchestrator round-trip kept a job `running` indefinitely (observed: # 17+ minutes) and, before concurrent processing, stalled every job @@ -169,10 +173,10 @@ def _verification_next_action(status_code: str) -> str: return { VERIFICATION_SKIPPED: "Enable public verification to check eligible public claims.", VERIFICATION_UNAVAILABLE: "Ask a workspace administrator to enable public verification, then retry.", - VERIFICATION_NO_PUBLIC_CLAIMS: "Inspect the authorized cited posts and their evidence.", + VERIFICATION_NO_PUBLIC_CLAIMS: "Ask about a specific claim or narrow the time range, then retry.", VERIFICATION_COMPLETED: "Inspect public evidence separately before any governed graph review.", CLAIM_NOT_ENOUGH_INFORMATION: "Collect stronger authoritative evidence before accepting the claim.", - }.get(status_code, "Inspect the authorized cited posts and their evidence.") + }.get(status_code, "Ask about a specific claim or narrow the time range, then retry.") async def _verify_public_claims( @@ -348,7 +352,7 @@ def can_see(row: asyncpg.Record) -> bool: record_server_failure("global_ask", exc, outcome="internal_error") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Ask Agent is unavailable: authorized evidence could not be assembled", + _ASK_RETRY_MESSAGE, ) from exc cutoff_text = knowledge_cutoff.isoformat() if knowledge_cutoff else None grounding_status = ask_grounding_status(sources, cutoff_text) @@ -404,7 +408,7 @@ def can_see(row: asyncpg.Record) -> bool: record_server_failure("global_ask", exc, outcome="provider_unavailable") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Ask Agent is unavailable: contextual-orchestrator could not complete the answer", + _ASK_RETRY_MESSAGE, ) from exc except (KeyError, ValueError) as exc: # Contract/schema fault: the orchestrator responded but its payload @@ -413,7 +417,7 @@ def can_see(row: asyncpg.Record) -> bool: record_server_failure("global_ask", exc, outcome="provider_unavailable") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Ask Agent is unavailable: contextual-orchestrator could not complete the answer", + _ASK_RETRY_MESSAGE, ) from exc except Exception as exc: # Unexpected defect. Keep the customer boundary and emit a full @@ -422,7 +426,7 @@ def can_see(row: asyncpg.Record) -> bool: record_server_failure("global_ask", exc, outcome="internal_error") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Ask Agent is unavailable: contextual-orchestrator could not complete the answer", + _ASK_RETRY_MESSAGE, ) from exc cited_ids = list(answer.cited_post_ids) verification_status, external_claims = await _verify_public_claims( @@ -552,7 +556,7 @@ async def process_global_ask_job( chat_client = chat_factory() if not chat_client.available: raise _SafeJobError( - "Ask Agent is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY" + _ASK_RETRY_MESSAGE ) payload = await asyncio.wait_for( compute_global_ask_answer( @@ -588,16 +592,13 @@ async def process_global_ask_job( # state / missing config) — never a provider-boundary leak. detail = str(exc) elif isinstance(exc, asyncio.TimeoutError): - detail = f"job exceeded the {JOB_DEADLINE_SECONDS}s deadline" + detail = _ASK_RETRY_MESSAGE else: # Provider responses/exceptions can carry credentials, gateway # diagnostics, or model output (ADR 0123): never persist the # raw exception text as a durable `failure_detail`. The # traceback just logged keeps it for operator debugging only. - detail = ( - "Ask Agent is unavailable: contextual-orchestrator returned " - "no complete evidence object" - ) + detail = _ASK_RETRY_MESSAGE async with pool.acquire() as conn: await conn.execute( """ diff --git a/backend/app/main.py b/backend/app/main.py index 95ed60f74..722cae1db 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -340,6 +340,10 @@ async def lifespan(app: FastAPI): logger = logging.getLogger(__name__) +_POST_CHAT_RETRY_DETAIL = ( + "Post chat is temporarily unavailable. Review the saved evidence, then " + "retry in a moment. If this continues, contact your workspace administrator." +) app = FastAPI(title="LineageWeave API", lifespan=lifespan) app.add_middleware( @@ -1266,12 +1270,12 @@ async def resolve_customer_master_hint( # verify-relations' identical try/except). raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Hint resolution is unavailable: the orchestrator or search provider did not respond", + "Hint resolution is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Hint resolution is unavailable: the orchestrator or search provider did not respond", + "Hint resolution is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc if resolution is None: raise HTTPException( @@ -1316,8 +1320,7 @@ async def rebuild_lineage_graph( except ChannelWeightsNotEstimated as exc: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Channel weights are not estimated yet. Run " - "scripts/estimate_channel_weights.py, then rebuild again.", + "Lineage calibration evidence is unavailable. Ask your workspace administrator to complete calibration, then rebuild again.", ) from exc except (HttpClientError, OSError) as exc: # This can issue up to MAXIMUM_LIVE_LLM_PAIR_EVALUATIONS sequential @@ -1327,7 +1330,7 @@ async def rebuild_lineage_graph( # discipline as this file's other orchestrator call sites. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Lineage rebuild is unavailable: the orchestrator did not respond", + "Lineage rebuild is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc return {"edge_count": len(edges)} @@ -1882,7 +1885,7 @@ async def read_similar_voc( if client is None: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "similar VOC inference is unavailable; configure contextual-orchestrator and retry", + "Similar VOC evidence is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) async with pool.acquire() as conn: # Safe SQL: the sole interpolation is the closed eligibility fragment; request and identity values remain asyncpg parameters. @@ -2355,7 +2358,7 @@ async def verify_post_entity_relationships( if not client.available: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Relation verification is unavailable: set SEARXNG_BASE_URL", + "Relation verification is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) try: verified = await verify_post_relations_from_pool( @@ -2369,12 +2372,12 @@ async def verify_post_entity_relationships( # provider failure into a clean 503 rather than persisting a miss. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Relation verification is unavailable: the search provider did not respond", + "Relation verification is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Relation verification is unavailable: the search provider did not respond", + "Relation verification is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc await publish_activity_event( valkey, @@ -2419,7 +2422,7 @@ async def extract_post_keymen( if not keyman_client.available: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Keymen extraction is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + "Keymen extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) relationship_client = _entity_relationship_client() async with pool.acquire() as conn: @@ -2449,12 +2452,12 @@ async def extract_post_keymen( except (HttpClientError, KeyError, OSError, TypeError, ValueError, RuntimeError) as exc: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Keymen extraction is unavailable: contextual-orchestrator or corroboration provider returned no complete evidence object", + "Keymen extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Keymen extraction is unavailable: contextual-orchestrator or corroboration provider returned no complete evidence object", + "Keymen extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc # Live bug (2026-08-19): an organization affiliated ONLY with an # our_side person (our own factory, our own affiliate) got fed @@ -2478,12 +2481,12 @@ async def extract_post_keymen( except (HttpClientError, KeyError, OSError, TypeError, ValueError, RuntimeError) as exc: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Keymen extraction is unavailable: contextual-orchestrator or corroboration provider returned no complete evidence object", + "Keymen extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Keymen extraction is unavailable: contextual-orchestrator or corroboration provider returned no complete evidence object", + "Keymen extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc async with conn.transaction(): await persist_edges_for_post(conn, post_id) @@ -2633,12 +2636,12 @@ async def evaluate_post( except (HttpClientError, KeyError, OSError, TypeError, ValueError, RuntimeError) as exc: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post evaluation is unavailable: contextual-orchestrator returned no complete evidence object", + "Post evaluation is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post evaluation is unavailable: contextual-orchestrator returned no complete evidence object", + "Post evaluation is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc await publish_activity_event( valkey, @@ -2905,7 +2908,7 @@ def stale_fallback( return stale_fallback("orchestrator_unavailable") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post summary is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + "Post summary is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) context_hints = await _load_post_semantic_hints(conn, post_id) summarize_with_hints = getattr(client, "summarize_with_hints", None) @@ -2923,14 +2926,14 @@ def stale_fallback( return stale_fallback("orchestrator_failure", exc) raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post summary is unavailable: contextual-orchestrator returned no complete evidence object", + "Post summary is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. if stale is not None: return stale_fallback("orchestrator_unexpected_failure", exc) raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post summary is unavailable: contextual-orchestrator returned no complete evidence object", + "Post summary is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc try: payload = await persist_post_summary( @@ -2946,7 +2949,7 @@ def stale_fallback( return stale_fallback("summary_persist_failure", exc) raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post summary is unavailable: contextual-orchestrator or corroboration provider returned no complete evidence object", + "Post summary is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc content_complete = await post_content_is_complete( conn, @@ -3152,8 +3155,7 @@ async def chat_about_post( ) raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post chat is temporarily unavailable. " - "Saved evidence is still available.", + _POST_CHAT_RETRY_DETAIL, ) async with pool.acquire() as conn: sources = await gather_chat_sources( @@ -3176,15 +3178,13 @@ async def chat_about_post( record_server_failure("post_chat", exc, outcome="provider_unavailable") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post chat is temporarily unavailable. " - "Saved evidence is still available.", + _POST_CHAT_RETRY_DETAIL, ) from exc except Exception as exc: record_server_failure("post_chat", exc, outcome="internal_error") raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Post chat is temporarily unavailable. " - "Saved evidence is still available.", + _POST_CHAT_RETRY_DETAIL, ) from exc cited_ids = list(answer.cited_post_ids) source_ids = [source.post_id for source in sources] @@ -3534,7 +3534,7 @@ async def derive_post_commitment( if not client.available: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Commitment derivation is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + "Commitment derivation is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) async with pool.acquire() as conn: body_row = await conn.fetchrow("select post_body from source_post where post_id = $1", post_id) @@ -3555,12 +3555,12 @@ async def derive_post_commitment( except (HttpClientError, KeyError, OSError, TypeError, ValueError, RuntimeError) as exc: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Commitment derivation is unavailable: contextual-orchestrator returned no complete evidence object", + "Commitment derivation is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc except Exception as exc: # noqa: BLE001 - provider boundary is fail-closed. raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, - "Commitment derivation is unavailable: contextual-orchestrator returned no complete evidence object", + "Commitment derivation is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", ) from exc if not commitment.has_commitment: return {"post_id": str(post["post_id"]), "has_commitment": False, "ticket": None} diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py index 37c78fec7..02eaa4d40 100644 --- a/backend/tests/test_api.py +++ b/backend/tests/test_api.py @@ -3881,7 +3881,8 @@ def answer(self, question: str, sources) -> None: assert response.status_code == 503 assert response.json()["detail"] == ( - "Post chat is temporarily unavailable. Saved evidence is still available." + "Post chat is temporarily unavailable. Review the saved evidence, then " + "retry in a moment. If this continues, contact your workspace administrator." ) @@ -3970,6 +3971,7 @@ def extract(self, post_title: str, post_body: str) -> object: assert response.status_code == 503 assert "raw-keyman-provider-secret" not in response.text + assert response.json()["detail"].endswith("contact your workspace administrator.") def test_evaluation_provider_error_does_not_leak_raw_error( @@ -3995,6 +3997,7 @@ def evaluate(self, post_title: str, post_body: str) -> object: assert response.status_code == 503 assert "raw-evaluation-provider-secret" not in response.text + assert response.json()["detail"].endswith("contact your workspace administrator.") def test_commitment_provider_error_does_not_leak_raw_error( @@ -4020,6 +4023,7 @@ def extract(self, post_title: str, post_body: str, reference_date: str) -> objec assert response.status_code == 503 assert "raw-commitment-provider-secret" not in response.text + assert response.json()["detail"].endswith("contact your workspace administrator.") def test_summary_enrichment_provider_error_does_not_leak_raw_error( @@ -4047,6 +4051,7 @@ async def _fail_persist(*args, **kwargs): assert response.status_code == 503 assert "raw-summary-provider-secret" not in response.text + assert response.json()["detail"].endswith("contact your workspace administrator.") def test_evaluate_is_unavailable_without_orchestrator(client, demo_analyst_token, seeded_db) -> None: diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 52c2f4728..3a6c1b575 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 32 open PRs and 10 open issues. The exact-head +At this snapshot there were 37 open PRs and 10 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 02:40 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 04:27 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, @@ -78,27 +78,33 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 32 open PRs and 10 +at this refresh. The live queue contains 37 open PRs (22 targeting `main`, +15 stacked on non-default parents) and 10 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 | | ---: | --- | --- | -| #726 | `00e7a6fb` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. A valid empty result remains distinct from unavailable analysis; no crosswalk, score, weight, similarity, or person-trait inference is added. The branch preserves a concurrent requeue-migration repair and uses unique ADR 0253; focused extraction/schema/worker/docs checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #725 | `74c8eb73` | stacked on #640 and records non-identifying worker memory/PostgreSQL evidence without proposing arbitrary headroom, limits, or tuning values. The current repair discovers exited containers, retains Docker terminal state, keeps unavailable post-exit cgroup readings null, bounds pre-exit peak evidence, classifies OOM only from Docker/kernel evidence, leaves uncorroborated exit 137 unattributed, and rejects missing required event keys. Nineteen focused tests pass with 100% changed-script statement coverage; all threads are resolved and auto-merge remains disabled pending parent delivery | -| #724 | `96bd422d` | targets the occupational-taxonomy stack and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. The branch now uses unique ADR 0252; one hundred ten focused ontology/publication/docstring checks plus direct renumber contracts pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #723 | `30ddc8fd` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The current repair normalizes whitespace-only descriptions to unavailable rather than publishing empty literals. Seven focused catalog/docstring checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | +| #735 | `76b3ef2a` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and idempotent insertion without local weighting, aggregation, normalization, or psychometric arithmetic. Thirty focused checks and a throwaway-PostgreSQL full-artifact replay report 94,640 observations across 910 occupations and 52 elements plus all 33 scale rows; only aggregate counts enter this repository. Review threads are currently empty, frontend/CodeRabbit pass, and the full suite/Devin/independent review remain in progress | +| #734 | `99f098fe` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL now rejects future source dates and out-of-declared-scale observations before insert, rejects update/delete on immutable observations, and retains idempotent conflict handling; 24 migration/rerun/schema checks pass and both review threads are resolved. Hosted backend/frontend/full-suite and independent review remain in progress, so this is not accepted measurement or protected delivery | +| #733 | `f2b1e464` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence now uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline, so the distinction does not depend on color; the intro follows the filtered visible set. Fifty-eight focused backend/frontend checks, lint, production/Storybook builds pass; desktop 1440x1182 and mobile 390x852 renders were inspected, all review threads are resolved, and fresh hosted checks remain queued | +| #732 | `9e714f65` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. Forty focused linkage/publication/hygiene checks pass, the sampled official artifact digest matches its pin, all review threads are resolved, and the frontend/review checks pass; the full suite and independent review remain in progress | +| #731 | `88ae5796` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; it introduces no rating, person trait, score, weight, or inferred crosswalk. Numeric outline ordering now places `2.C.2` before `2.C.10`, and the decision file moved to union-free ADR 0255; child synchronization and hosted gates remain in progress. During earlier concurrent-head handling an unsafe guard permitted one brief `--force-with-lease`; the overwritten `38812fc1` change was recovered as a parent and normal push restored the remote. Preserved ancestry is code-preservation evidence, not approval of the process defect | +| #728 | `e52a8272` | now stacks on exact #640 instead of extending protected-main NumPy arithmetic. It pins fast-mlsirm PR #1457 exact `5c7dc9ea` and consumes the owner-produced Rust/PyO3 explained-share field while retaining LineageWeave validation, persistence projection, API, and presentation only. The audit also moved the schema change to union-free migration 0236 and made the production-equivalent bootstrap execute it. Upstream Rust tests pass; LineageWeave backend/schema/frontend focused checks pass; both review queues have zero unresolved threads. The upstream PR remains draft with hosted gates in progress and the LineageWeave parent remains non-default, so neither is protected delivery | +| #726 | `fd1cac66` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. PR #729 merged normally after exact-head checks passed. The shared loader fences stale assertions with the current content digest; retry re-extraction remains deliberate because semantic-unit replacement invalidates prior unit identities, and reclaimed jobs reset their retry budget. Evidence status now prioritizes queued/running processing over same-digest completion, so atomic unit/assertion replacement cannot briefly report `complete` with an empty list. Focused synced-stack checks pass, all threads are resolved, frontend hosted checks pass, and the full suite/independent review remain in progress | +| #724 | `fdec8f65` | targets the occupational-taxonomy stack and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. The served Turtle is now a canonical parsed graph rather than source-document concatenation, is proved isomorphic with the governed source graph, and the manifest lists and hashes every source file instead of naming one misleading source. Thirty publication checks pass, all threads are resolved, and fresh hosted checks remain queued pending parent delivery | +| #723 | `d257187a` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The official 485,151-byte, 3,006-row source artifact is pinned by canonical SHA-256 before a database transaction; the governed scope admits 2,529 constructs, rejects changed or whitespace-mutated labels, and keeps absent descriptions as `NULL`. Eight focused checks and the official digest/count replay pass, all threads are resolved, and fresh hosted checks remain in progress pending parent delivery | | #721 | `9214c50f` | stacked occupational-construct persistence candidate. The current head synchronizes its parent and removes the duplicate construct-detail field; lint and production build pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #720 | `dda0531d` | cancels stale test runs after PR closure; normal auto-merge is enabled, but independent review remains required before protected delivery | +| #720 | `dda0531d` | cancels stale test runs after PR closure. A normal failed-job rerun reached terminal attempt 2 and again failed closed only after NVIDIA primary `429`, retired NVIDIA fallback `410`, and direct OpenAI `insufficient_quota`; this is current provider-infrastructure evidence, not a code finding or a passing scan. Normal auto-merge is enabled, but authoritative Strix evidence and independent review remain required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `e3ecb3b2` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Concurrent follow-ups completed all Voice labels, retain authorized imported voices across ontology cutoffs, and add evidence assignments while preserving combined-voice cutoff semantics, client filtering, and historical primary `recorded_at`. The branch reserves unique ADR 0251; focused backend/schema checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #716 | `55655681` | stacked on #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. It preserves the concurrent runtime-endpoint/readiness repairs and synchronizes the current parent without force. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 is still absent, so its performance thread honestly remains unresolved; auto-merge remains disabled pending parent delivery and that evidence | -| #714 | `98149723` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. The current repair isolates malformed ports, discards late responses after post switches, blocks private-post execution, rejects transition addresses, and retries a separately verified public IPv4 address when the first verified IPv6 connection fails; policy/content rejection remains immediate. Forty focused checks pass, all threads are resolved, auto-merge is enabled, and exact-head hosted checks plus independent review remain required | -| #713 | `cc3dfc14` | proposes a twelve-code stakeholder Voice-of-X post taxonomy. The current audit moved the decision to unique ADR 0246 and migration 0235, removed unsupported named-organization projections, and preserves the independently governed organization-relationship vocabulary. Exact-head hosted checks and independent review remain required | -| #711 | `8fa6688f` | stacked on #640 rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. Its runtime-evidence thread stays unresolved and auto-merge correctly remains disabled pending protected upstream delivery and canonical runtime proof | -| #710 | `47dbd335` | records the worker-function delivery gap against #709. One review thread remains unresolved; exact-head hosted checks and independent review remain required | +| #717 | `9db158c4` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. Twenty-six focused backend and sixty-nine frontend/i18n tests plus lint/build pass; desktop/mobile rejected-evidence scenes were inspected, all threads are resolved, and fresh hosted checks remain in progress | +| #716 | `c01de078` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. The worker health probe is lightweight, POSIX-compatible, and accepts a valid newline-free heartbeat; the k6 summary contract reads the actual flat export fields instead of silently accepting missing metrics. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 is still absent, so that one performance thread honestly remains unresolved; auto-merge remains disabled pending parent delivery and that evidence | +| #714 | `76a602c8` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. Private posts now return no persisted citations after a visibility change. Text and image-region lead streams preserve source order and alternate without weights, so text volume cannot starve image evidence when the bounded budget admits both. Twenty-five focused checks pass, both new review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #713 | `850494c3` | proposes the ADR 0246 twelve-code atomic stakeholder Voice-of-X post taxonomy while preserving ADR 0251's separate extensible combination model and the independently governed organization-relationship vocabulary. The audit moved all twelve labels into the parent so Korean, Chinese, Japanese, and Vietnamese filters do not fall back to English immediately after this PR lands. Sixty-eight i18n and 24 ontology checks plus production build pass; a 1280x720 Korean filter render was inspected, all threads are resolved, auto-merge is enabled, and fresh hosted checks plus independent review remain required | +| #711 | `05e5f520` | stacked on the current #640 head rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. It now includes the normally merged worker-memory evidence stack. Its canonical upstream runtime-evidence thread stays unresolved and auto-merge remains disabled pending protected upstream delivery and exact-image proof | +| #710 | `2f6b7ae7` | records the worker-function delivery gap against #709 without duplicating #702's corpus audit. Exact-head hosted checks and independent review remain required | | #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | | #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | | #702 | `eda7083b` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The current 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The full 43,814-row replay records zero nonblank bodies and separates fourteen deployed PROV-O tables from the still-missing linkage of 3,190 evidence edges; a missing PROV support profile now fails closed instead of producing an environment-dependent term set. Twenty-nine focused audit/docstring/hygiene checks pass, all threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | @@ -108,12 +114,12 @@ context only. | #679 | `01cb291f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and wraps claim/evidence rows at desktop and mobile widths. A Storybook interaction test, 167 focused tests, lint, build, and committed synthetic desktop/mobile screenshots verify the state; all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `2525244b` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches and records hard deletion as an intentional erasure boundary distinct from visibility revocation. Focused interaction tests, lint, production build, and documentation checks pass; re-fetch the resulting PR head for lifecycle use | +| #667 | pre-documentation parent `bc399e89` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches, records hard deletion as an intentional erasure boundary distinct from visibility revocation, and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific retry, saved-evidence, calibration, or administrator actions. Pending-run and no-public-claim guidance is conditional and actionable; the Chat unavailable Storybook scene keeps saved evidence visible and its 1440x900/390x844 renders were inspected. Focused interaction, i18n, backend, container-policy, lint, Storybook-build, and documentation checks pass; re-fetch the resulting PR head for lifecycle use | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `8767de1b` | accessible status notices; hosted checks and independent review remain required | -| #640 | `353dfd01` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. PR #727 merged normally into this non-default parent after replacing two remaining general-reader implementation-boundary messages with locale-aware evidence actions; backend/i18n/rendered tests, lint/build/Storybook, and exact-head desktop/mobile inspection pass. This remains stack integration, not protected delivery; exact-head hosted checks and independent review remain required | +| #640 | `ebfe60af` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. PRs #727, #730, and #725 merged normally into this non-default parent: public failures no longer expose provider, environment-variable, timeout, or evidence-assembly boundaries and instead give a retry/administrator action; empty verification gives a specific-claim/time-range retry; worker memory evidence remains aggregate and non-identifying. Focused backend/i18n/rendered tests, lint/build/Storybook, and desktop/mobile inspection pass. Exact-head hosted checks and independent review remain required before protected delivery | | #639 | `2f4b1bff` | running-action/config repair now also makes the documented `make seed` contract install its declared script/runtime extras and documents the canonical Keyverse frontend variables with a container-contract regression. The exact-head repair updates the Makefile contract test to require those owned extras; 13 focused Makefile/config tests pass locally. Fresh hosted checks are running, auto-merge remains enabled, and independent review is required | | #632 | `24262a99` | graph-fact provenance repair also carries the current bounded MCP request contract, token-backed Ask layout, ontology-label wrapping, and normalized-table evidence-search index repair. Both live migration fixtures execute the production-equivalent `psql -X -v ON_ERROR_STOP=1 -f` path; 38 schema/replay/contract checks pass locally. A normal Strix rerun request was accepted with HTTP 201 and the replacement exact-head job is queued; acceptance is not a passing scan. Full tests remain in progress and coverage-source-tree is queued, so exact-head terminal revalidation and independent approval remain required | | #629 | `b721b0f2` | provider-work release and bounded reads now preserve relationship type, capture update status, remove a shadowed legacy verifier, persist each completed result before a later provider failure, fence deleted evidence, and execute both Global Ask migrations twice in the real PostgreSQL fixture. Focused migration/schema tests pass; hosted checks and independent review remain required | @@ -379,11 +385,13 @@ merged at exact head `897819c4` to repair the pnpm/coverage-evidence workflow; newly created exact PR heads must still prove the runtime behavior because merged workflow source alone is not check evidence. The local `com.contextualwisdomlab.lineageweave-hourly` launchd registration -was live-audited at this snapshot with a 3,600-second interval, 16 recorded -runs, and last exit code 0; its output log contains completed queue/repair -iterations. Registration and prior successful exits do not prove the next run -or transfer protected-head evidence, so every invocation still re-reads live -PR state. +was live-audited at this snapshot with a 3,600-second interval, 18 recorded +launches, and process exit code 0. Its output log contains earlier completed +queue/repair iterations, but the two latest invocations reported tool-host +negotiation timeouts; a zero Codex process exit therefore does not prove a +successful maintenance iteration. Registration and prior successful work do +not prove the next run or transfer protected-head evidence, so every invocation +still re-reads live PR state and the loop retains explicit fail-closed reporting. Figma design-system boundary (ADR 0002): File ID `1Su3lDRmiZdcUs47t1QwIX`. The sanitized file now contains synthetic Event Lineage desktop (`5:14`) and @@ -543,7 +551,7 @@ for wholesale replay from #490. | Gap | Current evidence | Acceptance requirement | | --- | --- | --- | -| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Thirty-two PRs remain open at the 02:40 KST snapshot: twenty-two target `main` and ten target non-default stack branches. Every candidate still requires exact-head checks and independent approval before protected delivery | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | +| Protected release | Protected `main@ff7431bd` includes #631's ADR-decomposition documentation and #663's project-ontology/caller-parsed semantic-unit seam in addition to the #660/#664 semantic-unit/backend stack and #659 ontology readability/token repair. Thirty-seven PRs remain open at the 04:13 KST snapshot: twenty-two target `main` and fifteen target non-default stack branches. Every candidate still requires exact-head checks and independent approval before protected delivery | Terminal exact-head checks, no unresolved threads, the current ruleset's independent approval, and a protected merge SHA; re-fetch the ruleset before every lifecycle claim | | Evidence-grounded operations workspace | Protected-main #614 delivers governed semantic Ask, live Similar VOC, disjoint pending/failed analysis metrics, full Storybook state inventory, and current desktop/mobile screenshot evidence. Authorized-corpus backfill acceptance remains unavailable | Perform authenticated authorized-corpus acceptance with aggregate evidence and retain fail-closed no-match behavior | | Cancelled analysis guidance | PRD-FR-5 requires every lifecycle state to identify a valid next action, while ADR 0013 makes Cancelled terminal. Protected `main@494b54e2` rendered Cancelled without a next action. This stacked candidate adds kind-specific guidance for lineage, TEPP, topic lineage, and period reports; 390×844 and 1440×1000 authenticated synthetic-runtime audits are retained in `docs/screenshots/cancelled-analysis-runs-{mobile,desktop}.png`. The audit also found and repaired attached count/action text and the three-column mobile squeeze | Land through the protected gate, then repeat authenticated keyboard and screen-reader acceptance on the exact release head; no cancelled run may imply that it can resume or that a measurement exists | | 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 | @@ -562,7 +570,7 @@ for wholesale replay from #490. | SKOS organization aliases | Catalog binding and chip caption live on #480 / #482 | One catalog row per corroborated org; companion caption is hint-only until bound | | Event Lineage evidence | Channel evidence and Allen relations were delivered by merged #387 / #484 | Persist channel scores, explain them in the popup, never invent a fused score | | Scientific measurement | Durable accepted TEPP receipts, LineageWeave #614's exact accepted snapshot/cutoff/run/pair-count consumer, and TEPP #237's criterion-anchor wire contract are protected. #237 intentionally does not implement the estimator, so no emitted digest-bound terminal artifact exists yet. Merged #387 removes inferred/default persistence weights, but several older reconstruction tests still pass hand-authored numeric dictionaries that are not estimator evidence | Implement and verify the TEPP estimator behind the protected #237 contract, then replace remaining reconstruction-test constants with provenance-bearing fast-mlsirm estimates over synthetic fixtures. Retain true-parameter RMSE recovery as the acceptance bar | -| Python mathematical-compute boundary | ADR 0208's first deletion slice moved leftover residual/SVD/Gabriel arithmetic to fast-mlsirm, and #697 merged only into #693's non-default composition after deleting unused local cosine helpers. Active debt remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. The Global Ask SQL cosine path is separately frozen. fast-mlsirm #1445 exact head `e2e86a7d` now supplies a content-addressed Rust finite-population proportion design artifact with exact `(n_h, N_h)` ratios bound through Rust, PyO3/Python, output hash, and artifact hash; #702 exact head `7de6af0c` only replays and binds that owner output. Neither is protected delivery, and no terminal estimator/variance/interval artifact exists. RankWeave #41 (`e95ed46f`) composes the shared Rust/PyO3 calculation boundary with #48's deterministic semantic-unit cosine ranking, winning-unit evidence, and no local model/provider/weight selection. Its required hosted gates remain queued, so it is not protected delivery | Land composed RankWeave #41 before LineageWeave consumes it; replace the LineageWeave text-vector path with request/validation/persistence only. Land fast-mlsirm #1445 and #702 before corpus inference. Add graph-ranking, fusion-contribution, and estimator/variance/interval Rust artifacts at their owning boundaries before deleting remaining local paths; require CPU/GPU parity and true-parameter recovery where applicable | +| Python mathematical-compute boundary | Protected `main` and #667 still execute residual construction, complete-case selection, NumPy SVD, Gabriel coordinates, distances, reconstruction, cross share, inertia, and coverage in `lineageweave/leftover_pairs.py`; therefore the candidate-stack deletion must not be described as shipped. Open parent #640 delegates the interaction map to fast-mlsirm but remains non-default delivery. fast-mlsirm draft #1417 exact head `e2d2ac27` defines the versioned Rust/PyO3 residual-interaction-map envelope; child draft #1457 exact `5c7dc9ea` adds owner-computed explained share with Rust/PyO3/Python parity, and LineageWeave #728 pins that exact candidate while performing projection only. Both drafts still require protected upstream acceptance and an immutable released pin before #640 reaches `main`. Active debt also remains in period-report GRM/GPCM matrix construction and theta summaries, Knowledge Graph random-walk vector iteration, channel-weight estimation, fusion normalization/contribution recomputation, and lexical overlap ranking. fast-mlsirm #1445 exact head `0b3a794e` supplies the separate Rust finite-population design artifact; #702 exact head `eda7083b` replays it but neither candidate is protected delivery. RankWeave #41 exact head `21fed0dc` proposes the shared Rust/PyO3 retrieval calculation boundary and likewise remains unshipped | Land fast-mlsirm #1417 then #1457 through protected gates and publish an immutable release before #640/#728 reaches `main`; LineageWeave must retain only validation, identifiers, persistence projection, API, and presentation. Land #1445/#702 before corpus inference and RankWeave #41 before vector ranking consumption. Add graph-ranking, fusion-contribution, and estimator/variance/interval Rust artifacts at their owning boundaries; require CPU/GPU parity and true-parameter recovery where applicable | | Failed measurement recovery | A Failed measurement/topic-lineage run is immutable, but the prior UI delegated recovery and exposed no product retry action | Request a new authorized current-snapshot run, submit it through the existing outbox/TEPP boundary, retain the Failed history, and expose the action in all five locales | | Asynchronous authorization | Protected `main` includes #468's 3NF Keyverse organization/process-unit scope and rebuilds Global Ask worker authorization after the bearer token leaves the request | Prove on the exact release head that a second affiliation and a revoked process unit cannot widen delayed-job evidence | | Planned-facility intent | Planned-facility relationship intent remains only on closed, unmerged #490; earlier stack-only merges were not protected delivery | Recreate the evidence-backed slice on a current base and land through protected `main` before a release claim | diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md index 91970f75b..d83e579b1 100644 --- a/docs/storybook-inventory.md +++ b/docs/storybook-inventory.md @@ -32,8 +32,11 @@ https://www.w3.org/community/reports/design-tokens/CG-FINAL-format-20251028/ Storybook. (2026). *Storybook for React & Vite*. https://storybook.js.org/docs/get-started/frameworks/react-vite -`Workspace/ChatPanel` covers seeded-only, saved-history, and narrow mobile -states for the ADR 0235 list/select/new conversation controls. +`Workspace/ChatPanel` covers seeded-only, saved-history, narrow mobile, and +provider-neutral unavailable states for the ADR 0235 list/select/new +conversation controls. The unavailable scene keeps saved evidence visible and +tells the reader to review it before retrying; its 1440x900 and 390x844 renders +were inspected on 2026-08-27. World Wide Web Consortium. (2024). *Web Content Accessibility Guidelines (WCAG) 2.2* (W3C Recommendation). https://www.w3.org/TR/WCAG22/ diff --git a/frontend/src/AnalysisRunGuidance.stories.tsx b/frontend/src/AnalysisRunGuidance.stories.tsx index 4555d3415..e6eb8e6dc 100644 --- a/frontend/src/AnalysisRunGuidance.stories.tsx +++ b/frontend/src/AnalysisRunGuidance.stories.tsx @@ -61,7 +61,7 @@ export const StatusAndCorpusMatrix: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await expect(canvas.getByText("‘측정 다시 실행’을 선택하세요.", { exact: false })).toBeVisible(); - await expect(canvas.getByText("이 실행이 끝나면 LineageWeave가 이 글들을 토픽 계보로 구성합니다.")).toBeVisible(); + await expect(canvas.getByText("이 실행을 시작해 글을 토픽 계보 분석 대상으로 제출하세요. 결과가 보장되지는 않습니다.")).toBeVisible(); await expect(canvas.getByText("측정 다시 실행")).toBeVisible(); }, }; diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index ef1d783e8..b5b9aebcc 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -274,7 +274,8 @@ describe("App, authenticated", () => { return Promise.resolve( new Response( JSON.stringify({ - detail: "Commitment extraction is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + detail: + "Commitment extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", }), { status: 503, headers: { "Content-Type": "application/json" } }, ), @@ -1473,7 +1474,8 @@ describe("App, authenticated", () => { return Promise.resolve( new Response( JSON.stringify({ - detail: "Keymen extraction is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + detail: + "Keymen extraction is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", }), { status: 503, headers: { "Content-Type": "application/json" } }, ), @@ -1486,7 +1488,8 @@ describe("App, authenticated", () => { return Promise.resolve( new Response( JSON.stringify({ - detail: "Post evaluation is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + detail: + "Post evaluation is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", }), { status: 503, headers: { "Content-Type": "application/json" } }, ), @@ -1778,7 +1781,10 @@ describe("App, authenticated", () => { if (options?.searchUnavailable) { return Promise.resolve( new Response( - JSON.stringify({ detail: "Relation verification is unavailable: set SEARXNG_BASE_URL" }), + JSON.stringify({ + detail: + "Relation verification is temporarily unavailable. Retry in a moment. If this continues, contact your workspace administrator.", + }), { status: 503, headers: { "Content-Type": "application/json" } }, ), ); @@ -1837,7 +1843,8 @@ describe("App, authenticated", () => { return Promise.resolve( new Response( JSON.stringify({ - detail: "Post chat is unavailable: set ORCHESTRATOR_BASE_URL / ORCHESTRATOR_API_KEY", + detail: + "Post chat is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", }), { status: 503, headers: { "Content-Type": "application/json" } }, ), @@ -2758,7 +2765,11 @@ describe("App, authenticated", () => { await userEvent.click(screen.getByRole("button", { name: /^ask$/i })); await waitFor(() => - expect(screen.getByText("Chat is temporarily unavailable. Saved evidence is still available.")).toBeInTheDocument(), + expect( + screen.getByText( + "Chat is temporarily unavailable. Review the saved evidence below, then retry in a moment.", + ), + ).toBeInTheDocument(), ); expect(screen.queryByText(/HTTP 503/)).not.toBeInTheDocument(); expect(screen.queryByPlaceholderText(/what happened/i)).not.toBeInTheDocument(); @@ -2782,7 +2793,11 @@ describe("App, authenticated", () => { await userEvent.click(await screen.findByRole("button", { name: /evaluate post/i })); await waitFor(() => - expect(screen.getByText("Evaluation is temporarily unavailable. Saved evidence is still available.")).toBeInTheDocument(), + expect( + screen.getByText( + "Evaluation is temporarily unavailable. Review the saved evidence below, then retry in a moment.", + ), + ).toBeInTheDocument(), ); expect(screen.queryByText(/HTTP 503/)).not.toBeInTheDocument(); expect(screen.queryByRole("button", { name: /evaluate post/i })).not.toBeInTheDocument(); @@ -2796,7 +2811,11 @@ describe("App, authenticated", () => { await userEvent.click(await screen.findByRole("button", { name: /extract keymen/i })); await waitFor(() => - expect(screen.getByText("Keymen extraction is temporarily unavailable. Saved evidence is still available.")).toBeInTheDocument(), + expect( + screen.getByText( + "Keymen extraction is temporarily unavailable. Review the saved evidence below, then retry in a moment.", + ), + ).toBeInTheDocument(), ); expect(screen.queryByText(/HTTP 503/)).not.toBeInTheDocument(); expect(screen.queryByRole("button", { name: /extract keymen/i })).not.toBeInTheDocument(); @@ -2811,7 +2830,9 @@ describe("App, authenticated", () => { await waitFor(() => expect( - screen.getByText("Commitment derivation is temporarily unavailable. Saved evidence is still available."), + screen.getByText( + "Commitment derivation is temporarily unavailable. Review the saved evidence below, then retry in a moment.", + ), ).toBeInTheDocument(), ); expect(screen.queryByText(/HTTP 503/)).not.toBeInTheDocument(); @@ -2826,7 +2847,11 @@ describe("App, authenticated", () => { await userEvent.click(await screen.findByRole("button", { name: /verify against web search/i })); await waitFor(() => - expect(screen.getByText("Verification unavailable (search is not configured).")).toBeInTheDocument(), + expect( + screen.getByText( + "Verification is temporarily unavailable. Retry in a moment; if this continues, contact your workspace administrator.", + ), + ).toBeInTheDocument(), ); expect(screen.queryByText(/HTTP 503/)).not.toBeInTheDocument(); expect(screen.queryByRole("button", { name: /verify against web search/i })).not.toBeInTheDocument(); @@ -3912,7 +3937,7 @@ describe("App, authenticated", () => { }), ); expect( - await screen.findByText("LineageWeave will measure these posts when this run finishes."), + await screen.findByText("Start this run to submit these posts for measurement. A result is not guaranteed."), ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); expect(screen.queryByText(/this TEPP run measured/i)).not.toBeInTheDocument(); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 4334db94e..51615c510 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -130,7 +130,7 @@ import "./App.css"; function orchestratorUnavailableMessage(err: unknown, action: string): string { if (err instanceof BackendError && err.status === 503) { - return `${action} ${t("is temporarily unavailable.")} ${t("Saved evidence is still available.")}`; + return `${action} ${t("is temporarily unavailable.")} ${t("Review the saved evidence below, then retry in a moment.")}`; } return String(err); } @@ -162,7 +162,9 @@ function LanguageSwitcher({ accessToken }: { accessToken?: string }) { function searchUnavailableMessage(err: unknown): string { if (err instanceof BackendError && err.status === 503) { - return t("Verification unavailable (search is not configured)."); + return t( + "Verification is temporarily unavailable. Retry in a moment; if this continues, contact your workspace administrator.", + ); } return String(err); } diff --git a/frontend/src/ChatPanel.stories.tsx b/frontend/src/ChatPanel.stories.tsx index 7089027f1..867525b30 100644 --- a/frontend/src/ChatPanel.stories.tsx +++ b/frontend/src/ChatPanel.stories.tsx @@ -2,7 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import { expect, userEvent, within } from "storybook/test"; import { ChatPanel } from "./App"; -type Fixture = "empty" | "saved"; +type Fixture = "empty" | "saved" | "unavailable"; function jsonResponse(body: unknown, status = 200) { return new Response(JSON.stringify(body), { @@ -12,8 +12,18 @@ function jsonResponse(body: unknown, status = 200) { } function installFixture(fixture: Fixture) { - globalThis.fetch = async (input) => { + globalThis.fetch = async (input, init) => { const url = input instanceof Request ? input.url : String(input); + const method = input instanceof Request ? input.method : init?.method; + if (fixture === "unavailable" && url.endsWith("/api/posts/post-1/chat") && method === "POST") { + return jsonResponse( + { + detail: + "Post chat is unavailable. Retry in a moment. If this continues, contact your workspace administrator.", + }, + 503, + ); + } if (url.endsWith("/api/posts/post-1/chat/conversations/conversation-post-1")) { return jsonResponse({ conversation_id: "conversation-post-1", @@ -113,3 +123,20 @@ export const Phone: Story = { viewport: { defaultViewport: "mobile1" }, }, }; + +export const UnavailableWithNextAction: Story = { + render(args) { + installFixture("unavailable"); + return ; + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.type(canvas.getByPlaceholderText(/what happened/i), "What changed?"); + await userEvent.click(canvas.getByRole("button", { name: /^ask$/i })); + await expect( + await canvas.findByText( + "Chat is temporarily unavailable. Review the saved evidence below, then retry in a moment.", + ), + ).toBeVisible(); + }, +}; diff --git a/frontend/src/analysisRunI18n.ts b/frontend/src/analysisRunI18n.ts index 3d946ceca..cffd610c0 100644 --- a/frontend/src/analysisRunI18n.ts +++ b/frontend/src/analysisRunI18n.ts @@ -37,7 +37,7 @@ const ENGLISH_ANALYSIS_RUN_COPY = { corpusFailedMeasurement: "These posts were selected for measurement at this snapshot. Choose Retry measurement to measure the current snapshot.", corpusSucceededMeasurement: "LineageWeave measured these posts in this run.", - corpusPendingMeasurement: "LineageWeave will measure these posts when this run finishes.", + corpusPendingMeasurement: "Start this run to submit these posts for measurement. A result is not guaranteed.", corpusCancelledMeasurement: "These posts would have been measured. The run was cancelled before a calibrated result was created.", corpusAttachedMeasurement: "These posts are attached to this measurement run.", @@ -45,7 +45,7 @@ const ENGLISH_ANALYSIS_RUN_COPY = { "These posts were selected for topic-lineage analysis at this snapshot. Choose Retry topic lineage to analyze the current snapshot.", corpusSucceededTopicLineage: "LineageWeave organized these posts into topic lineage in this run.", corpusPendingTopicLineage: - "LineageWeave will organize these posts into topic lineage when this run finishes.", + "Start this run to submit these posts for topic-lineage analysis. A result is not guaranteed.", corpusCancelledTopicLineage: "These posts would have formed the topic lineage. The run was cancelled before a calibrated topic result was created.", corpusAttachedTopicLineage: "These posts are attached to this topic-lineage run.", @@ -82,12 +82,12 @@ const ANALYSIS_RUN_COPY: Record< emptyReport: "이 스냅샷에는 기간 보고서에 사용할 글이 없습니다. 이후 실행을 열거나 관리자에게 최신 스냅샷 생성을 요청하세요.", corpusFailedMeasurement: "이 글들은 이 스냅샷에서 측정 대상으로 선택되었습니다. ‘측정 다시 실행’을 선택해 현재 스냅샷을 측정하세요.", corpusSucceededMeasurement: "LineageWeave가 이 실행에서 이 글들을 측정했습니다.", - corpusPendingMeasurement: "이 실행이 끝나면 LineageWeave가 이 글들을 측정합니다.", + corpusPendingMeasurement: "이 실행을 시작해 글을 측정 대상으로 제출하세요. 결과가 보장되지는 않습니다.", corpusCancelledMeasurement: "이 글들은 측정될 예정이었습니다. 보정된 결과가 생성되기 전에 실행이 취소되었습니다.", corpusAttachedMeasurement: "이 글들은 이 측정 실행에 연결되어 있습니다.", corpusFailedTopicLineage: "이 글들은 이 스냅샷에서 토픽 계보 분석 대상으로 선택되었습니다. ‘토픽 계보 다시 실행’을 선택해 현재 스냅샷을 분석하세요.", corpusSucceededTopicLineage: "LineageWeave가 이 실행에서 이 글들을 토픽 계보로 구성했습니다.", - corpusPendingTopicLineage: "이 실행이 끝나면 LineageWeave가 이 글들을 토픽 계보로 구성합니다.", + corpusPendingTopicLineage: "이 실행을 시작해 글을 토픽 계보 분석 대상으로 제출하세요. 결과가 보장되지는 않습니다.", corpusCancelledTopicLineage: "이 글들은 토픽 계보를 구성할 예정이었습니다. 보정된 토픽 결과가 생성되기 전에 실행이 취소되었습니다.", corpusAttachedTopicLineage: "이 글들은 이 토픽 계보 실행에 연결되어 있습니다.", retryMeasurement: "측정 다시 실행", @@ -115,12 +115,12 @@ const ANALYSIS_RUN_COPY: Record< emptyReport: "此快照中没有可用于周期报告的文章。请打开较晚的运行,或请管理员创建更新的快照。", corpusFailedMeasurement: "这些文章已在此快照中选为测量对象。选择“重新运行测量”以测量当前快照。", corpusSucceededMeasurement: "LineageWeave 已在此运行中测量这些文章。", - corpusPendingMeasurement: "此运行完成后,LineageWeave 将测量这些文章。", + corpusPendingMeasurement: "启动此运行以提交这些文章进行测量。结果不作保证。", corpusCancelledMeasurement: "这些文章原本将被测量。运行在生成校准结果前已取消。", corpusAttachedMeasurement: "这些文章已附加到此测量运行。", corpusFailedTopicLineage: "这些文章已在此快照中选为主题谱系分析对象。选择“重新运行主题谱系”以分析当前快照。", corpusSucceededTopicLineage: "LineageWeave 已在此运行中将这些文章整理为主题谱系。", - corpusPendingTopicLineage: "此运行完成后,LineageWeave 将把这些文章整理为主题谱系。", + corpusPendingTopicLineage: "启动此运行以提交这些文章进行主题谱系分析。结果不作保证。", corpusCancelledTopicLineage: "这些文章原本将构成主题谱系。运行在生成校准后的主题结果前已取消。", corpusAttachedTopicLineage: "这些文章已附加到此主题谱系运行。", retryMeasurement: "重新运行测量", @@ -148,12 +148,12 @@ const ANALYSIS_RUN_COPY: Record< emptyReport: "このスナップショットには期間レポートで使用できる投稿がありません。後の実行を開くか、管理者に新しいスナップショットの作成を依頼してください。", corpusFailedMeasurement: "これらの投稿は、このスナップショットで測定対象に選ばれました。「測定を再実行」を選択して現在のスナップショットを測定してください。", corpusSucceededMeasurement: "LineageWeave がこの実行でこれらの投稿を測定しました。", - corpusPendingMeasurement: "この実行が完了すると、LineageWeave がこれらの投稿を測定します。", + corpusPendingMeasurement: "この実行を開始して、投稿を測定対象として送信してください。結果は保証されません。", corpusCancelledMeasurement: "これらの投稿は測定される予定でした。校正済みの結果が作成される前に実行がキャンセルされました。", corpusAttachedMeasurement: "これらの投稿はこの測定実行に関連付けられています。", corpusFailedTopicLineage: "これらの投稿は、このスナップショットでトピック系譜分析の対象に選ばれました。「トピック系譜を再実行」を選択して現在のスナップショットを分析してください。", corpusSucceededTopicLineage: "LineageWeave がこの実行でこれらの投稿をトピック系譜にまとめました。", - corpusPendingTopicLineage: "この実行が完了すると、LineageWeave がこれらの投稿をトピック系譜にまとめます。", + corpusPendingTopicLineage: "この実行を開始して、投稿をトピック系譜分析に送信してください。結果は保証されません。", corpusCancelledTopicLineage: "これらの投稿はトピック系譜を構成する予定でした。校正済みのトピック結果が作成される前に実行がキャンセルされました。", corpusAttachedTopicLineage: "これらの投稿はこのトピック系譜実行に関連付けられています。", retryMeasurement: "測定を再実行", @@ -181,12 +181,12 @@ const ANALYSIS_RUN_COPY: Record< emptyReport: "Không có bài viết cho báo cáo kỳ trong ảnh chụp này. Hãy mở một lượt chạy sau hoặc yêu cầu quản trị viên tạo ảnh chụp mới hơn.", corpusFailedMeasurement: "Các bài viết này đã được chọn để đo trong ảnh chụp này. Chọn Chạy lại phép đo để đo ảnh chụp hiện tại.", corpusSucceededMeasurement: "LineageWeave đã đo các bài viết này trong lượt chạy này.", - corpusPendingMeasurement: "LineageWeave sẽ đo các bài viết này khi lượt chạy hoàn tất.", + corpusPendingMeasurement: "Bắt đầu lượt chạy này để gửi các bài viết đi đo. Kết quả không được đảm bảo.", corpusCancelledMeasurement: "Các bài viết này lẽ ra sẽ được đo. Lượt chạy đã bị hủy trước khi tạo kết quả đã hiệu chuẩn.", corpusAttachedMeasurement: "Các bài viết này được đính kèm với lượt chạy đo này.", corpusFailedTopicLineage: "Các bài viết này đã được chọn để phân tích phả hệ chủ đề trong ảnh chụp này. Chọn Chạy lại phả hệ chủ đề để phân tích ảnh chụp hiện tại.", corpusSucceededTopicLineage: "LineageWeave đã sắp xếp các bài viết này thành phả hệ chủ đề trong lượt chạy này.", - corpusPendingTopicLineage: "LineageWeave sẽ sắp xếp các bài viết này thành phả hệ chủ đề khi lượt chạy hoàn tất.", + corpusPendingTopicLineage: "Bắt đầu lượt chạy này để gửi các bài viết đi phân tích phả hệ chủ đề. Kết quả không được đảm bảo.", corpusCancelledTopicLineage: "Các bài viết này lẽ ra sẽ tạo thành phả hệ chủ đề. Lượt chạy đã bị hủy trước khi tạo kết quả chủ đề đã hiệu chuẩn.", corpusAttachedTopicLineage: "Các bài viết này được đính kèm với lượt chạy phả hệ chủ đề này.", retryMeasurement: "Chạy lại phép đo", diff --git a/frontend/src/i18n.test.ts b/frontend/src/i18n.test.ts index afd047874..b620de4e8 100644 --- a/frontend/src/i18n.test.ts +++ b/frontend/src/i18n.test.ts @@ -79,7 +79,7 @@ describe("i18n", () => { "No observed calendar events are available.", "Open this observed occurrence. It is not a LineageWeave commitment.", "Collect stronger authoritative evidence before accepting the claim.", - "Inspect the authorized cited posts and their evidence.", + "Ask about a specific claim or narrow the time range, then retry.", "Ask a workspace administrator to enable public verification, then retry.", "Open supporting post", "Review unavailable historical channels before relying on this cutoff answer.", diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 57fe26d6e..bbf7abb81 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -76,7 +76,8 @@ const TRANSLATIONS: Partial>> = { "Stored semantic evidence": "저장된 의미 기반 근거", "Recorded evidence": "기록된 근거", "Lineage maintenance": "계보 관리", - "Verification unavailable (search is not configured).": "검증을 사용할 수 없습니다(검색이 설정되지 않았습니다).", + "Verification is temporarily unavailable. Retry in a moment; if this continues, contact your workspace administrator.": + "검증을 일시적으로 사용할 수 없습니다. 잠시 후 다시 시도하고, 문제가 계속되면 워크스페이스 관리자에게 문의하십시오.", "No customer commitment found in this post.": "이 글에서 고객 약속을 찾지 못했습니다.", due: "기한", "Ticket created": "티켓 생성", @@ -193,7 +194,7 @@ const TRANSLATIONS: Partial>> = { "Open supporting post": "근거 글 열기", "Inspect public evidence separately before any governed graph review.": "거버넌스 그래프 검토 전에 공개 근거를 별도로 확인하세요.", "Collect stronger authoritative evidence before accepting the claim.": "주장을 받아들이기 전에 더 강한 권위 있는 근거를 확보하세요.", - "Inspect the authorized cited posts and their evidence.": "권한이 있는 인용 글과 근거를 확인하세요.", + "Ask about a specific claim or narrow the time range, then retry.": "확인할 주장을 구체적으로 묻거나 기간을 좁힌 뒤 다시 시도하세요.", "Review unavailable historical channels before relying on this cutoff answer.": "이 컷오프 답변을 사용하기 전에 사용할 수 없는 과거 채널을 검토하세요.", "Compare these cutoff-grounded citations with live evidence next.": "다음으로 컷오프 시점 인용과 현재 근거를 비교하세요.", Ask: "질의", @@ -449,7 +450,8 @@ const TRANSLATIONS: Partial>> = { "Share unavailable.": "공유할 수 없습니다.", "Bookmark unavailable.": "북마크를 사용할 수 없습니다.", "No summary is available for this record yet.": "이 기록의 요약이 아직 없습니다.", - "Saved evidence is still available.": "저장된 근거는 계속 확인할 수 있습니다.", + "Review the saved evidence below, then retry in a moment.": + "아래의 저장된 근거를 검토한 후 잠시 뒤 다시 시도하십시오.", "Showing the first {shown} of {total} posts known at this cutoff.": "이 기준 시점에 알려진 {total}개 글 중 처음 {shown}개를 표시합니다.", "Showing the first {shown} of {total} observed customer identifiers, ranked by post count.": @@ -608,7 +610,8 @@ const TRANSLATIONS: Partial>> = { "Stored semantic evidence": "已存储的语义证据", "Recorded evidence": "已记录的证据", "Lineage maintenance": "谱系维护", - "Verification unavailable (search is not configured).": "无法验证(未配置搜索)。", + "Verification is temporarily unavailable. Retry in a moment; if this continues, contact your workspace administrator.": + "验证暂时不可用。请稍后重试;如果问题持续,请联系工作区管理员。", "No customer commitment found in this post.": "未在此文章中找到客户承诺。", due: "截止日期", "Ticket created": "工单已创建", @@ -725,7 +728,7 @@ const TRANSLATIONS: Partial>> = { "Open supporting post": "打开支持性帖子", "Inspect public evidence separately before any governed graph review.": "在治理图谱审查前单独检查公开证据。", "Collect stronger authoritative evidence before accepting the claim.": "接受该声明前,请收集更有力的权威证据。", - "Inspect the authorized cited posts and their evidence.": "检查已获授权的引用文章及其证据。", + "Ask about a specific claim or narrow the time range, then retry.": "请明确要核实的主张或缩小时间范围,然后重试。", "Review unavailable historical channels before relying on this cutoff answer.": "依赖此截止时间答案前,请检查不可用的历史渠道。", "Compare these cutoff-grounded citations with live evidence next.": "接下来请将截止时间依据的引用与当前证据进行比较。", Ask: "提问", @@ -974,7 +977,8 @@ const TRANSLATIONS: Partial>> = { "Share unavailable.": "分享不可用。", "Bookmark unavailable.": "书签不可用。", "No summary is available for this record yet.": "此记录暂时没有摘要。", - "Saved evidence is still available.": "仍可查看已保存的证据。", + "Review the saved evidence below, then retry in a moment.": + "请先查看下方已保存的证据,然后稍后重试。", "Showing the first {shown} of {total} posts known at this cutoff.": "显示此截止时间已知的 {total} 篇文章中的前 {shown} 篇。", "Showing the first {shown} of {total} observed customer identifiers, ranked by post count.": @@ -1156,7 +1160,8 @@ const TRANSLATIONS: Partial>> = { "Stored semantic evidence": "保存された意味的証拠", "Recorded evidence": "記録された証拠", "Lineage maintenance": "系譜管理", - "Verification unavailable (search is not configured).": "確認できません(検索が設定されていません)。", + "Verification is temporarily unavailable. Retry in a moment; if this continues, contact your workspace administrator.": + "確認機能は一時的に利用できません。しばらくしてから再試行し、問題が続く場合はワークスペース管理者にお問い合わせください。", "No customer commitment found in this post.": "この投稿に顧客コミットメントは見つかりませんでした。", due: "期限", "Ticket created": "チケットを作成", @@ -1273,7 +1278,7 @@ const TRANSLATIONS: Partial>> = { "Open supporting post": "根拠となる投稿を開く", "Inspect public evidence separately before any governed graph review.": "管理対象グラフをレビューする前に公開証拠を別途確認してください。", "Collect stronger authoritative evidence before accepting the claim.": "主張を受け入れる前に、より強い権威ある証拠を集めてください。", - "Inspect the authorized cited posts and their evidence.": "許可された引用投稿とその証拠を確認してください。", + "Ask about a specific claim or narrow the time range, then retry.": "確認する主張を具体化するか期間を絞って、もう一度お試しください。", "Review unavailable historical channels before relying on this cutoff answer.": "このカットオフ回答を利用する前に、利用できない履歴チャネルを確認してください。", "Compare these cutoff-grounded citations with live evidence next.": "次に、カットオフ時点の引用を現在の証拠と比較してください。", Ask: "質問する", @@ -1500,7 +1505,8 @@ const TRANSLATIONS: Partial>> = { "Share unavailable.": "共有できません。", "Bookmark unavailable.": "ブックマークを利用できません。", "No summary is available for this record yet.": "この記録の概要はまだありません。", - "Saved evidence is still available.": "保存された証拠は引き続き確認できます。", + "Review the saved evidence below, then retry in a moment.": + "下に保存された証拠を確認してから、しばらくして再試行してください。", "Showing the first {shown} of {total} posts known at this cutoff.": "この基準時点で把握されている{total}件の投稿のうち、最初の{shown}件を表示しています。", "Showing the first {shown} of {total} observed customer identifiers, ranked by post count.": @@ -1683,7 +1689,8 @@ const TRANSLATIONS: Partial>> = { "Stored semantic evidence": "Bằng chứng ngữ nghĩa đã lưu", "Recorded evidence": "Bằng chứng đã ghi nhận", "Lineage maintenance": "Bảo trì dòng sự kiện", - "Verification unavailable (search is not configured).": "Không thể xác minh (chưa cấu hình tìm kiếm).", + "Verification is temporarily unavailable. Retry in a moment; if this continues, contact your workspace administrator.": + "Tính năng xác minh tạm thời không khả dụng. Hãy thử lại sau ít phút; nếu sự cố tiếp diễn, hãy liên hệ quản trị viên không gian làm việc.", "No customer commitment found in this post.": "Không tìm thấy cam kết của khách hàng trong bài viết này.", due: "Hạn", "Ticket created": "Đã tạo phiếu", @@ -1800,7 +1807,7 @@ const TRANSLATIONS: Partial>> = { "Open supporting post": "Mở bài viết làm bằng chứng", "Inspect public evidence separately before any governed graph review.": "Kiểm tra riêng bằng chứng công khai trước khi rà soát đồ thị được quản trị.", "Collect stronger authoritative evidence before accepting the claim.": "Thu thập bằng chứng có thẩm quyền mạnh hơn trước khi chấp nhận tuyên bố.", - "Inspect the authorized cited posts and their evidence.": "Kiểm tra các bài viết được trích dẫn đã cấp quyền và bằng chứng của chúng.", + "Ask about a specific claim or narrow the time range, then retry.": "Hãy nêu rõ tuyên bố cần xác minh hoặc thu hẹp khoảng thời gian, rồi thử lại.", "Review unavailable historical channels before relying on this cutoff answer.": "Xem lại các kênh lịch sử không khả dụng trước khi dựa vào câu trả lời tại mốc cắt này.", "Compare these cutoff-grounded citations with live evidence next.": "Tiếp theo, hãy so sánh các trích dẫn tại mốc cắt với bằng chứng hiện tại.", Ask: "Hỏi", @@ -2027,7 +2034,8 @@ const TRANSLATIONS: Partial>> = { "Share unavailable.": "Không thể chia sẻ.", "Bookmark unavailable.": "Không thể dùng dấu trang.", "No summary is available for this record yet.": "Chưa có bản tóm tắt cho bản ghi này.", - "Saved evidence is still available.": "Bằng chứng đã lưu vẫn có thể xem.", + "Review the saved evidence below, then retry in a moment.": + "Hãy xem bằng chứng đã lưu bên dưới, rồi thử lại sau ít phút.", "Showing the first {shown} of {total} posts known at this cutoff.": "Đang hiển thị {shown} bài viết đầu tiên trong số {total} bài viết được biết tại thời điểm chốt này.", "Showing the first {shown} of {total} observed customer identifiers, ranked by post count.": diff --git a/tests/test_analysis_run_start.py b/tests/test_analysis_run_start.py index 8f508e954..41414118f 100644 --- a/tests/test_analysis_run_start.py +++ b/tests/test_analysis_run_start.py @@ -492,6 +492,29 @@ def fail(*_args, **_kwargs): assert "raw-tepp-provider-secret" not in str(exc_info.value) +def test_lineage_provider_failure_returns_customer_action(monkeypatch) -> None: + """Lineage failures expose a retry action, not the provider boundary.""" + plan = analysis_run_start._DeliveryPlan( + "analysis_run_lineage", + datetime(2026, 8, 27, tzinfo=timezone.utc), + {}, + weights={"llm": 1.0}, + ) + + def fail(*_args, **_kwargs): + raise analysis_run_start._AdjudicationProviderError("raw-provider-secret") + + monkeypatch.setattr(analysis_run_start, "lineage_edge_specs", fail) + with pytest.raises(AnalysisRunStartError) as exc_info: + analysis_run_start._execute_delivery_plan(plan, TeppClient(), object()) + + assert exc_info.value.status_code == 503 + assert "Start this run again" in exc_info.value.detail + assert "workspace administrator" in exc_info.value.detail + assert "provider" not in exc_info.value.detail + assert "contextual-orchestrator" not in exc_info.value.detail + + def test_hidden_run_start_is_not_found() -> None: """Operators get a 404 next action, not an internal exception name.""" error = AnalysisRunStartError(404, "This analysis run is not visible.") diff --git a/tests/test_frontend_container_install_policy.py b/tests/test_frontend_container_install_policy.py index dacae246c..b8cbc4dce 100644 --- a/tests/test_frontend_container_install_policy.py +++ b/tests/test_frontend_container_install_policy.py @@ -5,9 +5,25 @@ def test_frontend_container_copies_the_single_build_script_policy() -> None: - """The image install layer must receive the fail-closed pnpm allowlist.""" + """Each image install must receive the fail-closed pnpm allowlist first.""" workspace = (ROOT / "frontend" / "pnpm-workspace.yaml").read_text(encoding="utf-8") - dockerfile = (ROOT / "frontend" / "Dockerfile").read_text(encoding="utf-8") + dockerfile = (ROOT / "frontend" / "Dockerfile").read_text(encoding="utf-8").splitlines() assert workspace == "allowBuilds:\n esbuild: true\n" - assert "COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./" in dockerfile + stage = -1 + policy_copies: list[tuple[int, int]] = [] + installs: list[tuple[int, int]] = [] + for line_number, line in enumerate(dockerfile, start=1): + command = line.strip() + if command.upper().startswith("FROM "): + stage += 1 + if command == "COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./": + policy_copies.append((line_number, stage)) + if command.startswith("RUN ") and "pnpm install" in command: + installs.append((line_number, stage)) + + assert installs + assert all( + any(copy_stage == install_stage and copy_line < install_line for copy_line, copy_stage in policy_copies) + for install_line, install_stage in installs + ) diff --git a/tests/test_global_ask_queue.py b/tests/test_global_ask_queue.py index d272ddd8e..21c55bbf3 100644 --- a/tests/test_global_ask_queue.py +++ b/tests/test_global_ask_queue.py @@ -118,7 +118,7 @@ def test_no_public_claim_next_action_opens_authorized_evidence() -> None: cv.VERIFICATION_NO_PUBLIC_CLAIMS ) - assert next_action == "Inspect the authorized cited posts and their evidence." + assert next_action == "Ask about a specific claim or narrow the time range, then retry." assert "internal" not in next_action.lower() @@ -421,9 +421,7 @@ async def _fake_compute_global_ask_answer(*_args, **_kwargs): assert "failure_detail" in settle_query failure_detail = settle_args[-1] assert secret_bearing_message not in failure_detail - assert failure_detail == ( - "Ask Agent is unavailable: contextual-orchestrator returned no complete evidence object" - ) + assert failure_detail == global_ask_queue._ASK_RETRY_MESSAGE def test_permission_and_connection_errors_keep_their_pre_authored_safe_message( @@ -486,7 +484,7 @@ async def _fake_compute_global_ask_answer(*_args, **_kwargs): ) _settle_query, settle_args = connection.executed[-1] - assert settle_args[-1] == f"job exceeded the {global_ask_queue.JOB_DEADLINE_SECONDS}s deadline" + assert settle_args[-1] == global_ask_queue._ASK_RETRY_MESSAGE def test_job_visibility_never_expands_past_queued_scope() -> None: diff --git a/tests/test_server_diagnostics.py b/tests/test_server_diagnostics.py index a81aea95e..a2bbc9344 100644 --- a/tests/test_server_diagnostics.py +++ b/tests/test_server_diagnostics.py @@ -56,9 +56,7 @@ async def _sources(*args: object, **kwargs: object) -> list[object]: ) ) assert raised.value.status_code == 503 - assert raised.value.detail == ( - "Ask Agent is unavailable: contextual-orchestrator could not complete the answer" - ) + assert raised.value.detail == global_ask_queue._ASK_RETRY_MESSAGE def test_global_ask_provider_failure_is_reader_safe_and_classified( @@ -153,9 +151,7 @@ async def _sources(*args: object, **kwargs: object) -> list[object]: ) ) assert raised.value.status_code == 503 - assert raised.value.detail == ( - "Ask Agent is unavailable: authorized evidence could not be assembled" - ) + assert raised.value.detail == global_ask_queue._ASK_RETRY_MESSAGE record = next( item for item in caplog.records if item.msg == "lineageweave.server_failure" ) From 92a64c40d4717ae5c9ebd05b7ac9b8a2377c8ab6 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 05:14:11 +0900 Subject: [PATCH 229/238] docs: refresh ontology stack exact heads --- docs/product-technical-gap-baseline.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 3a6c1b575..6793f3218 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 04:27 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 05:07 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, @@ -86,15 +86,15 @@ context only. | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- | -| #735 | `76b3ef2a` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and idempotent insertion without local weighting, aggregation, normalization, or psychometric arithmetic. Thirty focused checks and a throwaway-PostgreSQL full-artifact replay report 94,640 observations across 910 occupations and 52 elements plus all 33 scale rows; only aggregate counts enter this repository. Review threads are currently empty, frontend/CodeRabbit pass, and the full suite/Devin/independent review remain in progress | -| #734 | `99f098fe` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL now rejects future source dates and out-of-declared-scale observations before insert, rejects update/delete on immutable observations, and retains idempotent conflict handling; 24 migration/rerun/schema checks pass and both review threads are resolved. Hosted backend/frontend/full-suite and independent review remain in progress, so this is not accepted measurement or protected delivery | -| #733 | `f2b1e464` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence now uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline, so the distinction does not depend on color; the intro follows the filtered visible set. Fifty-eight focused backend/frontend checks, lint, production/Storybook builds pass; desktop 1440x1182 and mobile 390x852 renders were inspected, all review threads are resolved, and fresh hosted checks remain queued | -| #732 | `9e714f65` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. Forty focused linkage/publication/hygiene checks pass, the sampled official artifact digest matches its pin, all review threads are resolved, and the frontend/review checks pass; the full suite and independent review remain in progress | -| #731 | `88ae5796` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; it introduces no rating, person trait, score, weight, or inferred crosswalk. Numeric outline ordering now places `2.C.2` before `2.C.10`, and the decision file moved to union-free ADR 0255; child synchronization and hosted gates remain in progress. During earlier concurrent-head handling an unsafe guard permitted one brief `--force-with-lease`; the overwritten `38812fc1` change was recovered as a parent and normal push restored the remote. Preserved ancestry is code-preservation evidence, not approval of the process defect | +| #735 | `c0f31f11` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. Thirty-two focused/live-PostgreSQL checks and a full-artifact replay report 94,640 observations across 910 occupations and 52 elements plus all 33 scale rows; only aggregate counts enter this repository. Review threads are empty and exact-head hosted checks remain in progress | +| #734 | `549a7e1e` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. Twenty-four migration/rerun/schema checks pass; the two PostgreSQL/ADR information threads were evidence-replied and resolved, and exact-head hosted checks remain in progress, so this is not accepted measurement or protected delivery | +| #733 | `8a4b0d96` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels now agree, construct focus fails closed instead of exposing a raw UUID, and the intro gives a scoped next action. Focused ontology/frontend checks and lint pass, prior desktop/mobile renders were inspected, all review threads are resolved, and exact-head hosted checks remain in progress | +| #732 | `3e30402d` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. Forty focused linkage/publication/hygiene checks pass, the official artifact digest matches its pin, all review threads are resolved, and all observed exact-head hosted checks pass; independent review remains required | +| #731 | `9654bb8b` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; ADR 0255 explicitly supersedes only ADR 0248's prohibition on complete pinned O*NET vocabulary publication and preserves the evidence/no-equivalence boundaries. Canonical graph publication is verified by RDF isomorphism and per-source manifest digests; all review threads and observed exact-head checks pass, while independent review and parent delivery remain required | | #728 | `e52a8272` | now stacks on exact #640 instead of extending protected-main NumPy arithmetic. It pins fast-mlsirm PR #1457 exact `5c7dc9ea` and consumes the owner-produced Rust/PyO3 explained-share field while retaining LineageWeave validation, persistence projection, API, and presentation only. The audit also moved the schema change to union-free migration 0236 and made the production-equivalent bootstrap execute it. Upstream Rust tests pass; LineageWeave backend/schema/frontend focused checks pass; both review queues have zero unresolved threads. The upstream PR remains draft with hosted gates in progress and the LineageWeave parent remains non-default, so neither is protected delivery | -| #726 | `fd1cac66` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. PR #729 merged normally after exact-head checks passed. The shared loader fences stale assertions with the current content digest; retry re-extraction remains deliberate because semantic-unit replacement invalidates prior unit identities, and reclaimed jobs reset their retry budget. Evidence status now prioritizes queued/running processing over same-digest completion, so atomic unit/assertion replacement cannot briefly report `complete` with an empty list. Focused synced-stack checks pass, all threads are resolved, frontend hosted checks pass, and the full suite/independent review remain in progress | +| #726 | `d4e78034` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. Attempt-fenced lease refresh prevents concurrent long extraction, a later-enabled analysis service wakes succeeded current-digest rows that lack construct evidence, and the API/UI distinguishes setup required from retryable failure without leaking implementation boundaries. Focused backend/frontend/docs checks and lint pass, all threads are resolved, and exact-head hosted checks remain in progress | | #724 | `fdec8f65` | targets the occupational-taxonomy stack and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. The served Turtle is now a canonical parsed graph rather than source-document concatenation, is proved isomorphic with the governed source graph, and the manifest lists and hashes every source file instead of naming one misleading source. Thirty publication checks pass, all threads are resolved, and fresh hosted checks remain queued pending parent delivery | -| #723 | `d257187a` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The official 485,151-byte, 3,006-row source artifact is pinned by canonical SHA-256 before a database transaction; the governed scope admits 2,529 constructs, rejects changed or whitespace-mutated labels, and keeps absent descriptions as `NULL`. Eight focused checks and the official digest/count replay pass, all threads are resolved, and fresh hosted checks remain in progress pending parent delivery | +| #723 | `316fc190` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The official 485,151-byte, 3,006-row source artifact is pinned by canonical SHA-256 before a database transaction; the governed scope admits 2,529 constructs, rejects changed or whitespace-mutated labels, and keeps absent descriptions as `NULL`. Synthetic fixtures inject their own declared digest rather than weakening the production pin. Focused checks and the official digest/count replay pass; all threads are resolved and hosted checks remain in progress pending parent delivery | | #721 | `9214c50f` | stacked occupational-construct persistence candidate. The current head synchronizes its parent and removes the duplicate construct-detail field; lint and production build pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #720 | `dda0531d` | cancels stale test runs after PR closure. A normal failed-job rerun reached terminal attempt 2 and again failed closed only after NVIDIA primary `429`, retired NVIDIA fallback `410`, and direct OpenAI `insufficient_quota`; this is current provider-infrastructure evidence, not a code finding or a passing scan. Normal auto-merge is enabled, but authoritative Strix evidence and independent review remain required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | @@ -110,11 +110,11 @@ context only. | #702 | `eda7083b` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The current 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The full 43,814-row replay records zero nonblank bodies and separates fourteen deployed PROV-O tables from the still-missing linkage of 3,190 evidence edges; a missing PROV support profile now fails closed instead of producing an environment-dependent term set. Twenty-nine focused audit/docstring/hygiene checks pass, all threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | -| #680 | `876129e5` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The follow-up fixes the Vietnamese action-label mismatch and adds four-locale containment coverage; 68 i18n checks and lint pass, all threads are resolved, and hosted checks plus independent review remain required | +| #680 | `b05e3100` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The latest repair replaces search-configuration text with saved-evidence/retry guidance in five locales, suppresses raw failure codes, and removes the persistence-delivery outbox from the customer screen while retaining the API record. All 166 App/i18n checks and lint pass; fresh hosted checks, rendered Compose inspection, and independent review remain required | | #679 | `01cb291f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and wraps claim/evidence rows at desktop and mobile widths. A Storybook interaction test, 167 focused tests, lint, build, and committed synthetic desktop/mobile screenshots verify the state; all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | -| #667 | pre-documentation parent `bc399e89` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches, records hard deletion as an intentional erasure boundary distinct from visibility revocation, and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific retry, saved-evidence, calibration, or administrator actions. Pending-run and no-public-claim guidance is conditional and actionable; the Chat unavailable Storybook scene keeps saved evidence visible and its 1440x900/390x844 renders were inspected. Focused interaction, i18n, backend, container-policy, lint, Storybook-build, and documentation checks pass; re-fetch the resulting PR head for lifecycle use | +| #667 | `f1e71d59` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches, records hard deletion as an intentional erasure boundary distinct from visibility revocation, and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific retry, saved-evidence, calibration, or administrator actions. Pending-run and no-public-claim guidance is conditional and actionable; the Chat unavailable Storybook scene keeps saved evidence visible and its 1440x900/390x844 renders were inspected. Focused interaction, i18n, backend, container-policy, lint, Storybook-build, and documentation checks pass; exact-head hosted checks and independent review remain required | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | From ec7438d7b67f037ea2067dbfa5750fcda0cefe64 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 05:42:37 +0900 Subject: [PATCH 230/238] docs: record customer boundary audits --- 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 6793f3218..e321d5543 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 05:07 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 05:42 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, @@ -110,10 +110,10 @@ context only. | #702 | `eda7083b` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The current 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The full 43,814-row replay records zero nonblank bodies and separates fourteen deployed PROV-O tables from the still-missing linkage of 3,190 evidence edges; a missing PROV support profile now fails closed instead of producing an environment-dependent term set. Twenty-nine focused audit/docstring/hygiene checks pass, all threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | -| #680 | `b05e3100` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The latest repair replaces search-configuration text with saved-evidence/retry guidance in five locales, suppresses raw failure codes, and removes the persistence-delivery outbox from the customer screen while retaining the API record. All 166 App/i18n checks and lint pass; fresh hosted checks, rendered Compose inspection, and independent review remain required | -| #679 | `01cb291f` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and wraps claim/evidence rows at desktop and mobile widths. A Storybook interaction test, 167 focused tests, lint, build, and committed synthetic desktop/mobile screenshots verify the state; all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | +| #680 | `b05e3100` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The latest repair replaces search-configuration text with saved-evidence/retry guidance in five locales, suppresses raw failure codes, and removes the persistence-delivery outbox from the customer screen while retaining the API record. All 166 App/i18n checks and lint pass; fixed-project Compose renders at 1440x1100 and 390x844 show the status history and next actions without raw failure/outbox terms or horizontal overflow. Fresh hosted checks and independent review remain required | +| #679 | `135dfe7c` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and maps unknown future claim/status codes to localized `Recorded claim` / `Status unavailable` instead of exposing wire values. Sixty-nine focused UI/i18n checks pass, all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | -| #668 | `1194f44d` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, localizes action/loading guidance, and carries one non-conflicting evidence snapshot. The current head reserves union-free ADR 0243 across its changelog, decision index, product baseline, and Storybook inventory; hosted checks and independent review remain required | +| #668 | `234f975b` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, and carries one non-conflicting evidence snapshot. Project-match provenance and unknown future event codes now map to localized Source record / Supporting record / Recorded evidence labels instead of exposing relational field names. Seventy-four focused project-history/UI/i18n checks pass; hosted checks and independent review remain required | | #667 | `f1e71d59` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches, records hard deletion as an intentional erasure boundary distinct from visibility revocation, and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific retry, saved-evidence, calibration, or administrator actions. Pending-run and no-public-claim guidance is conditional and actionable; the Chat unavailable Storybook scene keeps saved evidence visible and its 1440x900/390x844 renders were inspected. Focused interaction, i18n, backend, container-policy, lint, Storybook-build, and documentation checks pass; exact-head hosted checks and independent review remain required | | #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | From 251640d5f996c2fe3f2567e9842b5050db54d76e Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 05:54:14 +0900 Subject: [PATCH 231/238] fix: keep Ask history pagination stable --- backend/app/main.py | 8 +++---- backend/app/post_ask_history.py | 21 ++++++++++--------- .../adr/0235-post-ask-conversation-history.md | 6 ++++-- frontend/src/ChatPanel.test.tsx | 8 +++---- frontend/src/api.ts | 6 +++--- .../0223_post_ask_conversation_history.sql | 4 ++-- tests/test_post_ask_history.py | 14 ++++++++----- 7 files changed, 37 insertions(+), 30 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index 722cae1db..35c82bb85 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -3222,17 +3222,17 @@ async def chat_about_post( async def read_post_chat_conversations( post_id: str, limit: int = Query(50, ge=1, le=50), - before_updated_at: datetime | None = Query(None), + before_created_at: datetime | None = Query(None), before_conversation_id: UUID | None = Query(None), account: CurrentAccount = Depends(get_current_account), pool: asyncpg.Pool = Depends(get_pool), ) -> dict[str, Any]: """List this account's saved Ask conversations on one visible post.""" await _load_visible_post(post_id, account, pool) - if (before_updated_at is None) != (before_conversation_id is None): + if (before_created_at is None) != (before_conversation_id is None): raise HTTPException( status.HTTP_422_UNPROCESSABLE_CONTENT, - "before_updated_at and before_conversation_id must be provided together", + "before_created_at and before_conversation_id must be provided together", ) async with pool.acquire() as conn: return await list_post_ask_conversations( @@ -3240,7 +3240,7 @@ async def read_post_chat_conversations( account.user_account_id, post_id, limit=limit, - before_updated_at=before_updated_at, + before_created_at=before_created_at, before_conversation_id=before_conversation_id, ) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 5a13b3197..448749a98 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -55,12 +55,12 @@ async def list_conversations( post_id: str, *, limit: int = 50, - before_updated_at: datetime | None = None, + before_created_at: datetime | None = None, before_conversation_id: UUID | None = None, ) -> dict[str, Any]: - """Return this account's conversations on ``post_id``, newest first.""" - if (before_updated_at is None) != (before_conversation_id is None): - raise ValueError("before_updated_at and before_conversation_id must be provided together") + """Return this account's conversations on ``post_id``, newest-created first.""" + if (before_created_at is None) != (before_conversation_id is None): + raise ValueError("before_created_at and before_conversation_id must be provided together") rows = await conn.fetch( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli """ select session.post_ask_session_id, @@ -69,6 +69,7 @@ async def list_conversations( where turn.post_ask_session_id = session.post_ask_session_id order by turn.turn_ordinal limit 1) as conversation_title, + session.created_at, session.updated_at, count(turn.turn_ordinal)::int as turn_count from post_ask_session session @@ -79,16 +80,16 @@ async def list_conversations( and ( $3 is null or $4 is null - or session.updated_at < $3 - or (session.updated_at = $3 and session.post_ask_session_id < $4) + or session.created_at < $3 + or (session.created_at = $3 and session.post_ask_session_id < $4) ) - group by session.post_ask_session_id, session.updated_at - order by session.updated_at desc, session.post_ask_session_id desc + group by session.post_ask_session_id, session.created_at, session.updated_at + order by session.created_at desc, session.post_ask_session_id desc limit $5 """, user_account_id, post_id, - before_updated_at, + before_created_at, before_conversation_id, limit + 1, ) @@ -97,7 +98,7 @@ async def list_conversations( if len(rows) > limit and page_rows: last = page_rows[-1] next_cursor = { - "updated_at": last["updated_at"], + "created_at": last["created_at"], "conversation_id": str(last["post_ask_session_id"]), } return { diff --git a/docs/adr/0235-post-ask-conversation-history.md b/docs/adr/0235-post-ask-conversation-history.md index eeda9c01b..5c0c5c3ac 100644 --- a/docs/adr/0235-post-ask-conversation-history.md +++ b/docs/adr/0235-post-ask-conversation-history.md @@ -34,9 +34,11 @@ Normalized tables: * `post_ask_turn_citation` / `post_ask_turn_source` — cited and retrieved posts -The composite index `(user_account_id, post_id, updated_at desc)` leads +The composite index `(user_account_id, post_id, created_at desc)` leads with the account so a hot post cannot concentrate list traffic on one -partition key. A turn is written only after a complete answer exists +partition key. Conversation pagination uses that immutable creation key; +`updated_at` remains display metadata but cannot move a row across a cursor +while a reader loads later pages. A turn is written only after a complete answer exists (seeded cache hit or orchestrator object). History reads re-apply current post visibility before returning titles or citations. diff --git a/frontend/src/ChatPanel.test.tsx b/frontend/src/ChatPanel.test.tsx index ade858572..df66106df 100644 --- a/frontend/src/ChatPanel.test.tsx +++ b/frontend/src/ChatPanel.test.tsx @@ -153,7 +153,7 @@ describe("ChatPanel conversation history", () => { conversation_id: "conversation-1", }); } - if (url.includes("before_updated_at=")) { + if (url.includes("before_created_at=")) { return jsonResponse({ conversations: [ { conversation_id: "conversation-1", title: "Saved question", updated_at: "2026-08-26T00:02:00Z", turn_count: 2 }, @@ -165,7 +165,7 @@ describe("ChatPanel conversation history", () => { if (url.endsWith("/chat/conversations")) { return jsonResponse({ conversations: [{ conversation_id: "conversation-1", title: "Saved question", updated_at: "2026-08-26T00:01:00Z", turn_count: 1 }], - next_cursor: { updated_at: "2026-08-26T00:00:00Z", conversation_id: "conversation-2" }, + next_cursor: { created_at: "2026-08-26T00:00:00Z", conversation_id: "conversation-2" }, }); } return jsonResponse({ post_id: "post-1", exchanges: [] }); @@ -192,7 +192,7 @@ describe("ChatPanel conversation history", () => { if (url.endsWith("post-1/chat/conversations")) { return jsonResponse({ conversations: [], - next_cursor: { updated_at: "2026-08-26T00:00:00Z", conversation_id: "conversation-old" }, + next_cursor: { created_at: "2026-08-26T00:00:00Z", conversation_id: "conversation-old" }, }); } if (url.endsWith("post-2/chat/conversations")) { @@ -496,7 +496,7 @@ describe("ChatPanel conversation history", () => { it("offers a next action when another history page cannot be loaded", async () => { vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL) => { const url = input instanceof Request ? input.url : String(input); - if (url.includes("before_updated_at=")) throw new TypeError("network unavailable"); + if (url.includes("before_created_at=")) throw new TypeError("network unavailable"); if (url.endsWith("/chat/conversations")) { return jsonResponse({ conversations: [{ diff --git a/frontend/src/api.ts b/frontend/src/api.ts index f798e2b31..6d978f01d 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -368,7 +368,7 @@ export interface PostAskConversationSummary { export interface PostAskConversationPage { conversations: PostAskConversationSummary[]; - next_cursor?: { updated_at: string; conversation_id: string } | null; + next_cursor?: { created_at: string; conversation_id: string } | null; } export interface PostAskConversation { @@ -1191,10 +1191,10 @@ export function askPostChat( export function fetchPostChatConversations( accessToken: string, postId: string, - cursor?: { updated_at: string; conversation_id: string }, + cursor?: { created_at: string; conversation_id: string }, ): Promise { const query = cursor - ? `?before_updated_at=${encodeURIComponent(cursor.updated_at)}&before_conversation_id=${encodeURIComponent(cursor.conversation_id)}` + ? `?before_created_at=${encodeURIComponent(cursor.created_at)}&before_conversation_id=${encodeURIComponent(cursor.conversation_id)}` : ""; return backendFetch(`/api/posts/${postId}/chat/conversations${query}`, accessToken); } diff --git a/migrations/0223_post_ask_conversation_history.sql b/migrations/0223_post_ask_conversation_history.sql index 3308ca0e0..0d9c00f45 100644 --- a/migrations/0223_post_ask_conversation_history.sql +++ b/migrations/0223_post_ask_conversation_history.sql @@ -11,8 +11,8 @@ create table if not exists post_ask_session ( updated_at timestamptz not null default now() ); -create index if not exists post_ask_session_account_post_idx - on post_ask_session (user_account_id, post_id, updated_at desc); +create index if not exists post_ask_session_account_post_created_idx + on post_ask_session (user_account_id, post_id, created_at desc); create table if not exists post_ask_turn ( post_ask_session_id uuid not null diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py index 75a0a2400..b163eed2d 100644 --- a/tests/test_post_ask_history.py +++ b/tests/test_post_ask_history.py @@ -65,12 +65,14 @@ def test_list_conversations_binds_account_post_and_cursor() -> None: { "post_ask_session_id": UUID("00000000-0000-0000-0000-000000000001"), "conversation_title": "First", - "updated_at": datetime(2026, 1, 2, tzinfo=UTC), + "created_at": datetime(2026, 1, 2, tzinfo=UTC), + "updated_at": datetime(2026, 1, 5, tzinfo=UTC), "turn_count": 1, }, { "post_ask_session_id": UUID("00000000-0000-0000-0000-000000000002"), "conversation_title": "Second", + "created_at": datetime(2026, 1, 1, tzinfo=UTC), "updated_at": datetime(2026, 1, 1, tzinfo=UTC), "turn_count": 2, }, @@ -84,7 +86,7 @@ def test_list_conversations_binds_account_post_and_cursor() -> None: "account-1", "post-1", limit=1, - before_updated_at=cursor_time, + before_created_at=cursor_time, before_conversation_id=UUID("00000000-0000-0000-0000-000000000003"), ) ) @@ -92,6 +94,7 @@ def test_list_conversations_binds_account_post_and_cursor() -> None: query, arguments = connection.calls[0] assert "{cursor_clause}" not in query assert "post_ask_session" in query + assert "order by session.created_at desc" in query assert arguments == ( "account-1", "post-1", @@ -101,18 +104,19 @@ def test_list_conversations_binds_account_post_and_cursor() -> None: ) assert len(result["conversations"]) == 1 assert result["next_cursor"] is not None + assert result["next_cursor"]["created_at"] == datetime(2026, 1, 2, tzinfo=UTC) assert result["conversations"][0]["conversation_id"] == "00000000-0000-0000-0000-000000000001" @pytest.mark.parametrize( - ("before_updated_at", "before_conversation_id"), + ("before_created_at", "before_conversation_id"), [ (datetime(2026, 1, 3, tzinfo=UTC), None), (None, UUID("00000000-0000-0000-0000-000000000003")), ], ) def test_list_conversations_rejects_a_partial_cursor( - before_updated_at: datetime | None, + before_created_at: datetime | None, before_conversation_id: UUID | None, ) -> None: """Direct callers cannot silently turn a partial cursor into page one.""" @@ -124,7 +128,7 @@ def test_list_conversations_rejects_a_partial_cursor( connection, "account-1", "post-1", - before_updated_at=before_updated_at, + before_created_at=before_created_at, before_conversation_id=before_conversation_id, ) ) From 3606e7e0b1b96ef7c32a6658dc41fc8f66b4d2c5 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 06:13:32 +0900 Subject: [PATCH 232/238] docs: refresh exact-head product gap evidence --- docs/product-technical-gap-baseline.md | 38 ++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e321d5543..797ba0718 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 37 open PRs and 10 open issues. The exact-head +At this snapshot there were 41 open PRs and 11 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 05:42 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 06:13 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, @@ -78,44 +78,48 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 37 open PRs (22 targeting `main`, -15 stacked on non-default parents) and 10 +at this refresh. The live queue contains 41 open PRs (22 targeting `main`, +19 stacked on non-default parents) and 11 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 | | ---: | --- | --- | -| #735 | `c0f31f11` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. Thirty-two focused/live-PostgreSQL checks and a full-artifact replay report 94,640 observations across 910 occupations and 52 elements plus all 33 scale rows; only aggregate counts enter this repository. Review threads are empty and exact-head hosted checks remain in progress | -| #734 | `549a7e1e` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. Twenty-four migration/rerun/schema checks pass; the two PostgreSQL/ADR information threads were evidence-replied and resolved, and exact-head hosted checks remain in progress, so this is not accepted measurement or protected delivery | -| #733 | `8a4b0d96` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels now agree, construct focus fails closed instead of exposing a raw UUID, and the intro gives a scoped next action. Focused ontology/frontend checks and lint pass, prior desktop/mobile renders were inspected, all review threads are resolved, and exact-head hosted checks remain in progress | -| #732 | `3e30402d` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. Forty focused linkage/publication/hygiene checks pass, the official artifact digest matches its pin, all review threads are resolved, and all observed exact-head hosted checks pass; independent review remains required | -| #731 | `9654bb8b` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; ADR 0255 explicitly supersedes only ADR 0248's prohibition on complete pinned O*NET vocabulary publication and preserves the evidence/no-equivalence boundaries. Canonical graph publication is verified by RDF isomorphism and per-source manifest digests; all review threads and observed exact-head checks pass, while independent review and parent delivery remain required | +| #743 | `bfdff9a5` | stacked on exact #740 and catalogs only imported occupation-rating artifacts that contain observations, preserving release, publisher, license, URL, digest, and declared row-count provenance while excluding the scale support artifact. The native selector replaces internal release/source entry; pagination remains bound to the loaded profile and non-HTTP artifact values render a provenance-verification action instead of an unsafe link. The latest head normally reconciles concurrent source-catalog work; twelve focused frontend checks, lint, and six backend projection/catalog checks pass, while fresh hosted checks and independent review remain required | +| #742 | `e21b25f0` | sibling to #739 on exact operations parent `0a8bd0b6`; it persists request-scoped normalized product mentions and closed-code relations atomically, re-applies eligibility and ABAC on reads, projects OWL/SHACL assertions, and keeps provider-backed production fail-closed. The latest repair includes predicate and product identity in each RDF assertion IRI so distinct supported relations cannot collapse into one reification. Sixty-two post-rebase focused ontology/product/worker checks pass and review threads are empty; hosted checks and independent review remain required | +| #740 | `b24e8fa3` | stacked on the current occupation-rating read branch and adds an authenticated Dashboard evidence view without changing the governed GNB. It preserves exact values, bounds, sample/error/interval evidence, dates, suppression/not-relevant warnings, and provenance while distinguishing unavailable source from an imported empty profile. Pagination is fenced to the loaded occupation/release/source, stale or superseded evidence clears on a new request, and artifact links are HTTP(S)-only with an actionable fallback. Focused frontend and backend projection/catalog checks plus lint pass; review threads are empty, while fresh hosted checks and independent review remain required | +| #739 | `73848b2e` | sibling to #742 on exact operations parent `0a8bd0b6`; it replaces a corpus-wide priority sort with exact two-tier admission while retaining ordered pages and `SKIP LOCKED`. The latest repair prevents a priority row that changes tier under READ COMMITTED from reappearing in the remaining-tier page, and ADR 0206 records the snapshot/de-duplication contract. Forty-three focused queue, EXPLAIN, and SQL-contract checks pass; aggregate synthetic plan evidence is explicitly not a capacity or latency SLO, review threads are empty, and hosted checks plus independent review remain required | +| #735 | `e2042093` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. The latest importer rejects short and extra-field CSV rows with exact line evidence; normally merged #738 adds an authenticated bounded read projection whose merge tree exactly matched its audited head. Parent hosted checks restarted after that merge, and independent review plus parent delivery remain required | +| #734 | `4c3677af` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. The latest head is an ancestry-only restack carrying #724's publication-label repair; review threads are empty and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | +| #733 | `b53c1edd` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels agree, construct focus fails closed instead of exposing a raw UUID, and disabled construct analysis no longer misreports another channel's durable job as construct processing. Fifty-three backend and twenty-one frontend focused checks plus lint pass, review threads are empty, and the exact-head full suite remains in progress | +| #732 | `7f60aa8e` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. The latest head is an ancestry-only restack carrying #724's publication-label repair; focused publication evidence, review threads, and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | +| #731 | `b3b9b360` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; ADR 0255 explicitly supersedes only ADR 0248's prohibition on complete pinned O*NET vocabulary publication and preserves the evidence/no-equivalence boundaries. The latest head is an ancestry-only restack carrying #724's publication-label repair; canonical graph publication, review threads, and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | | #728 | `e52a8272` | now stacks on exact #640 instead of extending protected-main NumPy arithmetic. It pins fast-mlsirm PR #1457 exact `5c7dc9ea` and consumes the owner-produced Rust/PyO3 explained-share field while retaining LineageWeave validation, persistence projection, API, and presentation only. The audit also moved the schema change to union-free migration 0236 and made the production-equivalent bootstrap execute it. Upstream Rust tests pass; LineageWeave backend/schema/frontend focused checks pass; both review queues have zero unresolved threads. The upstream PR remains draft with hosted gates in progress and the LineageWeave parent remains non-default, so neither is protected delivery | -| #726 | `d4e78034` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. Attempt-fenced lease refresh prevents concurrent long extraction, a later-enabled analysis service wakes succeeded current-digest rows that lack construct evidence, and the API/UI distinguishes setup required from retryable failure without leaking implementation boundaries. Focused backend/frontend/docs checks and lint pass, all threads are resolved, and exact-head hosted checks remain in progress | -| #724 | `fdec8f65` | targets the occupational-taxonomy stack and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. The served Turtle is now a canonical parsed graph rather than source-document concatenation, is proved isomorphic with the governed source graph, and the manifest lists and hashes every source file instead of naming one misleading source. Thirty publication checks pass, all threads are resolved, and fresh hosted checks remain queued pending parent delivery | +| #726 | `d6a12fbb` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. Attempt-fenced lease refresh prevents concurrent long extraction, a later-enabled analysis service wakes succeeded current-digest rows that lack construct evidence, and disabled construct analysis no longer exposes another channel's queued/running job as construct processing. Twenty-three focused checks pass with one live integration skip, review threads are empty, and all observed exact-head hosted checks pass; independent review and parent delivery remain required | +| #724 | `1d2f8052` | targets the occupational-taxonomy stack and publishes the complete official 2018 SOC hierarchy from pinned, digest-verified source artifacts. Source-column hierarchy becomes `skos:broader` without title/code inference, and no occupation-to-person trait, employer job-family mapping, crosswalk, score, or weight is invented. The served Turtle is a deterministic generated equivalent of the governed source graph, not mislabeled as the authoritative source, and RDF isomorphism plus the source manifest prove that boundary. The focused publication regression, review threads, and all observed exact-head hosted checks pass; independent review and parent delivery remain required | | #723 | `316fc190` | stacked on exact #721 and synchronizes the official O*NET 31.0 construct catalog under ADR 0250 without importing ratings, scores, crosswalks, affect labels, or person traits. The official 485,151-byte, 3,006-row source artifact is pinned by canonical SHA-256 before a database transaction; the governed scope admits 2,529 constructs, rejects changed or whitespace-mutated labels, and keeps absent descriptions as `NULL`. Synthetic fixtures inject their own declared digest rather than weakening the production pin. Focused checks and the official digest/count replay pass; all threads are resolved and hosted checks remain in progress pending parent delivery | | #721 | `9214c50f` | stacked occupational-construct persistence candidate. The current head synchronizes its parent and removes the duplicate construct-detail field; lint and production build pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #720 | `dda0531d` | cancels stale test runs after PR closure. A normal failed-job rerun reached terminal attempt 2 and again failed closed only after NVIDIA primary `429`, retired NVIDIA fallback `410`, and direct OpenAI `insufficient_quota`; this is current provider-infrastructure evidence, not a code finding or a passing scan. Normal auto-merge is enabled, but authoritative Strix evidence and independent review remain required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `9db158c4` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. Twenty-six focused backend and sixty-nine frontend/i18n tests plus lint/build pass; desktop/mobile rejected-evidence scenes were inspected, all threads are resolved, and fresh hosted checks remain in progress | -| #716 | `c01de078` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. The worker health probe is lightweight, POSIX-compatible, and accepts a valid newline-free heartbeat; the k6 summary contract reads the actual flat export fields instead of silently accepting missing metrics. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 is still absent, so that one performance thread honestly remains unresolved; auto-merge remains disabled pending parent delivery and that evidence | +| #717 | `3e18e7cd` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest head refreshes snapshot-relative evidence after the parent movement; focused backend and frontend/i18n tests plus lint/build pass, while hosted checks and independent review remain required | +| #716 | `0a8bd0b6` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. The current head normally merges the completed Voice taxonomy child while preserving the worker-health and k6 contracts. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 remains absent, so performance acceptance and protected parent delivery remain incomplete | | #714 | `76a602c8` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. Private posts now return no persisted citations after a visibility change. Text and image-region lead streams preserve source order and alternate without weights, so text volume cannot starve image evidence when the bounded budget admits both. Twenty-five focused checks pass, both new review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #713 | `850494c3` | proposes the ADR 0246 twelve-code atomic stakeholder Voice-of-X post taxonomy while preserving ADR 0251's separate extensible combination model and the independently governed organization-relationship vocabulary. The audit moved all twelve labels into the parent so Korean, Chinese, Japanese, and Vietnamese filters do not fall back to English immediately after this PR lands. Sixty-eight i18n and 24 ontology checks plus production build pass; a 1280x720 Korean filter render was inspected, all threads are resolved, auto-merge is enabled, and fresh hosted checks plus independent review remain required | | #711 | `05e5f520` | stacked on the current #640 head rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. It now includes the normally merged worker-memory evidence stack. Its canonical upstream runtime-evidence thread stays unresolved and auto-merge remains disabled pending protected upstream delivery and exact-image proof | -| #710 | `2f6b7ae7` | records the worker-function delivery gap against #709 without duplicating #702's corpus audit. Exact-head hosted checks and independent review remain required | +| #710 | `27a917ee` | records the worker-function delivery gap against #709 without duplicating #702's corpus audit; the latest documentation repair makes all referenced heads explicitly snapshot-relative. Exact-head hosted checks and independent review remain required | | #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | | #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | -| #702 | `eda7083b` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact, replayed fast-mlsirm Rust sampling-design artifact. The current 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The full 43,814-row replay records zero nonblank bodies and separates fourteen deployed PROV-O tables from the still-missing linkage of 3,190 evidence edges; a missing PROV support profile now fails closed instead of producing an environment-dependent term set. Twenty-nine focused audit/docstring/hygiene checks pass, all threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #702 | `9d171004` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact replayed fast-mlsirm Rust design artifact. For the 43,814-record eligible frame, the predeclared SRSWOR design yields `n=381` at 95% confidence, error bound 0.05, and `p=0.5`; the earlier 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The latest repair drains spawned-process results under a wall-clock timeout before join, preventing large valid provider responses from deadlocking; 123 focused checks pass, all review threads are resolved, auto-merge is enabled, and upstream Rust delivery, hosted checks, plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `b05e3100` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The latest repair replaces search-configuration text with saved-evidence/retry guidance in five locales, suppresses raw failure codes, and removes the persistence-delivery outbox from the customer screen while retaining the API record. All 166 App/i18n checks and lint pass; fixed-project Compose renders at 1440x1100 and 390x844 show the status history and next actions without raw failure/outbox terms or horizontal overflow. Fresh hosted checks and independent review remain required | | #679 | `135dfe7c` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and maps unknown future claim/status codes to localized `Recorded claim` / `Status unavailable` instead of exposing wire values. Sixty-nine focused UI/i18n checks pass, all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `234f975b` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, and carries one non-conflicting evidence snapshot. Project-match provenance and unknown future event codes now map to localized Source record / Supporting record / Recorded evidence labels instead of exposing relational field names. Seventy-four focused project-history/UI/i18n checks pass; hosted checks and independent review remain required | -| #667 | `f1e71d59` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; enforces both-or-neither cursor validation; applies the shared source-eligibility boundary; includes ADR 0237's accelerator boundary; and uses the shared workflow contract to run Tests on product-affecting documentation. It also retains one retry key per failed measurement run across run switches, records hard deletion as an intentional erasure boundary distinct from visibility revocation, and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific retry, saved-evidence, calibration, or administrator actions. Pending-run and no-public-claim guidance is conditional and actionable; the Chat unavailable Storybook scene keeps saved evidence visible and its 1440x900/390x844 renders were inspected. Focused interaction, i18n, backend, container-policy, lint, Storybook-build, and documentation checks pass; exact-head hosted checks and independent review remain required | -| #658 | `15d670f0` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, aligns blank/live and cutoff-error guidance across five locales, and includes `verify_external` in the request contract. The current head restores the exact documented missing-cover contract and removes a cited-post badge branch that the source-eligibility API can never reach, so the screen does not imply unavailable historical evidence. The focused frontend test and lint pass locally; review threads are resolved, while exact-head hosted checks and independent review remain required | +| #667 | `251640d5` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. The latest repair pages saved conversations on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; `updated_at` remains display metadata. Backend 44 checks and ChatPanel 12 checks plus lint pass, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #658 | `5f3bc384` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, and keeps database-clock cutoff validation and evidence authorization intact. The latest repair replaces transport-oriented cutoff wording and raw RFC3339 output with a five-locale, device-time action and local display formatting; the Storybook interaction follows the same contract. Sixty-seven focused frontend/i18n checks and lint pass, review threads are empty, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `8767de1b` | accessible status notices; hosted checks and independent review remain required | From 24644d74962a7b99fe257f3915f3c55510fd8455 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 06:17:33 +0900 Subject: [PATCH 233/238] docs: record repaired ontology stack check --- docs/product-technical-gap-baseline.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 797ba0718..7d9d916bd 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 06:13 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 06:16 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, @@ -92,7 +92,7 @@ context only. | #739 | `73848b2e` | sibling to #742 on exact operations parent `0a8bd0b6`; it replaces a corpus-wide priority sort with exact two-tier admission while retaining ordered pages and `SKIP LOCKED`. The latest repair prevents a priority row that changes tier under READ COMMITTED from reappearing in the remaining-tier page, and ADR 0206 records the snapshot/de-duplication contract. Forty-three focused queue, EXPLAIN, and SQL-contract checks pass; aggregate synthetic plan evidence is explicitly not a capacity or latency SLO, review threads are empty, and hosted checks plus independent review remain required | | #735 | `e2042093` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. The latest importer rejects short and extra-field CSV rows with exact line evidence; normally merged #738 adds an authenticated bounded read projection whose merge tree exactly matched its audited head. Parent hosted checks restarted after that merge, and independent review plus parent delivery remain required | | #734 | `4c3677af` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. The latest head is an ancestry-only restack carrying #724's publication-label repair; review threads are empty and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | -| #733 | `b53c1edd` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels agree, construct focus fails closed instead of exposing a raw UUID, and disabled construct analysis no longer misreports another channel's durable job as construct processing. Fifty-three backend and twenty-one frontend focused checks plus lint pass, review threads are empty, and the exact-head full suite remains in progress | +| #733 | `17c554a9` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels agree, construct focus fails closed instead of exposing a raw UUID, and disabled construct analysis no longer misreports another channel's durable job as construct processing. The latest repair replaces an unrelated global vocabulary-count assertion with a direct proof that every worker-function IRI lacks `lookupCode`; forty-five focused ontology checks pass, review threads are empty, and hosted checks restarted | | #732 | `7f60aa8e` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. The latest head is an ancestry-only restack carrying #724's publication-label repair; focused publication evidence, review threads, and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | | #731 | `b3b9b360` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; ADR 0255 explicitly supersedes only ADR 0248's prohibition on complete pinned O*NET vocabulary publication and preserves the evidence/no-equivalence boundaries. The latest head is an ancestry-only restack carrying #724's publication-label repair; canonical graph publication, review threads, and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | | #728 | `e52a8272` | now stacks on exact #640 instead of extending protected-main NumPy arithmetic. It pins fast-mlsirm PR #1457 exact `5c7dc9ea` and consumes the owner-produced Rust/PyO3 explained-share field while retaining LineageWeave validation, persistence projection, API, and presentation only. The audit also moved the schema change to union-free migration 0236 and made the production-equivalent bootstrap execute it. Upstream Rust tests pass; LineageWeave backend/schema/frontend focused checks pass; both review queues have zero unresolved threads. The upstream PR remains draft with hosted gates in progress and the LineageWeave parent remains non-default, so neither is protected delivery | @@ -118,7 +118,7 @@ context only. | #679 | `135dfe7c` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and maps unknown future claim/status codes to localized `Recorded claim` / `Status unavailable` instead of exposing wire values. Sixty-nine focused UI/i18n checks pass, all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `234f975b` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, and carries one non-conflicting evidence snapshot. Project-match provenance and unknown future event codes now map to localized Source record / Supporting record / Recorded evidence labels instead of exposing relational field names. Seventy-four focused project-history/UI/i18n checks pass; hosted checks and independent review remain required | -| #667 | `251640d5` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. The latest repair pages saved conversations on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; `updated_at` remains display metadata. Backend 44 checks and ChatPanel 12 checks plus lint pass, all review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #667 | `3606e7e0` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also carries the 06:13 exact-head queue refresh. Backend 44 checks and ChatPanel 12 checks plus lint pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | | #658 | `5f3bc384` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, and keeps database-clock cutoff validation and evidence authorization intact. The latest repair replaces transport-oriented cutoff wording and raw RFC3339 output with a five-locale, device-time action and local display formatting; the Storybook interaction follows the same contract. Sixty-seven focused frontend/i18n checks and lint pass, review threads are empty, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | From e3f8a8953514787054649cb9146cea89fa6ee64d Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 06:27:53 +0900 Subject: [PATCH 234/238] docs: track current semantic evidence queue --- docs/product-technical-gap-baseline.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 7d9d916bd..271aaf17b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 41 open PRs and 11 open issues. The exact-head +At this snapshot there were 42 open PRs and 11 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 06:16 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 06:27 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, @@ -78,18 +78,19 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 41 open PRs (22 targeting `main`, -19 stacked on non-default parents) and 11 +at this refresh. The live queue contains 42 open PRs (22 targeting `main`, +20 stacked on non-default parents) and 11 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 | | ---: | --- | --- | -| #743 | `bfdff9a5` | stacked on exact #740 and catalogs only imported occupation-rating artifacts that contain observations, preserving release, publisher, license, URL, digest, and declared row-count provenance while excluding the scale support artifact. The native selector replaces internal release/source entry; pagination remains bound to the loaded profile and non-HTTP artifact values render a provenance-verification action instead of an unsafe link. The latest head normally reconciles concurrent source-catalog work; twelve focused frontend checks, lint, and six backend projection/catalog checks pass, while fresh hosted checks and independent review remain required | +| #745 | `c8a702ec` | stacked on exact #744 and keeps the occupation identity control as a native catalog select while adding case-insensitive published-title or retained-code substring filtering. It has no ranking or typed SOC fallback, fails closed on no match, resets when source scope reloads, and keeps profile pagination bound to the opened identity. Seven documentation/docstring and sixteen focused frontend/API checks plus lint/build/Storybook pass; exact ancestry, rendered accessibility, review threads, hosted checks, and independent review remain under current-head audit | +| #744 | `f19a663b` | stacked on exact #743 and catalogs occupations that actually have observations in one imported rating source. It preserves published title and O*NET-SOC code, orders by title then code, distinguishes unavailable source from an empty catalog, resets selection when source scope changes, and derives no ranking, recommendation, or local score. Sixteen backend and fourteen frontend focused checks plus lint/build/Storybook pass; the PostgreSQL importer integration was not available in the originating sandbox, so live schema evidence, hosted checks, review threads, and independent review still require exact-head verification | +| #743 | `a18e89f7` | stacked on exact #740 and catalogs only imported occupation-rating artifacts that contain observations, preserving release, publisher, license, URL, digest, and declared row-count provenance while excluding the scale support artifact. The native selector replaces internal release/source entry; pagination remains bound to the loaded profile and non-HTTP artifact values render a provenance-verification action instead of an unsafe link. The latest head normally reconciles concurrent evidence-view work; focused frontend/backend checks and lint pass, while fresh hosted checks and independent review remain required | | #742 | `e21b25f0` | sibling to #739 on exact operations parent `0a8bd0b6`; it persists request-scoped normalized product mentions and closed-code relations atomically, re-applies eligibility and ABAC on reads, projects OWL/SHACL assertions, and keeps provider-backed production fail-closed. The latest repair includes predicate and product identity in each RDF assertion IRI so distinct supported relations cannot collapse into one reification. Sixty-two post-rebase focused ontology/product/worker checks pass and review threads are empty; hosted checks and independent review remain required | | #740 | `b24e8fa3` | stacked on the current occupation-rating read branch and adds an authenticated Dashboard evidence view without changing the governed GNB. It preserves exact values, bounds, sample/error/interval evidence, dates, suppression/not-relevant warnings, and provenance while distinguishing unavailable source from an imported empty profile. Pagination is fenced to the loaded occupation/release/source, stale or superseded evidence clears on a new request, and artifact links are HTTP(S)-only with an actionable fallback. Focused frontend and backend projection/catalog checks plus lint pass; review threads are empty, while fresh hosted checks and independent review remain required | -| #739 | `73848b2e` | sibling to #742 on exact operations parent `0a8bd0b6`; it replaces a corpus-wide priority sort with exact two-tier admission while retaining ordered pages and `SKIP LOCKED`. The latest repair prevents a priority row that changes tier under READ COMMITTED from reappearing in the remaining-tier page, and ADR 0206 records the snapshot/de-duplication contract. Forty-three focused queue, EXPLAIN, and SQL-contract checks pass; aggregate synthetic plan evidence is explicitly not a capacity or latency SLO, review threads are empty, and hosted checks plus independent review remain required | | #735 | `e2042093` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. The latest importer rejects short and extra-field CSV rows with exact line evidence; normally merged #738 adds an authenticated bounded read projection whose merge tree exactly matched its audited head. Parent hosted checks restarted after that merge, and independent review plus parent delivery remain required | | #734 | `4c3677af` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. The latest head is an ancestry-only restack carrying #724's publication-label repair; review threads are empty and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | | #733 | `17c554a9` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels agree, construct focus fails closed instead of exposing a raw UUID, and disabled construct analysis no longer misreports another channel's durable job as construct processing. The latest repair replaces an unrelated global vocabulary-count assertion with a direct proof that every worker-function IRI lacks `lookupCode`; forty-five focused ontology checks pass, review threads are empty, and hosted checks restarted | @@ -103,24 +104,24 @@ context only. | #720 | `dda0531d` | cancels stale test runs after PR closure. A normal failed-job rerun reached terminal attempt 2 and again failed closed only after NVIDIA primary `429`, retired NVIDIA fallback `410`, and direct OpenAI `insufficient_quota`; this is current provider-infrastructure evidence, not a code finding or a passing scan. Normal auto-merge is enabled, but authoritative Strix evidence and independent review remain required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `3e18e7cd` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest head refreshes snapshot-relative evidence after the parent movement; focused backend and frontend/i18n tests plus lint/build pass, while hosted checks and independent review remain required | -| #716 | `0a8bd0b6` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. The current head normally merges the completed Voice taxonomy child while preserving the worker-health and k6 contracts. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 remains absent, so performance acceptance and protected parent delivery remain incomplete | +| #717 | `ebb4ef1d` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest head records the paged Voice JSON-LD evidence repair in snapshot documentation; focused backend and frontend/i18n tests plus lint/build pass, while hosted checks and independent review remain required | +| #716 | `e1e5d9d3` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. PR #739 merged normally into this parent with the READ COMMITTED two-tier de-duplication repair and scoped aggregate EXPLAIN evidence. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 remains absent, so production performance acceptance and protected parent delivery remain incomplete | | #714 | `76a602c8` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. Private posts now return no persisted citations after a visibility change. Text and image-region lead streams preserve source order and alternate without weights, so text volume cannot starve image evidence when the bounded budget admits both. Twenty-five focused checks pass, both new review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #713 | `850494c3` | proposes the ADR 0246 twelve-code atomic stakeholder Voice-of-X post taxonomy while preserving ADR 0251's separate extensible combination model and the independently governed organization-relationship vocabulary. The audit moved all twelve labels into the parent so Korean, Chinese, Japanese, and Vietnamese filters do not fall back to English immediately after this PR lands. Sixty-eight i18n and 24 ontology checks plus production build pass; a 1280x720 Korean filter render was inspected, all threads are resolved, auto-merge is enabled, and fresh hosted checks plus independent review remain required | | #711 | `05e5f520` | stacked on the current #640 head rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. It now includes the normally merged worker-memory evidence stack. Its canonical upstream runtime-evidence thread stays unresolved and auto-merge remains disabled pending protected upstream delivery and exact-image proof | | #710 | `27a917ee` | records the worker-function delivery gap against #709 without duplicating #702's corpus audit; the latest documentation repair makes all referenced heads explicitly snapshot-relative. Exact-head hosted checks and independent review remain required | | #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | | #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | -| #702 | `9d171004` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact replayed fast-mlsirm Rust design artifact. For the 43,814-record eligible frame, the predeclared SRSWOR design yields `n=381` at 95% confidence, error bound 0.05, and `p=0.5`; the earlier 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The latest repair drains spawned-process results under a wall-clock timeout before join, preventing large valid provider responses from deadlocking; 123 focused checks pass, all review threads are resolved, auto-merge is enabled, and upstream Rust delivery, hosted checks, plus independent review remain required | +| #702 | `92294223` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact replayed fast-mlsirm Rust design artifact. For the 43,814-record eligible frame, the predeclared SRSWOR design yields `n=381` at 95% confidence, error bound 0.05, and `p=0.5`; the earlier 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The current head drains spawned-process results before join and correlates provider trace with attempt provenance; focused checks pass, review threads are resolved, auto-merge is enabled, and upstream Rust delivery, hosted checks, plus independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `b05e3100` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The latest repair replaces search-configuration text with saved-evidence/retry guidance in five locales, suppresses raw failure codes, and removes the persistence-delivery outbox from the customer screen while retaining the API record. All 166 App/i18n checks and lint pass; fixed-project Compose renders at 1440x1100 and 390x844 show the status history and next actions without raw failure/outbox terms or horizontal overflow. Fresh hosted checks and independent review remain required | | #679 | `135dfe7c` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and maps unknown future claim/status codes to localized `Recorded claim` / `Status unavailable` instead of exposing wire values. Sixty-nine focused UI/i18n checks pass, all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `234f975b` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, and carries one non-conflicting evidence snapshot. Project-match provenance and unknown future event codes now map to localized Source record / Supporting record / Recorded evidence labels instead of exposing relational field names. Seventy-four focused project-history/UI/i18n checks pass; hosted checks and independent review remain required | -| #667 | `3606e7e0` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also carries the 06:13 exact-head queue refresh. Backend 44 checks and ChatPanel 12 checks plus lint pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | +| #667 | `24644d74` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also carries the repaired Ontology stack check evidence. Backend 44 checks and ChatPanel 12 checks plus lint pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | | #658 | `5f3bc384` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, and keeps database-clock cutoff validation and evidence authorization intact. The latest repair replaces transport-oriented cutoff wording and raw RFC3339 output with a five-locale, device-time action and local display formatting; the Storybook interaction follows the same contract. Sixty-seven focused frontend/i18n checks and lint pass, review threads are empty, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | -| #657 | `9f71681c` | TEPP lifecycle persistence and fail-closed topic acceptance; BLOCKED with hosted checks queued and review required | +| #657 | `355a5796` | persists strict TEPP accepted receipts without treating acceptance as measurement, resumes a stored remote run through the pluggable status port, validates and persists the terminal DTO before Succeeded, and keeps all arithmetic in TEPP. The latest UI repair removes TEPP, provider, remote-run identifier, and reconciliation internals from the customer surface; the accepted state now asks the user to refresh for result readiness. Sixty-nine backend/schema checks, five focused frontend checks, lint, and Storybook build pass; the 1440×720 accepted-state render was inspected, all review threads are resolved, auto-merge is enabled, and hosted checks plus independent review remain required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | | #643 | `8767de1b` | accessible status notices; hosted checks and independent review remain required | | #640 | `ebfe60af` | dashboard ranking and topic-influence stack preserves Ask service imports, authorization, ontology parity, transactional schema fixtures, the durable worker, bounded structured validation, and atomic voice-backfill completion. PRs #727, #730, and #725 merged normally into this non-default parent: public failures no longer expose provider, environment-variable, timeout, or evidence-assembly boundaries and instead give a retry/administrator action; empty verification gives a specific-claim/time-range retry; worker memory evidence remains aggregate and non-identifying. Focused backend/i18n/rendered tests, lint/build/Storybook, and desktop/mobile inspection pass. Exact-head hosted checks and independent review remain required before protected delivery | From ea17b17d677194491f47c04fae973ab9c026a4ff Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 06:55:38 +0900 Subject: [PATCH 235/238] docs: reconcile live semantic delivery stack --- docs/product-technical-gap-baseline.md | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 271aaf17b..8fc4d9689 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -68,7 +68,7 @@ are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 06:27 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 06:51 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, @@ -78,19 +78,20 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 42 open PRs (22 targeting `main`, -20 stacked on non-default parents) and 11 +at this refresh. The live queue contains 42 open PRs (21 targeting `main`, +21 stacked on non-default parents) and 11 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 | | ---: | --- | --- | -| #745 | `c8a702ec` | stacked on exact #744 and keeps the occupation identity control as a native catalog select while adding case-insensitive published-title or retained-code substring filtering. It has no ranking or typed SOC fallback, fails closed on no match, resets when source scope reloads, and keeps profile pagination bound to the opened identity. Seven documentation/docstring and sixteen focused frontend/API checks plus lint/build/Storybook pass; exact ancestry, rendered accessibility, review threads, hosted checks, and independent review remain under current-head audit | -| #744 | `f19a663b` | stacked on exact #743 and catalogs occupations that actually have observations in one imported rating source. It preserves published title and O*NET-SOC code, orders by title then code, distinguishes unavailable source from an empty catalog, resets selection when source scope changes, and derives no ranking, recommendation, or local score. Sixteen backend and fourteen frontend focused checks plus lint/build/Storybook pass; the PostgreSQL importer integration was not available in the originating sandbox, so live schema evidence, hosted checks, review threads, and independent review still require exact-head verification | -| #743 | `a18e89f7` | stacked on exact #740 and catalogs only imported occupation-rating artifacts that contain observations, preserving release, publisher, license, URL, digest, and declared row-count provenance while excluding the scale support artifact. The native selector replaces internal release/source entry; pagination remains bound to the loaded profile and non-HTTP artifact values render a provenance-verification action instead of an unsafe link. The latest head normally reconciles concurrent evidence-view work; focused frontend/backend checks and lint pass, while fresh hosted checks and independent review remain required | -| #742 | `e21b25f0` | sibling to #739 on exact operations parent `0a8bd0b6`; it persists request-scoped normalized product mentions and closed-code relations atomically, re-applies eligibility and ABAC on reads, projects OWL/SHACL assertions, and keeps provider-backed production fail-closed. The latest repair includes predicate and product identity in each RDF assertion IRI so distinct supported relations cannot collapse into one reification. Sixty-two post-rebase focused ontology/product/worker checks pass and review threads are empty; hosted checks and independent review remain required | -| #740 | `b24e8fa3` | stacked on the current occupation-rating read branch and adds an authenticated Dashboard evidence view without changing the governed GNB. It preserves exact values, bounds, sample/error/interval evidence, dates, suppression/not-relevant warnings, and provenance while distinguishing unavailable source from an imported empty profile. Pagination is fenced to the loaded occupation/release/source, stale or superseded evidence clears on a new request, and artifact links are HTTP(S)-only with an actionable fallback. Focused frontend and backend projection/catalog checks plus lint pass; review threads are empty, while fresh hosted checks and independent review remain required | +| #747 | `effbbc3f` | stacked on exact #716 and adds linked user, operations, and MCP manuals for the current product contract instead of duplicating behavior across README and ADRs. The manuals cover Dashboard/Voice/Ask evidence actions, owner-scoped asynchronous MCP reads, OAuth/session/quota recovery, canonical Compose and database observation while excluding provider models, secrets, runtime identifiers, and real records. Thirty-four exact-head manual/schema/docstring checks and diff hygiene pass; API/ADR truth, review threads, hosted checks, and independent review remain under current-head audit | +| #746 | `4983b291` | replaces closed-unmerged #744 and exposes authenticated occupations represented in one imported rating source. It preserves the complete persisted rating and source/scale provenance domain, uses the observed title/code catalog and native selection without ranking or typed fallback, fences authentication/source/occupation/late responses, distinguishes unavailable catalog from an imported empty result, and aligns empty-evidence guidance with the selector's next action. Hosted checks and independent review remain required | +| #745 | `8aa97347` | stacked on exact #746 and adds only case-insensitive published-title or retained-code substring filtering over the native catalog, without ranking or typed SOC fallback. The current normal-merge ancestry preserves #746's request, authentication, source, occupation, loading, unavailable-catalog, and empty-guidance fences; invalid selection clears and requires a visible catalog choice. Review threads are resolved, while hosted checks and independent review remain required | +| #743 | `d23e1deb` | stacked on exact #740 and catalogs only imported occupation-rating artifacts that contain observations, preserving release, publisher, license, URL, digest, and declared row-count provenance while excluding the scale support artifact. The latest head normally reconciles the advanced evidence-view parent while retaining authentication and late-response fencing; hosted checks and independent review remain required | +| #742 | `72782870` | stacked on the latest operations candidate and persists request-scoped normalized product mentions and closed-code relations atomically, re-applies eligibility and ABAC on reads, projects OWL/SHACL assertions, and keeps provider-backed production fail-closed. The latest repair authorizes product-relation target evidence while retaining predicate/product assertion identity; hosted checks and independent review remain required | +| #740 | `e6efa6fe` | stacked on the current occupation-rating read branch and adds an authenticated Dashboard evidence view without changing the governed GNB. It preserves exact values, bounds, sample/error/interval evidence, dates, suppression/not-relevant warnings, and provenance while distinguishing unavailable source from an imported empty profile. The latest repair hides stale occupation pagination as soon as a new request supersedes it, keeps artifact links HTTP(S)-only, and retains the actionable fallback; focused checks pass, while hosted checks and independent review remain required | | #735 | `e2042093` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. The latest importer rejects short and extra-field CSV rows with exact line evidence; normally merged #738 adds an authenticated bounded read projection whose merge tree exactly matched its audited head. Parent hosted checks restarted after that merge, and independent review plus parent delivery remain required | | #734 | `4c3677af` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. The latest head is an ancestry-only restack carrying #724's publication-label repair; review threads are empty and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | | #733 | `17c554a9` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels agree, construct focus fails closed instead of exposing a raw UUID, and disabled construct analysis no longer misreports another channel's durable job as construct processing. The latest repair replaces an unrelated global vocabulary-count assertion with a direct proof that every worker-function IRI lacks `lookupCode`; forty-five focused ontology checks pass, review threads are empty, and hosted checks restarted | @@ -104,22 +105,21 @@ context only. | #720 | `dda0531d` | cancels stale test runs after PR closure. A normal failed-job rerun reached terminal attempt 2 and again failed closed only after NVIDIA primary `429`, retired NVIDIA fallback `410`, and direct OpenAI `insufficient_quota`; this is current provider-infrastructure evidence, not a code finding or a passing scan. Normal auto-merge is enabled, but authoritative Strix evidence and independent review remain required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `ebb4ef1d` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest head records the paged Voice JSON-LD evidence repair in snapshot documentation; focused backend and frontend/i18n tests plus lint/build pass, while hosted checks and independent review remain required | -| #716 | `e1e5d9d3` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. PR #739 merged normally into this parent with the READ COMMITTED two-tier de-duplication repair and scoped aggregate EXPLAIN evidence. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 remains absent, so production performance acceptance and protected parent delivery remain incomplete | -| #714 | `76a602c8` | proposes post-scoped public-source research with bounded public-only egress, fail-closed retrieval, contextual-orchestrator verification, normalized citation persistence, API/UI actions, and Storybook evidence. Private posts now return no persisted citations after a visibility change. Text and image-region lead streams preserve source order and alternate without weights, so text volume cannot starve image evidence when the bounded budget admits both. Twenty-five focused checks pass, both new review threads are resolved, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | +| #717 | `b2e0c963` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest head refreshes exact gate evidence for paged Voice JSON-LD; hosted checks and independent review remain required | +| #716 | `65e1dcdc` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. PRs #739 and #714 merged normally into this parent, carrying READ COMMITTED two-tier de-duplication plus bounded public-source research with fail-closed visibility and provenance. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 remains absent, so production performance acceptance and protected parent delivery remain incomplete | | #713 | `850494c3` | proposes the ADR 0246 twelve-code atomic stakeholder Voice-of-X post taxonomy while preserving ADR 0251's separate extensible combination model and the independently governed organization-relationship vocabulary. The audit moved all twelve labels into the parent so Korean, Chinese, Japanese, and Vietnamese filters do not fall back to English immediately after this PR lands. Sixty-eight i18n and 24 ontology checks plus production build pass; a 1280x720 Korean filter render was inspected, all threads are resolved, auto-merge is enabled, and fresh hosted checks plus independent review remain required | | #711 | `05e5f520` | stacked on the current #640 head rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. It now includes the normally merged worker-memory evidence stack. Its canonical upstream runtime-evidence thread stays unresolved and auto-merge remains disabled pending protected upstream delivery and exact-image proof | -| #710 | `27a917ee` | records the worker-function delivery gap against #709 without duplicating #702's corpus audit; the latest documentation repair makes all referenced heads explicitly snapshot-relative. Exact-head hosted checks and independent review remain required | +| #710 | `020ff089` | records the worker-function delivery gap against #709 without duplicating #702's corpus audit; the latest documentation refresh records the exact protected queue evidence and keeps all referenced heads snapshot-relative. Hosted checks and independent review remain required | | #709 | `8ef4090c` | publishes the DOT/FJA worker-function taxonomy and fail-closed read model without converting definitional ranks into weights or asserting an unsupported term-level crosswalk. Exact-head hosted checks and independent review remain required | | #704 | `7b9a70ee` | publishes the bounded external-lineage contract with fail-closed structured adjudication and exact same-group inference eligibility. The hosted full-suite repair removes fabricated random LLM-channel measurement from tests, keeps LLM fusion unavailable without an estimated LLM-inclusive weight, tests the provider boundary directly, and restores public-docstring coverage. Thirty focused checks and Ruff pass locally; fresh hosted checks and independent review remain required | -| #702 | `92294223` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact replayed fast-mlsirm Rust design artifact. For the 43,814-record eligible frame, the predeclared SRSWOR design yields `n=381` at 95% confidence, error bound 0.05, and `p=0.5`; the earlier 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The current head drains spawned-process results before join and correlates provider trace with attempt provenance; focused checks pass, review threads are resolved, auto-merge is enabled, and upstream Rust delivery, hosted checks, plus independent review remain required | +| #702 | `8b51c738` | makes missing source-body evidence explicit, carries governed source classifications through semantic hints and RDF/SHACL, and requires probability-sample manifest v3 plus an exact replayed fast-mlsirm Rust design artifact. For the 43,814-record eligible frame, the predeclared SRSWOR design yields `n=381` at 95% confidence, error bound 0.05, and `p=0.5`; the earlier 500-record diagnostic remains explicitly non-probability-selected and cannot support corpus prevalence or confidence intervals. The current head drains spawned-process results before join, correlates provider trace with attempt provenance, and refreshes stacked estimator delivery evidence; upstream Rust delivery, hosted checks, and independent review remain required | | #701 | `cc3351a9` | repairs both integration fixtures by invoking `psql -X -v ON_ERROR_STOP=1 -f` exactly like the ADR 0166 production runner, so concurrent indexes remain outside a transaction without a fixture-owned SQL parser; no migration is skipped or suppressed. Forty schema/replay/backend checks pass; protected hosted checks and independent review remain required | | #700 | `1bc99eca` | adds ADR 0238's bounded versioned caller-parsed conversation-turn envelope, fail-closed whole-result preflight, ordered semantic-unit persistence, and opaque caller evidence references without body-pattern speaker inference. Caller units cannot inherit opaque-body metadata, trigger unused vision work, or admit text the database cannot persist. The current head moves its schema change and paired rollback to union-free migration 0233, applies that migration in the real-PostgreSQL fixture, and binds each evidence action to the inclusion channel that admitted it; protected hosted checks and independent review remain required | | #680 | `b05e3100` | replaces rendered implementation-boundary language with customer actions, including topic-specific measurement access and exact empty-state actions. The latest repair replaces search-configuration text with saved-evidence/retry guidance in five locales, suppresses raw failure codes, and removes the persistence-delivery outbox from the customer screen while retaining the API record. All 166 App/i18n checks and lint pass; fixed-project Compose renders at 1440x1100 and 390x844 show the status history and next actions without raw failure/outbox terms or horizontal overflow. Fresh hosted checks and independent review remain required | | #679 | `135dfe7c` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and maps unknown future claim/status codes to localized `Recorded claim` / `Status unavailable` instead of exposing wire values. Sixty-nine focused UI/i18n checks pass, all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `234f975b` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, and carries one non-conflicting evidence snapshot. Project-match provenance and unknown future event codes now map to localized Source record / Supporting record / Recorded evidence labels instead of exposing relational field names. Seventy-four focused project-history/UI/i18n checks pass; hosted checks and independent review remain required | -| #667 | `24644d74` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also carries the repaired Ontology stack check evidence. Backend 44 checks and ChatPanel 12 checks plus lint pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | +| #667 | `e3f8a895` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also tracks the current semantic-evidence queue. Focused checks pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | | #658 | `5f3bc384` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, and keeps database-clock cutoff validation and evidence authorization intact. The latest repair replaces transport-oriented cutoff wording and raw RFC3339 output with a five-locale, device-time action and local display formatting; the Storybook interaction follows the same contract. Sixty-seven focused frontend/i18n checks and lint pass, review threads are empty, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #657 | `355a5796` | persists strict TEPP accepted receipts without treating acceptance as measurement, resumes a stored remote run through the pluggable status port, validates and persists the terminal DTO before Succeeded, and keeps all arithmetic in TEPP. The latest UI repair removes TEPP, provider, remote-run identifier, and reconciliation internals from the customer surface; the accepted state now asks the user to refresh for result readiness. Sixty-nine backend/schema checks, five focused frontend checks, lint, and Storybook build pass; the 1440×720 accepted-state render was inspected, all review threads are resolved, auto-merge is enabled, and hosted checks plus independent review remain required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | From 5e653f1c52ca92a810514e75439a0393e23fb25f Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 07:01:21 +0900 Subject: [PATCH 236/238] docs: record semantic stack merges --- docs/product-technical-gap-baseline.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 8fc4d9689..9b6e98019 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,14 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 42 open PRs and 11 open issues. The exact-head +At this snapshot there were 41 open PRs and 11 open issues. The exact-head inventory in section 1 is authoritative for this snapshot. Every open head remained blocked on hosted gates and/or independent review. These observations are not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 06:51 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 06:57 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, @@ -78,24 +78,23 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 42 open PRs (21 targeting `main`, -21 stacked on non-default parents) and 11 +at this refresh. The live queue contains 41 open PRs (21 targeting `main`, +20 stacked on non-default parents) and 11 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 | | ---: | --- | --- | -| #747 | `effbbc3f` | stacked on exact #716 and adds linked user, operations, and MCP manuals for the current product contract instead of duplicating behavior across README and ADRs. The manuals cover Dashboard/Voice/Ask evidence actions, owner-scoped asynchronous MCP reads, OAuth/session/quota recovery, canonical Compose and database observation while excluding provider models, secrets, runtime identifiers, and real records. Thirty-four exact-head manual/schema/docstring checks and diff hygiene pass; API/ADR truth, review threads, hosted checks, and independent review remain under current-head audit | +| #747 | `659c100c` | stacked on exact #716 and adds linked user, operations, and MCP manuals for the current product contract instead of duplicating behavior across README and ADRs. The audited copy directs tied/missing/unavailable relationships to the catalog steward instead of claiming an unshipped product control, names the shipped failed-content requeue command, and prohibits direct row/wake-up manipulation. Both MCP tools, owner-scoped states, citations, Retry-After, Compose/Make targets, and relative links match code; no provider model, credential, real record, or runtime identifier is embedded. Thirty-four focused checks pass, review threads are resolved, and hosted checks plus independent review remain required | | #746 | `4983b291` | replaces closed-unmerged #744 and exposes authenticated occupations represented in one imported rating source. It preserves the complete persisted rating and source/scale provenance domain, uses the observed title/code catalog and native selection without ranking or typed fallback, fences authentication/source/occupation/late responses, distinguishes unavailable catalog from an imported empty result, and aligns empty-evidence guidance with the selector's next action. Hosted checks and independent review remain required | | #745 | `8aa97347` | stacked on exact #746 and adds only case-insensitive published-title or retained-code substring filtering over the native catalog, without ranking or typed SOC fallback. The current normal-merge ancestry preserves #746's request, authentication, source, occupation, loading, unavailable-catalog, and empty-guidance fences; invalid selection clears and requires a visible catalog choice. Review threads are resolved, while hosted checks and independent review remain required | | #743 | `d23e1deb` | stacked on exact #740 and catalogs only imported occupation-rating artifacts that contain observations, preserving release, publisher, license, URL, digest, and declared row-count provenance while excluding the scale support artifact. The latest head normally reconciles the advanced evidence-view parent while retaining authentication and late-response fencing; hosted checks and independent review remain required | | #742 | `72782870` | stacked on the latest operations candidate and persists request-scoped normalized product mentions and closed-code relations atomically, re-applies eligibility and ABAC on reads, projects OWL/SHACL assertions, and keeps provider-backed production fail-closed. The latest repair authorizes product-relation target evidence while retaining predicate/product assertion identity; hosted checks and independent review remain required | | #740 | `e6efa6fe` | stacked on the current occupation-rating read branch and adds an authenticated Dashboard evidence view without changing the governed GNB. It preserves exact values, bounds, sample/error/interval evidence, dates, suppression/not-relevant warnings, and provenance while distinguishing unavailable source from an imported empty profile. The latest repair hides stale occupation pagination as soon as a new request supersedes it, keeps artifact links HTTP(S)-only, and retains the actionable fallback; focused checks pass, while hosted checks and independent review remain required | -| #735 | `e2042093` | stacked on exact #734 and imports caller-pinned O*NET rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and the exact `MM/YYYY` source month without local weighting, aggregation, normalization, or psychometric arithmetic. The latest importer rejects short and extra-field CSV rows with exact line evidence; normally merged #738 adds an authenticated bounded read projection whose merge tree exactly matched its audited head. Parent hosted checks restarted after that merge, and independent review plus parent delivery remain required | -| #734 | `4c3677af` | stacked on exact #732 under union-free ADR 0257 and proposes a partitioned 3NF O*NET occupation-rating evidence store without importing production data or computing local weights. PostgreSQL rejects future or malformed source months, out-of-scale observations, divergent duplicates, row mutation, and whole-store truncation while preserving the explicit partition detach/archive boundary. The latest head is an ancestry-only restack carrying #724's publication-label repair; review threads are empty and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | +| #735 | `3d3463e8` | stacked on the current O*NET linkage branch and imports caller-pinned rating and Scales Reference artifacts under the ADR 0257 schema boundary. It preserves exact decimals, uncertainty, optional category/relevance, release/source partitions, both artifact digests, and exact source month without local weighting or psychometric arithmetic. PRs #734 and #738 merged normally into the parent chain, carrying the partitioned 3NF store and authenticated bounded read projection; hosted checks, independent review, and parent delivery remain required | | #733 | `17c554a9` | stacked on exact #726 under union-free ADR 0258 and projects authorized occupational assertions into the bounded ontology neighborhood with source eligibility, cutoff, and persisted-truth boundaries. Work evidence uses a double-outline rounded rectangle and a visible localized type label while Team remains single-outline; DB and ontology labels agree, construct focus fails closed instead of exposing a raw UUID, and disabled construct analysis no longer misreports another channel's durable job as construct processing. The latest repair replaces an unrelated global vocabulary-count assertion with a direct proof that every worker-function IRI lacks `lookupCode`; forty-five focused ontology checks pass, review threads are empty, and hosted checks restarted | -| #732 | `7f60aa8e` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. The latest head is an ancestry-only restack carrying #724's publication-label repair; focused publication evidence, review threads, and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | +| #732 | `8dd5adb2` | stacked on exact #731 under union-free ADR 0256 and publishes 1,417 directed O*NET linkage assertions from eight pinned source tables with reified subject, predicate, object, and provenance and without weights or causal claims. PR #734 merged normally into this branch, carrying the partitioned 3NF rating store without local weighting; hosted checks, independent review, and parent delivery remain required | | #731 | `b3b9b360` | stacked on exact #724 and publishes all 3,006 O*NET 31.0 Content Model reference elements as deterministic SKOS with exact source identifiers, hierarchy, provenance, license, and artifact digest; ADR 0255 explicitly supersedes only ADR 0248's prohibition on complete pinned O*NET vocabulary publication and preserves the evidence/no-equivalence boundaries. The latest head is an ancestry-only restack carrying #724's publication-label repair; canonical graph publication, review threads, and all observed exact-head hosted checks pass, while independent review and parent delivery remain required | | #728 | `e52a8272` | now stacks on exact #640 instead of extending protected-main NumPy arithmetic. It pins fast-mlsirm PR #1457 exact `5c7dc9ea` and consumes the owner-produced Rust/PyO3 explained-share field while retaining LineageWeave validation, persistence projection, API, and presentation only. The audit also moved the schema change to union-free migration 0236 and made the production-equivalent bootstrap execute it. Upstream Rust tests pass; LineageWeave backend/schema/frontend focused checks pass; both review queues have zero unresolved threads. The upstream PR remains draft with hosted gates in progress and the LineageWeave parent remains non-default, so neither is protected delivery | | #726 | `d6a12fbb` | stacked on exact #723 and admits occupational constructs only through contextual-orchestrator conduct, offered permanent IRIs, and verbatim semantic-unit evidence. Attempt-fenced lease refresh prevents concurrent long extraction, a later-enabled analysis service wakes succeeded current-digest rows that lack construct evidence, and disabled construct analysis no longer exposes another channel's queued/running job as construct processing. Twenty-three focused checks pass with one live integration skip, review threads are empty, and all observed exact-head hosted checks pass; independent review and parent delivery remain required | @@ -105,7 +104,7 @@ context only. | #720 | `dda0531d` | cancels stale test runs after PR closure. A normal failed-job rerun reached terminal attempt 2 and again failed closed only after NVIDIA primary `429`, retired NVIDIA fallback `410`, and direct OpenAI `insufficient_quota`; this is current provider-infrastructure evidence, not a code finding or a passing scan. Normal auto-merge is enabled, but authoritative Strix evidence and independent review remain required before protected delivery | | #719 | `6ee2278a` | stacked on current #718, exposes the governed `dcterms:rights` read model, and preserves parent ancestry through a normal merge. Fifty-four focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | | #718 | `2723fea3` | stacked on #709 and adds evidence-bound occupational constructs with governed provenance wording. Eighteen focused checks pass, all threads are resolved, and auto-merge remains disabled pending parent delivery | -| #717 | `b2e0c963` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest head refreshes exact gate evidence for paged Voice JSON-LD; hosted checks and independent review remain required | +| #717 | `3e332fdb` | stacked on #713 and persists governed evidence-bearing Voice-of-X combinations. Customer-visible assignment events are localized, unchanged Voice codes retain their original effective time, and rejected/superseded assignments render their persisted truth state rather than appearing accepted. The latest documentation distinguishes cutoff-scoped Voice evidence from history while retaining paged JSON-LD evidence; hosted checks and independent review remain required | | #716 | `65e1dcdc` | stacked on exact #711 and prioritizes the evidence-bound operations backfill with isolated responsive dashboard acceptance. PRs #739 and #714 merged normally into this parent, carrying READ COMMITTED two-tier de-duplication plus bounded public-source research with fail-closed visibility and provenance. The representative anonymized-runtime `EXPLAIN (ANALYZE, BUFFERS)` evidence required by ADR 0206 remains absent, so production performance acceptance and protected parent delivery remain incomplete | | #713 | `850494c3` | proposes the ADR 0246 twelve-code atomic stakeholder Voice-of-X post taxonomy while preserving ADR 0251's separate extensible combination model and the independently governed organization-relationship vocabulary. The audit moved all twelve labels into the parent so Korean, Chinese, Japanese, and Vietnamese filters do not fall back to English immediately after this PR lands. Sixty-eight i18n and 24 ontology checks plus production build pass; a 1280x720 Korean filter render was inspected, all threads are resolved, auto-merge is enabled, and fresh hosted checks plus independent review remain required | | #711 | `05e5f520` | stacked on the current #640 head rather than `main`. A proposed pin advance was reverted after exact ancestry showed contextual-orchestrator #882 merged only into a non-default upstream stack and is not protected-main delivery; the immutable runtime pin therefore remains unchanged. It now includes the normally merged worker-memory evidence stack. Its canonical upstream runtime-evidence thread stays unresolved and auto-merge remains disabled pending protected upstream delivery and exact-image proof | @@ -119,7 +118,7 @@ context only. | #679 | `135dfe7c` | ADR 0229 public-claim envelope, async verification, locale-aware next actions, opt-in search setup, and rollback protection for truth-owned fields. The current head always renders the aggregate verification action alongside per-claim actions, removes internal graph-review copy, and maps unknown future claim/status codes to localized `Recorded claim` / `Status unavailable` instead of exposing wire values. Sixty-nine focused UI/i18n checks pass, all threads are resolved and normal auto-merge is enabled, while exact-head hosted checks and independent review remain required | | #672 | `a3e87a89` | persisted semantic-evidence nomination for Global Ask uses unique ADR 0233/0234 and migration 0225/0226 identities; production nominee wiring includes organization/team evidence and typed public claims, removes duplicate embedding and token-overlap inference, and separates visible from all KG evidence so hidden identifiers cannot render. The current head repairs the server-diagnostics fixture to follow the configured Global Ask embedding contract after the prior exact head failed; fresh hosted checks and independent review remain required | | #668 | `234f975b` | evidence-bound project history orders by recorded event time, retains explicit source identity alongside NFKC-deduplicated semantic keys, suppresses false direct handovers, and carries one non-conflicting evidence snapshot. Project-match provenance and unknown future event codes now map to localized Source record / Supporting record / Recorded evidence labels instead of exposing relational field names. Seventy-four focused project-history/UI/i18n checks pass; hosted checks and independent review remain required | -| #667 | `e3f8a895` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also tracks the current semantic-evidence queue. Focused checks pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | +| #667 | `ea17b17d` | this refresh branch prevents stale conversation pagination, recovery, delayed answers, and typed drafts from contaminating a replacement post or conversation; keeps saved turns out of the demo-seed presentation; applies the shared source-eligibility boundary; and replaces provider, transport, environment-variable, timeout, calibration-script, and search-configuration copy with task-specific next actions. Saved conversations page on immutable creation time plus conversation id so a concurrent new turn cannot move a row above the reader's cursor; the observed head also reconciles the live semantic delivery stack. Focused checks pass, all review threads are resolved, normal auto-merge is enabled, and hosted checks plus independent review remain required | | #658 | `5f3bc384` | sends the validated UTC cutoff directly, removes duplicate/unreachable cutoff state and SQL parameter conflicts, and keeps database-clock cutoff validation and evidence authorization intact. The latest repair replaces transport-oriented cutoff wording and raw RFC3339 output with a five-locale, device-time action and local display formatting; the Storybook interaction follows the same contract. Sixty-seven focused frontend/i18n checks and lint pass, review threads are empty, normal auto-merge is enabled, and exact-head hosted checks plus independent review remain required | | #657 | `355a5796` | persists strict TEPP accepted receipts without treating acceptance as measurement, resumes a stored remote run through the pluggable status port, validates and persists the terminal DTO before Succeeded, and keeps all arithmetic in TEPP. The latest UI repair removes TEPP, provider, remote-run identifier, and reconciliation internals from the customer surface; the accepted state now asks the user to refresh for result readiness. Sixty-nine backend/schema checks, five focused frontend checks, lint, and Storybook build pass; the 1440×720 accepted-state render was inspected, all review threads are resolved, auto-merge is enabled, and hosted checks plus independent review remain required | | #644 | `f53dd28e` | current-main reconciliation preserves all existing workspace surfaces and adds Public Claim Verification as the ninth lazy boundary; a subsequent normal merge reconciles concurrent ADR/baseline evidence without deleting either implementation path. Frontend 42 files/391 tests, lint, production build, and Storybook build pass; refreshed desktop loading and mobile error screenshots confirm the actionable alert/Refresh states. The observed 509.58 kB app chunk still triggers Vite's warning and remains measured performance debt; hosted checks and independent review remain required | From e15c507d8608520384442dd6147db9e1437509fe Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 27 Aug 2026 07:18:21 +0900 Subject: [PATCH 237/238] fix(history): recover deleted session before evidence check --- backend/app/post_ask_history.py | 6 +++-- tests/test_post_ask_history.py | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/backend/app/post_ask_history.py b/backend/app/post_ask_history.py index 448749a98..87a8dfd84 100644 --- a/backend/app/post_ask_history.py +++ b/backend/app/post_ask_history.py @@ -326,9 +326,9 @@ async def persist_turn( dict.fromkeys(str(post_id_value) for post_id_value in cited_post_ids if str(post_id_value) in source_set) ) async with conn.transaction(): - if can_see_post is not None: - await _ensure_sources_visible(conn, source_ids, can_see_post) if conversation_id is None: + if can_see_post is not None: + await _ensure_sources_visible(conn, source_ids, can_see_post) conversation_id = uuid4() await conn.execute( """ @@ -355,6 +355,8 @@ async def persist_turn( ) if conversation is None: raise PostAskConversationNotFound + if can_see_post is not None: + await _ensure_sources_visible(conn, source_ids, can_see_post) ordinal = int( await conn.fetchval( diff --git a/tests/test_post_ask_history.py b/tests/test_post_ask_history.py index b163eed2d..04f3af09f 100644 --- a/tests/test_post_ask_history.py +++ b/tests/test_post_ask_history.py @@ -435,6 +435,47 @@ async def persist( assert exc_info.value.status_code == 503 +def test_deleted_conversation_is_detected_before_recovery_reauthorizes_evidence() -> None: + """The real persistence path enters recovery before checking changed evidence.""" + + class _DeletedConversationConnection(_Connection): + async def fetchrow(self, query: str, *arguments: object) -> None: + self.calls.append((query, arguments)) + return None + + connection = _DeletedConversationConnection() + account = CurrentAccount( + user_account_id="account-1", + external_subject_id="subject-1", + display_name="Synthetic analyst", + preferred_locale="en", + corporate_entity_ids=frozenset(), + process_unit_ids=frozenset(), + permission_codes=frozenset({"post_read"}), + ) + + with pytest.raises(HTTPException) as exc_info: + asyncio.run( + post_ask_main._persist_post_ask_turn( + connection, + account, + "post-1", + UUID("00000000-0000-0000-0000-000000000008"), + "What changed?", + "The completed answer remains available.", + ["post-1"], + [], + recover_deleted_conversation=True, + ) + ) + + statements = [query for query, _arguments in connection.calls] + assert exc_info.value.status_code == 503 + assert "from post_ask_session" in statements[0] + assert any("for share of post" in query.lower() for query in statements[1:]) + assert not any("insert into post_ask_session" in query for query in statements) + + def test_persist_turn_aborts_when_a_citation_loses_authorization() -> None: """The transaction fails closed if cited evidence is no longer visible.""" connection = _Connection([ From 0c0f4af572a94e63cc8ea4545e48f5eda32a389c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 13:42:20 +0900 Subject: [PATCH 238/238] docs(gap): refresh exact protected queue evidence Signed-off-by: Seongho Bae --- docs/product-technical-gap-baseline.md | 59 +++++++++++++++++++++----- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 9b6e98019..dc281fb0d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -61,14 +61,15 @@ only aggregate, non-identifying evidence to this repository. ### Exact open-PR boundary -At this snapshot there were 41 open PRs and 11 open issues. The exact-head -inventory in section 1 is authoritative for this snapshot. Every open head -remained blocked on hosted gates and/or independent review. These observations -are not merge readiness. Re-fetch exact heads, +At this snapshot there were 35 open PRs and 12 open issues. The compact +exact-head inventory in section 1 is authoritative for this snapshot. Main- +target heads remained blocked on hosted gates and/or independent review, while +stacked heads require protected parent delivery first. These observations are +not merge readiness. Re-fetch exact heads, unresolved threads, checks, approvals, rulesets, and merge SHA before any lifecycle claim. -> Audit snapshot: 2026-08-27 06:57 KST (refreshed by the autonomous merge +> Audit snapshot: 2026-08-27 13:41 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, @@ -78,11 +79,49 @@ lifecycle claim. ## 1. Exact-head and governance evidence The protected default branch is `ff7431bd1851c03e737808d22c6a2d43968582f9` -at this refresh. The live queue contains 41 open PRs (21 targeting `main`, -20 stacked on non-default parents) and 11 -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. +at this refresh. The live queue contains 35 open PRs (19 targeting `main`, +16 stacked on non-default parents) and 12 open issues. The compact live index +below is the exact-head authority for lifecycle state at this snapshot. The +longer narrative rows that follow remain requirement evidence, but their heads +are historical and must not be used for a merge decision. + +| PR | Exact observed head | Base | Observed lifecycle state | +| ---: | --- | --- | --- | +| #749 | `634b2601` | `feat/onet-rating-occupation-filter` | clean stack; auto-merge off | +| #747 | `e20673a0` | `feat/operations-candidate-priority` | clean stack; auto-merge off | +| #746 | `17e87747` | `feat/onet-rating-source-catalog` | clean stack; auto-merge off | +| #745 | `771cc889` | `feat/onet-occupation-selector` | clean stack; auto-merge off | +| #743 | `85af0fca` | `feat/onet-rating-evidence-ui` | clean stack; auto-merge off | +| #742 | `72fe9b8b` | `feat/operations-candidate-priority` | clean stack; auto-merge off | +| #740 | `36aa851f` | `feat/onet-occupation-ratings-contract` | clean stack; auto-merge off | +| #733 | `822059ca` | `feat/io-psych-construct-extraction` | clean stack; auto-merge off | +| #732 | `8d50f454` | `feat/soc-2018-full-hierarchy` | clean stack; auto-merge off | +| #726 | `eeea3bcc` | `feat/io-psych-construct-catalog` | clean stack; auto-merge off | +| #720 | `dda0531d` | `main` | blocked on required review; auto-merge on | +| #719 | `396b712c` | `feat/io-psych-construct-ontology` | clean stack; auto-merge off | +| #718 | `962022fe` | `feat/fja-worker-function-ontology` | clean stack; auto-merge off | +| #717 | `7a259a42` | `feat/voice-of-x-complete-taxonomy` | clean stack; parent #713 first | +| #716 | `65e1dcdc` | `fix/structured-workflow-exact-pin` | clean stack; auto-merge off | +| #713 | `850494c3` | `main` | blocked on required review; auto-merge on | +| #711 | `27f5ba38` | `feat/dashboard-case-metrics` | clean stack; auto-merge off | +| #709 | `8ef4090c` | `main` | blocked on required review; auto-merge on | +| #704 | `7b9a70ee` | `main` | blocked on required review; auto-merge on | +| #702 | `4325941e` | `main` | repair checks/review pending; auto-merge on | +| #701 | `cc3351a9` | `main` | blocked on required review; auto-merge on | +| #700 | `1bc99eca` | `main` | blocked on required review; auto-merge on | +| #680 | `d7f3e609` | `main` | blocked on required review; auto-merge on | +| #679 | `135dfe7c` | `main` | blocked on required review; auto-merge on | +| #672 | `a3e87a89` | `main` | blocked on required review; auto-merge on | +| #668 | `234f975b` | `main` | blocked on required review; auto-merge on | +| #667 | `e15c507d` | `main` | blocked on required review; auto-merge on | +| #658 | `5f3bc384` | `main` | blocked on required review; auto-merge on | +| #657 | `355a5796` | `main` | blocked on required review; auto-merge on | +| #644 | `f53dd28e` | `main` | blocked on required review; auto-merge on | +| #643 | `bae04cff` | `main` | blocked on required review; auto-merge on | +| #640 | `cede3add` | `main` | review required by ruleset; auto-merge on | +| #639 | `2f4b1bff` | `main` | blocked on required review; auto-merge on | +| #632 | `24262a99` | `main` | blocked on required review; auto-merge on | +| #629 | `b721b0f2` | `main` | blocked on required review; auto-merge on | | PR | Exact observed head | Merge/check state at this snapshot | | ---: | --- | --- |