Skip to content

feat(enrichment): add enrichment details sidebar with cost + provider cascade#5139

Merged
TheodoreSpeaks merged 5 commits into
stagingfrom
feat/enrichment-cost
Jun 19, 2026
Merged

feat(enrichment): add enrichment details sidebar with cost + provider cascade#5139
TheodoreSpeaks merged 5 commits into
stagingfrom
feat/enrichment-cost

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • Add an Enrichment Details slideout, opened from the table "View execution" pill (and cell context menu), styled to match Log Details
  • Result tab: status, duration, total cost, matched provider; Cascade tab: full provider cascade as a trace-style waterfall with brand icons, per-provider cost/duration, and errors
  • Capture per-provider cascade detail in the runner (status, cost, timing) — previously only the aggregate was recorded; persist it on a new nullable table_row_executions.enrichment_details column, read on demand via a new contract-bound route + query hook (kept off the hot grid read)
  • Migration 0241 (nullable ADD COLUMN, backward-compatible); centralize trace icon-contrast helpers into log-details/utils

Type of Change

  • New feature

Testing

  • New unit + route tests (9) pass; existing table/enrichment tests pass
  • bun run lint, check:api-validation:strict, and check:migrations origin/staging all pass
  • Type-check clean

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 19, 2026 8:54pm

Request Review

@cursor

cursor Bot commented Jun 19, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches background enrichment execution persistence, a DB migration, and table grid “View execution” routing; billing/cost display is read-only but execution writes now carry larger JSON payloads on terminal cells.

Overview
Adds/lib/table/types gains **EnrichmentRunDetail** and per-provider outcomes; the enrichment runner now records the full cascade (status, cost, timing, skipped/not_run) and persists it on a new nullable **table_row_executions.enrichment_details** column. Grid reads stay lean by omitting that JSON from loadExecutionsByRow; a new authenticated GET route, contract, **useEnrichmentDetail** hook, and **loadEnrichmentDetail`** fetch it when the panel opens.

The table UI adds an Enrichment Details slideout (Result + Cascade waterfall, log-details styling/resizer) wired through slideout state, the action bar View execution pill, and the cell context menu for terminal enrichment cells—replacing the previous “no trace for enrichments” behavior. iconColorClass / adjustBgForContrast move to shared log-details utils for reuse in the cascade view.

Migration 0244 adds the column; upserts use sticky coalesce so interim running writes do not wipe stored detail. Unit and route tests cover the runner detail shape and the new API.

Reviewed by Cursor Bugbot for commit aecc236. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread apps/sim/background/workflow-column-execution.ts
Comment thread apps/sim/hooks/queries/tables.ts
@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an Enrichment Details slideout panel (Result + Cascade tabs) to the tables view, capturing per-provider cascade detail during enrichment runs that was previously discarded. A new nullable enrichment_details jsonb column on table_row_executions persists the breakdown, read on-demand via a new authenticated GET route — intentionally kept off the hot grid read path.

  • New API + hook: GET /api/table/[tableId]/rows/[rowId]/enrichment/[groupId] returns the cascade breakdown on demand; useEnrichmentDetail uses staleTime: 0 so each panel open always fetches fresh data.
  • Runner changes: runEnrichment now returns a full EnrichmentRunDetail alongside the existing scalar outcome; skippedEnrichmentDetail covers early-abort and missing-input paths; providers not yet reached are appended as not_run after the cascade loop.
  • UI: EnrichmentDetails slides in from the right edge, sharing the log-details resize store and helper utilities (iconColorClass, adjustBgForContrast) that were promoted from a local trace-view function to the shared log-details/utils.ts.

Confidence Score: 5/5

Safe to merge — the change is well-scoped, backward-compatible (nullable ADD COLUMN), and all enrichment exit paths correctly write the cascade detail.

The runner changes thread the new EnrichmentRunDetail through every exit path (skipped inputs, early abort, post-run abort, error, success). The COALESCE upsert correctly preserves a prior cascade on intermediate writes while re-runs overwrite it on completion. The hot grid read path is unaffected. Access control on the new route is correct (auth + tableId-scoped access check). Nine new tests cover the cascade logic and route behavior.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/enrichments/run.ts Refactored cascade loop to collect per-provider outcomes and return a full EnrichmentRunDetail; added skippedEnrichmentDetail for pre-run exits. Logic is sound — matched break, not_run fill, aborted flag, and error-only heuristic all correctly handled.
apps/sim/lib/table/rows/executions.ts Adds loadEnrichmentDetail (on-demand read) and wires enrichmentDetails into writeExecutionsPatch with a COALESCE to preserve a prior cascade when intermediate writes omit it. The explicit column list in loadExecutionsByRow correctly excludes the large enrichmentDetails column from the hot path.
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/enrichment-details/enrichment-details.tsx New slideout component with Result and Cascade tabs. didRun() helper correctly excludes both skipped and not_run; deriveResultStatus correctly mirrors executor logic. Minor: deriveResultStatus(detail) is computed 2x per render cycle instead of once.
apps/sim/app/api/table/[tableId]/rows/[rowId]/enrichment/[groupId]/route.ts Clean new GET route: auth → access check → loadEnrichmentDetail. Contract-validated, scoped to tableId in both the access check and the DB query.
apps/sim/hooks/queries/tables.ts useEnrichmentDetail added with staleTime: 0 (always refetches on open) and guarded by enabled flag. Correctly addresses the stale-cascade concern noted in the previous review thread.
packages/db/migrations/0244_table_row_executions_enrichment_details.sql Simple nullable ADD COLUMN migration — backward-compatible, no default needed since existing rows correctly read as null.
apps/sim/background/workflow-column-execution.ts All enrichment exit paths (missing inputs, early abort, post-run abort, error, success) now write enrichmentDetails. Both skippedEnrichmentDetail and the detail from runEnrichment are correctly threaded through.
apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx canViewEnrichment flag correctly restricts to terminal enrichment runs; contextMenuEnrichment is properly null-initialized per render; handleViewExecution branches correctly between enrichment and workflow paths.
apps/sim/app/workspace/[workspaceId]/logs/components/log-details/utils.ts iconColorClass and adjustBgForContrast promoted from local trace-view functions to shared utils — straightforward code move with no logic changes.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as EnrichmentDetails Panel
    participant TG as TableGrid
    participant Table as table.tsx
    participant Hook as useEnrichmentDetail
    participant API as GET /enrichment/[groupId]
    participant DB as DB (tableRowExecutions)

    Note over TG: User right-clicks / selects enrichment cell (status: completed | error)
    TG->>Table: onOpenEnrichmentDetails(rowId, groupId)
    Table->>Table: dispatch OPEN_ENRICHMENT_DETAILS
    Table->>UI: "isOpen=true, rowId, groupId"

    UI->>Hook: "useEnrichmentDetail(tableId, rowId, groupId, {enabled: true})"
    Note over Hook: staleTime: 0 — always fetches fresh
    Hook->>API: GET /api/table/[tableId]/rows/[rowId]/enrichment/[groupId]
    API->>API: checkSessionOrInternalAuth
    API->>API: checkAccess(tableId, userId, 'read')
    API->>DB: SELECT enrichment_details WHERE tableId+rowId+groupId
    DB-->>API: "EnrichmentRunDetail | null"
    API-->>Hook: "{ success: true, data: { detail } }"
    Hook-->>UI: "{ data: detail, isLoading: false }"

    UI->>UI: deriveResultStatus(detail)
    UI->>UI: Render Result tab or Cascade tab waterfall

    Note over DB: Written by background runner
    Note over DB: runEnrichment → EnrichmentRunDetail
    Note over DB: skippedEnrichmentDetail (missing inputs / early abort)
    Note over DB: COALESCE preserves prior detail on intermediate writes
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as EnrichmentDetails Panel
    participant TG as TableGrid
    participant Table as table.tsx
    participant Hook as useEnrichmentDetail
    participant API as GET /enrichment/[groupId]
    participant DB as DB (tableRowExecutions)

    Note over TG: User right-clicks / selects enrichment cell (status: completed | error)
    TG->>Table: onOpenEnrichmentDetails(rowId, groupId)
    Table->>Table: dispatch OPEN_ENRICHMENT_DETAILS
    Table->>UI: "isOpen=true, rowId, groupId"

    UI->>Hook: "useEnrichmentDetail(tableId, rowId, groupId, {enabled: true})"
    Note over Hook: staleTime: 0 — always fetches fresh
    Hook->>API: GET /api/table/[tableId]/rows/[rowId]/enrichment/[groupId]
    API->>API: checkSessionOrInternalAuth
    API->>API: checkAccess(tableId, userId, 'read')
    API->>DB: SELECT enrichment_details WHERE tableId+rowId+groupId
    DB-->>API: "EnrichmentRunDetail | null"
    API-->>Hook: "{ success: true, data: { detail } }"
    Hook-->>UI: "{ data: detail, isLoading: false }"

    UI->>UI: deriveResultStatus(detail)
    UI->>UI: Render Result tab or Cascade tab waterfall

    Note over DB: Written by background runner
    Note over DB: runEnrichment → EnrichmentRunDetail
    Note over DB: skippedEnrichmentDetail (missing inputs / early abort)
    Note over DB: COALESCE preserves prior detail on intermediate writes
Loading

Reviews (5): Last reviewed commit: "fix(enrichment): show Cancelled in detai..." | Re-trigger Greptile

Comment thread apps/sim/hooks/queries/tables.ts
…ude not_run from ran count, refetch on panel open
# Conflicts:
#	packages/db/migrations/meta/0241_snapshot.json
#	packages/db/migrations/meta/_journal.json
#	scripts/check-api-validation-contracts.ts
@TheodoreSpeaks TheodoreSpeaks requested a review from a team as a code owner June 19, 2026 20:17
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

Addressed the review findings + resolved the staging conflict:

  • ranCount inflated by not_run (P1)ranCount and the cascade summary now count only providers that actually executed (excludes skipped and not_run), via a shared didRun() helper. Added a not_run result status so a cell where nothing executed reads "Not run" instead of "No match".
  • Cancel write drops cascade detail (Medium) — the post-cascade abort now persists enrichmentDetails: detail, and the pre-run abort persists a skippedEnrichmentDetail, so a cancelled run shows its partial/empty cascade instead of an empty panel.
  • View execution without cascade — missing required inputs (Low) — the missing-inputs branch now writes skippedEnrichmentDetail(enrichment) (all providers skipped), so opening the panel shows "Not run" with the configured cascade instead of an empty state.
  • Stale enrichment detail cache (Medium/P2)useEnrichmentDetail now uses staleTime: 0; since the panel is opened on demand, every open refetches, so a re-run between opens never serves a stale cascade.

Merge conflict with staging resolved: migration renumbered 0241 → 0244 (staging took 0241–0243), route-count baseline bumped to 857, bun install to relink the @sim/platform-authz rename.

tsc, lint, check:api-validation:strict, check:migrations origin/staging, and tests all green.

@greptile review

Comment thread apps/sim/lib/table/rows/executions.ts Outdated
Comment thread apps/sim/enrichments/run.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

1 similar comment
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@BugBot review

Comment thread apps/sim/lib/table/rows/executions.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@BugBot review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit aecc236. Configure here.

@TheodoreSpeaks TheodoreSpeaks merged commit 208d135 into staging Jun 19, 2026
16 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the feat/enrichment-cost branch June 19, 2026 21:19
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.

2 participants