save checkpoint: save features

This commit is contained in:
master
2026-02-12 10:27:23 +02:00
parent dca86e1248
commit 5bca406787
8837 changed files with 1796879 additions and 5294 deletions

View File

@@ -0,0 +1,95 @@
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Doctor.AdvisoryAI;
using StellaOps.Doctor.Models;
using StellaOps.TestKit.Templates;
using Xunit;
namespace StellaOps.Doctor.Tests.AdvisoryAI;
[Trait("Category", "Unit")]
public sealed class DoctorContextAdapterTests
{
[Fact]
public async Task CreateContextAsync_ProjectsSummaryAndEnrichedEvidence()
{
var registry = new InMemoryEvidenceSchemaRegistry();
registry.RegisterCommonSchemas();
var timeProvider = new FlakyToDeterministicPattern.FakeTimeProvider(
new DateTimeOffset(2026, 2, 11, 18, 0, 0, TimeSpan.Zero));
var adapter = new DoctorContextAdapter(
registry,
NullLogger<DoctorContextAdapter>.Instance,
timeProvider);
var report = new DoctorReport
{
RunId = "dr_context_001",
StartedAt = new DateTimeOffset(2026, 2, 11, 17, 59, 0, TimeSpan.Zero),
CompletedAt = new DateTimeOffset(2026, 2, 11, 18, 0, 0, TimeSpan.Zero),
Duration = TimeSpan.FromMinutes(1),
OverallSeverity = DoctorSeverity.Fail,
Summary = new DoctorReportSummary
{
Passed = 0,
Info = 0,
Warnings = 0,
Failed = 1,
Skipped = 0
},
Results =
[
new DoctorCheckResult
{
CheckId = "check.integration.latency",
PluginId = "stellaops.doctor.integration",
Category = "Integration",
Severity = DoctorSeverity.Fail,
Diagnosis = "Latency is too high.",
Evidence = new Evidence
{
Description = "Connection probe metrics",
Data = new Dictionary<string, string>
{
["connection_latency_ms"] = "1450",
["endpoint"] = "http://localhost:9000"
}
},
LikelyCauses = ["network_issue"],
Remediation = new Remediation
{
RequiresBackup = false,
SafetyNote = "No backup required.",
RunbookUrl = "https://docs.stella-ops.local/runbooks/network-latency",
Steps =
[
new RemediationStep
{
Order = 1,
Description = "Inspect endpoint latency",
Command = "stella doctor --check check.integration.latency",
CommandType = CommandType.Api
}
]
},
VerificationCommand = "stella doctor --check check.integration.latency",
Duration = TimeSpan.FromMilliseconds(200),
ExecutedAt = new DateTimeOffset(2026, 2, 11, 17, 59, 30, TimeSpan.Zero)
}
]
};
var context = await adapter.CreateContextAsync(report, CancellationToken.None);
context.RunId.Should().Be("dr_context_001");
context.Summary.FailedChecks.Should().Be(1);
context.Summary.CategoriesWithIssues.Should().ContainSingle("Integration");
context.Results.Should().HaveCount(1);
context.Results[0].Evidence.Fields.Should().ContainKey("connection_latency_ms");
context.Results[0].Evidence.Fields["connection_latency_ms"].ExpectedRange.Should().Be("< 1000");
context.Results[0].Remediation.Should().NotBeNull();
context.Results[0].Remediation!.RunbookUrl.Should().Be("https://docs.stella-ops.local/runbooks/network-latency");
context.PlatformContext.Should().ContainKey("captured_at_utc");
context.PlatformContext.Should().ContainKey("doctor_version");
}
}

View File

@@ -0,0 +1,40 @@
using FluentAssertions;
using StellaOps.Doctor.AdvisoryAI;
using Xunit;
namespace StellaOps.Doctor.Tests.AdvisoryAI;
[Trait("Category", "Unit")]
public sealed class InMemoryEvidenceSchemaRegistryTests
{
[Fact]
public void RegisterCommonSchemas_ExposesWildcardSchemaLookup()
{
var registry = new InMemoryEvidenceSchemaRegistry();
registry.RegisterCommonSchemas();
var schema = registry.GetFieldSchema("check.integration.example", "connection_latency_ms");
schema.Should().NotBeNull();
schema!.ExpectedRange.Should().Be("< 1000");
schema.IsKeyDiagnostic.Should().BeTrue();
}
[Fact]
public void RegisterSchema_OverridesWildcardForSpecificCheck()
{
var registry = new InMemoryEvidenceSchemaRegistry();
registry.RegisterCommonSchemas();
registry.RegisterSchema("check.specific", "connection_latency_ms", new EvidenceFieldSchema
{
ExpectedRange = "< 100",
Description = "Strict latency threshold."
});
var schema = registry.GetFieldSchema("check.specific", "connection_latency_ms");
schema.Should().NotBeNull();
schema!.ExpectedRange.Should().Be("< 100");
schema.Description.Should().Be("Strict latency threshold.");
}
}

View File

@@ -176,6 +176,26 @@ public sealed class JsonReportFormatterTests
doc.RootElement.TryGetProperty("duration", out _).Should().BeTrue();
}
[Fact]
public void Format_WithRunbookUrlInRemediation_ContainsRunbookUrl()
{
// Arrange
var formatter = new JsonReportFormatter();
var report = CreateReportWithRemediationRunbook("https://docs.stella-ops.org/runbooks/test-check");
// Act
var output = formatter.Format(report);
using var doc = JsonDocument.Parse(output);
// Assert
var runbookUrl = doc.RootElement
.GetProperty("results")[0]
.GetProperty("remediation")
.GetProperty("runbookUrl")
.GetString();
runbookUrl.Should().Be("https://docs.stella-ops.org/runbooks/test-check");
}
private static DoctorReport CreateEmptyReport(string? runId = null)
{
return new DoctorReport
@@ -249,6 +269,55 @@ public sealed class JsonReportFormatterTests
};
}
private static DoctorReport CreateReportWithRemediationRunbook(string runbookUrl)
{
var remediation = new Remediation
{
RunbookUrl = runbookUrl,
Steps =
[
new RemediationStep
{
Order = 1,
Description = "Apply deterministic fix",
Command = "stella doctor fix --from report.json",
CommandType = CommandType.Shell
}
]
};
var result = new DoctorCheckResult
{
CheckId = "check.test.remediation.runbook",
PluginId = "test.plugin",
Category = "Test",
Severity = DoctorSeverity.Fail,
Diagnosis = "Runbook projection test",
Evidence = new Evidence
{
Description = "Test evidence",
Data = new Dictionary<string, string>()
},
Remediation = remediation,
Duration = TimeSpan.FromMilliseconds(50),
ExecutedAt = DateTimeOffset.UtcNow
};
var results = ImmutableArray.Create(result);
var summary = DoctorReportSummary.FromResults(results);
return new DoctorReport
{
RunId = $"dr_test_{Guid.NewGuid():N}",
StartedAt = DateTimeOffset.UtcNow.AddSeconds(-1),
CompletedAt = DateTimeOffset.UtcNow,
Duration = TimeSpan.FromSeconds(1),
OverallSeverity = DoctorSeverity.Fail,
Summary = summary,
Results = results
};
}
private static DoctorCheckResult CreateCheckResult(DoctorSeverity severity, string checkId)
{
return new DoctorCheckResult

View File

@@ -0,0 +1,73 @@
// <copyright file="MarkdownReportFormatterTests.cs" company="Stella Operations">
// Copyright (c) Stella Operations. Licensed under BUSL-1.1.
// </copyright>
using System.Collections.Immutable;
using FluentAssertions;
using StellaOps.Doctor.Models;
using StellaOps.Doctor.Output;
using Xunit;
namespace StellaOps.Doctor.Tests.Output;
[Trait("Category", "Unit")]
public sealed class MarkdownReportFormatterTests
{
[Fact]
public void Format_WithRunbookUrlInRemediation_ContainsClickableRunbookLink()
{
var formatter = new MarkdownReportFormatter();
var report = CreateReportWithRemediationRunbook("https://docs.stella-ops.org/runbooks/markdown-check");
var output = formatter.Format(report);
output.Should().Contain("**Runbook:** [https://docs.stella-ops.org/runbooks/markdown-check](https://docs.stella-ops.org/runbooks/markdown-check)");
}
private static DoctorReport CreateReportWithRemediationRunbook(string runbookUrl)
{
var result = new DoctorCheckResult
{
CheckId = "check.test.markdown.runbook",
PluginId = "test.plugin",
Category = "Test",
Severity = DoctorSeverity.Fail,
Diagnosis = "Runbook markdown output test",
Evidence = new Evidence
{
Description = "Test evidence",
Data = new Dictionary<string, string>()
},
Remediation = new Remediation
{
RunbookUrl = runbookUrl,
Steps =
[
new RemediationStep
{
Order = 1,
Description = "Apply fix",
Command = "stella doctor fix --from report.json",
CommandType = CommandType.Shell
}
]
},
Duration = TimeSpan.FromMilliseconds(10),
ExecutedAt = DateTimeOffset.UtcNow
};
var results = ImmutableArray.Create(result);
var summary = DoctorReportSummary.FromResults(results);
return new DoctorReport
{
RunId = $"dr_test_{Guid.NewGuid():N}",
StartedAt = DateTimeOffset.UtcNow.AddSeconds(-1),
CompletedAt = DateTimeOffset.UtcNow,
Duration = TimeSpan.FromSeconds(1),
OverallSeverity = DoctorSeverity.Fail,
Summary = summary,
Results = results
};
}
}

View File

@@ -133,6 +133,21 @@ public sealed class TextReportFormatterTests
output.Should().Contain("check.test.example");
}
[Fact]
public void Format_WithRunbookUrlInRemediation_ContainsRunbookLink()
{
// Arrange
var formatter = new TextReportFormatter();
var report = CreateReportWithRemediationRunbook("https://docs.stella-ops.org/runbooks/text-check");
// Act
var output = formatter.Format(report);
// Assert
output.Should().Contain("Runbook:");
output.Should().Contain("https://docs.stella-ops.org/runbooks/text-check");
}
private static DoctorReport CreateEmptyReport(string? runId = null)
{
return new DoctorReport
@@ -224,4 +239,51 @@ public sealed class TextReportFormatterTests
ExecutedAt = DateTimeOffset.UtcNow
};
}
private static DoctorReport CreateReportWithRemediationRunbook(string runbookUrl)
{
var result = new DoctorCheckResult
{
CheckId = "check.test.runbook.output",
PluginId = "test.plugin",
Category = "Test",
Severity = DoctorSeverity.Fail,
Diagnosis = "Runbook output test",
Evidence = new Evidence
{
Description = "Test evidence",
Data = new Dictionary<string, string>()
},
Remediation = new Remediation
{
RunbookUrl = runbookUrl,
Steps =
[
new RemediationStep
{
Order = 1,
Description = "Apply fix",
Command = "stella doctor fix --from report.json",
CommandType = CommandType.Shell
}
]
},
Duration = TimeSpan.FromMilliseconds(50),
ExecutedAt = DateTimeOffset.UtcNow
};
var results = ImmutableArray.Create(result);
var summary = DoctorReportSummary.FromResults(results);
return new DoctorReport
{
RunId = $"dr_test_{Guid.NewGuid():N}",
StartedAt = DateTimeOffset.UtcNow.AddSeconds(-1),
CompletedAt = DateTimeOffset.UtcNow,
Duration = TimeSpan.FromSeconds(1),
OverallSeverity = DoctorSeverity.Fail,
Summary = summary,
Results = results
};
}
}

View File

@@ -4,5 +4,7 @@ Source of truth: `docs/implplan/SPRINT_20260130_002_Tools_csproj_remediation_sol
| Task ID | Status | Notes |
| --- | --- | --- |
| DOC-RMD-B1-001 | DONE | Added runbook URL projection coverage in JSON/Text/Markdown formatter tests for `doctor-runbook-url-integration` run-002 remediation. |
| DOC-RMD-B1-003 | DONE | Added AdvisoryAI unit coverage (`DoctorContextAdapterTests`, `InMemoryEvidenceSchemaRegistryTests`) for run-002 diagnosis remediation in shared Doctor library. |
| REMED-05 | TODO | Remediation checklist: docs/implplan/audits/csproj-standards/remediation/checklists/src/__Libraries/__Tests/StellaOps.Doctor.Tests/StellaOps.Doctor.Tests.md. |
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |