COD-52 fix: wire maxTodos + todoExpirationMinutes through ralph-config to the tracker

The Ralph settings modal sent maxTodos/todoExpirationMinutes but RalphConfigSchema
(zod) stripped them and the ralph-config route never applied them, so the inputs
were silent no-ops.

Fix: add both as optional positive-int fields to RalphConfigSchema; destructure
and apply them in the ralph-config route (matching the maxIterations pattern).
RalphTracker had no setters (the values were module constants) — added per-instance
_maxTodos/_todoExpiryMs (defaulting to the same constants, behavior unchanged),
switched the eviction + expiry sites to read them, and added
setMaxTodos/setTodoExpirationMinutes (minutes→ms) + getters.

Test: route test POSTs the two fields and asserts the route applies them to the
tracker. Verified RED (setters not called — fields stripped) → GREEN. 34/34
ralph-routes tests pass; tsc + eslint(src) + prettier + build clean. Frontend
already sent the fields (no change).
This commit is contained in:
Aamer Akhter
2026-06-19 18:00:29 -04:00
parent 1255e28f6f
commit 509595b837
4 changed files with 78 additions and 14 deletions
+21
View File
@@ -21,6 +21,8 @@ function createMockRalphTracker() {
disableAutoEnable: vi.fn(),
startLoop: vi.fn(),
setMaxIterations: vi.fn(),
setMaxTodos: vi.fn(),
setTodoExpirationMinutes: vi.fn(),
resetCircuitBreaker: vi.fn(),
generateFixPlanMarkdown: vi.fn(() => '# Fix Plan\n\n- [ ] Task 1\n'),
importFixPlanMarkdown: vi.fn(() => 3),
@@ -158,6 +160,25 @@ describe('ralph-routes', () => {
expect(tracker.setMaxIterations).toHaveBeenCalledWith(50);
});
it('applies maxTodos and todoExpirationMinutes to the tracker (COD-52)', async () => {
const tracker = (harness.ctx._session as Record<string, unknown>).ralphTracker as ReturnType<
typeof createMockRalphTracker
>;
const res = await harness.app.inject({
method: 'POST',
url: `/api/sessions/${harness.ctx._sessionId}/ralph-config`,
payload: { maxTodos: 25, todoExpirationMinutes: 90 },
});
expect(res.statusCode).toBe(200);
const body = JSON.parse(res.body);
// The ralph-config success path returns a bare {} envelope (matching its
// sibling config routes); an error would surface as { success: false }.
expect(body.success).not.toBe(false);
expect(tracker.setMaxTodos).toHaveBeenCalledWith(25);
expect(tracker.setTodoExpirationMinutes).toHaveBeenCalledWith(90);
});
it('returns error for unknown session', async () => {
const res = await harness.app.inject({
method: 'POST',