Skip to content

P6: publish per-rule quality and make calibration evidence-based - #35

Merged
therandomsecurityguy merged 1 commit into
mainfrom
dac/predictive-p6-quality
Oct 26, 2026
Merged

therandomsecurityguy merged 1 commit into
mainfrom
dac/predictive-p6-quality

Conversation

@therandomsecurityguy

Copy link
Copy Markdown
Owner

Summary

Predictive security roadmap P6 (calibration and feedback). 19 files, +573/−4.

  • buildRuleQuality() — from each rule's open/suppressed/resolved issue counts: handled = suppressed + resolved, dismissalRate = suppressed ÷ handled, and a verdict (reliable <20% over ≥10 closed, noisy ≥50%, mixed between, insufficient-data before that), sorted noisy-first. Documented explicitly as a noise proxy, not precision — suppression is the recorded human judgement (reason/actor/expiry live in status history); ground truth needs outcome labels from GuardDuty/Security Hub/incidents (later phase).
  • getRuleStatusCounts() — same bounded StatusIndex projections the severity summary uses, projecting ruleId.
  • GET /rules/quality (Viewer; static route registered before /rules/:id) joins counts with the catalogue (name, team, severity, enabled, auto-ticket, inCatalogue for retired rules) and returns the thresholds, so the verdict rule is visible rather than implied.
  • /rules page under Risks — table sorted noisy-first with the proxy and thresholds explained; nav + nav test updated.
  • Calibration policy — severity/scoring-weight/auto-ticket changes cite the report as evidence (now in AGENTS.md §2.3); thresholds are constants. Per the parity decision RULE-006/031–034 stay off auto-ticket until measured — the CHANGELOG states the first live change awaits production data rather than guessing one.

Why this is safe

  • Strictly additive and read-only: no issue, severity, or published claim changes.
  • Viewer-gated; bounded by the same reads /issues/summary already makes.
  • Retired rule ids are flagged (inCatalogue: false) rather than silently hidden.

Test plan

  • npx jest --runInBand — 17 projects / 1723 tests passed
  • new tests: verdict bounds/sorting, API join + unknown-rule + 500, routing order, UI table + explanation + empty state, nav update
  • npm run typecheck; full workspace lint; npm run format:check
  • npm run ci:build; npm run package:lambdas && npm run smoke:lambdas

Predictive security roadmap P6 (calibration and feedback):

- buildRuleQuality() (packages/risk-engine/src/rule-quality.ts): from a
  rule's open/suppressed/resolved issue counts it computes handled =
  suppressed + resolved, dismissalRate = suppressed / handled, and a
  verdict — reliable under 20% over at least RULE_QUALITY_MIN_HANDLED
  (10) closed issues, noisy at 50% or more, mixed between,
  insufficient-data before that — sorted noisy-first. The doc comment is
  explicit that suppression is the recorded human judgement (reason,
  actor, expiry live in the status history) and the rate is a noise
  proxy, not precision: ground truth needs outcome labels from
  GuardDuty/Security Hub and incidents, which remain a later phase.
- DynamoDBIssueRepository.getRuleStatusCounts() reads the counts through
  the same bounded StatusIndex projections the severity summary uses,
  projecting ruleId instead of severity.
- GET /rules/quality (Viewer, static route before /rules/:id) joins the
  counts with the catalogue (name, team, severity, enabled, auto-ticket,
  inCatalogue for retired rules) and returns the thresholds alongside, so
  the verdict rule is visible rather than implied. A /rules page under
  Risks renders the table sorted noisy-first with the proxy and threshold
  explained.
- Calibration policy: severity, scoring-weight, and auto-ticket changes
  cite the report as evidence; AGENTS.md 2.3 now says so, and the
  thresholds are constants so the change is an edit with recorded
  evidence. Per the parity port decision, RULE-006/031-034 stay off
  auto-ticket until their measured rate supports turning it on — the
  first live enablement waits for production data, and the CHANGELOG note
  says exactly that rather than guessing a change.

Why this is safe: strictly additive and read-only — no issue, severity,
or published claim changes; the endpoint is Viewer-gated, bounded by the
same reads the issue summary already makes, and unknown rule ids are
flagged instead of hidden.
@therandomsecurityguy
therandomsecurityguy merged commit 084af2c into main Oct 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant