SCRUM-216 — Config: version history, one version, and diff¶
Plan ref: CFG-B6 (docs/11-admin-plane-plan.md). Stacked on SCRUM-215.
What changed (all viewer)¶
| Route | Returns |
|---|---|
GET /namespaces/{ns}/versions?before=&limit= |
{"versions":[{version, schema_version, sha256, message, created_by, created_at}], "next_before": <int\|null>}, newest first; limit 50 default, 200 max |
GET /namespaces/{ns}/versions/{v} |
the list fields + size (length of the canonical bytes) + document |
GET /namespaces/{ns}/diff?from=<v\|draft>&to=<v\|draft> |
{"from":{ref,document}, "to":{ref,document}, "changes":[…]} |
changes comes from the new internal/diff package:
{"op":"replace","path":"/weapons/0/damage","from":5,"to":7}, add (to only),
remove (from only). Objects are compared key by key in sorted order (output is
deterministic); arrays index by index (a reorder shows as index replaces — the
UI gets both full documents for a richer view); numbers compare by canonical value
(1 = 1.0); a type change is one replace; paths are RFC 6901 (~0, ~1); the
root is ""; [] when identical, never null.
Errors: bad limit/before/{v}/from/to → 400 validation_failed; unknown
version → 404; unknown ns → 404.
How to verify¶
cd services/config
export CONFIG_TEST_DATABASE_URL='postgres://USER:PASS@127.0.0.1:5433/config_test?sslmode=disable'
go vet ./... && go test -race -count=1 ./...
go test -count=1 -v -run 'Diff|History' ./internal/diff/ ./internal/server/
| Test | Proves |
|---|---|
diff.TestDiff |
nested replace, add/remove key, array grow/shrink/change, reorder as index replaces, object→array as one replace, 1 vs 1.0 equal, / and ~ escaped |
diff.TestDiffIdenticalIsNeverNull, …OrderIsDeterministic, …RejectsInvalidJSON |
as named |
server.TestVersionHistoryAndDiffThroughTheLiveServer |
three real versions: newest-first list; limit=2 → next_before=2; before=2 → v1 and null; single version has size + document; diff 1→3 and 3→draft; 404/400 cases; viewer can read |
By hand (viewer token $T):
curl -s -H "Authorization: Bearer $T" "localhost:8080/api/admin/config/namespaces/ui.motd/diff?from=1&to=draft"
Results at time of writing¶
go vet,go test -race ./...against Postgres 16: pass (8 packages).
How it was built¶
DeepSeek run scoped (Landlock) to services/config (171 s, ~36k output tokens).
Claude review: diff semantics read against the spec, suite re-run. No changes needed.