Skip to content

feat(impact): Impact Trace — downstream causal analysis - #76

Open
saadamjad wants to merge 1 commit into
feat/dashboard-why-pagefrom
feat/impact-trace
Open

feat(impact): Impact Trace — downstream causal analysis#76
saadamjad wants to merge 1 commit into
feat/dashboard-why-pagefrom
feat/impact-trace

Conversation

@saadamjad

Copy link
Copy Markdown
Collaborator

Closes #75.

What

Impact Trace — the downstream mirror of Causal Trace. /why walks
parent_event_id up to the origin; Impact Trace walks the causal graph
down through children to reveal an event's blast radius ("what did this
event cause?").

Stacked on feat/dashboard-why-page (Causal Trace / Debugging nav), so the diff
is scoped to just Impact Trace. Retarget to main once #71 merges.

Changes

Backend (core/api/events.py)

  • GET /v1/events/{id}/impact?depth= — recursive WITH RECURSIVE walking forward
    (JOIN ON e.parent_event_id = it.event_id), bounded by depth (≤50), reusing
    idx_events_parent. Returns {event_id, node_count, nodes:[{…event…, depth}]}
    a flat list the client renders as a fan-out tree.
  • G5 security hardening: backfills assert_agent_allowed on both impact
    and the existing why so agent-scoped keys can't trace other agents' events.

Frontend

  • lib/api.ts: getImpactChain() + ImpactTree/ImpactNode types.
  • New /dashboard/debugging/impact page — mirrors Causal Trace UX: single Event ID
    input, deep-linkable (?event_id=), loading/empty/error/success states, downstream
    tree (indented by depth, error badges, expandable node detail, "trace impact from
    here").
  • DashboardShell: Impact Trace entry under the Debugging nav group.

How to test

cd dashboard && npm run build   # gate

Then, against a running stack, deep-link /dashboard/debugging/impact?event_id=<id>.

Verified live (seeded chain user_message → planning → tool_call → tool_error)

Case Result
impact(user_message) 4 nodes, depths 0–3 ✅
impact(tool_call) 2 nodes (tool_call → tool_error) ✅
impact(tool_error) (leaf) 1 node, "no downstream events" ✅
bad / unknown UUID 404 ✅
?depth=1 from root 2 nodes ✅
scoped key, other agent (why & impact) 403 ✅
dashboard build compiles clean; page 200 ✅

Part of the debugging-system roadmap — see docs/DEBUGGING_SYSTEM_REVIEW.md (HIGH tier).

🤖 Generated with Claude Code

Impact Trace is the downstream mirror of Causal Trace: where /why walks
parent_event_id UP to the origin, Impact Trace walks the causal graph
DOWN through children to show an event's blast radius.

Backend (core/api/events.py):
- New GET /v1/events/{id}/impact?depth= — recursive WITH RECURSIVE walking
  forward (JOIN ON e.parent_event_id = it.event_id), bounded by depth,
  reusing idx_events_parent. Returns a flat node list with per-node depth
  so the client renders the fan-out tree. Tenant-isolated; enforces
  assert_agent_allowed on the root event.
- Security hardening (G5): also backfills assert_agent_allowed on the
  existing /why endpoint so agent-scoped keys can't trace other agents'
  events.

Frontend:
- lib/api.ts: getImpactChain() + ImpactTree/ImpactNode types.
- New /dashboard/debugging/impact page mirroring the Causal Trace UX —
  single Event ID input, deep-linkable, loading/empty/error/success
  states, a downstream tree (indented by depth, error badges, expandable
  node detail, "trace impact from here").
- DashboardShell: "Impact Trace" entry under the Debugging nav group.

Verified live against the seeded chain user_message → planning →
tool_call → tool_error: impact(root)=4 nodes (depths 0–3),
impact(tool_call)=2, impact(tool_error)=1; bad/unknown UUID→404;
depth=1→2 nodes; dashboard build compiles clean; page loads 200.

Closes #75

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant