GitHub
08/21/2026, 4:52 PMpkg/posture. The frontend does not reimplement that evaluation logic — it only re-sums numbers the server already computed:
• Added max_score to ControlResult (pkg/posture/scoring.go): the risk points a control would contribute if it failed, now reported even when it passes. This was the only piece missing — status, score, and severity were already in the API response.
• New `frontend/src/features/nodes/postureScore.ts`: a small pure function mirroring only the aggregation math from ScoreCalculator.Score (earned/possible normalization) and `riskLevel`'s critical/high escalation rule — applied to whichever controls are currently checked.
• `NodeDetailPage.tsx`: each control row is a checkbox, checked by default. The gauge, risk badge, and pass/warn/fail counts always reflect the checked subset; with everything checked this is byte-for-byte the server's PostureScore.
Why this is safe from drift
The per-rule Evaluate() functions (dozens of them, one per compliance control) never leave the Go backend. If a rule's logic ever changes, the frontend doesn't need to change — it only consumes each control's already-decided `status`/`score`/`max_score`.
Files
• pkg/posture/scoring.go — ControlResult.MaxScore
• frontend/src/features/nodes/postureScore.ts (new) — recomputePostureScore, riskLevelFromScore, controlKey
• frontend/src/features/nodes/NodeDetailPage.tsx — checkbox UI, live recompute wiring in PostureScorePanel
• frontend/src/api/types.ts — ControlResult.max_score
• osctrl-api.yaml — regenerated (make openapi)
Testing
• `pkg/posture/scoring_test.go`: asserts MaxScore sums to the same normalization denominator the score itself was computed from.
• frontend/src/features/nodes/postureScore.test.ts (new): threshold table, critical/high escalation, empty-selection (no divide-by-zero), and that recomputePostureScore reproduces the server score when nothing is excluded.
• `NodeDetailPage.test.tsx`: new interaction test — unchecking a failing critical control drops the score/level live, re-checking restores it, and getNodePostureScore is called exactly once (proving no extra network round-trip).
• Full suite green: `go build`/`go test`/`go vet`, make openapi-check, frontend 255 tests, tsc.
jmpsec/osctrlGitHub
08/21/2026, 4:56 PM