Files
bermudalambandClaude Opus 5 55cb7eaa13 feat(intake): count submissions across every link, and alert on abnormal volume (#227)
The count comes from item_drafts rather than a tally. Every submission creates exactly one row in the same transaction that creates the item, so the rows are the truth — a separate counter would be a second thing that can disagree with them, and the one that disagrees silently is always the counter.

windowStart is the part worth testing on its own and the part most likely to be quietly wrong. A reset older than the window must not widen it, which would make the ceiling stricter over time rather than rolling; a reset in the future must not disable it; and a malformed value must not produce an Invalid Date, which compares false against everything and would silently switch off the limit it was set to impose. Each is a test.

Alerts go through sendMail directly rather than the editable templates. An abuse alert is not copy anyone will want to reword, and making it editable means it can be broken — a required placeholder removed from an alert nobody reads until an incident is a poor way to discover the validation.

The throttle is in memory, so a restart during an incident can send one extra alert. That beats writing to admin_settings from the request path on every refused submission; a replicated deployment would have to move it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 16:20:44 -05:00

38 lines
1.5 KiB
TypeScript

import { windowStart, WINDOW_MS } from '../../src/intake/capacity';
const NOW = new Date('2026-09-01T12:00:00.000Z');
const DAY_AGO = new Date(NOW.getTime() - WINDOW_MS);
describe('windowStart', () => {
it('is 24 hours ago when there has been no reset', () => {
expect(windowStart(NOW, '').toISOString()).toBe(DAY_AGO.toISOString());
});
// A reset inside the window is the point of it: it forgives what came before
// without deleting anything.
it('is the reset when the reset is more recent', () => {
const reset = '2026-09-01T09:00:00.000Z';
expect(windowStart(NOW, reset).toISOString()).toBe(reset);
});
// An old reset must not widen the window beyond 24 hours, which would make
// the ceiling stricter over time rather than rolling.
it('ignores a reset older than the window', () => {
expect(windowStart(NOW, '2026-08-01T00:00:00.000Z').toISOString()).toBe(DAY_AGO.toISOString());
});
// A malformed stored value must not produce an Invalid Date, which compares
// false against everything and would silently disable the ceiling.
it('falls back to 24 hours ago for an unparseable reset', () => {
expect(windowStart(NOW, 'not-a-date').toISOString()).toBe(DAY_AGO.toISOString());
});
it('falls back for a reset in the future', () => {
expect(windowStart(NOW, '2027-01-01T00:00:00.000Z').toISOString()).toBe(DAY_AGO.toISOString());
});
it('tolerates whitespace around an empty setting', () => {
expect(windowStart(NOW, ' ').toISOString()).toBe(DAY_AGO.toISOString());
});
});