Make delivery and integration failures explicit

Persist reminder presentations and retry state, atomically complete collapsed deliveries, fall back across away reaches, and block permanent failures visibly (V-715, V-678). Fail closed when enabled integrations lack credentials and keep remote arms explicitly dark (V-691). Give mavweb one sanitized, request-correlated error contract (V-689). Owner explicitly requested direct commits to master.
This commit is contained in:
2026-08-13 02:50:59 +04:00
parent da9114b623
commit 35c6ff5a71
67 changed files with 3174 additions and 477 deletions
+17 -17
View File
@@ -5,7 +5,6 @@ import (
_ "embed"
"errors"
"fmt"
"log"
"net/http"
"strconv"
"strings"
@@ -41,7 +40,7 @@ type routineView struct {
// gated — it only ever removes a reason to speak, so the worst a weaker caller
// can do is make maven quieter.
func handleRoutines(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI, session *webauthn.PasskeySession, requireStepUp bool) {
if !requireCore(w, core, "routines") {
if !requireCore(w, r, core, "routines") {
return
}
ctx := r.Context()
@@ -54,8 +53,8 @@ func handleRoutines(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI, se
}
proposed, err := core.ListProposedRoutines(ctx)
if err != nil {
log.Printf("routines: list: %v", err)
http.Error(w, "routines error: "+err.Error(), http.StatusBadGateway)
writeProblem(w, r, http.StatusBadGateway, problemCoreReadFailed,
"routines unavailable", fmt.Errorf("list proposed routines: %w", err))
return
}
renderPage(w, routinesTmpl, struct {
@@ -76,44 +75,45 @@ func applyRoutinePost(w http.ResponseWriter, r *http.Request, core ipc.CoreAPI,
// already the step-up-gated surface for this table, and a second gated
// surface is a second thing to get wrong.
if action == "seed" {
if !stepUpGate(w, session, requireStepUp) {
if !stepUpGate(w, r, session, requireStepUp) {
return "", false
}
out, err := seedRoutineEvent(ctx, core, r)
if err != nil {
log.Printf("routines: seed: %v", err)
http.Error(w, "seed failed: "+err.Error(), http.StatusBadGateway)
writeProblem(w, r, http.StatusBadGateway, problemRoutinesChange,
"seed failed", fmt.Errorf("seed routine event: %w", err))
return "", false
}
return out, true
}
idStr := r.FormValue("id")
var rid int64
if n, _ := fmt.Sscanf(idStr, "%d", &rid); n != 1 {
http.Error(w, "invalid id", http.StatusBadRequest)
rid, err := strconv.ParseInt(strings.TrimSpace(r.FormValue("id")), 10, 64)
if err != nil || rid <= 0 {
writeProblem(w, r, http.StatusBadRequest, problemInvalidRequest,
"invalid id", err)
return "", false
}
switch action {
case "accept":
if !stepUpGate(w, session, requireStepUp) {
if !stepUpGate(w, r, session, requireStepUp) {
return "", false
}
if err := acceptRoutine(ctx, core, rid); err != nil {
log.Printf("routines: accept %d: %v", rid, err)
http.Error(w, "accept failed: "+err.Error(), http.StatusBadGateway)
writeProblem(w, r, http.StatusBadGateway, problemRoutinesChange,
"accept failed", fmt.Errorf("accept routine %d: %w", rid, err))
return "", false
}
return "accepted routine — maven will remind you", true
case "dismiss":
if err := core.DismissProposedRoutine(ctx, rid); err != nil {
log.Printf("routines: dismiss %d: %v", rid, err)
http.Error(w, "dismiss failed: "+err.Error(), http.StatusBadGateway)
writeProblem(w, r, http.StatusBadGateway, problemRoutinesChange,
"dismiss failed", fmt.Errorf("dismiss routine %d: %w", rid, err))
return "", false
}
return "dismissed routine", true
default:
http.Error(w, "unknown action", http.StatusBadRequest)
writeProblem(w, r, http.StatusBadRequest, problemInvalidRequest,
"unknown action", nil)
return "", false
}
}