Skip to content

fix(terminal): attribute repeated block output by invocation - #7002

Closed
BillLeoutsakosvl346 wants to merge 5 commits into
stagingfrom
fix/iteration-output-attribution
Closed

fix(terminal): attribute repeated block output by invocation#7002
BillLeoutsakosvl346 wants to merge 5 commits into
stagingfrom
fix/iteration-output-attribution

Conversation

@BillLeoutsakosvl346

@BillLeoutsakosvl346 BillLeoutsakosvl346 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Root cause

Workflow-terminal updates identified entries with the static block ID and execution ID. Repeated invocations of the same block can share those values, so later iteration events could update or reconcile multiple terminal rows. Deployment traces remained correct because their final block logs and spans retained per-occurrence ordering.

Fix

  • Mint one optional server-side blockExecutionId for each user-visible block invocation.
  • Preserve that ID through start, completion, error, child-workflow, streaming, final-log reconciliation, nested traces, and retries.
  • Add a direct blockExecutionId-to-entry index to the terminal store.
  • Make replayed starts idempotent and update exactly one identified invocation.
  • Keep a strict exact-one legacy fallback using the full existing composite identity.
  • Key client stream accumulators and timers by invocation while retaining blockId for existing UI contracts.
  • Suppress mixed streamed/non-streamed selected output consistently in deployment and chat execution paths.

The field remains optional for mixed-version reconnects and hydrated legacy data. This does not alter database schemas, public REST APIs, terminal grouping, row ordering, rendering, or deployment-trace grouping.

Focused coverage

The regression coverage verifies colliding loop rows remain isolated, replayed starts are idempotent, ambiguous legacy updates do not fan out, invocation IDs are distinct and stable through retries and lifecycle callbacks, final reconciliation targets the correct invocation, nested traces preserve identity, every agent-stream event variant forwards the ID, legacy child-workflow rows can be enriched safely, and mixed streamed/non-streamed sibling invocations do not duplicate or leak selected output.

Verification

  • Focused attribution suite: 322 passed
  • Follow-up chat/deployment streaming suite: 46 passed
  • Repository audits: 33 passed
  • git diff --check
  • bun run type-check
  • bun run lint:check
  • bun run test: 31,061 passed, 46 skipped
  • Browser E2E: Start → Loop (2) → Function verified iteration 0 succeeds with result.iteration = 0 and iteration 1 contains only iteration-1-failure in both terminal and deployment trace
  • Browser screenshots: fix(terminal): attribute repeated block output by invocation #7002 (comment)

Automated review

Greptile and Bugbot findings covering final stream reconciliation, legacy child-workflow enrichment, deployment mixed-invocation output, and chat mixed-invocation output were resolved with focused tests. The latest Bugbot and required checks are green, with no unresolved review threads.

@vercel

vercel Bot commented Aug 23, 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 Aug 23, 2026 1:12am

Request Review

@cursor

cursor Bot commented Aug 23, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches executor callbacks, SSE events, terminal indexing, and chat stream de-duplication. The field is optional with a strict one-match legacy fallback, but a mismatch could drop live updates or skip selected outputs.

Overview
Stops later loop/parallel/retry runs of the same block from overwriting another terminal row or appending a sibling’s selected output after a stream.

The executor now mints a stable blockExecutionId per user-visible invocation (kept across retries, new ID on the next run) and threads it through start/complete/error, child-workflow, agent-stream, traces, and HITL resume. The terminal store indexes by that ID, treats replayed starts as idempotent, and refuses ambiguous legacy matches. Chat/SSE stream bookkeeping keys by invocation while still using blockId for UI, so a streamed block does not pick up a later sibling’s output.

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

Comment thread apps/sim/stores/terminal/console/store.ts
@greptile-apps

greptile-apps Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a per-invocation block execution identifier and carries it through executor callbacks, streaming events, traces, reconciliation, and terminal-store indexing.

  • Adds invocation identity to block logs, lifecycle callbacks, child workflows, retries, and agent-stream events.
  • Keys terminal and stream state by invocation to isolate repeated executions of the same block.
  • Adds exact-one legacy reconciliation and regression coverage for repeated starts and colliding loop rows.
  • Leaves final selected-output suppression keyed by blockId, causing invocation-keyed streamed output to be included again.

Confidence Score: 4/5

The PR should not merge until final selected-output assembly consistently recognizes invocation-keyed streamed content.

Production streams are stored under blockExecutionId, while final-result suppression still queries by blockId and can therefore re-emit streamed content or select the first repeated invocation's log.

Files Needing Attention: apps/sim/lib/workflows/streaming/streaming.ts

Important Files Changed

Filename Overview
apps/sim/lib/workflows/streaming/streaming.ts Invocation-keyed stream accumulation is inconsistent with block-keyed final-result suppression, allowing duplicate or stale final output.
apps/sim/executor/execution/block-executor.ts Mints a distinct invocation ID per block execution and preserves it through retries, callbacks, and streaming.
apps/sim/stores/terminal/console/store.ts Adds direct invocation indexing with validated lookup, legacy fallback, and coherent rebuild/removal paths.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-execution-utils.ts Reconciles lifecycle events, final logs, and nested spans by invocation ID with strict legacy fallback.
apps/sim/lib/workflows/executor/execution-events.ts Propagates invocation identity across block lifecycle and agent-stream event variants.

Sequence Diagram

sequenceDiagram
  participant Executor
  participant Stream as Streaming adapter
  participant State as Stream state
  participant Final as Final-result builder
  Executor->>Stream: onStream(blockId, blockExecutionId)
  Stream->>State: "streamedChunks[blockExecutionId] += chunk"
  Executor->>Stream: onBlockComplete(blockId, blockExecutionId)
  Stream->>State: completedBlockIds.add(blockId)
  Final->>State: streamedContent.has(blockId)
  State-->>Final: false
  Final->>Final: find first log by blockId
  Final-->>Stream: Include already-streamed or stale output
Loading

Reviews (1): Last reviewed commit: "fix(terminal): attribute repeated block ..." | Re-trigger Greptile

Comment thread apps/sim/lib/workflows/streaming/streaming.ts
@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author

Browser E2E evidence (local app, commit 08e9b86):

Iteration 1/2 selected — successful output is isolated to { iteration: 0 }:

Iteration 1 successful output

Iteration 2/2 selected — failure is isolated to iteration-1-failure:

Iteration 2 isolated failure

@BillLeoutsakosvl346
BillLeoutsakosvl346 force-pushed the fix/iteration-output-attribution branch from 08e9b86 to b983bd2 Compare August 23, 2026 00:40
Comment thread apps/sim/lib/workflows/streaming/streaming.ts Outdated
@BillLeoutsakosvl346
BillLeoutsakosvl346 force-pushed the fix/iteration-output-attribution branch from 42c3b4e to 20dc04e Compare August 23, 2026 01:01

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 20dc04e. Configure here.

@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author
Screen.Recording.2026-08-22.at.6.56.46.PM.mov

@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author

Closing after validating the reported attribution path directly on clean origin/staging at bbf408b.\n\nBrowser baseline results:\n- Start -> Loop (2) -> Function, with iteration 0 succeeding and iteration 1 failing: each terminal row kept its own output/status.\n- Start -> Loop (2) -> Slack list-channels, with the Slack error port routed through a local Wait so both generic-handler invocations completed: the terminal rendered Slack (iteration 0) at 10ms and Slack (iteration 1) at 9ms as separate rows, and selecting either row retained that invocation's state.\n\nThis confirms the existing executionOrder correlation already covers the reported non-streaming Slack case on staging. The blockExecutionId protocol in this PR is therefore redundant, and its central duplicate-executionOrder fixture does not represent the executor's documented invariant. I am not replacing it with a speculative streaming-only change because there is no failing in-scope reproduction for that path.\n\nAll disposable browser-test workflows were deleted. The branch is being left intact for audit/history.

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