Implement MongoDB-based storage for Pack Run approval, artifact, log, and state management
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Added MongoPackRunApprovalStore for managing approval states with MongoDB. - Introduced MongoPackRunArtifactUploader for uploading and storing artifacts. - Created MongoPackRunLogStore to handle logging of pack run events. - Developed MongoPackRunStateStore for persisting and retrieving pack run states. - Implemented unit tests for MongoDB stores to ensure correct functionality. - Added MongoTaskRunnerTestContext for setting up MongoDB test environment. - Enhanced PackRunStateFactory to correctly initialize state with gate reasons.
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace StellaOps.AdvisoryAI.Diagnostics;
|
||||
|
||||
internal static class AdvisoryAiActivitySource
|
||||
{
|
||||
public static readonly ActivitySource Instance = new("StellaOps.AdvisoryAI");
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using StellaOps.AdvisoryAI.Guardrails;
|
||||
using StellaOps.AdvisoryAI.Outputs;
|
||||
using StellaOps.AdvisoryAI.Orchestration;
|
||||
@@ -53,27 +56,72 @@ internal sealed class AdvisoryPipelineExecutor : IAdvisoryPipelineExecutor
|
||||
|
||||
var prompt = await _promptAssembler.AssembleAsync(plan, cancellationToken).ConfigureAwait(false);
|
||||
var guardrailResult = await _guardrailPipeline.EvaluateAsync(prompt, cancellationToken).ConfigureAwait(false);
|
||||
var violationCount = guardrailResult.Violations.Length;
|
||||
|
||||
if (guardrailResult.Blocked)
|
||||
{
|
||||
_logger?.LogWarning(
|
||||
"Guardrail blocked advisory pipeline output for {TaskType} on advisory {AdvisoryKey}",
|
||||
"Guardrail blocked advisory pipeline output for {TaskType} on advisory {AdvisoryKey} with {ViolationCount} violations",
|
||||
plan.Request.TaskType,
|
||||
plan.Request.AdvisoryKey,
|
||||
violationCount);
|
||||
}
|
||||
else if (violationCount > 0)
|
||||
{
|
||||
_logger?.LogInformation(
|
||||
"Guardrail recorded {ViolationCount} advisory validation violations for {TaskType} on advisory {AdvisoryKey}",
|
||||
violationCount,
|
||||
plan.Request.TaskType,
|
||||
plan.Request.AdvisoryKey);
|
||||
}
|
||||
|
||||
var citationCoverage = CalculateCitationCoverage(plan, prompt);
|
||||
var activity = Activity.Current;
|
||||
activity?.SetTag("advisory.guardrail_blocked", guardrailResult.Blocked);
|
||||
activity?.SetTag("advisory.validation_failures", violationCount);
|
||||
activity?.SetTag("advisory.citation_coverage", citationCoverage);
|
||||
_metrics.RecordGuardrailOutcome(plan.Request.TaskType, guardrailResult.Blocked, violationCount);
|
||||
_metrics.RecordCitationCoverage(
|
||||
plan.Request.TaskType,
|
||||
citationCoverage,
|
||||
prompt.Citations.Length,
|
||||
plan.StructuredChunks.Length);
|
||||
|
||||
var generatedAt = _timeProvider.GetUtcNow();
|
||||
var output = AdvisoryPipelineOutput.Create(plan, prompt, guardrailResult, generatedAt, planFromCache);
|
||||
await _outputStore.SaveAsync(output, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_metrics.RecordGuardrailResult(plan.Request.TaskType, guardrailResult.Blocked);
|
||||
_metrics.RecordOutputStored(plan.Request.TaskType, planFromCache, guardrailResult.Blocked);
|
||||
|
||||
_logger?.LogInformation(
|
||||
"Stored advisory pipeline output {CacheKey} (task {TaskType}, cache:{CacheHit}, guardrail_blocked:{Blocked})",
|
||||
"Stored advisory pipeline output {CacheKey} (task {TaskType}, cache:{CacheHit}, guardrail_blocked:{Blocked}, validation_failures:{ValidationFailures}, citation_coverage:{CitationCoverage:0.00})",
|
||||
output.CacheKey,
|
||||
plan.Request.TaskType,
|
||||
planFromCache,
|
||||
guardrailResult.Blocked);
|
||||
guardrailResult.Blocked,
|
||||
violationCount,
|
||||
citationCoverage);
|
||||
}
|
||||
|
||||
private static double CalculateCitationCoverage(AdvisoryTaskPlan plan, AdvisoryPrompt prompt)
|
||||
{
|
||||
var structuredCount = plan.StructuredChunks.Length;
|
||||
if (structuredCount <= 0)
|
||||
{
|
||||
return 0d;
|
||||
}
|
||||
|
||||
if (prompt.Citations.IsDefaultOrEmpty)
|
||||
{
|
||||
return 0d;
|
||||
}
|
||||
|
||||
var uniqueCitations = prompt.Citations
|
||||
.Select(citation => (citation.DocumentId, citation.ChunkId))
|
||||
.Distinct()
|
||||
.Count();
|
||||
|
||||
var coverage = (double)uniqueCitations / structuredCount;
|
||||
return Math.Clamp(coverage, 0d, 1d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,10 @@ public sealed class AdvisoryPipelineMetrics : IDisposable
|
||||
private readonly Counter<long> _plansProcessed;
|
||||
private readonly Counter<long> _outputsStored;
|
||||
private readonly Counter<long> _guardrailBlocks;
|
||||
private readonly Counter<long> _validationFailures;
|
||||
private readonly Histogram<double> _planBuildDuration;
|
||||
private readonly Histogram<double> _pipelineLatencySeconds;
|
||||
private readonly Histogram<double> _citationCoverageRatio;
|
||||
private bool _disposed;
|
||||
|
||||
public AdvisoryPipelineMetrics(IMeterFactory meterFactory)
|
||||
@@ -25,8 +28,11 @@ public sealed class AdvisoryPipelineMetrics : IDisposable
|
||||
_plansQueued = _meter.CreateCounter<long>("advisory_plans_queued");
|
||||
_plansProcessed = _meter.CreateCounter<long>("advisory_plans_processed");
|
||||
_outputsStored = _meter.CreateCounter<long>("advisory_outputs_stored");
|
||||
_guardrailBlocks = _meter.CreateCounter<long>("advisory_guardrail_blocks");
|
||||
_guardrailBlocks = _meter.CreateCounter<long>("advisory_ai_guardrail_blocks_total");
|
||||
_validationFailures = _meter.CreateCounter<long>("advisory_ai_validation_failures_total");
|
||||
_planBuildDuration = _meter.CreateHistogram<double>("advisory_plan_build_duration_seconds");
|
||||
_pipelineLatencySeconds = _meter.CreateHistogram<double>("advisory_ai_latency_seconds");
|
||||
_citationCoverageRatio = _meter.CreateHistogram<double>("advisory_ai_citation_coverage_ratio");
|
||||
}
|
||||
|
||||
public void RecordPlanCreated(double buildSeconds, AdvisoryTaskType taskType)
|
||||
@@ -55,12 +61,40 @@ public sealed class AdvisoryPipelineMetrics : IDisposable
|
||||
KeyValuePair.Create<string, object?>("guardrail_blocked", guardrailBlocked));
|
||||
}
|
||||
|
||||
public void RecordGuardrailResult(AdvisoryTaskType taskType, bool blocked)
|
||||
public void RecordGuardrailOutcome(AdvisoryTaskType taskType, bool blocked, int validationFailures)
|
||||
{
|
||||
if (blocked)
|
||||
{
|
||||
_guardrailBlocks.Add(1, KeyValuePair.Create<string, object?>("task_type", taskType.ToString()));
|
||||
}
|
||||
|
||||
if (validationFailures > 0)
|
||||
{
|
||||
_validationFailures.Add(
|
||||
validationFailures,
|
||||
KeyValuePair.Create<string, object?>("task_type", taskType.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
public void RecordPipelineLatency(AdvisoryTaskType taskType, double seconds, bool planFromCache)
|
||||
{
|
||||
_pipelineLatencySeconds.Record(
|
||||
seconds,
|
||||
KeyValuePair.Create<string, object?>("task_type", taskType.ToString()),
|
||||
KeyValuePair.Create<string, object?>("plan_cache_hit", planFromCache));
|
||||
}
|
||||
|
||||
public void RecordCitationCoverage(
|
||||
AdvisoryTaskType taskType,
|
||||
double coverageRatio,
|
||||
int citationCount,
|
||||
int structuredChunkCount)
|
||||
{
|
||||
_citationCoverageRatio.Record(
|
||||
coverageRatio,
|
||||
KeyValuePair.Create<string, object?>("task_type", taskType.ToString()),
|
||||
KeyValuePair.Create<string, object?>("citations", citationCount),
|
||||
KeyValuePair.Create<string, object?>("structured_chunks", structuredChunkCount));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
| AIAI-31-003 | DONE (2025-11-04) | Advisory AI Guild | AIAI-31-001..002 | Implement deterministic toolset (version comparators, range checks, dependency analysis, policy lookup) exposed via orchestrator. | Tools validated with property tests; outputs cached; docs updated. |
|
||||
| AIAI-31-004 | DONE (2025-11-04) | Advisory AI Guild | AIAI-31-001..003, AUTH-VULN-29-001 | Build orchestration pipeline for Summary/Conflict/Remediation tasks (prompt templates, tool calls, token budgets, caching). | Pipeline executes tasks deterministically; caches keyed by tuple+policy; integration tests cover tasks. |
|
||||
| AIAI-31-004A | DONE (2025-11-04) | Advisory AI Guild, Platform Guild | AIAI-31-004, AIAI-31-002 | Wire `AdvisoryPipelineOrchestrator` into WebService/Worker, expose API/queue contracts, emit metrics, and stand up cache stub. | API returns plan metadata; worker executes queue message; metrics recorded; doc updated. |
|
||||
| AIAI-31-004B | TODO | Advisory AI Guild, Security Guild | AIAI-31-004A, DOCS-AIAI-31-003, AUTH-AIAI-31-004 | Implement prompt assembler, guardrail plumbing, cache persistence, DSSE provenance; add golden outputs. | Deterministic outputs cached; guardrails enforced; tests cover prompt assembly + caching. |
|
||||
| AIAI-31-004C | TODO | Advisory AI Guild, CLI Guild, Docs Guild | AIAI-31-004B, CLI-AIAI-31-003 | Deliver CLI `stella advise run <task>` command, renderers, documentation updates, and CLI golden tests. | CLI command produces deterministic output; docs published; smoke run recorded. |
|
||||
| AIAI-31-004B | DONE (2025-11-06) | Advisory AI Guild, Security Guild | AIAI-31-004A, DOCS-AIAI-31-003, AUTH-AIAI-31-004 | Implement prompt assembler, guardrail plumbing, cache persistence, DSSE provenance; add golden outputs. | Deterministic outputs cached; guardrails enforced; tests cover prompt assembly + caching. |
|
||||
| AIAI-31-004C | DONE (2025-11-06) | Advisory AI Guild, CLI Guild, Docs Guild | AIAI-31-004B, CLI-AIAI-31-003 | Deliver CLI `stella advise run <task>` command, renderers, documentation updates, and CLI golden tests. | CLI command produces deterministic output; docs published; smoke run recorded. |
|
||||
| AIAI-31-005 | DONE (2025-11-04) | Advisory AI Guild, Security Guild | AIAI-31-004 | Implement guardrails (redaction, injection defense, output validation, citation enforcement) and fail-safe handling. | Guardrails block adversarial inputs; output validator enforces schemas; security tests pass. |
|
||||
| AIAI-31-006 | DONE (2025-11-04) | Advisory AI Guild | AIAI-31-004..005 | Expose REST API endpoints (`/advisory/ai/*`) with RBAC, rate limits, OpenAPI schemas, and batching support. | Endpoints deployed with schema validation; rate limits enforced; integration tests cover error codes. |
|
||||
| AIAI-31-007 | TODO | Advisory AI Guild, Observability Guild | AIAI-31-004..006 | Instrument metrics (`advisory_ai_latency`, `guardrail_blocks`, `validation_failures`, `citation_coverage`), logs, and traces; publish dashboards/alerts. | Telemetry live; dashboards approved; alerts configured. |
|
||||
| AIAI-31-007 | DONE (2025-11-06) | Advisory AI Guild, Observability Guild | AIAI-31-004..006 | Instrument metrics (`advisory_ai_latency`, `guardrail_blocks`, `validation_failures`, `citation_coverage`), logs, and traces; publish dashboards/alerts. | Telemetry live; dashboards approved; alerts configured. |
|
||||
| AIAI-31-008 | TODO | Advisory AI Guild, DevOps Guild | AIAI-31-006..007 | Package inference on-prem container, remote inference toggle, Helm/Compose manifests, scaling guidance, offline kit instructions. | Deployment docs merged; smoke deploy executed; offline kit updated; feature flags documented. |
|
||||
| AIAI-31-010 | DONE (2025-11-02) | Advisory AI Guild | CONCELIER-VULN-29-001, EXCITITOR-VULN-29-001 | Implement Concelier advisory raw document provider mapping CSAF/OSV payloads into structured chunks for retrieval. | Provider resolves content format, preserves metadata, and passes unit tests covering CSAF/OSV cases. |
|
||||
| AIAI-31-011 | DONE (2025-11-02) | Advisory AI Guild | EXCITITOR-LNM-21-201, EXCITITOR-CORE-AOC-19-002 | Implement Excititor VEX document provider to surface structured VEX statements for vector retrieval. | Provider returns conflict-aware VEX chunks with deterministic metadata and tests for representative statements. |
|
||||
@@ -31,3 +31,5 @@
|
||||
> 2025-11-04: AIAI-31-005 DONE – guardrail pipeline redacts secrets, enforces citation/injection policies, emits block counters, and tests (`AdvisoryGuardrailPipelineTests`) cover redaction + citation validation.
|
||||
|
||||
> 2025-11-04: AIAI-31-006 DONE – REST endpoints enforce header scopes, apply token bucket rate limiting, sanitize prompts via guardrails, and queue execution with cached metadata. Tests executed via `dotnet test src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj --no-restore`.
|
||||
> 2025-11-06: AIAI-31-004B/C – Resuming prompt/cache hardening and CLI integration; first focus on backend client wiring and deterministic CLI outputs before full suite.
|
||||
> 2025-11-06: AIAI-31-004B/C DONE – Advisory AI Mongo integration validated, backend client + CLI `advise run` wired, deterministic console renderer with provenance/guardrail display added, docs refreshed, and targeted CLI tests executed.
|
||||
|
||||
Reference in New Issue
Block a user