fix(resolve): correct persistence and cooldown state transitions - #23
fix(resolve): correct persistence and cooldown state transitions#23LordMikkel wants to merge 2 commits into
Conversation
davgonsan
left a comment
There was a problem hiding this comment.
Reviewed and ran the suite — the change looks sound. Dropping the receipt_id FK from resolve_witnesses and keying on target_sos_id (with resolve_receipts.target_sos_id now unique) is consistent across resolvesRepo, routes.ts, store.ts, and both schema.sql + the new migration. I confirmed no dangling receipt_id references remain (the leftover receiptId in routes/store is the receipt's own PK / the in-memory pendingClears value, which is correct), and the in-memory upsertReceipt now keeps pendingClears in sync — good parity with the Supabase path.
Verified: bun test → 31 pass / 0 fail.
Two things before merge:
-
No test covers the changed flow. The resolve tests live in
packages/shared/src/resolve.test.tsand only exercise the canonical/crypto format — there's no backend store/routes test. So the "corrected persistence and cooldown state transitions" this PR fixes aren't proven by anything. For a persistence + state-machine fix I'd really want a store-level test (pending → cooldown → cleared, and the one-pending-per-author invariant viapendingClears). Happy to help add it. -
Migration could fail on existing data.
0001_fix_resolve_schema.sqlrunsadd constraint … unique (target_sos_id)without deduping first — if any duplicatetarget_sos_idrows already exist inresolve_receipts, the ALTER fails and the wholebegin/commitrolls back. Low risk pre-prod, but a dedupe step (or a comment noting the assumption) would make it safe to run anywhere.
Also: please retarget to develop rather than main, to match where the rest of the backend work is landing.
43202a3 to
79028d8
Compare
|
Thanks, addressed all three points:
|
|
@vmlcode Me gustaría poder seguir aportando al proyecto pero veo que estos últimos días ha parado mucho la actividad y hasta tener estas dos primeras PR no he querido seguir desarrollando, es posible estar en algún grupo o chat de trabajo con ustedes para estar al tanto de como va avanzando el proyecto? |
Buenas @LordMikkel. Un placer, si la actividad ha bajado un poco últimamente debido a que estamos conversando con algunos miembros externos interesados en el app, coordinando casos de usos así como el futuro de la aplicación en general (El como expandirnos), me encantaría que fueras parte de la discusión entonces te invito al discord de guacamalla para que coordinemos en conjunto la siguiente fase de este proyecto |
¿Qué hace este PR?
Corrige cómo el backend guarda y transiciona el flujo
resolve(SOS resuelto por testigos).¿Por qué?
Si un rescatista llega al sitio de un SOS, toma foto como evidencia, y firma que el SOS fue atendido. El backend debería:
cleared.disputed.Ahora esto falla de dos formas:
Con Supabase:
POST /resolvedevuelve500. La tablaresolve_witnessestiene una FK que exige que ya exista el receipt padre enresolve_receipts. Pero el código intenta guardar testigos antes de crear ese receipt. No puedes crear el receipt sin los testigos, ni guardar los testigos sin el receipt.Sin Supabase (modo desarrollo): el backend acepta el resolve, pero nunca registra el cooldown en memoria. Hay un mapa
pendingClearsque debería llenarse cuando un receipt entra en cooldown, pero nadie lo llama. Así que al pasar los 15 minutos, el sweeper no tiene nada que promover. El SOS se queda comopendingpara siempre.¿Cómo lo arregla?
resolve_witnessesya no tienereceipt_id. Se relaciona portarget_sos_id, que es la clave estable del flujo.resolve_receiptsahora garantiza un único receipt portarget_sos_id(que es lo que la documentación ya dice).upsertReceipt(...)guarda portarget_sos_iden vez de porid(que cambia con cada testigo nuevo).cooldownEndsAt.cooldown_ends_at IS NOT NULL).Test manual
Probado localmente sin Supabase:
/ingest→ OK/resolve→accepted: true,quorumSeen: 1, quorum no alcanzado/resolve→accepted: true,quorumSeen: 2, quorum alcanzado,cooldownEndsAtseteadoresueltoemitió registro firmado conevent: "pending"→ OKcooldownEndsAtse mantiene (no se reinicia)¿Cómo probarlo?
bun run --cwd backend tsc --noEmitpasa limpiobun testpasa (31 tests)POST /resolvecon quorum funciona sin SupabaseChecklist
bun test)/ingestni firma Ed25519