package opportunities import ( "net/http" "github.com/shopspring/decimal" ) // captureReview returns the board: every live pursuit, its gate decisions, and what is unresolved. func (h *Handler) captureReview(w http.ResponseWriter, r *http.Request) { out, err := h.svc.Review(r.Context(), r.URL.Query().Get("include_closed") == "true") if err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusOK, out) } func (h *Handler) listGateDecisions(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "id") if !ok { return } out, err := h.svc.ListDecisions(r.Context(), id) if err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusOK, map[string]any{"decisions": out, "count": len(out)}) } // recordGateDecision writes one go or no go. // // The advisory numbers arrive from the CLIENT rather than being recomputed here, and that is deliberate // rather than lazy. The number that belongs in the record is the one the decider was looking at when they // decided. Recomputing at write time would store a number nobody saw, which is precisely the rewriting of // history the snapshot exists to prevent. func (h *Handler) recordGateDecision(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "id") if !ok { return } var in struct { Gate string `json:"gate"` Decision string `json:"decision"` Rationale string `json:"rationale"` ReadinessScore *decimal.Decimal `json:"readiness_score"` ReadinessBand string `json:"readiness_band"` WinProbability *decimal.Decimal `json:"win_probability"` } if !decodeTeaming(w, r, &in) { return } out, err := h.svc.RecordDecision(r.Context(), id, in.Gate, in.Decision, in.Rationale, in.ReadinessScore, in.ReadinessBand, in.WinProbability) if err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusCreated, out) }