From 987b2ceb47f14096f072a93bab89cfcd05a88de9 Mon Sep 17 00:00:00 2001 From: mrambossek Date: Sun, 2 Aug 2026 10:52:25 +0200 Subject: [PATCH] server: read the verdict from where the schema puts it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every uploaded run showed "not recorded" in the web UI because the meta extractor read summary.verdict. Schema §7.3 calls that field summary.overall; "verdict" is the per-category field one level down. So the verdict was never stored, and the UI faithfully reported a gap that was this parser's doing rather than the document's. The test encoded the same mistake — its fixture posted summary.verdict:"warn" — so it passed throughout against a parser that read a field nothing writes. Corrected to summary.overall, and to a verdict that exists: §7.3 defines green|yellow|red|inconclusive, and "warn" was never one of them. The eleven runs already stored had their meta backfilled from the documents, which are kept byte-for-byte and still carry the real value. Co-Authored-By: Claude Opus 5 --- server/internal/runs/runs.go | 8 ++++++-- server/internal/runs/runs_test.go | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/server/internal/runs/runs.go b/server/internal/runs/runs.go index e2d2c05..46567bf 100644 --- a/server/internal/runs/runs.go +++ b/server/internal/runs/runs.go @@ -158,7 +158,11 @@ func (s *Store) Put(deviceID string, body []byte, linked bool) (Meta, error) { } `json:"run"` Findings []json.RawMessage `json:"findings"` Summary struct { - Verdict string `json:"verdict"` + // measurement-schema.md §7.3 calls this "overall"; "verdict" is the per-category + // field one level down. Reading the wrong one stored an empty verdict on every run + // ever uploaded, which the UI showed as "not recorded" — a claim about the document + // that was really a bug in this parser. + Overall string `json:"overall"` } `json:"summary"` } if err := json.Unmarshal(body, &doc); err != nil || doc.Run.ID == "" { @@ -192,7 +196,7 @@ func (s *Store) Put(deviceID string, body []byte, linked bool) (Meta, error) { meta := Meta{ ID: id, DeviceID: deviceID, UploadedAt: time.Now().UTC(), StartedAt: doc.Run.StartedAt, Anonymization: level, - SizeBytes: int64(len(body)), Verdict: doc.Summary.Verdict, + SizeBytes: int64(len(body)), Verdict: doc.Summary.Overall, FindingCount: len(doc.Findings), } if err := os.WriteFile(filepath.Join(devDir, id+".meta.json"), mustJSON(meta), 0o600); err != nil { diff --git a/server/internal/runs/runs_test.go b/server/internal/runs/runs_test.go index e0810b7..2757be9 100644 --- a/server/internal/runs/runs_test.go +++ b/server/internal/runs/runs_test.go @@ -17,7 +17,7 @@ import ( func doc(id, anon string) []byte { return []byte(fmt.Sprintf( `{"run":{"id":%q,"started_at":"2026-08-01T10:00:00Z","privacy":{"anonymization":%q}},`+ - `"findings":[{"id":"f1"},{"id":"f2"}],"summary":{"verdict":"warn"}}`, id, anon)) + `"findings":[{"id":"f1"},{"id":"f2"}],"summary":{"overall":"yellow"}}`, id, anon)) } func open(t *testing.T, p Policy) (*Store, string) { @@ -193,7 +193,7 @@ func TestMetaSummarisesTheDocument(t *testing.T) { if err != nil { t.Fatal(err) } - if m.FindingCount != 2 || m.Verdict != "warn" || m.Anonymization != AnonBalanced { + if m.FindingCount != 2 || m.Verdict != "yellow" || m.Anonymization != AnonBalanced { t.Fatalf("meta not extracted: %+v", m) } if m.StartedAt != "2026-08-01T10:00:00Z" {