engine: realistic config bounds, enforced and served

ConfigBounds (students 10-500, edgesPerNode 1-8, forwardProb 0-0.9,
triangleProb 0-1) caps what RunScenario accepts: a student does not
keep 150 close friendships and a guaranteed forward is not a real
base rate. numEducated gains its missing upper limit (numStudents).
Bounds-side validation also protects the public server from absurd
numStudents values. GET /api/config/default now returns
{config, bounds} so the frontend can drive its controls from the
same numbers; the frontend does not call it yet, so this commit
changes no UI behaviour.
This commit is contained in:
Justin Visser 2026-06-11 15:54:07 +02:00
parent 232faf892e
commit bd890384e5
7 changed files with 194 additions and 15 deletions

View file

@ -11,6 +11,14 @@ import (
"github.com/JustinZeus/spreadlab/internal/engine"
)
// DefaultConfigResponse is the body of GET /api/config/default: the
// default world plus the engine's field bounds, so the frontend drives
// its controls and clamping from the same numbers the engine enforces.
type DefaultConfigResponse struct {
Config engine.Config `json:"config"`
Bounds engine.Bounds `json:"bounds"`
}
// ComparisonResponse bundles what the dashboard needs to render one
// comparison: the config that was run, echoed back so frontend state stays
// honest, and one result per strategy.
@ -53,7 +61,10 @@ func NewServer() http.Handler {
}
func handleDefaultConfig(w http.ResponseWriter, _ *http.Request) {
writeJSON(w, http.StatusOK, engine.DefaultConfig())
writeJSON(w, http.StatusOK, DefaultConfigResponse{
Config: engine.DefaultConfig(),
Bounds: engine.ConfigBounds(),
})
}
func handleComparison(w http.ResponseWriter, r *http.Request) {