tests/post-merge.test.ts
Rama main · réplica de lectura del repositorio original.
import assert from 'node:assert/strict';
import test from 'node:test';
import { evaluateGoals } from '../src/application/evaluation.js';
import { trackPostMerge } from '../src/application/post-merge.js';
import type { AutomationDependencies } from '../src/application/automation.js';
import { executeGoals } from '../src/cli/commands/goals.js';
import { configSchema } from '../src/domain/config.js';
import type { GoalState } from '../src/domain/iteration.js';
import type { IterationStore } from '../src/ports/iteration.js';
import { pr } from './helpers.js';
function goal(id = 'a'.repeat(24)): GoalState {
return { schemaVersion: 1, id, repository: 'owner/repo', configHash: 'config',
spec: { title: 'Implement benchmark behavior', objective: 'Implement benchmark behavior safely.', mode: 'feature',
acceptance: [{ id: 'works', text: 'The benchmark behavior works correctly.' }], allowedPaths: ['src'],
evaluation: { suite: 'core-suite', case: 'feature-case', profile: 'codex-default' } },
branch: 'main', sha: pr.base.sha, createdAt: '2026-01-01T00:00:00Z', updatedAt: '2026-01-01T00:00:00Z',
status: 'published', steps: [{ id: 'works', title: 'Implement benchmark behavior', acceptanceIds: ['works'], dependsOn: [] }],
completed: ['works'], changes: [], reports: [], rounds: 2, calls: 3, tokens: 100, elapsedMs: 500,
notes: [], publication: 'b'.repeat(24), pullRequestUrl: 'https://github.com/owner/repo/pull/1' };
}
function memoryStore(state: GoalState): IterationStore {
return { read: async id => id === state.id ? state : undefined, save: async next => { Object.assign(state, next); },
list: async () => [state], pause: async () => {}, paused: async () => false, unpause: async () => {},
remember: async () => {}, experiences: async () => [] };
}
test('post-merge tracking waits for merge evidence, verifies the merge commit and records regressions', async () => {
const state = goal(), goals = memoryStore(state), merged = 'c'.repeat(40);
let pull = { ...pr, head: { ...pr.head, ref: `autofix/goal-${state.id}/${state.publication}` },
state: 'open', merged_at: null as string | null, merge_commit_sha: null as string | null };
let checks = [{ name: 'tests', status: 'completed', conclusion: 'success' as string | null }], issueState = 'open';
const github = { target: async () => ({ branch: 'main', sha: pr.base.sha }), issue: async () => ({ number: 7, title: 'Issue title', body: '', state: issueState }),
issues: async () => [], feedback: async () => { throw new Error('Unexpected feedback'); }, updatePull: async () => undefined,
recoverPull: async () => undefined, propose: async () => '', outcome: async () => ({ pr: pull, checks }) };
const deps = { repository: 'owner/repo', requiredChecks: ['tests'], requireIssueClosed: true, goals, github };
assert.equal((await trackPostMerge(state.id, deps))?.status, 'waiting_for_merge');
state.spec.issue = 7;
pull = { ...pull, state: 'closed', merged_at: '2026-01-02T00:00:00Z', merge_commit_sha: merged };
checks = [{ name: 'tests', status: 'in_progress', conclusion: null }];
assert.equal((await trackPostMerge(state.id, deps))?.status, 'observing');
checks = [{ name: 'tests', status: 'completed', conclusion: 'failure' }];
assert.equal((await trackPostMerge(state.id, deps))?.status, 'regressed');
assert.match(state.notes.at(-1)!, /Post-merge regression/);
const notes = state.notes.length;
await trackPostMerge(state.id, deps);
assert.equal(state.notes.length, notes, 'repeated polling must not duplicate regression notes');
checks = [{ name: 'tests', status: 'completed', conclusion: 'success' }]; issueState = 'closed';
const healthy = await trackPostMerge(state.id, deps);
assert.equal(healthy?.status, 'healthy'); assert.equal(healthy?.mergeSha, merged);
});
test('evaluation reports deterministic evidence by suite and profile', () => {
const healthy = goal(), failed = goal('b'.repeat(24));
healthy.postMerge = { pull: 1, status: 'healthy', mergeSha: 'c'.repeat(40), checkedAt: '2026-01-02T00:00:00Z', checks: [], reasons: [] };
failed.spec.evaluation = { suite: 'core-suite', case: 'bug-case', profile: 'codex-default' };
failed.status = 'needs_attention'; failed.completed = [];
const report = evaluateGoals([failed, healthy], 'core-suite');
assert.equal(report.records.length, 2); assert.equal(report.profiles[0]?.verificationRate, 0.5);
assert.equal(report.profiles[0]?.postMergePassRate, 1); assert.equal(report.profiles[0]?.averageCalls, 3);
assert.equal(report.digest, evaluateGoals([healthy, failed], 'core-suite').digest);
assert.deepEqual(report.duplicateKeys, []); assert.deepEqual(report.inconsistentCases, []);
});
test('iteration switches a merged goal from PR maintenance to post-merge tracking', async () => {
const state = goal(), goals = memoryStore(state), merge = 'd'.repeat(40);
const config = configSchema.parse({ repository: state.repository, iteration: { postMerge: { requiredChecks: ['tests'] } } });
const owned = { ...pr, head: { ...pr.head, ref: `autofix/goal-${state.id}/${state.publication}` }, state: 'closed',
merged_at: '2026-01-02T00:00:00Z', merge_commit_sha: merge };
const deps: AutomationDependencies = { config, goals, signal: new AbortController().signal,
store: {} as AutomationDependencies['store'], repository: {} as AutomationDependencies['repository'],
github: { listPulls: async () => [], pull: async () => owned, current: async () => undefined, publish: async () => undefined,
target: async () => ({ branch: 'main', sha: pr.base.sha }), issue: async () => { throw new Error('Unexpected Issue read'); },
issues: async () => [], feedback: async () => { throw new Error('Unexpected feedback'); }, updatePull: async () => undefined,
recoverPull: async () => undefined, propose: async () => '',
outcome: async () => ({ pr: owned, checks: [{ name: 'tests', status: 'completed', conclusion: 'success' }] }) } };
const output: string[] = [];
assert.equal(await executeGoals('iterate', undefined, undefined, { once: true }, deps,
{ write: value => output.push(value), error: value => assert.fail(value) }), 0);
assert.equal(state.postMerge?.status, 'healthy');
assert.equal(JSON.parse(output[0]!).mergeSha, merge);
});