Pulse/pkg/reporting
rcourtman c3319b6304 Make Narrative / FleetOutlier JSON shape consistent with prompt schema
Found by exercising pulse_summarize in a real chat session. The
chat-tool response surfaced:

  "observations": [{"Text": "...", "Severity": "info"}]

The AI narrator's system prompt (report_narrator.go) tells the
model to emit lowercase keys:

  {"text": "...", "severity": "..."}

The model was being taught one schema and shown a different one
in the tool response for the same shape. NarrativeBullet,
FleetOutlier, Narrative, and FleetNarrative had no JSON tags, so
embedded struct fields serialised with their Go names.

Add struct tags so the wire shape matches the prompt schema. Pure
marshaling change — JSON tags don't affect Go field access, so
PDF rendering (which reads fields directly) is unchanged. Tests
in narrative_json_test.go pin the shape so the inconsistency
can't reappear silently.

Process note: this is a class of bug that only appears when an
LLM actually consumes the output. No unit test caught it; no
review of the code showed it; the model running through the chat
path is what surfaced it. Another argument for "exercise the
artifact" — even the tool surface that looks correct in
isolation has hidden inconsistencies you only see when something
external reads it.
2026-05-11 11:29:35 +01:00
..
catalog.go Refresh advanced_reporting paywall and guidance copy 2026-05-11 10:16:27 +01:00
catalog_test.go Remove customer commercial analytics wrappers 2026-04-30 11:46:16 +01:00
csv.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
csv_additional_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
engine.go Expose engine narrative entry points for non-rendering callers 2026-05-10 22:23:09 +01:00
engine_additional2_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
engine_additional3_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
engine_additional_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
engine_integration_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
engine_narrative_test.go Expose engine narrative entry points for non-rendering callers 2026-05-10 22:23:09 +01:00
engine_test.go Add agentless availability targets 2026-05-06 10:35:34 +01:00
fleet_narrative.go Make Narrative / FleetOutlier JSON shape consistent with prompt schema 2026-05-11 11:29:35 +01:00
fleet_narrative_test.go Add fleet-level AI narrative for multi-resource reports 2026-05-10 21:23:12 +01:00
multi_report_visual_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
narrative.go Make Narrative / FleetOutlier JSON shape consistent with prompt schema 2026-05-11 11:29:35 +01:00
narrative_json_test.go Make Narrative / FleetOutlier JSON shape consistent with prompt schema 2026-05-11 11:29:35 +01:00
narrative_test.go Replace heuristic report narrative with optional AI-generated layer 2026-05-10 19:30:54 +01:00
pdf.go Fix HEALTHY-on-empty and surface AI discoverability in reports 2026-05-11 11:13:34 +01:00
pdf_additional2_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
pdf_additional_test.go feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
pdf_insights_test.go Replace heuristic report narrative with optional AI-generated layer 2026-05-10 19:30:54 +01:00
pdf_ux_test.go Fix HEALTHY-on-empty and surface AI discoverability in reports 2026-05-11 11:13:34 +01:00
reporting.go Expose engine narrative entry points for non-rendering callers 2026-05-10 22:23:09 +01:00
reporting_test.go Expose engine narrative entry points for non-rendering callers 2026-05-10 22:23:09 +01:00
vm_inventory.go Canonicalize reporting fallback filename date style 2026-03-26 09:28:17 +00:00
vm_inventory_test.go Define VM inventory export schema contract 2026-03-25 22:09:37 +00:00