Date: Wed, 14 Oct 2026 02:10:17 +0800
Subject: [PATCH 49/53] security+fixes: dedicated proxy claim signing key,
registrar teaching write lockdown migration, single 20261013140000 version,
safe numbers step every weekday, v2 answer threads kept with capped label
---
src/components/on-call/safe-number-editor.tsx | 34 +++++++----
src/lib/answer-thread-storage.ts | 26 ++++++++-
src/lib/env.ts | 2 +
src/lib/supabase/proxy-auth-crypto.ts | 5 +-
supabase/applied-migration-hashes.json | 6 +-
...le_always_release_records_immutability.sql | 4 --
...0000_registrar_teaching_write_lockdown.sql | 56 +++++++++++++++++++
tests/answer-thread-storage.test.ts | 38 +++++++------
tests/proxy-auth.test.ts | 34 ++++++++---
tests/safe-number-concurrency.test.ts | 18 +++++-
10 files changed, 176 insertions(+), 47 deletions(-)
delete mode 100644 supabase/migrations/20261013140000_enable_always_release_records_immutability.sql
create mode 100644 supabase/migrations/20261013170000_registrar_teaching_write_lockdown.sql
diff --git a/src/components/on-call/safe-number-editor.tsx b/src/components/on-call/safe-number-editor.tsx
index 24c08c945e..3612e70e34 100644
--- a/src/components/on-call/safe-number-editor.tsx
+++ b/src/components/on-call/safe-number-editor.tsx
@@ -65,13 +65,19 @@ export function SafeNumberEditor({
const isDirty = !sameSafeNumbers(currentGrid, confirmed);
const handleStepperChange = useCallback(
- (kind: SafeNumberKind, weekday: number, delta: number) => {
+ // Each row is the whole week (Monday to Sunday): the step applies to every weekday, so a
+ // row never reads as "all days" while only Monday changes. Days that differ keep their
+ // difference and each is clamped on its own.
+ (kind: SafeNumberKind, delta: number) => {
setSuccessMessage(null);
setErrorMessage(null);
setConflict(null);
- const currentValue = currentGrid[kind][weekday - 1] ?? 0;
- const nextValue = Math.max(0, Math.min(SAFE_NUMBER_MAX, currentValue + delta));
- setDraft(setSafeNumber(currentGrid, kind, [weekday], nextValue));
+ let next = currentGrid;
+ currentGrid[kind].forEach((currentValue, index) => {
+ const nextValue = Math.max(0, Math.min(SAFE_NUMBER_MAX, (currentValue ?? 0) + delta));
+ next = setSafeNumber(next, kind, [index + 1], nextValue);
+ });
+ setDraft(next);
},
[currentGrid],
);
@@ -202,7 +208,10 @@ export function SafeNumberEditor({
{SAFE_NUMBER_KINDS.map((kind) => {
const meta = KIND_METADATA[kind];
const Icon = meta.icon;
- const weekdayVal = currentGrid[kind][0] ?? 0;
+ const week = currentGrid[kind].map((value) => value ?? 0);
+ const lowest = Math.min(...week);
+ const highest = Math.max(...week);
+ const weekLabel = lowest === highest ? String(lowest) : `${lowest}–${highest}`;
return (
{meta.label}
+ Mon–Sun