Deterministic classification spine (D-0028): detect -> correlate -> classify -> decide #9

Merged
hannah-vernon merged 2 commits from feature/deterministic-classification into dev 2026-08-21 13:18:16 -05:00

What does this PR do?

Completes the deterministic pipeline spine per D-0028: incidents now flow detect -> correlate -> classify -> policy-decide -> persisted Decision with zero inference dependency. LLM classification remains a fully optional future enrichment (Phase 6), per Hannah's requirement that the platform be fully operational without a (slow) LLM.

  • DeterministicIncidentClassifier (deterministic-evidence-v1): converts incident evidence into schema-valid Classifications: normalized confidence from total evidence score, severity scaling, keyword-derived categories (credential-attack, path-traversal, sql-injection, command-injection, vulnerability-scanner, reconnaissance), block-source-ip recommendation only for IP-keyed incidents at or above the D-0027 provisional evidence threshold; mail incidents flag-for-review only (email actions are Phase 7). All tunables in ClassifierOptions with validation.
  • Durable hand-offs: typed IncidentWorkItem/ClassificationWorkItem queues ("incidents", "classifications") registered for both persistence providers and feeding queue telemetry (D-0012).
  • ClassificationWorker (classification role): lease incident -> classify -> persist -> audit -> enqueue for policy.
  • PolicyWorker (policy role, placeholder replaced): lease classification -> DefaultPolicyEngine -> persist Decision -> audit -> incident marked Decided. Posture (dry-run/approval/emergency-stop) bound from configuration with D-0027 shipped defaults.
  • D-0028 recorded in DECISIONS.md.

Fixes #

How was this tested?

  • dotnet build Viegard.slnx - 0 errors, 0 warnings
  • dotnet test Viegard.slnx - 240/240 pass (agent run + independent re-run)
  • Flagship test Deterministic_spine_end_to_end_produces_dry_run_decision: hostile HTTP event -> correlator -> classifier -> policy engine -> persisted Decision with DryRun outcome and full guardrail chain
  • Host smoke boot: ClassificationWorker and PolicyWorker start under default roles
  • PostgreSQL integration tests skipped this run: WSL2 on the dev workstation lost the "Log on as a service" right to a GPO refresh (known managed-machine issue). Queue mechanics passed live earlier today (18/18); the new code adds queue registrations, not queue internals. Live re-verification lands with Debian VM deployment.

Implementation drafted by a coding agent against the D-0027/D-0028 spec, independently reviewed and re-verified.

Checklist

  • I have read the Contributing Guide
  • Changes are focused - one logical change per PR
  • Documentation updated (AGENT-README.md, TODO.md, DECISIONS.md D-0028)
  • New dependencies: none
  • No secrets, credentials, or real infrastructure identifiers in the diff
  • No commented-out code or debug leftovers
## What does this PR do? Completes the deterministic pipeline spine per D-0028: incidents now flow detect -> correlate -> classify -> policy-decide -> persisted Decision with **zero inference dependency**. LLM classification remains a fully optional future enrichment (Phase 6), per Hannah's requirement that the platform be fully operational without a (slow) LLM. - **`DeterministicIncidentClassifier`** (`deterministic-evidence-v1`): converts incident evidence into schema-valid Classifications: normalized confidence from total evidence score, severity scaling, keyword-derived categories (credential-attack, path-traversal, sql-injection, command-injection, vulnerability-scanner, reconnaissance), `block-source-ip` recommendation only for IP-keyed incidents at or above the D-0027 provisional evidence threshold; mail incidents flag-for-review only (email actions are Phase 7). All tunables in `ClassifierOptions` with validation. - **Durable hand-offs:** typed `IncidentWorkItem`/`ClassificationWorkItem` queues ("incidents", "classifications") registered for both persistence providers and feeding queue telemetry (D-0012). - **`ClassificationWorker`** (classification role): lease incident -> classify -> persist -> audit -> enqueue for policy. - **`PolicyWorker`** (policy role, placeholder replaced): lease classification -> `DefaultPolicyEngine` -> persist Decision -> audit -> incident marked Decided. Posture (dry-run/approval/emergency-stop) bound from configuration with D-0027 shipped defaults. - **D-0028** recorded in DECISIONS.md. Fixes # ## How was this tested? - [x] `dotnet build Viegard.slnx` - 0 errors, 0 warnings - [x] `dotnet test Viegard.slnx` - **240/240 pass** (agent run + independent re-run) - [x] Flagship test `Deterministic_spine_end_to_end_produces_dry_run_decision`: hostile HTTP event -> correlator -> classifier -> policy engine -> persisted Decision with DryRun outcome and full guardrail chain - [x] Host smoke boot: ClassificationWorker and PolicyWorker start under default roles - [ ] PostgreSQL integration tests skipped this run: WSL2 on the dev workstation lost the "Log on as a service" right to a GPO refresh (known managed-machine issue). Queue mechanics passed live earlier today (18/18); the new code adds queue registrations, not queue internals. Live re-verification lands with Debian VM deployment. Implementation drafted by a coding agent against the D-0027/D-0028 spec, independently reviewed and re-verified. ## Checklist - [x] I have read the [Contributing Guide](../CONTRIBUTING.md) - [x] Changes are focused - one logical change per PR - [x] Documentation updated (AGENT-README.md, TODO.md, DECISIONS.md D-0028) - [x] New dependencies: none - [x] No secrets, credentials, or real infrastructure identifiers in the diff - [x] No commented-out code or debug leftovers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the deterministic evidence classifier, typed incident and classification queue messages, and durable queue registration for both in-memory and PostgreSQL providers.

Wire correlation to hand off incidents, add the classification worker, replace the policy placeholder with classification intake, and persist policy decisions while marking incident subjects decided.

Document the deterministic-only state and add classifier plus end-to-end spine coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
hannah-vernon/viegard-sentinel!9
No description provided.