Phase 3 skeleton: domain model, ports, queue, secrets, hosts #1

Merged
hannah-vernon merged 1 commit from feature/solution-skeleton into dev 2026-08-18 17:16:58 -05:00

What does this PR do?

Implements the Phase 3 skeleton per the approved architecture (D-0017): solution structure, core domain model, application ports, working queue/secret implementations, and both host executables.

  • Directory.Build.props: net10.0, nullable, warnings-as-errors, NuGetAudit enforcement (mode=all, level=low, NU1901-NU1904 as build errors)
  • Viegard.Domain: events (RawObservation, NormalizedEvent, EntityRef, payloads incl. MalformedRecordPayload), incidents + evidence, Classification with validated invariants (confidence/severity/uncertainty ranges), Decision with guardrail evaluations, ActionRecord with rollback info, AuditRecord, Correction, ComponentHealth, AdminCommand
  • Viegard.Application: all ports from ARCHITECTURE.md (data source, normalizer, work/command queues, stores, correlator, classifier, inference with trust-tagged prompt variables, policy, action provider, notifications, audit ledger, secrets, health); ChannelWorkQueue (broker semantics: ack/abandon, dead-lettering, age-preserving redelivery, stats for D-0012); FileSecretProvider (path-traversal-safe) and ConfigurationSecretProvider; Secret type that never reveals its value via ToString/interpolation
  • Viegard.Persistence: development-only in-memory stores (until D-0004)
  • Viegard.PipelineHost: role-configurable host (D-0011); startup validation refuses unknown/empty/duplicate roles; configuration-driven secret provider selection; heartbeat worker
  • Viegard.AdminApi: Blazor Web App shell (D-0016) with /healthz
  • Docs: AGENT-README verified commands + structure, THIRD-PARTY-NOTICES entries, TODO Phase 3 progress + HashiCorp Vault discussion item

Fixes #

How was this tested?

  • dotnet build Viegard.slnx - 0 errors, 0 warnings
  • dotnet test Viegard.slnx - 33/33 tests pass (queue semantics: FIFO, redelivery counts, dead-lettering, stale-age telemetry, double-settle protection; secret masking, path-traversal rejection; classification invariants)
  • Manually tested: pipeline host boots and logs roles; invalid role configuration fails startup with OptionsValidationException

Checklist

  • I have read the Contributing Guide
  • Changes are focused - one logical change per PR
  • Documentation updated (AGENT-README.md, TODO.md, ARCHITECTURE.md, THIRD-PARTY-NOTICES.md)
  • New dependencies are MIT/Apache-2.0 and security-vetted (Microsoft.Extensions.Configuration[.Abstractions] 10.0.11, test tooling; recorded in THIRD-PARTY-NOTICES.md)
  • No secrets, credentials, or real infrastructure identifiers in the diff
  • No commented-out code or debug leftovers
## What does this PR do? Implements the Phase 3 skeleton per the approved architecture (D-0017): solution structure, core domain model, application ports, working queue/secret implementations, and both host executables. - `Directory.Build.props`: net10.0, nullable, warnings-as-errors, NuGetAudit enforcement (mode=all, level=low, NU1901-NU1904 as build errors) - `Viegard.Domain`: events (RawObservation, NormalizedEvent, EntityRef, payloads incl. MalformedRecordPayload), incidents + evidence, Classification with validated invariants (confidence/severity/uncertainty ranges), Decision with guardrail evaluations, ActionRecord with rollback info, AuditRecord, Correction, ComponentHealth, AdminCommand - `Viegard.Application`: all ports from ARCHITECTURE.md (data source, normalizer, work/command queues, stores, correlator, classifier, inference with trust-tagged prompt variables, policy, action provider, notifications, audit ledger, secrets, health); `ChannelWorkQueue` (broker semantics: ack/abandon, dead-lettering, age-preserving redelivery, stats for D-0012); `FileSecretProvider` (path-traversal-safe) and `ConfigurationSecretProvider`; `Secret` type that never reveals its value via ToString/interpolation - `Viegard.Persistence`: development-only in-memory stores (until D-0004) - `Viegard.PipelineHost`: role-configurable host (D-0011); startup validation refuses unknown/empty/duplicate roles; configuration-driven secret provider selection; heartbeat worker - `Viegard.AdminApi`: Blazor Web App shell (D-0016) with `/healthz` - Docs: AGENT-README verified commands + structure, THIRD-PARTY-NOTICES entries, TODO Phase 3 progress + HashiCorp Vault discussion item Fixes # ## How was this tested? - [x] `dotnet build Viegard.slnx` - 0 errors, 0 warnings - [x] `dotnet test Viegard.slnx` - 33/33 tests pass (queue semantics: FIFO, redelivery counts, dead-lettering, stale-age telemetry, double-settle protection; secret masking, path-traversal rejection; classification invariants) - [x] Manually tested: pipeline host boots and logs roles; invalid role configuration fails startup with OptionsValidationException ## 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, ARCHITECTURE.md, THIRD-PARTY-NOTICES.md) - [x] New dependencies are MIT/Apache-2.0 and security-vetted (Microsoft.Extensions.Configuration[.Abstractions] 10.0.11, test tooling; recorded in THIRD-PARTY-NOTICES.md) - [x] No secrets, credentials, or real infrastructure identifiers in the diff - [x] No commented-out code or debug leftovers
- Directory.Build.props: net10.0, nullable, warnings-as-errors, NuGetAudit
  (mode=all, level=low, NU1901-NU1904 as errors)
- Viegard.Domain: RawObservation, NormalizedEvent, EntityRef, payloads,
  Incident/Evidence, Classification (validated invariants), Decision with
  guardrail evaluations, ActionRecord, AuditRecord, Correction,
  ComponentHealth, AdminCommand
- Viegard.Application: ports (IDataSource, IEventNormalizer, IWorkQueue,
  ICommandQueue, stores, ICorrelator, IClassifier, IInferenceProvider with
  trust-tagged prompt variables, IPolicyEngine, IActionProvider,
  INotificationProvider, IAuditLedger, ISecretProvider, IHealthContributor);
  ChannelWorkQueue with ack/abandon, dead-lettering, and age-preserving
  redelivery; FileSecretProvider (path-traversal-safe) and
  ConfigurationSecretProvider; Secret type that never reveals via ToString
- Viegard.Persistence: development-only in-memory stores and audit ledger
- Viegard.PipelineHost: role-configurable host (D-0011) with startup
  validation that refuses unknown/empty/duplicate roles; secret provider
  selection via configuration; heartbeat worker
- Viegard.AdminApi: Blazor Web App template shell (D-0016) plus /healthz
- Tests: 33 passing (classification invariants, queue semantics including
  FIFO, redelivery counts, dead-lettering, stale-age telemetry, double-settle
  protection; secret masking, path traversal rejection, config secrets)
- Docs: AGENT-README verified commands, THIRD-PARTY-NOTICES entries,
  TODO Phase 3 progress + HashiCorp Vault discussion item, .gitattributes
  *.slnx rule

Verified: dotnet build (0 warnings), dotnet test (33/33), host boots with
valid roles and fails fast on invalid topology.

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!1
No description provided.