synergy moats product advisory implementations

This commit is contained in:
master
2026-01-17 01:30:03 +02:00
parent 77ff029205
commit 702a27ac83
112 changed files with 21356 additions and 127 deletions

View File

@@ -0,0 +1,131 @@
// -----------------------------------------------------------------------------
// InstallTimestampService.cs
// Sprint: SPRINT_20260117_028_Telemetry_p0_metrics
// Task: P0M-001 - Time-to-First-Verified-Release Metric
// Description: Service to record and retrieve install timestamp for P0M-001
// -----------------------------------------------------------------------------
using Microsoft.Extensions.Logging;
namespace StellaOps.Telemetry.Core;
/// <summary>
/// Service for tracking install timestamp to enable time-to-first-release metrics.
/// </summary>
public sealed class InstallTimestampService
{
private readonly ILogger<InstallTimestampService>? _logger;
private readonly string _timestampFilePath;
private DateTimeOffset? _cachedTimestamp;
/// <summary>
/// Initializes the install timestamp service.
/// </summary>
/// <param name="dataPath">Path to data directory for storing timestamp.</param>
/// <param name="logger">Optional logger.</param>
public InstallTimestampService(string dataPath, ILogger<InstallTimestampService>? logger = null)
{
_logger = logger;
_timestampFilePath = Path.Combine(dataPath, ".install-timestamp");
}
/// <summary>
/// Records the install timestamp if not already recorded.
/// Call this on first service startup.
/// </summary>
/// <returns>The install timestamp (existing or newly recorded).</returns>
public async Task<DateTimeOffset> EnsureInstallTimestampAsync(CancellationToken ct = default)
{
if (_cachedTimestamp.HasValue)
{
return _cachedTimestamp.Value;
}
// Check if timestamp already exists
if (File.Exists(_timestampFilePath))
{
try
{
var content = await File.ReadAllTextAsync(_timestampFilePath, ct);
if (DateTimeOffset.TryParse(content.Trim(), out var existing))
{
_cachedTimestamp = existing;
_logger?.LogDebug("Existing install timestamp loaded: {Timestamp}", existing);
return existing;
}
}
catch (Exception ex)
{
_logger?.LogWarning(ex, "Failed to read install timestamp file");
}
}
// Record new timestamp
var timestamp = DateTimeOffset.UtcNow;
try
{
var directory = Path.GetDirectoryName(_timestampFilePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
await File.WriteAllTextAsync(_timestampFilePath, timestamp.ToString("o"), ct);
_cachedTimestamp = timestamp;
_logger?.LogInformation("Install timestamp recorded: {Timestamp}", timestamp);
}
catch (Exception ex)
{
_logger?.LogWarning(ex, "Failed to persist install timestamp");
_cachedTimestamp = timestamp;
}
return timestamp;
}
/// <summary>
/// Gets the install timestamp if available.
/// </summary>
/// <returns>The install timestamp or null if not yet recorded.</returns>
public DateTimeOffset? GetInstallTimestamp()
{
if (_cachedTimestamp.HasValue)
{
return _cachedTimestamp.Value;
}
if (File.Exists(_timestampFilePath))
{
try
{
var content = File.ReadAllText(_timestampFilePath);
if (DateTimeOffset.TryParse(content.Trim(), out var existing))
{
_cachedTimestamp = existing;
return existing;
}
}
catch
{
// Ignore read errors
}
}
return null;
}
/// <summary>
/// Calculates duration from install to now.
/// </summary>
/// <returns>Duration since install, or null if not installed.</returns>
public TimeSpan? GetTimeSinceInstall()
{
var installTime = GetInstallTimestamp();
if (!installTime.HasValue)
{
return null;
}
return DateTimeOffset.UtcNow - installTime.Value;
}
}

View File

@@ -0,0 +1,160 @@
// -----------------------------------------------------------------------------
// P0ProductMetrics.cs
// Sprint: SPRINT_20260117_028_Telemetry_p0_metrics
// Task: P0M-001 through P0M-004 - P0 Product Metrics
// Description: P0 product-level metrics as defined in AI Economics Moat advisory
// -----------------------------------------------------------------------------
using System.Diagnostics.Metrics;
namespace StellaOps.Telemetry.Core;
/// <summary>
/// P0 product-level metrics for tracking Stella Ops health and adoption.
/// These metrics are the scoreboard - prioritize work that improves them.
/// </summary>
public sealed class P0ProductMetrics : IDisposable
{
/// <summary>
/// Meter name for P0 product metrics.
/// </summary>
public const string MeterName = "StellaOps.P0Metrics";
private readonly Meter _meter;
private bool _disposed;
// P0M-001: Time to First Verified Release
private readonly Histogram<double> _timeToFirstVerifiedRelease;
// P0M-002: Mean Time to Answer "Why Blocked"
private readonly Histogram<double> _whyBlockedLatency;
// P0M-003: Support Minutes per Customer
private readonly Counter<long> _supportBurdenMinutes;
// P0M-004: Determinism Regressions
private readonly Counter<long> _determinismRegressions;
/// <summary>
/// Initializes P0 product metrics.
/// </summary>
public P0ProductMetrics()
{
_meter = new Meter(MeterName, "1.0.0");
// P0M-001: Time from fresh install to first successful verified promotion
// Buckets: 5m, 15m, 30m, 1h, 2h, 4h, 8h, 24h, 48h, 168h (1 week)
_timeToFirstVerifiedRelease = _meter.CreateHistogram<double>(
name: "stella_time_to_first_verified_release_seconds",
unit: "s",
description: "Elapsed time from fresh install to first successful verified promotion");
// P0M-002: Time from block decision to user viewing explanation
// Buckets: 1s, 5s, 30s, 1m, 5m, 15m, 1h, 4h, 24h
_whyBlockedLatency = _meter.CreateHistogram<double>(
name: "stella_why_blocked_latency_seconds",
unit: "s",
description: "Time from block decision to user viewing explanation");
// P0M-003: Accumulated support time per customer per month
_supportBurdenMinutes = _meter.CreateCounter<long>(
name: "stella_support_burden_minutes_total",
unit: "min",
description: "Accumulated support time per customer");
// P0M-004: Count of detected determinism failures
_determinismRegressions = _meter.CreateCounter<long>(
name: "stella_determinism_regressions_total",
unit: "{regression}",
description: "Count of detected determinism failures in production");
}
/// <summary>
/// Records time to first verified release for a tenant.
/// Call this when a tenant completes their first successful verified promotion.
/// </summary>
/// <param name="durationSeconds">Time in seconds from install to first verified release.</param>
/// <param name="tenant">Tenant identifier.</param>
/// <param name="deploymentType">fresh or upgrade.</param>
public void RecordTimeToFirstVerifiedRelease(
double durationSeconds,
string tenant,
string deploymentType = "fresh")
{
_timeToFirstVerifiedRelease.Record(
durationSeconds,
new KeyValuePair<string, object?>("tenant", tenant),
new KeyValuePair<string, object?>("deployment_type", deploymentType));
}
/// <summary>
/// Records latency for "why blocked" explanation view.
/// Call this when a user views a block explanation via CLI, UI, or API.
/// </summary>
/// <param name="durationSeconds">Time in seconds from block decision to explanation view.</param>
/// <param name="tenant">Tenant identifier.</param>
/// <param name="surface">Surface where explanation was viewed: cli, ui, api.</param>
/// <param name="resolutionType">immediate (same session) or delayed (different session).</param>
public void RecordWhyBlockedLatency(
double durationSeconds,
string tenant,
string surface,
string resolutionType = "immediate")
{
_whyBlockedLatency.Record(
durationSeconds,
new KeyValuePair<string, object?>("tenant", tenant),
new KeyValuePair<string, object?>("surface", surface),
new KeyValuePair<string, object?>("resolution_type", resolutionType));
}
/// <summary>
/// Records support time spent on a customer.
/// Call this when logging support events via CLI or API.
/// </summary>
/// <param name="minutes">Support time in minutes.</param>
/// <param name="tenant">Tenant identifier.</param>
/// <param name="category">Support category: install, config, policy, integration, bug, other.</param>
/// <param name="month">Month in YYYY-MM format.</param>
public void RecordSupportBurden(
long minutes,
string tenant,
string category,
string month)
{
_supportBurdenMinutes.Add(
minutes,
new KeyValuePair<string, object?>("tenant", tenant),
new KeyValuePair<string, object?>("category", category),
new KeyValuePair<string, object?>("month", month));
}
/// <summary>
/// Records a determinism regression detection.
/// Call this when determinism verification fails.
/// </summary>
/// <param name="tenant">Tenant identifier.</param>
/// <param name="component">Component where regression occurred: scanner, policy, attestor, export.</param>
/// <param name="severity">Fidelity tier: bitwise, semantic, policy.</param>
public void RecordDeterminismRegression(
string tenant,
string component,
string severity)
{
_determinismRegressions.Add(
1,
new KeyValuePair<string, object?>("tenant", tenant),
new KeyValuePair<string, object?>("component", component),
new KeyValuePair<string, object?>("severity", severity));
}
/// <inheritdoc />
public void Dispose()
{
if (!_disposed)
{
_meter.Dispose();
_disposed = true;
}
}
}