fix(016-load-concurrency-testing): US3 — finish escalation idempotency plumbing

Completes the escalation-event repository/service changes from the prior
commit: normalizes the exactOptionalPropertyTypes mismatch in the
findFirst fallback lookup, and updates every existing unit test
(sla-pause-resume, sla-breach-detection, sla-compliance-metric,
escalation-rule-match) to the new SlaRunRepository.updateWithVersion and
EscalationEventRepository.create({event, wasNewlyCreated}) signatures.
Full typecheck/lint/architecture-check clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
saqib mir
2026-09-10 11:13:46 +05:30
co-authored by Claude Sonnet 5
parent 794e16f349
commit 93d6fe8b94
5 changed files with 31 additions and 23 deletions
@@ -50,7 +50,10 @@ export class EscalationEventRepository {
if (!isDuplicateRuleEscalationConflict(error)) throw error;
const existing = await this.prisma.escalationEvent.findFirst({
where: { ticketId: data.ticketId, ruleId: data.ruleId },
where: {
ticketId: data.ticketId,
...(data.ruleId !== undefined ? { ruleId: data.ruleId } : {}),
},
});
if (!existing) throw error; // conflict raced with a delete — surface the original error.
return { event: existing, wasNewlyCreated: false };
@@ -7,6 +7,7 @@ function fakeRun(overrides: Partial<Record<string, unknown>> = {}) {
id: 'run-1',
ticketId: 'ticket-1',
status: 'running',
version: 1,
...overrides,
};
}
@@ -20,7 +21,7 @@ describe('SLA compliance metric (014-full-observability data-model.md #6)', () =
const incSpy = vi.spyOn(observability.slaRunOutcomesCounter, 'inc');
const runs = {
findByTicketId: vi.fn().mockResolvedValue(fakeRun({ status: 'running' })),
update: vi.fn().mockResolvedValue(undefined),
updateWithVersion: vi.fn().mockResolvedValue(fakeRun({ status: 'completed' })),
} as never;
const service = new SlaService(undefined, runs);
@@ -33,7 +34,7 @@ describe('SLA compliance metric (014-full-observability data-model.md #6)', () =
const incSpy = vi.spyOn(observability.slaRunOutcomesCounter, 'inc');
const runs = {
findByTicketId: vi.fn().mockResolvedValue(fakeRun({ status: 'breached' })),
update: vi.fn().mockResolvedValue(undefined),
updateWithVersion: vi.fn().mockResolvedValue(fakeRun({ status: 'completed' })),
} as never;
const service = new SlaService(undefined, runs);
@@ -46,13 +47,13 @@ describe('SLA compliance metric (014-full-observability data-model.md #6)', () =
const incSpy = vi.spyOn(observability.slaRunOutcomesCounter, 'inc');
const runs = {
findByTicketId: vi.fn().mockResolvedValue(fakeRun({ status: 'completed' })),
update: vi.fn().mockResolvedValue(undefined),
updateWithVersion: vi.fn().mockResolvedValue(undefined),
} as never;
const service = new SlaService(undefined, runs);
await service.complete('ticket-1');
expect(incSpy).not.toHaveBeenCalled();
expect((runs as unknown as { update: ReturnType<typeof vi.fn> }).update).not.toHaveBeenCalled();
expect((runs as unknown as { updateWithVersion: ReturnType<typeof vi.fn> }).updateWithVersion).not.toHaveBeenCalled();
});
});
@@ -19,7 +19,9 @@ describe('EscalationService.handleBreach', () => {
findApplicable: vi.fn().mockResolvedValue({ id: 'policy-1', productId: 'prod-1' }),
} as never;
const rules = { findActiveRules: vi.fn().mockResolvedValue([rule]) } as never;
const events = { create: vi.fn().mockResolvedValue({ id: 'event-1' }) } as never;
const events = {
create: vi.fn().mockResolvedValue({ event: { id: 'event-1' }, wasNewlyCreated: true }),
} as never;
const assignmentEngine = {
assignToSpecificNode: vi.fn().mockResolvedValue(undefined),
} as never;
@@ -10,6 +10,7 @@ function run(overrides: Partial<SLARun>): SLARun {
firstResponseDueAt: null,
resolutionDueAt: null,
status: 'running',
version: 1,
pausedAt: null,
resumedAt: null,
breachedAt: null,
@@ -22,11 +23,11 @@ function run(overrides: Partial<SLARun>): SLARun {
describe('SlaService.runBreachDetectionSweep', () => {
it('marks every running run past its resolution due date as breached and fires escalation', async () => {
const overdue = run({ id: 'r1', ticketId: 't1' });
const update = vi.fn().mockResolvedValue(overdue);
const updateWithVersion = vi.fn().mockResolvedValue(overdue);
const runsRepo = {
findRunningPastResolutionDueAt: vi.fn().mockResolvedValue([overdue]),
findRunningPastFirstResponseDueAt: vi.fn().mockResolvedValue([]),
update,
updateWithVersion,
} as never;
const handleBreach = vi.fn().mockResolvedValue(undefined);
const escalation = { handleBreach } as never;
@@ -34,7 +35,7 @@ describe('SlaService.runBreachDetectionSweep', () => {
const service = new SlaService(undefined, runsRepo, undefined, undefined, escalation);
await service.runBreachDetectionSweep();
expect(update).toHaveBeenCalledWith('r1', expect.objectContaining({ status: 'breached' }));
expect(updateWithVersion).toHaveBeenCalledWith('r1', 1, expect.objectContaining({ status: 'breached' }));
expect(handleBreach).toHaveBeenCalledWith('t1', 'resolution_breach');
});
@@ -42,7 +43,7 @@ describe('SlaService.runBreachDetectionSweep', () => {
const runsRepo = {
findRunningPastResolutionDueAt: vi.fn().mockResolvedValue([]),
findRunningPastFirstResponseDueAt: vi.fn().mockResolvedValue([]),
update: vi.fn(),
updateWithVersion: vi.fn(),
} as never;
const handleBreach = vi.fn();
const service = new SlaService(undefined, runsRepo, undefined, undefined, {
@@ -10,6 +10,7 @@ function run(overrides: Partial<SLARun>): SLARun {
firstResponseDueAt: new Date('2026-01-05T12:00:00.000Z'),
resolutionDueAt: new Date('2026-01-05T17:00:00.000Z'),
status: 'running',
version: 1,
pausedAt: null,
resumedAt: null,
breachedAt: null,
@@ -22,13 +23,13 @@ function run(overrides: Partial<SLARun>): SLARun {
describe('SlaService pause/resume', () => {
it('pause records pausedAt and flips status to paused', async () => {
const found = run({});
const update = vi.fn().mockResolvedValue(found);
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(found), update } as never;
const updateWithVersion = vi.fn().mockResolvedValue(found);
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(found), updateWithVersion } as never;
const service = new SlaService(undefined, runsRepo);
await service.pause('ticket-1');
expect(update).toHaveBeenCalledWith('run-1', expect.objectContaining({ status: 'paused' }));
expect(updateWithVersion).toHaveBeenCalledWith('run-1', 1, expect.objectContaining({ status: 'paused' }));
});
it('resume shifts both due dates forward by exactly the paused wall-clock duration', async () => {
@@ -39,16 +40,16 @@ describe('SlaService pause/resume', () => {
firstResponseDueAt: new Date('2026-01-05T12:00:00.000Z'),
resolutionDueAt: new Date('2026-01-05T17:00:00.000Z'),
});
const update = vi.fn().mockResolvedValue(paused);
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(paused), update } as never;
const updateWithVersion = vi.fn().mockResolvedValue(paused);
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(paused), updateWithVersion } as never;
const service = new SlaService(undefined, runsRepo);
const before = Date.now();
await service.resume('ticket-1');
const after = Date.now();
expect(update).toHaveBeenCalledTimes(1);
const [, patch] = update.mock.calls[0] as [string, Record<string, unknown>];
expect(updateWithVersion).toHaveBeenCalledTimes(1);
const [, , patch] = updateWithVersion.mock.calls[0] as [string, number, Record<string, unknown>];
expect(patch.status).toBe('running');
expect(patch.pausedAt).toBeNull();
@@ -74,13 +75,13 @@ describe('SlaService pause/resume', () => {
status: 'paused',
pausedAt: secondPausedAt,
} as SLARun;
const update = vi.fn().mockResolvedValue(pausedAgain);
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(pausedAgain), update } as never;
const updateWithVersion = vi.fn().mockResolvedValue(pausedAgain);
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(pausedAgain), updateWithVersion } as never;
const service = new SlaService(undefined, runsRepo);
await service.resume('ticket-1');
const [, patch] = update.mock.calls[0] as [string, Record<string, unknown>];
const [, , patch] = updateWithVersion.mock.calls[0] as [string, number, Record<string, unknown>];
const shifted = (patch.resolutionDueAt as Date).getTime();
// Must be shifted from the ALREADY-shifted 18:00 baseline, not the original 17:00 baseline.
expect(shifted).toBeGreaterThan(new Date('2026-01-05T18:00:00.000Z').getTime());
@@ -88,11 +89,11 @@ describe('SlaService pause/resume', () => {
it('never resumes a run that is not currently paused', async () => {
const runningRun = run({ status: 'running', pausedAt: null });
const update = vi.fn();
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(runningRun), update } as never;
const updateWithVersion = vi.fn();
const runsRepo = { findByTicketId: vi.fn().mockResolvedValue(runningRun), updateWithVersion } as never;
const service = new SlaService(undefined, runsRepo);
await service.resume('ticket-1');
expect(update).not.toHaveBeenCalled();
expect(updateWithVersion).not.toHaveBeenCalled();
});
});