From f11f69771d1b44dae95668720cb7860000671a14 Mon Sep 17 00:00:00 2001
From: candieduniverse <132302818+candieduniverse@users.noreply.github.com>
Date: Fri, 13 Mar 2026 11:50:28 -0700
Subject: [PATCH] Add task UI delta metadata and resync regression coverage
---
...cy-technique-04-task-ui-delta-sync-plan.md | 13 +-
src/test/controller-task-ui-metadata.test.ts | 67 ++++++++
.../context/ExtensionStateContext.test.tsx | 155 ++++++++++++++----
3 files changed, 198 insertions(+), 37 deletions(-)
create mode 100644 src/test/controller-task-ui-metadata.test.ts
diff --git a/docs/remote-workspace-latency-technique-04-task-ui-delta-sync-plan.md b/docs/remote-workspace-latency-technique-04-task-ui-delta-sync-plan.md
index fe6527342a..1de170f883 100644
--- a/docs/remote-workspace-latency-technique-04-task-ui-delta-sync-plan.md
+++ b/docs/remote-workspace-latency-technique-04-task-ui-delta-sync-plan.md
@@ -272,8 +272,8 @@ Keep the fallback path boring and reliable. Smart engineering here means preferr
### Tests
-- [ ] Unit test: metadata delta publishes for current active task.
-- [ ] Unit test: mismatched/non-active task falls back to snapshot path.
+- [x] Unit test: metadata delta publishes for current active task.
+- [x] Unit test: mismatched/non-active task falls back to snapshot path.
---
@@ -351,8 +351,8 @@ This step is essential to keeping the rest of Cline’s product surfaces healthy
### Tests
- [x] Regression test: initial load hydrates correctly without prior deltas.
-- [ ] Regression test: reopening or task switching still works.
-- [ ] Regression test: full snapshot repairs intentionally diverged delta state.
+- [x] Regression test: reopening or task switching still works.
+- [x] Regression test: full snapshot repairs intentionally diverged delta state.
---
@@ -471,12 +471,13 @@ That is why this technique still matters for large-file-write scenarios, even th
- Added extraction-branch follow-up coverage in commit `8839a5bf6` (`Add task UI delta sync test coverage and env flag helper`), including backend delta broadcaster tests, latency/env-flag helper coverage, reducer sequencing tests, and a webview context delta hydration test.
- Added latency-analysis helpers and validation scripts for comparing delta-enabled vs delta-disabled runs (`src/services/telemetry/taskLatencySummary.ts`, `scripts/validate-latency-scenarios.ts`, `scripts/analyze-task-latency-metrics.mjs`, and `scripts/compare-task-latency-metrics.mjs`).
- Added message-state regression coverage in commit `cdee38396` (`Add message-state task UI delta regression tests`) and fixed verification follow-up issues in commit `5548080d9`.
+- Added controller metadata delta coverage (`src/test/controller-task-ui-metadata.test.ts`) plus webview resync/task-switch regression coverage in `webview-ui/src/context/ExtensionStateContext.test.tsx`.
- Wired focus-chain metadata and background-command metadata through task-specific delta publication, with snapshot fallback when task identity is ambiguous.
- Preserved snapshot hydration/resync semantics alongside delta application and added frontend debug counters for snapshot, partial-message, delta, and resync activity.
- Installed dependencies, regenerated protos, and verified the focused backend and webview coverage locally. Successful verification included:
- - `npm run test:unit -- src/core/controller/ui/subscribeToTaskUiDeltas.test.ts src/test/message-state-handler.test.ts src/core/task/__tests__/latency.test.ts src/services/telemetry/__tests__/taskLatencySummary.test.ts`
+ - `npm run test:unit -- src/test/controller-task-ui-metadata.test.ts src/core/controller/ui/subscribeToTaskUiDeltas.test.ts src/test/message-state-handler.test.ts src/core/task/__tests__/latency.test.ts src/services/telemetry/__tests__/taskLatencySummary.test.ts`
- `cd webview-ui && npm run test -- src/context/taskUiDeltaState.test.ts src/context/ExtensionStateContext.test.tsx`
-- The webview verification passes, but still emits React `act(...)` warnings in `ExtensionStateContext.test.tsx`; these are test-harness hygiene issues rather than functional failures.
+- The webview verification now passes without the earlier React `act(...)` warning noise after wrapping streamed state updates in `act(...)`.
---
diff --git a/src/test/controller-task-ui-metadata.test.ts b/src/test/controller-task-ui-metadata.test.ts
new file mode 100644
index 0000000000..efc2d340ed
--- /dev/null
+++ b/src/test/controller-task-ui-metadata.test.ts
@@ -0,0 +1,67 @@
+import { describe, it } from "mocha"
+import "should"
+import * as sinon from "sinon"
+import { Controller } from "../core/controller"
+import * as taskUiDeltaModule from "../core/controller/ui/subscribeToTaskUiDeltas"
+
+describe("Controller.postTaskMetadataDelta", () => {
+ it("publishes metadata deltas for the current active task", async () => {
+ const sendTaskUiDeltaStub = sinon.stub(taskUiDeltaModule, "sendTaskUiDelta").resolves(undefined)
+ const postStateToWebview = sinon.stub().resolves()
+
+ const fakeController = {
+ task: {
+ taskId: "task-1",
+ taskState: {
+ taskUiDeltaSequence: 0,
+ },
+ },
+ postStateToWebview,
+ }
+
+ await Controller.prototype.postTaskMetadataDelta.call(fakeController as any, {
+ backgroundCommandRunning: true,
+ backgroundCommandTaskId: "task-1",
+ })
+
+ sinon.assert.calledOnce(sendTaskUiDeltaStub)
+ sinon.assert.calledWithExactly(sendTaskUiDeltaStub, {
+ type: "task_metadata_updated",
+ taskId: "task-1",
+ sequence: 1,
+ metadata: {
+ backgroundCommandRunning: true,
+ backgroundCommandTaskId: "task-1",
+ },
+ })
+ sinon.assert.notCalled(postStateToWebview)
+
+ sendTaskUiDeltaStub.restore()
+ })
+
+ it("falls back to posting full state when task identity is missing or mismatched", async () => {
+ const sendTaskUiDeltaStub = sinon.stub(taskUiDeltaModule, "sendTaskUiDelta").resolves(undefined)
+ const postStateToWebview = sinon.stub().resolves()
+
+ const fakeController = {
+ task: {
+ taskId: "task-1",
+ taskState: {
+ taskUiDeltaSequence: 4,
+ },
+ },
+ postStateToWebview,
+ }
+
+ await Controller.prototype.postTaskMetadataDelta.call(
+ fakeController as any,
+ { currentFocusChainChecklist: "- [x] one" },
+ "task-2",
+ )
+
+ sinon.assert.notCalled(sendTaskUiDeltaStub)
+ sinon.assert.calledOnce(postStateToWebview)
+
+ sendTaskUiDeltaStub.restore()
+ })
+})
diff --git a/webview-ui/src/context/ExtensionStateContext.test.tsx b/webview-ui/src/context/ExtensionStateContext.test.tsx
index 8c721acaac..56c85e58ae 100644
--- a/webview-ui/src/context/ExtensionStateContext.test.tsx
+++ b/webview-ui/src/context/ExtensionStateContext.test.tsx
@@ -1,4 +1,4 @@
-import { render, screen, waitFor } from "@testing-library/react"
+import { act, render, screen, waitFor } from "@testing-library/react"
import { describe, expect, it, vi } from "vitest"
import { ExtensionStateContextProvider, useExtensionState } from "./ExtensionStateContext"
@@ -90,26 +90,30 @@ describe("ExtensionStateContextProvider", () => {
,
)
- subscriptions.state?.onResponse?.({
- stateJson: JSON.stringify({
- version: "initial",
- clineMessages: [],
- currentTaskItem: { id: "task-1" },
- backgroundCommandRunning: false,
- }),
+ await act(async () => {
+ subscriptions.state?.onResponse?.({
+ stateJson: JSON.stringify({
+ version: "initial",
+ clineMessages: [],
+ currentTaskItem: { id: "task-1" },
+ backgroundCommandRunning: false,
+ }),
+ })
})
await waitFor(() => {
expect(screen.getByTestId("version").textContent).toBe("initial")
})
- subscriptions.delta?.onResponse?.({
- deltaJson: JSON.stringify({
- type: "message_added",
- taskId: "task-1",
- sequence: 1,
- message: { ts: 1, type: "say", say: "text", text: "hello" },
- }),
+ await act(async () => {
+ subscriptions.delta?.onResponse?.({
+ deltaJson: JSON.stringify({
+ type: "message_added",
+ taskId: "task-1",
+ sequence: 1,
+ message: { ts: 1, type: "say", say: "text", text: "hello" },
+ }),
+ })
})
await waitFor(() => {
@@ -117,21 +121,23 @@ describe("ExtensionStateContextProvider", () => {
expect(screen.getByTestId("latest-message").textContent).toBe("hello")
})
- subscriptions.delta?.onResponse?.({
- deltaJson: JSON.stringify({
- type: "message_updated",
- taskId: "task-1",
- sequence: 2,
- message: { ts: 1, type: "say", say: "text", text: "hello world" },
- }),
- })
- subscriptions.delta?.onResponse?.({
- deltaJson: JSON.stringify({
- type: "task_metadata_updated",
- taskId: "task-1",
- sequence: 3,
- metadata: { backgroundCommandRunning: true, backgroundCommandTaskId: "task-1" },
- }),
+ await act(async () => {
+ subscriptions.delta?.onResponse?.({
+ deltaJson: JSON.stringify({
+ type: "message_updated",
+ taskId: "task-1",
+ sequence: 2,
+ message: { ts: 1, type: "say", say: "text", text: "hello world" },
+ }),
+ })
+ subscriptions.delta?.onResponse?.({
+ deltaJson: JSON.stringify({
+ type: "task_metadata_updated",
+ taskId: "task-1",
+ sequence: 3,
+ metadata: { backgroundCommandRunning: true, backgroundCommandTaskId: "task-1" },
+ }),
+ })
})
await waitFor(() => {
@@ -139,4 +145,91 @@ describe("ExtensionStateContextProvider", () => {
expect(screen.getByTestId("background-command").textContent).toBe("true")
})
})
-})
\ No newline at end of file
+
+ it("requests a full-state resync when a delta sequence gap is detected", async () => {
+ render(
+
+
+ ,
+ )
+
+ await act(async () => {
+ subscriptions.state?.onResponse?.({
+ stateJson: JSON.stringify({
+ version: "initial",
+ clineMessages: [],
+ currentTaskItem: { id: "task-1" },
+ }),
+ })
+ })
+
+ await act(async () => {
+ subscriptions.delta?.onResponse?.({
+ deltaJson: JSON.stringify({
+ type: "message_added",
+ taskId: "task-1",
+ sequence: 2,
+ message: { ts: 2, type: "say", say: "text", text: "should trigger resync" },
+ }),
+ })
+ })
+
+ await waitFor(() => {
+ expect(screen.getByTestId("version").textContent).toBe("resynced")
+ expect(screen.getByTestId("latest-message").textContent).toBe("resynced")
+ })
+ })
+
+ it("resets delta sequencing when a full snapshot switches to a different task", async () => {
+ render(
+
+
+ ,
+ )
+
+ await act(async () => {
+ subscriptions.state?.onResponse?.({
+ stateJson: JSON.stringify({
+ version: "task-1-state",
+ clineMessages: [],
+ currentTaskItem: { id: "task-1" },
+ }),
+ })
+ subscriptions.delta?.onResponse?.({
+ deltaJson: JSON.stringify({
+ type: "message_added",
+ taskId: "task-1",
+ sequence: 1,
+ message: { ts: 1, type: "say", say: "text", text: "task one" },
+ }),
+ })
+ })
+
+ await waitFor(() => {
+ expect(screen.getByTestId("latest-message").textContent).toBe("task one")
+ })
+
+ await act(async () => {
+ subscriptions.state?.onResponse?.({
+ stateJson: JSON.stringify({
+ version: "task-2-state",
+ clineMessages: [],
+ currentTaskItem: { id: "task-2" },
+ }),
+ })
+ subscriptions.delta?.onResponse?.({
+ deltaJson: JSON.stringify({
+ type: "message_added",
+ taskId: "task-2",
+ sequence: 1,
+ message: { ts: 2, type: "say", say: "text", text: "task two" },
+ }),
+ })
+ })
+
+ await waitFor(() => {
+ expect(screen.getByTestId("version").textContent).toBe("task-2-state")
+ expect(screen.getByTestId("latest-message").textContent).toBe("task two")
+ })
+ })
+})