Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
03c1946
feat: persist and explain Event Lineage channel evidence
seonghobae Aug 21, 2026
780fd57
test(schema): retain project event migration fixture
seonghobae Aug 21, 2026
cd7044a
fix(frontend): keep admin panel behind authentication
seonghobae Aug 21, 2026
c40d3a8
test: apply lineage evidence migration to API fixtures
seonghobae Aug 21, 2026
10cf59e
feat: route rebuild adjudication through orchestrator
seonghobae Aug 21, 2026
2c47b35
fix: preserve adjudication during PostgreSQL imports
seonghobae Aug 21, 2026
516cc55
fix: order persisted lineage weights deterministically
seonghobae Aug 21, 2026
4faf9a3
docs: record orchestrated lineage rebuild policy
seonghobae Aug 21, 2026
f145b83
fix(frontend): preserve structured footnote roles
seonghobae Aug 21, 2026
df2519c
fix(lineage): budget signal rounding tolerance
seonghobae Aug 21, 2026
81cd12f
fix(frontend): close HTML footnote containers reliably
seonghobae Aug 21, 2026
146cc56
fix: hide empty footnote markers
seonghobae Aug 21, 2026
383a013
fix(lineage): offload synchronous reconstruction
seonghobae Aug 21, 2026
4bf0613
perf(lineage): bound channel evidence reads
seonghobae Aug 21, 2026
ee5882a
Merge remote-tracking branch 'origin/feat/event-lineage-channel-evide…
seonghobae Aug 21, 2026
1b680a2
fix(frontend): bound footnote and anchor tag detection
seonghobae Aug 21, 2026
cb79302
fix: close rebuild transaction before reconstruction
seonghobae Aug 21, 2026
caea21b
fix(frontend): recognize wrapped footnote lists
seonghobae Aug 21, 2026
6e32eca
fix: release lineage pool during reconstruction
seonghobae Aug 21, 2026
86ac1d4
Merge remote-tracking branch 'origin/feat/event-lineage-channel-evide…
seonghobae Aug 21, 2026
068ed6a
fix(frontend): preserve structured footnote roles (#388)
seonghobae Aug 21, 2026
778c5df
fix(frontend): render markdown tables in post bodies (#389)
seonghobae Aug 21, 2026
13c1025
Merge remote-tracking branch 'origin/feat/post-body-footnote-display'…
seonghobae Aug 21, 2026
7a0a5f6
fix: make lineage evidence disclosure interactive
seonghobae Aug 21, 2026
16f2b13
fix(frontend): preserve nested list indentation (#391)
seonghobae Aug 21, 2026
eaea56d
fix(db): make tenant settings migration replay-safe
seonghobae Aug 21, 2026
16f6341
fix: bound live lineage adjudication work
seonghobae Aug 21, 2026
55a13f3
chore: nudge CI re-review (opencode-agent's prior REQUEST_CHANGES was…
seonghobae Aug 23, 2026
c34681f
fix: guard corpus lineage rebuild against orchestrator failures; drop…
seonghobae Aug 23, 2026
115bd3e
fix: allocate migration 0174 for lineage signals
seonghobae Aug 23, 2026
3c3bcb5
fix: close lineage evidence review gaps
seonghobae Aug 23, 2026
6bcd52f
Batch Event Lineage persistence writes
seonghobae Aug 23, 2026
5ef0f2e
fix(frontend): restore shared OIDC return-URL helpers on login
seonghobae Aug 24, 2026
44df750
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 24, 2026
5f02940
fix: reconcile merged accessibility roles, script normalization, and …
seonghobae Aug 24, 2026
7ab8026
Merge branch 'main' into feat/event-lineage-channel-evidence
seonghobae Aug 24, 2026
f1f16f6
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 24, 2026
4090494
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 24, 2026
43ebbcb
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 24, 2026
2a6c520
fix: resolve post-merge test breakage from combined LineageDag changes
seonghobae Aug 24, 2026
a99afcb
Merge remote-tracking branch 'origin/main' into codex/pr387-repair
seonghobae Aug 25, 2026
519d0e6
fix(lineage): persist estimated fusion weights
seonghobae Aug 25, 2026
2b95a8b
fix(lineage): load weights for the active channel set
seonghobae Aug 25, 2026
4742465
fix: align lineage weights with budgeted channels
seonghobae Aug 25, 2026
754f8c2
Merge remote-tracking branch 'origin/main' into codex/pr387-repair
seonghobae Aug 25, 2026
462b41f
Merge remote-tracking branch 'origin/main' into codex/pr387-repair
seonghobae Aug 25, 2026
f37a5a2
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
b798cef
fix: fail closed on adjudication errors
seonghobae Aug 25, 2026
be547fd
fix(lineage): wire the adjudication client into corpus-wide rebuild
seonghobae Aug 25, 2026
1890210
merge: reconcile adjudication stack with current base
seonghobae Aug 25, 2026
7bcaab8
Merge pull request #434 from ContextualWisdomLab/worktree-fix-adjudic…
seonghobae Aug 25, 2026
2620e0a
fix(ask): retain lineage reconstruction profile
seonghobae Aug 25, 2026
3fab1f6
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
728125c
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
bbe5489
Merge main into event lineage channel evidence
seonghobae Aug 25, 2026
ab5cf34
Merge current main into event lineage evidence
seonghobae Aug 25, 2026
b14725f
fix(lineage): preserve worker retries and parser edge cases
seonghobae Aug 25, 2026
a3acdaf
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
8b882d8
fix(ui): stop WorkspaceCalendar's fail-closed placeholder announcing …
seonghobae Aug 25, 2026
d6b74f5
fix(measurement): reject duplicated lineage channels
seonghobae Aug 25, 2026
ceb2c1d
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
9fbd5ae
Merge branch 'main' of https://github.com/ContextualWisdomLab/Lineage…
seonghobae Aug 25, 2026
d4fe51e
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
34e6e6f
fix(lineage): name connection direction correctly
seonghobae Aug 25, 2026
749afa0
Merge remote-tracking branch 'origin/main' into HEAD
seonghobae Aug 25, 2026
de9fc2e
fix(lineage): name follows direction correctly
seonghobae Aug 25, 2026
758b1c6
Merge remote-tracking branch 'refs/remotes/origin/pr-387' into HEAD
seonghobae Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ flowchart LR
| `tepp_client.py` | TEPP's published `AnalysisRunRequest` wire contract, pluggable transport |
| `rankweave_client.py` | Fail-closed RankWeave ranking port (`weighted_reciprocal_rank_fuse` in-process; never invent a fused score or a theta) |
| `reconstruct.py` | The pipeline: group → candidate window → score → fuse → thread |
| `lineage_persistence.py` | Flattens reconstruct trees into `post_lineage_edge` row specs (parent, child, fused_score) |
| `lineage_persistence.py` | Flattens reconstruct trees into `post_lineage_edge` rows plus `post_lineage_edge_signal` channel evidence |
| `interval_relation.py` | Allen (1983) closed interval relations for those edges. Each post is a point interval on its observed UTC `created_at` day; mutable ticket dates are not Event Lineage evidence. |
| `knowledge_graph.py` | Random-walk-with-restart relevance + per-node adaptive related-node cutoff (Tong et al., 2006) -- pure graph math, no Postgres |
| `keyman_extraction.py` | Pluggable LLM extraction of two-sided (our-side/counterparty) person mentions + N:N org affiliations from a post |
Expand Down Expand Up @@ -221,17 +221,20 @@ lives in `lineageweave/keyman_extraction.py` and talks to
contextual-orchestrator; persist is `backend/app/keyman_ingestion.py`.

`GET /api/lineage` returns the ABAC-filtered reconstruct graph
(`{nodes, edges, truncated}`) from persisted `post_lineage_edge` rows. Each node
includes `group` from the same `reconstruct_group_key()` rebuild uses
(persisted `thread_group_key`, else process unit, else corp). Each
direct edge includes `interval_relation_code` / `interval_relation_label`
(Allen, 1983; ADR 0161) computed from the two posts' observed windows.
(`{nodes, edges, truncated, reconstruction}`) from persisted `post_lineage_edge`
rows. Each edge includes additive `channel_evidence` from
`post_lineage_edge_signal`. Evidence for an endpoint the account cannot
see is omitted. Each node includes `group` from the same
`reconstruct_group_key()` rebuild uses (persisted `thread_group_key`,
else process unit, else corp).
Each direct edge includes `interval_relation_code` /
`interval_relation_label` computed from the posts' observed windows.
Global Ask merges cited threads from one post/edge fetch pair and
caps the payload at the landing node bound, keeping cited posts first
(ADR 0169). Open a cited post to read the focused thread.
`POST /api/lineage/rebuild` (`post_admin`) re-runs `reconstruct()` over
every `source_post` and rewrites those edges, then names the interval
relation in the same transaction. Reconstruct grouping is
every `source_post` and atomically rewrites edges, channel signals, and
Allen interval relations. Reconstruct grouping is
stored on the post as `thread_group_key` / `secondary_grouping_key`
(not derived from process unit or voc type).

Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.d/2.14.0-event-lineage-channel-evidence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 2.14.0 — Event Lineage channel evidence

Live Event Lineage now persists and explains the independent signals that
produced each reconstructed connection.

- `post_lineage_edge_signal` stores per-channel score, the normalized
active weight actually used, and `weight * score` contribution beside
each `post_lineage_edge` row. The optional LLM channel is omitted when
it did not participate; it is never fabricated.
- `event_lineage_rebuild` records reconstruction version, generated-at
time, and the active weight profile so a later rebuild cannot silently
rewrite historic evidence.
- Administrator rebuilds release their read connection before CPU and
orchestrator work, then acquire one short transaction for the atomic
live-graph replacement.
- `GET /api/lineage` returns additive `channel_evidence` on each visible
edge. ABAC never reveals evidence for an invisible endpoint.
- The Event Lineage DAG discloses exact values with keyboard and screen-reader
access, labels the relation as inferred rather than causal, and keeps
the same values in print.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ All notable changes to this project are documented here. Format follows

### Added

- Event Lineage now persists each reconstructed connection's independent
channel scores, the normalized weights actually used, and their
contributions. The Event Lineage DAG discloses those exact values as inferred
evidence, not a causal claim, and omits the LLM channel when it did
not participate.
- The repository-case public ontology namespace
`https://contextualwisdomlab.github.io/LineageWeave/ontology#` is canonical
(ADR 0207, superseding ADR 0157, resolving issue #372); the lowercase form
Expand Down Expand Up @@ -104,6 +109,10 @@ All notable changes to this project are documented here. Format follows

### Fixed

- Full-corpus Event Lineage rebuilds now count candidate pairs before provider
work and omit the optional LLM channel above the 5,000-pair ADR budget,
preventing millions of synchronous orchestrator calls while retaining one
auditable weight profile for the entire rebuild.
- Structure adjudication now rejects malformed or duplicate unit indexes before
calling the orchestrator.
- Event Lineage's DAG no longer leaves a linear (no-branch) reconstruct
Expand Down
51 changes: 28 additions & 23 deletions backend/app/analysis_run_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@

import asyncio
import logging
from uuid import UUID

import asyncpg
import redis.asyncio as redis
from uuid import UUID

from lineageweave.adjudication_client import AdjudicationClient
from lineageweave.observability import traced
from lineageweave.tepp_client import TeppClient

from backend.app.analysis_run_ingestion import AnalysisRunCreateError
from backend.app.analysis_run_outbox import OUTBOX_STREAM_KEY
from backend.app.analysis_run_start import deliver_queued_analysis_run
from lineageweave.adjudication_client import AdjudicationClient
from lineageweave.observability import traced
from lineageweave.tepp_client import TeppClient

_BROKER_RECOVERY_DELAY_SECONDS = 1.0
_worker_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -77,17 +76,17 @@ async def consume_analysis_run_stream_once(
# transaction rolls back, the durable outbox row stays
# available, and an explicit HTTP start retries the run
# once the operator resolves the named next action.
try:
async with pool.acquire() as conn:
owner = await conn.fetchrow(
"""
select requested_by_account_id
from analysis_run
where analysis_run_id = $1::uuid
""",
analysis_run_id,
)
if owner is not None:
async with pool.acquire() as conn:
owner = await conn.fetchrow(
"""
select requested_by_account_id
from analysis_run
where analysis_run_id = $1::uuid
""",
analysis_run_id,
)
if owner is not None:
try:
await deliver_queued_analysis_run(
pool,
database_url=database_url,
Expand All @@ -98,13 +97,19 @@ async def consume_analysis_run_stream_once(
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__,
)
Comment on lines 97 to +112

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.

last_id = str(entry_id)
return last_id

Expand Down
Loading
Loading