Skip to content

feat: persist and explain Event Lineage channel evidence - #387

Merged
seonghobae merged 67 commits into
mainfrom
feat/event-lineage-channel-evidence
Aug 25, 2026
Merged

feat: persist and explain Event Lineage channel evidence#387
seonghobae merged 67 commits into
mainfrom
feat/event-lineage-channel-evidence

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements issue #274 on current main (v2.14.0). Live Event Lineage no longer collapses a reconstructed connection to a fused score.

  • Persist post_lineage_edge_signal beside each post_lineage_edge row: score, the normalized active weight actually used, and weight * score contribution.
  • Batch rebuild-channel, edge, and signal writes with asyncpg.executemany so a full-corpus replacement does not make one database round-trip per row.
  • Persist singleton event_lineage_rebuild + event_lineage_rebuild_channel so reconstruction version, generated-at, and the weight profile cannot silently rewrite historic evidence.
  • ADR 0172 controlled lookups lineage_signal_temporal|secondary_key|text|llm, enforced by table-level CHECK constraints. The LLM row is omitted when it did not participate; it is never fabricated.
  • GET /api/lineage returns additive channel_evidence (signal_code, signal_label, score, weight, contribution, rank) ordered by contribution, then controlled signal order. ABAC never reveals evidence for an invisible endpoint.
  • Buyer DAG discloses exact values with keyboard and screen-reader access, labels the relation as inferred rather than causal, and prints the same values.

This is independent of #264 ontology-path repair, GNB, and unmerged PRs that claim ADR 0119 / 0122 / 0123 and migration 0104. Analysis-run reconstruction stays out of scope.

Head: 6bcd52f1d8b1efb76f160506e15b5fb2cea1dbf4

Tests

  • Latest persistence regression: 23 passed; real PostgreSQL API/schema partition: 110 passed, 6 capability-gated skips.

  • uv run --extra dev --with asyncpg pytest tests/test_lineage_ingestion.py tests/test_lineage_channel_evidence.py tests/test_schema.py — 35 passed against real PostgreSQL.

  • pnpm test — 157 passed in 14 files; lint and the 454.69 kB production build passed.

  • Ruff I001/RUF022, ShellCheck, sh -n, and git diff --check passed.

Merge gates

Independent exact-head APPROVE required. This request is not APPROVE. Do not squash-merge without independent APPROVE plus exact-head required success. Issues #79 and #87 stay open.


Open in Devin Review

Summary by CodeRabbit

  • 새 기능

    • Event Lineage 연결별 채널 점수, 가중치, 기여도와 재구성 정보를 제공합니다.
    • DAG에서 연결을 클릭하거나 키보드로 선택해 상세 근거를 확인할 수 있습니다.
    • 접근 가능한 데이터만 근거로 표시하며, 대규모 재구성에서는 선택적 분석을 자동 조정합니다.
    • 게시물 본문에서 Markdown 표와 각주를 더욱 정확하게 표시합니다.
  • 버그 수정

    • 분석 전달 중 예기치 않은 오류가 발생해도 후속 작업이 계속 처리됩니다.
    • 잘못된 외부 판정 응답은 명확한 오류로 처리되며 API가 적절한 실패 상태를 반환합니다.
  • 문서

    • Event Lineage 채널 근거와 관련된 설계 문서 및 변경 이력을 추가했습니다.

Reconstruct already computed per-channel scores, but live Event Lineage
collapsed each edge to a fused score. Persist the active signals beside
each edge, return them on GET /api/lineage, and disclose exact inferred
values in the Buyer DAG.
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 50 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ed8e6e9-3bb4-4c4b-8683-76b8c22f504c

📥 Commits

Reviewing files that changed from the base of the PR and between ab5cf34 and 758b1c6.

📒 Files selected for processing (22)
  • ARCHITECTURE.md
  • CHANGELOG.md
  • backend/app/analysis_run_worker.py
  • backend/app/lineage_ingestion.py
  • backend/app/main.py
  • backend/tests/test_api.py
  • docs/adr/README.md
  • docs/storybook-inventory.md
  • frontend/src/App.css
  • frontend/src/App.test.tsx
  • frontend/src/App.tsx
  • frontend/src/LineageDag.test.tsx
  • frontend/src/LineageDag.tsx
  • frontend/src/api.ts
  • frontend/src/i18n.test.ts
  • frontend/src/i18n.ts
  • frontend/src/postBodyDisplay.test.ts
  • frontend/src/postBodyDisplay.ts
  • lineageweave/channel_weight_estimation.py
  • tests/test_analysis_run_worker.py
  • tests/test_lineage_channel_evidence.py
  • tests/test_lineage_ingestion.py
📝 Walkthrough

Walkthrough

Event Lineage에 채널별 증거 저장, 원자적 재구성, 접근 제어 API 응답, DAG 표시가 추가되었습니다. 본문 변환기는 각주, 중첩 목록, Markdown 표를 처리합니다. 외부 판정과 작업자 오류 처리도 보강되었습니다.

Changes

Event Lineage 채널 근거

Layer / File(s) Summary
영속성 계약과 스키마
lineageweave/lineage_persistence.py, migrations/*, tests/test_lineage_channel_evidence.py, tests/test_schema.py
재구성 버전, 채널 점수, 가중치, 기여도와 순위 저장 계약을 추가했습니다. 관련 테이블과 제약을 추가했습니다.
재구성 실행과 원자적 저장
backend/app/lineage_ingestion.py, backend/app/main.py, scripts/*, tests/test_lineage_ingestion.py
후보 수에 따라 LLM 채널을 제외하고, 풀 연결을 반환한 뒤 새 트랜잭션에서 엣지와 증거를 저장합니다.
접근 제어 API 응답
backend/app/lineage_ingestion.py, backend/tests/test_api.py
API가 접근 가능한 엣지의 증거와 재구성 정보를 반환합니다. 비가시 노드를 통한 연결과 증거 노출을 제외합니다.
DAG 근거 표시와 접근성
frontend/src/LineageDag.tsx, frontend/src/api.ts, frontend/src/App.css, frontend/src/i18n.ts, frontend/src/*test*
DAG에서 엣지 증거와 재구성 프로필을 표시합니다. 엣지 선택, 키보드 상호작용, 번역, 인쇄 표시를 지원합니다.

본문 변환과 표시

Layer / File(s) Summary
각주·목록·표 변환
frontend/src/postBodyDisplay.ts, frontend/src/PostBody.tsx, frontend/src/*test*
HTML·Word 각주를 분류하고 중첩 목록의 들여쓰기를 보존합니다. Markdown 표와 이미지 OCR 표를 공통 경로로 렌더링합니다.

외부 판정과 작업자 오류 처리

Layer / File(s) Summary
외부 판정 오류 처리
lineageweave/adjudication_client.py, tests/test_adjudication_client.py, tests/test_estimate_llm_channel_weights_script.py
유효하지 않은 판정 응답을 HttpClientError로 처리합니다.
분석 실행 전달 계속 처리
backend/app/analysis_run_worker.py, tests/test_analysis_run_worker.py
예상하지 못한 전달 오류를 기록하고 커서를 갱신해 후속 실행을 처리합니다.

Estimated code review effort: 5 (Critical) | ~120 minutes

Merge Risk: 🟠 High · up to ab5cf

This PR adds persisted lineage evidence and new display behavior, but a transient database failure can permanently skip queued analysis deliveries, while schema validation, accessibility, lint, and test issues remain unresolved. Merge should wait for the delivery retry/cursor fix and cleanup of the remaining checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.32% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 182 functions across 30 files. (10 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 Event Lineage의 채널별 증거를 저장하고 설명하는 이 pull request의 주요 변경 사항을 정확하고 간결하게 요약합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 31.32% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 182 functions across 30 files. (10 skipped: 10 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/event-lineage-channel-evidence

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

Requesting independent Copilot review on exact head 03c1946. This is not APPROVE. Do not squash-merge without independent exact-head APPROVE plus required success.

devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Fixed on exact current head 780fd57: restored the 0102 project-bound summary-event migration constant while retaining the new 0105 channel-evidence migration, so the real PostgreSQL schema fixture applies both in dependency order. Exact schema suite: 10 passed. @claude please review this exact head.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Correction: the current exact PR head is 780fd57 (the prior comment used an incorrect full expansion after the remote head refresh). The migration fixture fix is present at this head, and tests/test_schema.py remains 10 passed. @claude please review this corrected exact head.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Reproduced and fixed a current frontend Checks failure on the exact PR stack.\n\nRoot cause: the unauthenticated render branch mounted AdminPanel with accessToken typed as string but actually undefined, and retained unused OIDC helper imports. That caused TypeScript TS2322 plus oxlint no-unused-vars. The unauthenticated branch now renders only the login screen; the authenticated admin route remains unchanged, and the unused imports are removed.\n\nExact head: cd7044a. Evidence after the concurrent 780fd57 base: server focused tests 20 passed; frontend focused tests 103 passed; lint, TypeScript/Vite build, Storybook build, and git diff --check passed. No approval is asserted; rerun all Checks on this exact head.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@claude Please review exact current head 2c47b353bd71dba78b720edf14bf5708c314f4a0.

The rebuild adjudication fix is present in the remote 10cf59ee base: API rebuild now passes the configured contextual-orchestrator client through lineage_edge_specs, and the separate PostgreSQL import path now passes the same client or the explicit unavailable null. The stale helper docstring was corrected.

Exact-head local validation: 768 passed, 17 skipped; targeted rebuild tests passed; git diff --check and compileall passed. Hosted Checks are queued for this head. This is a review request, not an approval or merge authorization.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Validated on exact concurrent head. Preserved 2c47b35 and pushed 516cc55. GET /api/lineage now orders rebuild weights from common_lookup_value.display_order with a deterministic code tie-breaker, so buyer-facing and audit output do not depend on PostgreSQL row order. Rebuild and PostgreSQL import continue to pass the configured ContextualOrchestratorAdjudicationClient; no local provider call or fabricated LLM score was added. Targeted lineage/adjudication/import tests: 40 passed. Full Python suite with dev and backend extras: 768 passed, 17 skipped; 4 existing dependency warnings. git diff --check: passed. Please rerun required checks for the new exact head.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@claude Please review exact current head 4faf9a31371195c5ec63fca42a5afbb93a95369b.

The current ancestry now also orders persisted rebuild weights by the controlled common_lookup_value.display_order with a code tie-breaker and documents the orchestrator boundary in ADR 0124. Exact-head targeted lineage/API tests passed (2 passed selected; prior full suite on the implementation head was 768 passed, 17 skipped), with diff check clean. Hosted Checks are still pending; this is not an approval.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Reconciled the current review notes on exact head 4faf9a3: (1) channel availability is run-scoped by reconstruct.active_weights, so the stored rebuild profile is uniform by contract; (2) weight_rows now join common_lookup_value and order by display_order plus signal_code, removing PostgreSQL row-order dependence; (3) the administrator rebuild and PostgreSQL import now pass the configured ContextualOrchestratorAdjudicationClient, while an unavailable gateway remains the explicit NullAdjudicationClient three-channel path. No fabricated LLM evidence is emitted.

devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head follow-up: df2519c09b224f05ac84e6997abd3b4f1bb94cb6 fixes the rounding defect in the channel-evidence persistence boundary.

  • reconciliation tolerance now includes a bounded half-quantum budget per persisted channel plus a small floating-point guard
  • added a four-channel regression whose six-decimal contributions previously exceeded the fixed 1e-6 tolerance and aborted rebuild/import
  • local verification: full backend 769 passed, 17 skipped, 4 warnings; focused channel/ingestion set 20 passed; git diff --check passed

Hosted Checks have restarted for this exact head. This is a review request, not an approval or merge instruction.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@claude Please review exact current head df2519c09b224f05ac84e6997abd3b4f1bb94cb6. The concurrent normal branch update now fixes the actionable corpus-rebuild rounding defect: reconciliation budget scales with active channel count (half-quantum per persisted contribution plus a bounded guard), so valid 3/4-channel evidence cannot abort a rebuild while materially mismatched fused scores still fail. The new regression exercises a four-channel quantization case. Exact-head validation on the remote head: focused channel-evidence checks passed (4 selected); diff check passed. This requests review and is not an approval.

devin-ai-integration[bot]

This comment was marked as resolved.

github-code-quality[bot]

This comment was marked as resolved.

@seonghobae
seonghobae enabled auto-merge (squash) August 25, 2026 08:45
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

coderabbitai[bot]

This comment was marked as resolved.

github-code-quality[bot]

This comment was marked as resolved.

@opencode-agent
opencode-agent Bot disabled auto-merge August 25, 2026 09:14
@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head b14725f keeps database owner lookup failures outside the per-delivery exception boundary, retains durable progress across one malformed provider delivery, makes channel weights required, aligns lineage viewport assertions with accessible names and stored direction, and accepts quoted or unquoted HTML footnote attributes. Verified 43 backend tests, 57 frontend tests, lint, and production build.

# Conflicts:
#	frontend/src/api.ts
@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head a3acdaf composes current protected main without dropping either reconstruction provenance or focused-isolation state. Revalidated 47 backend tests, 57 frontend tests, lint, and production build; independent exact-head approval remains required.

@opencode-agent
opencode-agent Bot disabled auto-merge August 25, 2026 09:38
@seonghobae
seonghobae enabled auto-merge August 25, 2026 09:44
@opencode-agent
opencode-agent Bot disabled auto-merge August 25, 2026 09:48
@seonghobae
seonghobae enabled auto-merge (squash) August 25, 2026 09:55
…as role=status

Its resolved empty/unavailable state carried role="status" like sibling
panels' transient loading text does, so mounting it inside the Board's
collapsed Advanced Review Tools details collided with every other status
region on the page (4 failing App.test.tsx assertions). RankingsPanel's
own resolved placeholders carry no ARIA role for the same reason -- only
the "Loading..." state announces.
# Conflicts:
#	CHANGELOG.md
#	backend/app/main.py
devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae
seonghobae merged commit 0bd93e9 into main Aug 25, 2026
18 of 22 checks passed

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment on lines 97 to +112
adjudication_client=adjudication_client,
valkey_stream_entry_id=str(entry_id),
)
except AnalysisRunCreateError as exc:
_worker_logger.warning(
"analysis-run %s delivery refused (%s): %s",
analysis_run_id,
exc.status_code,
exc.detail,
)
except AnalysisRunCreateError as exc:
_worker_logger.warning(
"analysis-run %s delivery refused (%s): %s",
analysis_run_id,
exc.status_code,
exc.detail,
)
except Exception as exc:
_worker_logger.warning(
"analysis-run %s delivery failed (error_type=%s)",
analysis_run_id,
type(exc).__name__,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Worker swallows all delivery errors and advances the cursor

The broad except Exception now sits inside the per-entry loop, so any delivery failure is logged instead of ending the worker task, and last_id advances regardless. A transiently-failed run has its Valkey cursor advanced and depends on the durable outbox plus an explicit HTTP retry for recovery. Documented and a net availability improvement over the prior crash-the-worker behavior.

(Refers to this code)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant