paired: disable latest owner final carry-forward by default

This commit is contained in:
ejclaw
2026-04-22 05:51:43 +09:00
parent 8fff703f84
commit 1122ace363
6 changed files with 27 additions and 8 deletions

View File

@@ -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';

View File

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

View File

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

View File

@@ -53,6 +53,7 @@ export interface AppConfig {
reviewerServiceIdForType: string;
arbiterAgentType?: AgentType;
arbiterServiceId: string | null;
carryForwardLatestOwnerFinal: boolean;
agentLanguage: string;
arbiterDeadlockThreshold: number;
maxRoundTrips: number;

View File

@@ -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', () => {

View File

@@ -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',