The README deploy section documents the GHCR image, the compose stack
that joins Caddy's external network, and that the Caddyfile entry is
managed by hand on the server. distroless has no shell, so the
healthcheck is the binary itself: a new -check flag probes /healthz
and exits 0 or 1, and the Dockerfile bakes it in as HEALTHCHECK.
Verified locally: the container reports healthy.
//go:embed needs internal/webdist/dist to exist at compile time, so a
one-line placeholder index.html is committed there and the real build
(Docker, or a manual copy of web/dist) overwrites it. One mux serves
/, /api, and a /healthz for the compose healthcheck to come.
internal/api stays a translation layer: decode (with
DisallowUnknownFields so typos 400 instead of silently defaulting),
run the engine, encode; all validation stays in the engine. Routes use
Go 1.22 mux patterns ('POST /api/comparison'), so wrong methods get
405 from the stdlib for free. httptest runs handlers fully in memory;
the API test re-pins the 99/70/7 golden values end to end.
ComparisonResponse is added to tygo.yaml with a type mapping so the
generated web/src/types/api.ts reuses the engine's TS types.
cmd/spreadlab now serves on -addr (default localhost:8080); -table
keeps the CLI comparison as a sanity check.
The strategy list moves into the engine (AllStrategies), where the API
and frontend will read it too: one source of truth, per the handoff.
main shrinks to the standard Go shell pattern: all work happens in
run(out io.Writer) error; main only maps the error to stderr and the
exit code. Writing to an interface instead of stdout is what lets
main_test.go capture output in a bytes.Buffer.
errcheck flagged every unchecked Fprintf, so formatting became pure
Sprintf string building with one checked write at the end: nicer than
discarding four errors with '_, _ ='.
Config is the single source of truth for parameters (TS types will be
generated from these structs in milestone 2); all randomness flows from
its three seeds, so identical configs give identical results. Golden
test pins the default world: none=99/120 (82%), random=70/120 (58%),
most-connected=7/120 (6%). Same story as the prototype's 85/64/8 with
different dice; the ordering and the collapse are asserted explicitly,
exact Python numbers are out of scope by design.
'go run ./cmd/spreadlab' prints the three-scenario comparison.
This completes milestone 1 (engine ported, parameterised, tested).
go.mod declares the module path (github.com/JustinZeus/spreadlab); every
import inside the repo is spelled relative to it. Layout follows the
standard Go shape: cmd/<binary>/main.go per executable, internal/ for
packages other modules may not import (the compiler enforces this).
No engine code yet, just a placeholder main that proves 'go build' works.