diff --git a/src/config.test.ts b/src/config.test.ts index e958ffd..6f21f11 100644 --- a/src/config.test.ts +++ b/src/config.test.ts @@ -29,6 +29,7 @@ describe('config/env loading', () => { delete process.env.DISCORD_CODEX_MAIN_BOT_TOKEN; delete process.env.DISCORD_REVIEW_BOT_TOKEN; delete process.env.DISCORD_CODEX_REVIEW_BOT_TOKEN; + delete process.env.PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL; delete process.env.SESSION_COMMAND_USER_IDS; vi.resetModules(); }); @@ -102,6 +103,16 @@ describe('config/env loading', () => { expect(config.TIMEZONE).toBe('UTC'); }); + it('defaults latest-owner-final carry-forward to disabled and honors explicit opt-in', async () => { + let config = await import('./config.js'); + expect(config.PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL).toBe(false); + + vi.resetModules(); + process.env.PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL = 'true'; + config = await import('./config.js'); + expect(config.PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL).toBe(true); + }); + it('fails fast when a legacy Discord token alias is configured', async () => { process.env.DISCORD_BOT_TOKEN = 'legacy-owner-token'; diff --git a/src/config.ts b/src/config.ts index ae928b9..ce5272e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -76,6 +76,10 @@ export const ARBITER_AGENT_TYPE = CONFIG.paired.arbiterAgentType; /** Service ID for the arbiter. Defaults to codex-review for internal routing when arbiter is enabled. */ export const ARBITER_SERVICE_ID = CONFIG.paired.arbiterServiceId; +/** Whether to re-inject the previous task's latest owner final into a superseding task. Default: false. */ +export const PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL = + CONFIG.paired.carryForwardLatestOwnerFinal; + /** Language for agent responses. When set, a language instruction is appended to all paired room prompts. */ export const AGENT_LANGUAGE = CONFIG.paired.agentLanguage; diff --git a/src/config/load-config.ts b/src/config/load-config.ts index 58b7d7a..fa7297f 100644 --- a/src/config/load-config.ts +++ b/src/config/load-config.ts @@ -223,6 +223,10 @@ export function loadConfig(): AppConfig { arbiterServiceId: arbiterAgentType ? (readText('ARBITER_SERVICE_ID') ?? codexReviewServiceId) : null, + carryForwardLatestOwnerFinal: readBoolean( + 'PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL', + false, + ), agentLanguage: readText('AGENT_LANGUAGE') ?? '', arbiterDeadlockThreshold: readInteger('ARBITER_DEADLOCK_THRESHOLD', 2), maxRoundTrips, diff --git a/src/config/schema.ts b/src/config/schema.ts index d659a6f..c2f07ae 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -53,6 +53,7 @@ export interface AppConfig { reviewerServiceIdForType: string; arbiterAgentType?: AgentType; arbiterServiceId: string | null; + carryForwardLatestOwnerFinal: boolean; agentLanguage: string; arbiterDeadlockThreshold: number; maxRoundTrips: number; diff --git a/src/paired-execution-context.test.ts b/src/paired-execution-context.test.ts index 376c186..bfee801 100644 --- a/src/paired-execution-context.test.ts +++ b/src/paired-execution-context.test.ts @@ -253,7 +253,7 @@ describe('paired execution context', () => { }); }); - it('carries forward the latest owner final when a merge_ready task is superseded by new human input', () => { + it('does not carry forward the latest owner final by default when a merge_ready task is superseded by new human input', () => { const supersededTask = buildPairedTask({ id: 'task-superseded', status: 'merge_ready', @@ -290,13 +290,7 @@ describe('paired execution context', () => { expect(db.createPairedTask).toHaveBeenCalledTimes(1); expect(result.supersededTask).toEqual(supersededTask); - expect(db.insertPairedTurnOutput).toHaveBeenCalledWith( - expect.any(String), - 0, - 'owner', - '[Carried forward context from the previous task: latest owner final]\nDONE_WITH_CONCERNS\n이전 task owner final', - '2026-03-28T00:01:00.000Z', - ); + expect(db.insertPairedTurnOutput).not.toHaveBeenCalled(); }); it('uses room role context agent overrides when creating a paired task', () => { diff --git a/src/paired-execution-context.ts b/src/paired-execution-context.ts index 972b52f..45038e3 100644 --- a/src/paired-execution-context.ts +++ b/src/paired-execution-context.ts @@ -14,6 +14,7 @@ import { CODEX_MAIN_SERVICE_ID, CODEX_REVIEW_SERVICE_ID, DATA_DIR, + PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL, PAIRED_MAX_ROUND_TRIPS, REVIEWER_AGENT_TYPE, } from './config.js'; @@ -207,6 +208,10 @@ function carryForwardLatestOwnerFinal(args: { sourceTask: PairedTask; targetTask: PairedTask; }): void { + if (!PAIRED_CARRY_FORWARD_LATEST_OWNER_FINAL) { + return; + } + const latestOwnerFinal = getLatestTurnOutputByRole( args.sourceTask.id, 'owner',