From 74e54b713bcb74b6eaa2656ffd760bd57476bf85 Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 9 Oct 2026 02:16:33 -0500 Subject: [PATCH 1/2] test(server): load feedback routes within suite setup Co-Authored-By: Paperclip --- server/src/__tests__/issue-feedback-routes.test.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/server/src/__tests__/issue-feedback-routes.test.ts b/server/src/__tests__/issue-feedback-routes.test.ts index e59fe6d1e9..2260676d6f 100644 --- a/server/src/__tests__/issue-feedback-routes.test.ts +++ b/server/src/__tests__/issue-feedback-routes.test.ts @@ -1,6 +1,6 @@ import express from "express"; import request from "supertest"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const mockFeedbackService = vi.hoisted(() => ({ getFeedbackTraceById: vi.fn(), @@ -127,11 +127,19 @@ vi.mock("../services/instance-settings.js", () => ({ instanceSettingsService: () => mockInstanceSettingsService, })); -async function createApp(actor: Record) { - const [{ issueRoutes }, { errorHandler }] = await Promise.all([ +let issueRoutes: typeof import("../routes/issues.js")["issueRoutes"]; +let errorHandler: typeof import("../middleware/index.js")["errorHandler"]; + +beforeAll(async () => { + // Route initialization belongs to the suite's setup deadline. The vote and + // flush assertions retain the ordinary per-test request deadline on CI. + [{ issueRoutes }, { errorHandler }] = await Promise.all([ import("../routes/issues.js"), import("../middleware/index.js"), ]); +}); + +async function createApp(actor: Record) { const app = express(); app.use(express.json()); app.use((req, _res, next) => { From 3fce49c5b9ff3e397fec9862040e2a49a8169cd1 Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 9 Oct 2026 02:18:38 -0500 Subject: [PATCH 2/2] fix(runner): carry steering identity into Hermes parent Co-Authored-By: Paperclip --- .../src/live/runnerd-codex-transport.test.ts | 6 ++++++ .../paperclip-runner/src/live/runnerd-codex-transport.ts | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts index 9d8a8586de..60df48f8ee 100644 --- a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts +++ b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts @@ -2050,6 +2050,12 @@ it("restores provider identity and streamed text from a canonical delta", () => .toMatchObject({ threadId: "root-thread", turnId: "provider-turn", delta: "Reading Gmail", itemId: "message-1" }); }); +it("keeps a flat steering acknowledgement recognizable for deduplication", () => { + const receipt = { kind: "steering_acknowledgement", correlationId: "steer-1", status: "accepted" }; + expect(rehydrateRunnerdItemNotification(receipt, "opened-thread", "provider-turn")) + .toEqual({ ...receipt, threadId: "opened-thread", turnId: "provider-turn" }); +}); + it("rehydrates a canonical agent item for the strict Codex facade", () => { expect( rehydrateRunnerdItemNotification( diff --git a/packages/paperclip-runner/src/live/runnerd-codex-transport.ts b/packages/paperclip-runner/src/live/runnerd-codex-transport.ts index fcdbb4b04e..8c99af2755 100644 --- a/packages/paperclip-runner/src/live/runnerd-codex-transport.ts +++ b/packages/paperclip-runner/src/live/runnerd-codex-transport.ts @@ -1886,6 +1886,11 @@ export function rehydrateRunnerdItemNotification( activeTurnId: string, ): Record { const rawItem = record(rawParams.item); + if (rawParams.kind === "steering_acknowledgement" && Object.keys(rawItem).length === 0) { + // Preserve runnerd's flat receipt so the driver recognizes the transport + // echo. The acknowledged request emits the user-visible bound item once. + return { ...rawParams, threadId: openedThreadId, turnId: activeTurnId }; + } const channel = rawItem.channel ?? rawParams.channel; const providerPhase = rawItem.phase ?? rawParams.providerPhase; const phase = @@ -3663,7 +3668,9 @@ class DurablePrpCodexTransport implements CodexAppServerTransport { "turn.steer", { text, - turnId: this.#durableTurnId, + // ACPX owns the requested provider turn, which can differ from the + // durable PRP turn that scopes control-plane and semantic events. + turnId: this.options.provider === "acpx" ? expectedTurnId : this.#durableTurnId, providerTurnId: expectedTurnId, ...(params.mode === "follow_up" ? { mode: "follow_up" } : {}), ...(correlationId ? { correlationId } : {}),