Mimir/src/Mimir.Well/Program.cs

1589 lines
58 KiB
C#
Raw Normal View History

2026-06-01 21:27:57 +01:00
using System.Net.WebSockets;
2026-06-02 00:47:25 +01:00
using System.Diagnostics;
2026-06-01 21:27:57 +01:00
using System.Text;
using System.Text.Json;
using Mimir.Runtime.Synchronization;
var options = MimirWellOptions.Parse(args);
var runtimeConfig = MimirRuntimeConfiguration.Load();
using var hub = new MimirSynchronizationHub(runtimeConfig.Settings);
var sourceErrors = new List<object>();
foreach (var factory in runtimeConfig.SourceFactories)
{
try
{
var source = factory.Create();
if (source == null)
{
sourceErrors.Add(new { factory.Descriptor.SourceId, status = "not-created" });
continue;
}
hub.AddSource(source);
}
catch (Exception ex)
{
sourceErrors.Add(new
{
factory.Descriptor.SourceId,
status = "create-error",
errorType = ex.GetType().Name,
ex.Message,
});
}
}
using var stopping = new CancellationTokenSource();
if (options.Seconds > 0)
{
stopping.CancelAfter(TimeSpan.FromSeconds(options.Seconds));
}
Console.CancelKeyPress += (_, eventArgs) =>
{
eventArgs.Cancel = true;
stopping.Cancel();
};
await using var publisher = new MimirWellPublisher(options.PublishUrl);
await publisher.ConnectAsync(stopping.Token).ConfigureAwait(false);
var sequence = 0L;
2026-06-02 00:07:21 +01:00
var captureSequence = 0L;
2026-06-01 21:27:57 +01:00
var startedAt = DateTimeOffset.UtcNow;
var nextPublish = DateTimeOffset.MinValue;
2026-06-02 00:07:21 +01:00
var nextCapture = DateTimeOffset.MinValue;
2026-06-01 21:27:57 +01:00
var nextSync = DateTimeOffset.MinValue;
2026-06-01 23:52:17 +01:00
var nextVisualCalibration = DateTimeOffset.MinValue;
2026-06-02 00:47:25 +01:00
var frameDegradedCount = 0L;
var nextFrameDegradedLog = DateTimeOffset.MinValue;
var streamTelemetry = new MimirWellStreamTelemetry();
2026-06-02 15:13:25 +01:00
var latencyController = new MimirWellLatencyController(options);
var featureSignals = new MimirWellFeatureSignalBank(options);
2026-06-01 21:27:57 +01:00
var presentation = new MimirPresentationControlState();
2026-06-01 23:52:17 +01:00
var exposureController = new MimirCameraExposureController(new MimirCameraExposureControlOptions(
options.VisualCalibrationEnabled,
options.VisualExpectedLedCount,
options.VisualMinimumLuma,
options.VisualSettingSeconds,
options.VisualResweepSeconds));
2026-06-01 21:27:57 +01:00
Console.Error.WriteLine($"Mimir Well publishing to {options.PublishUrl}");
Console.Error.WriteLine($"Mimir Well sources={runtimeConfig.SourceFactories.Count} buffers={hub.Buffers.Buffers.Count}");
while (!stopping.IsCancellationRequested)
{
2026-06-02 00:47:25 +01:00
var pollStopwatch = Stopwatch.StartNew();
var consumedSamples = hub.PollSources(options.MaxSamplesPerSource);
pollStopwatch.Stop();
streamTelemetry.ObservePoll(consumedSamples, pollStopwatch.Elapsed);
2026-06-01 21:27:57 +01:00
var now = DateTimeOffset.UtcNow;
if (now >= nextSync)
{
if (!string.IsNullOrWhiteSpace(runtimeConfig.Settings.Audio.ReferenceSourceId))
{
hub.AnalyzeAudioSynchronizationStep(
runtimeConfig.Settings.Audio.ReferenceSourceId,
runtimeConfig.Settings.Audio.Mode,
options.SyncCandidatesPerStep);
hub.AnalyzeComplexContourSynchronizationStep(
runtimeConfig.Settings.Audio.ReferenceSourceId,
(now - startedAt).TotalSeconds,
options.SyncCandidatesPerStep);
}
hub.UpdateBioacousticProbeSchedule(NowNs());
nextSync = now + TimeSpan.FromMilliseconds(options.SyncIntervalMs);
}
2026-06-01 23:52:17 +01:00
if (now >= nextVisualCalibration)
{
exposureController.Update(now, hub.Buffers.Buffers, hub.CameraExposureGainActuators);
nextVisualCalibration = now + TimeSpan.FromMilliseconds(options.VisualCalibrationIntervalMs);
}
2026-06-01 21:27:57 +01:00
if (now >= nextPublish)
{
presentation.SyncFromBuffers(hub.Buffers.Buffers);
2026-06-02 15:13:25 +01:00
var latencyDecision = latencyController.Decide(hub, now);
var frameResult = BuildFrameOrEmpty(hub, latencyDecision.PresentationDelay);
latencyController.ObserveFrame(frameResult);
var featureSignalFrame = featureSignals.Update(hub.Buffers.Buffers, frameResult.Frame);
2026-06-02 00:47:25 +01:00
if (!string.IsNullOrWhiteSpace(frameResult.DegradedReason))
{
frameDegradedCount++;
if (now >= nextFrameDegradedLog)
{
Console.Error.WriteLine(
$"mimir-well synchronized-frame degraded count={frameDegradedCount} reason={frameResult.DegradedReason}");
nextFrameDegradedLog = now + TimeSpan.FromSeconds(5);
}
}
var frame = frameResult.Frame;
2026-06-01 21:27:57 +01:00
var snapshot = MimirWellSnapshot.Build(
options,
runtimeConfig,
hub,
presentation,
2026-06-02 00:47:25 +01:00
frameResult,
2026-06-02 15:13:25 +01:00
latencyDecision,
featureSignalFrame,
2026-06-01 23:52:17 +01:00
exposureController.Statuses,
2026-06-01 21:27:57 +01:00
sourceErrors,
2026-06-02 00:47:25 +01:00
streamTelemetry.Snapshot(now, subscribersAreExternal: true),
2026-06-01 21:27:57 +01:00
++sequence,
startedAt);
2026-06-02 00:47:25 +01:00
streamTelemetry.ObservePublish(
await publisher.PublishAsync(snapshot, "mimir.well_snapshot.v1", stopping.Token).ConfigureAwait(false));
2026-06-02 00:07:21 +01:00
if (options.CapturePagesEnabled && now >= nextCapture)
{
2026-06-02 15:13:25 +01:00
var nextStreamSequence = captureSequence + 1;
if (options.StreamFramesEnabled)
{
foreach (var streamFrame in MimirWellCapturePage.BuildStreamFrames(
options,
frameResult,
hub.Buffers.Buffers,
nextStreamSequence,
startedAt))
{
streamTelemetry.ObservePublish(
await publisher.PublishAsync(streamFrame, "mimir.cultmesh_stream_frame.v1", stopping.Token).ConfigureAwait(false));
}
}
2026-06-02 00:07:21 +01:00
var capturePage = MimirWellCapturePage.Build(
options,
presentation,
2026-06-02 00:47:25 +01:00
frameResult,
2026-06-02 00:25:19 +01:00
hub.Buffers.Buffers,
2026-06-02 00:07:21 +01:00
++captureSequence,
startedAt);
2026-06-02 00:47:25 +01:00
streamTelemetry.ObservePublish(
await publisher.PublishAsync(capturePage, "mimir.well_capture_page.v1", stopping.Token).ConfigureAwait(false));
2026-06-02 00:07:21 +01:00
nextCapture = now + TimeSpan.FromMilliseconds(options.CaptureIntervalMs);
}
2026-06-01 21:27:57 +01:00
if (sequence % Math.Max(1, options.MeterEvery) == 0)
{
Console.Error.WriteLine(
$"mimir-well sequence={sequence} ingested={hub.IngestedSamples} ready={frame.Slices.Count(slice => slice.Status == MimirSynchronizedSliceStatus.Ready)}/{frame.Slices.Count}");
}
nextPublish = now + TimeSpan.FromMilliseconds(options.PublishIntervalMs);
}
try
{
await Task.Delay(Math.Max(1, options.PollMs), stopping.Token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
break;
}
}
Console.Error.WriteLine($"Mimir Well complete sequence={sequence} ingested={hub.IngestedSamples}");
static long NowNs() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 1_000_000L;
2026-06-02 00:47:25 +01:00
static MimirWellFrameBuildResult BuildFrameOrEmpty(MimirSynchronizationHub hub, TimeSpan presentationDelay)
2026-06-01 21:27:57 +01:00
{
try
{
2026-06-02 00:47:25 +01:00
return new MimirWellFrameBuildResult(
hub.BuildSynchronizedBufferFrame(presentationDelay),
"",
"");
2026-06-01 21:27:57 +01:00
}
catch (ArgumentException ex)
{
2026-06-02 00:47:25 +01:00
return new MimirWellFrameBuildResult(
new MimirSynchronizedBufferFrame(0, 0, 0, presentationDelay, []),
ex.GetType().Name,
ex.Message);
2026-06-01 21:27:57 +01:00
}
catch (OverflowException ex)
{
2026-06-02 00:47:25 +01:00
return new MimirWellFrameBuildResult(
new MimirSynchronizedBufferFrame(0, 0, 0, presentationDelay, []),
ex.GetType().Name,
ex.Message);
}
}
internal sealed record MimirWellFrameBuildResult(
MimirSynchronizedBufferFrame Frame,
string DegradedKind,
string DegradedReason);
2026-06-02 15:13:25 +01:00
internal sealed record MimirWellLatencyDecision(
TimeSpan PresentationDelay,
TimeSpan CeilingDelay,
TimeSpan FloorDelay,
TimeSpan RetainedOverlap,
TimeSpan EdgeSkew,
double ReadinessConfidence,
double SyncConfidence,
int ActiveBufferCount,
int ReadySliceCount,
int TotalSliceCount,
string Reason);
internal sealed class MimirWellLatencyController
{
private readonly MimirWellOptions options;
private readonly TimeSpan floor;
private TimeSpan current;
private int completeStreak;
private int degradedStreak;
private MimirWellFrameBuildResult? lastFrame;
public MimirWellLatencyController(MimirWellOptions options)
{
this.options = options;
floor = TimeSpan.FromMilliseconds(Math.Clamp(options.MinPresentationDelayMs, 0, options.PresentationDelayMs));
current = TimeSpan.FromMilliseconds(Math.Clamp(
options.TargetPresentationDelayMs,
options.MinPresentationDelayMs,
options.PresentationDelayMs));
}
public MimirWellLatencyDecision Decide(MimirSynchronizationHub hub, DateTimeOffset now)
{
var active = hub.Buffers.Buffers
.Where(static buffer => buffer.Latest.HasValue)
.ToArray();
if (active.Length == 0)
{
current = TimeSpan.FromMilliseconds(options.PresentationDelayMs);
return Decision(TimeSpan.Zero, TimeSpan.Zero, 0.0, 0.0, 0, 0, 0, "waiting-for-sources");
}
var latestEdges = active
.Select(static buffer => buffer.Latest?.TimestampNs ?? 0L)
.Where(static value => value > 0)
.ToArray();
var starts = active
.Select(static buffer => buffer.OldestSampleTimestampNs > 0 ? buffer.OldestSampleTimestampNs : buffer.WindowStartNs)
.Where(static value => value > 0)
.ToArray();
var minEdge = latestEdges.Length == 0 ? 0L : latestEdges.Min();
var maxEdge = latestEdges.Length == 0 ? 0L : latestEdges.Max();
var maxStart = starts.Length == 0 ? 0L : starts.Max();
var retainedOverlap = minEdge > 0 && maxStart > 0 ? TimeSpan.FromTicks(Math.Max(0L, (minEdge - maxStart) / 100L)) : TimeSpan.Zero;
var edgeSkew = minEdge > 0 && maxEdge > minEdge ? TimeSpan.FromTicks((maxEdge - minEdge) / 100L) : TimeSpan.Zero;
var syncConfidence = hub.AudioSynchronizationStates.Count == 0
? 0.0
: hub.AudioSynchronizationStates.Average(static state => Math.Clamp(state.Confidence, 0.0, 1.0));
var previousReady = lastFrame?.Frame.Slices.Count(static slice => slice.Status == MimirSynchronizedSliceStatus.Ready) ?? 0;
var previousTotal = lastFrame?.Frame.Slices.Count ?? 0;
var readiness = previousTotal == 0 ? 0.0 : previousReady / (double)previousTotal;
var ceiling = TimeSpan.FromMilliseconds(options.PresentationDelayMs);
var target = TimeSpan.FromMilliseconds(Math.Clamp(
Math.Max(options.MinPresentationDelayMs, edgeSkew.TotalMilliseconds + options.LatencyGuardMs),
options.MinPresentationDelayMs,
options.PresentationDelayMs));
var reason = "edge-skew-plus-guard";
if (retainedOverlap > TimeSpan.Zero)
{
var overlapBound = retainedOverlap - TimeSpan.FromMilliseconds(options.LatencyGuardMs);
if (overlapBound > floor)
{
target = target < overlapBound ? target : overlapBound;
}
else
{
target = floor;
reason = "overlap-thin";
}
}
if (lastFrame != null && !lastFrame.Frame.IsComplete)
{
target += TimeSpan.FromMilliseconds(options.LatencyStepMs * Math.Max(1, degradedStreak));
reason = "backoff-after-incomplete-frame";
}
else if (completeStreak >= Math.Max(1, options.LatencyConvergenceFrames) && readiness >= options.LatencyReadinessTarget)
{
target -= TimeSpan.FromMilliseconds(options.LatencyStepMs);
reason = "complete-frame-convergence";
}
current = ClampDelay(Smooth(current, target), floor, ceiling);
return Decision(retainedOverlap, edgeSkew, readiness, syncConfidence, active.Length, previousReady, previousTotal, reason);
}
public void ObserveFrame(MimirWellFrameBuildResult result)
{
lastFrame = result;
if (result.Frame.IsComplete)
{
completeStreak++;
degradedStreak = 0;
}
else
{
degradedStreak++;
completeStreak = 0;
}
}
private MimirWellLatencyDecision Decision(
TimeSpan retainedOverlap,
TimeSpan edgeSkew,
double readiness,
double syncConfidence,
int activeBuffers,
int readySlices,
int totalSlices,
string reason) =>
new(
current,
TimeSpan.FromMilliseconds(options.PresentationDelayMs),
floor,
retainedOverlap,
edgeSkew,
readiness,
syncConfidence,
activeBuffers,
readySlices,
totalSlices,
reason);
private static TimeSpan Smooth(TimeSpan current, TimeSpan target)
{
var alpha = target > current ? 0.65 : 0.20;
return TimeSpan.FromTicks((long)Math.Round(current.Ticks + (target.Ticks - current.Ticks) * alpha));
}
private static TimeSpan ClampDelay(TimeSpan value, TimeSpan floor, TimeSpan ceiling) =>
value < floor ? floor : value > ceiling ? ceiling : value;
}
internal sealed record MimirWellFeatureSignalFrame(
string Document,
long Sequence,
IReadOnlyList<MimirWellFeatureSignal> Signals,
double MeanConfidence,
double MeanMotionPixelsPerSecond,
int StableTrackCount,
string FaustSignalContract);
internal sealed record MimirWellFeatureSignal(
string SourceId,
long TimestampNs,
int Width,
int Height,
int StableTrackCount,
double Confidence,
double MeanMotionPixelsPerSecond,
double MotionEnergy,
double NormalizedCentroidX,
double NormalizedCentroidY,
IReadOnlyDictionary<string, float> FaustControls);
internal sealed class MimirWellFeatureSignalBank
{
private readonly MimirWellOptions options;
private readonly Dictionary<string, MimirSparseFeatureTracker> trackers = new(StringComparer.Ordinal);
private readonly Dictionary<string, ulong> lastSequences = new(StringComparer.Ordinal);
private long sequence;
public MimirWellFeatureSignalBank(MimirWellOptions options)
{
this.options = options;
}
public MimirWellFeatureSignalFrame Update(
IEnumerable<MimirRollingStreamBuffer> buffers,
MimirSynchronizedBufferFrame frame)
{
if (!options.VideoFeatureSignalsEnabled)
{
return Empty();
}
var signals = frame.VideoSlices
.Where(static slice => slice.Sample.HasValue)
.Select(slice => BuildSignal(slice.Sample!.Value))
.Where(static signal => signal != null)
.Select(static signal => signal!)
.ToArray();
if (signals.Length == 0)
{
signals = buffers
.Where(static buffer => buffer.Descriptor.Kind == MimirStreamKind.Video && buffer.Latest.HasValue)
.Select(buffer => BuildSignal(buffer.Latest!.Value))
.Where(static signal => signal != null)
.Select(static signal => signal!)
.ToArray();
}
if (signals.Length == 0)
{
return Empty();
}
return new MimirWellFeatureSignalFrame(
"mimir.well_feature_signals.v1",
++sequence,
signals,
signals.Average(static signal => signal.Confidence),
signals.Average(static signal => signal.MeanMotionPixelsPerSecond),
signals.Sum(static signal => signal.StableTrackCount),
"Faust controls are normalized scalar signals under video/<source>/{motion_energy,confidence,centroid_x,centroid_y}; Mimir estimates, Faust/native DSP consumes.");
}
private MimirWellFeatureSignalFrame Empty() =>
new("mimir.well_feature_signals.v1", sequence, [], 0.0, 0.0, 0, "no feature-bearing CPU video slice available");
private MimirWellFeatureSignal? BuildSignal(MimirStreamSample sample)
{
if (sample.VideoFrame is not { } video ||
sample.Data.IsEmpty ||
sample.Sequence == (lastSequences.TryGetValue(sample.SourceId, out var previous) ? previous : ulong.MaxValue))
{
return null;
}
var luma = ExtractLuma(video, sample.Data.Span);
if (luma.Length == 0)
{
return null;
}
lastSequences[sample.SourceId] = sample.Sequence;
if (!trackers.TryGetValue(sample.SourceId, out var tracker))
{
tracker = new MimirSparseFeatureTracker(new MimirSparseFeatureTrackerOptions(
MaxFeatures: options.VideoFeatureMaxTracks,
CellSizePixels: options.VideoFeatureCellSizePixels,
SearchRadiusPixels: options.VideoFeatureSearchRadiusPixels));
trackers.Add(sample.SourceId, tracker);
}
var tracked = tracker.Update(
sample.SourceId,
video.Width,
video.Height,
luma,
sample.TimestampNs);
if (tracked.Tracks.Count == 0)
{
return new MimirWellFeatureSignal(
sample.SourceId,
sample.TimestampNs,
video.Width,
video.Height,
0,
0.0,
0.0,
0.0,
0.5,
0.5,
FaustControls(sample.SourceId, 0.0, 0.0, 0.5, 0.5));
}
var stableTracks = tracked.Tracks.Where(track => track.AgeFrames >= 3).ToArray();
var points = stableTracks.Length == 0 ? tracked.Tracks : stableTracks;
var centroidX = points.Average(static track => track.ImageX) / Math.Max(1.0, video.Width);
var centroidY = points.Average(static track => track.ImageY) / Math.Max(1.0, video.Height);
var motionEnergy = Math.Clamp(tracked.MeanSpeedPixelsPerSecond / Math.Max(1.0, Math.Max(video.Width, video.Height)), 0.0, 1.0);
return new MimirWellFeatureSignal(
sample.SourceId,
sample.TimestampNs,
video.Width,
video.Height,
tracked.StableTrackCount,
tracked.Confidence,
tracked.MeanSpeedPixelsPerSecond,
motionEnergy,
Math.Clamp(centroidX, 0.0, 1.0),
Math.Clamp(centroidY, 0.0, 1.0),
FaustControls(sample.SourceId, tracked.Confidence, motionEnergy, centroidX, centroidY));
}
private static IReadOnlyDictionary<string, float> FaustControls(
string sourceId,
double confidence,
double motionEnergy,
double centroidX,
double centroidY)
{
var prefix = $"video/{sourceId}";
return new Dictionary<string, float>(StringComparer.Ordinal)
{
[$"{prefix}/confidence"] = (float)Math.Clamp(confidence, 0.0, 1.0),
[$"{prefix}/motion_energy"] = (float)Math.Clamp(motionEnergy, 0.0, 1.0),
[$"{prefix}/centroid_x"] = (float)Math.Clamp(centroidX, 0.0, 1.0),
[$"{prefix}/centroid_y"] = (float)Math.Clamp(centroidY, 0.0, 1.0),
};
}
private static byte[] ExtractLuma(MimirVideoFrameDescriptor video, ReadOnlySpan<byte> data) =>
video.PixelFormat switch
{
MimirVideoPixelFormat.Gray8 or MimirVideoPixelFormat.R8 or MimirVideoPixelFormat.Bayer8 =>
CopySinglePlane(video.Width, video.Height, Math.Max(video.Width, video.StrideBytes), data),
MimirVideoPixelFormat.LeapStereoIr or MimirVideoPixelFormat.Rg8 =>
CopyInterleavedLuma(video.Width, video.Height, Math.Max(video.Width * 2, video.StrideBytes), 2, data),
MimirVideoPixelFormat.Yuy2 =>
CopyInterleavedLuma(video.Width, video.Height, Math.Max(video.Width * 2, video.StrideBytes), 2, data),
MimirVideoPixelFormat.Bgra8 =>
CopyBgraLuma(video.Width, video.Height, Math.Max(video.Width * 4, video.StrideBytes), data),
_ => [],
};
private static byte[] CopySinglePlane(int width, int height, int stride, ReadOnlySpan<byte> data)
{
if (width <= 0 || height <= 0 || data.Length < stride * Math.Max(0, height - 1) + width)
{
return [];
}
var luma = new byte[width * height];
for (var y = 0; y < height; y++)
{
data.Slice(y * stride, width).CopyTo(luma.AsSpan(y * width, width));
}
return luma;
}
private static byte[] CopyInterleavedLuma(int width, int height, int stride, int step, ReadOnlySpan<byte> data)
{
if (width <= 0 || height <= 0 || step <= 0 || data.Length < stride * Math.Max(0, height - 1) + width * step)
{
return [];
}
var luma = new byte[width * height];
for (var y = 0; y < height; y++)
{
var row = data.Slice(y * stride, width * step);
for (var x = 0; x < width; x++)
{
luma[y * width + x] = row[x * step];
}
}
return luma;
}
private static byte[] CopyBgraLuma(int width, int height, int stride, ReadOnlySpan<byte> data)
{
if (width <= 0 || height <= 0 || data.Length < stride * Math.Max(0, height - 1) + width * 4)
{
return [];
}
var luma = new byte[width * height];
for (var y = 0; y < height; y++)
{
var row = data.Slice(y * stride, width * 4);
for (var x = 0; x < width; x++)
{
var offset = x * 4;
luma[y * width + x] = (byte)Math.Clamp(
(int)Math.Round(row[offset] * 0.114 + row[offset + 1] * 0.587 + row[offset + 2] * 0.299),
0,
255);
}
}
return luma;
}
}
2026-06-02 00:47:25 +01:00
internal sealed record MimirWellPublishReceipt(
string Document,
int ByteLength,
double SerializeMilliseconds,
double SendMilliseconds,
double TotalMilliseconds);
internal sealed class MimirWellStreamTelemetry
{
private long pollIterations;
private long consumedSamples;
private long zeroPollIterations;
private double maxPollMilliseconds;
private double totalPollMilliseconds;
private long publishedDocuments;
private long publishedBytes;
private double maxPublishMilliseconds;
private double totalPublishMilliseconds;
private string lastPublishedDocument = "";
private int lastPublishedBytes;
private double lastPublishMilliseconds;
public void ObservePoll(int consumed, TimeSpan elapsed)
{
pollIterations++;
consumedSamples += Math.Max(0, consumed);
if (consumed <= 0)
{
zeroPollIterations++;
}
var milliseconds = elapsed.TotalMilliseconds;
totalPollMilliseconds += milliseconds;
maxPollMilliseconds = Math.Max(maxPollMilliseconds, milliseconds);
}
public void ObservePublish(MimirWellPublishReceipt receipt)
{
publishedDocuments++;
publishedBytes += receipt.ByteLength;
totalPublishMilliseconds += receipt.TotalMilliseconds;
maxPublishMilliseconds = Math.Max(maxPublishMilliseconds, receipt.TotalMilliseconds);
lastPublishedDocument = receipt.Document;
lastPublishedBytes = receipt.ByteLength;
lastPublishMilliseconds = receipt.TotalMilliseconds;
2026-06-01 21:27:57 +01:00
}
2026-06-02 00:47:25 +01:00
public object Snapshot(DateTimeOffset now, bool subscribersAreExternal) => new
{
document = "mimir.well_stream_pressure.v1",
status = "transitional-websocket-json",
authority = "Mimir.Well observes producer pressure; CultMesh streaming organ should own durable body lanes.",
wallClockUtc = now.ToString("O"),
poll = new
{
iterations = pollIterations,
consumedSamples,
zeroPollIterations,
averageMilliseconds = pollIterations == 0 ? 0.0 : totalPollMilliseconds / pollIterations,
maxMilliseconds = maxPollMilliseconds,
},
publish = new
{
documents = publishedDocuments,
bytes = publishedBytes,
averageMilliseconds = publishedDocuments == 0 ? 0.0 : totalPublishMilliseconds / publishedDocuments,
maxMilliseconds = maxPublishMilliseconds,
lastDocument = lastPublishedDocument,
lastBytes = lastPublishedBytes,
lastMilliseconds = lastPublishMilliseconds,
subscribersAreExternal,
},
nextOrgan = new
{
controlLane = "CultMesh typed state and compact stream cursors",
bodyLane = "CultCache page/shard append stream with refs, hashes, and backpressure",
realtimeLane = "loss-aware latest-state observation stream for dashboards",
},
};
2026-06-01 21:27:57 +01:00
}
internal sealed record MimirWellOptions(
Uri PublishUrl,
string NodeId,
double Seconds,
int PollMs,
int PublishIntervalMs,
int SyncIntervalMs,
int PresentationDelayMs,
2026-06-02 15:13:25 +01:00
int TargetPresentationDelayMs,
int MinPresentationDelayMs,
int LatencyGuardMs,
int LatencyStepMs,
int LatencyConvergenceFrames,
double LatencyReadinessTarget,
2026-06-01 21:27:57 +01:00
int MaxSamplesPerSource,
int SyncCandidatesPerStep,
2026-06-02 15:13:25 +01:00
bool VideoFeatureSignalsEnabled,
int VideoFeatureMaxTracks,
int VideoFeatureCellSizePixels,
int VideoFeatureSearchRadiusPixels,
2026-06-01 23:52:17 +01:00
bool VisualCalibrationEnabled,
int VisualCalibrationIntervalMs,
int VisualExpectedLedCount,
double VisualMinimumLuma,
double VisualSettingSeconds,
double VisualResweepSeconds,
2026-06-02 00:07:21 +01:00
bool CapturePagesEnabled,
int CaptureIntervalMs,
int CaptureMaxBodyBytes,
bool CaptureInlineBodies,
2026-06-02 15:13:25 +01:00
bool StreamFramesEnabled,
bool StreamFrameInlineBodies,
2026-06-01 21:27:57 +01:00
int MeterEvery)
{
public static MimirWellOptions Parse(string[] args) => new(
new Uri(ParseString(args, "--publish-url", "ws://127.0.0.1:8796/eve/periwinkle")),
ParseString(args, "--node-id", Environment.MachineName.ToLowerInvariant()),
ParseDouble(args, "--seconds", 0.0),
ParseInt(args, "--poll-ms", 5),
ParseInt(args, "--publish-ms", 250),
ParseInt(args, "--sync-ms", 250),
ParseInt(args, "--presentation-delay-ms", 2500),
2026-06-02 15:13:25 +01:00
ParseInt(args, "--target-presentation-delay-ms", 750),
ParseInt(args, "--min-presentation-delay-ms", 40),
ParseInt(args, "--latency-guard-ms", 35),
ParseInt(args, "--latency-step-ms", 25),
ParseInt(args, "--latency-convergence-frames", 8),
ParseDouble(args, "--latency-readiness-target", 0.98),
2026-06-01 21:27:57 +01:00
ParseInt(args, "--max-samples-per-source", 4),
ParseInt(args, "--sync-candidates", 1),
2026-06-02 15:13:25 +01:00
ParseBool(args, "--video-feature-signals", true),
ParseInt(args, "--video-feature-max-tracks", 96),
ParseInt(args, "--video-feature-cell-size", 12),
ParseInt(args, "--video-feature-search-radius", 18),
2026-06-01 23:52:17 +01:00
ParseBool(args, "--visual-calibration", true),
ParseInt(args, "--visual-calibration-ms", 250),
ParseInt(args, "--visual-expected-leds", 38),
ParseDouble(args, "--visual-minimum-luma", 0.55),
ParseDouble(args, "--visual-setting-seconds", 0.75),
ParseDouble(args, "--visual-resweep-seconds", 12.0),
2026-06-02 00:07:21 +01:00
ParseBool(args, "--capture-pages", true),
ParseInt(args, "--capture-ms", 250),
ParseInt(args, "--capture-max-body-bytes", 4 * 1024 * 1024),
ParseBool(args, "--capture-inline-bodies", true),
2026-06-02 15:13:25 +01:00
ParseBool(args, "--stream-frames", true),
ParseBool(args, "--stream-frame-inline-bodies", true),
2026-06-01 21:27:57 +01:00
ParseInt(args, "--meter-every", 20));
private static string ParseString(IReadOnlyList<string> args, string name, string fallback)
{
for (var index = 0; index < args.Count - 1; index++)
{
if (string.Equals(args[index], name, StringComparison.OrdinalIgnoreCase))
{
return args[index + 1];
}
}
return fallback;
}
private static int ParseInt(IReadOnlyList<string> args, string name, int fallback) =>
int.TryParse(ParseString(args, name, ""), out var value) ? value : fallback;
private static double ParseDouble(IReadOnlyList<string> args, string name, double fallback) =>
double.TryParse(ParseString(args, name, ""), out var value) ? value : fallback;
2026-06-01 23:52:17 +01:00
private static bool ParseBool(IReadOnlyList<string> args, string name, bool fallback)
{
for (var index = 0; index < args.Count; index++)
{
if (!string.Equals(args[index], name, StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (index == args.Count - 1 ||
args[index + 1].StartsWith("--", StringComparison.Ordinal))
{
return true;
}
return bool.TryParse(args[index + 1], out var value) ? value : fallback;
}
return fallback;
}
2026-06-01 21:27:57 +01:00
}
internal sealed class MimirWellPublisher(Uri url) : IAsyncDisposable
{
private readonly ClientWebSocket socket = new();
public async Task ConnectAsync(CancellationToken stopping)
{
await socket.ConnectAsync(url, stopping).ConfigureAwait(false);
}
2026-06-02 00:47:25 +01:00
public async Task<MimirWellPublishReceipt> PublishAsync(
object document,
string documentName,
CancellationToken stopping)
2026-06-01 21:27:57 +01:00
{
2026-06-02 00:47:25 +01:00
var stopwatch = Stopwatch.StartNew();
2026-06-01 21:27:57 +01:00
var json = JsonSerializer.Serialize(document);
var bytes = Encoding.UTF8.GetBytes(json);
2026-06-02 00:47:25 +01:00
var serializeMilliseconds = stopwatch.Elapsed.TotalMilliseconds;
stopwatch.Restart();
2026-06-01 21:27:57 +01:00
await socket.SendAsync(bytes, WebSocketMessageType.Text, endOfMessage: true, stopping).ConfigureAwait(false);
2026-06-02 00:47:25 +01:00
stopwatch.Stop();
return new MimirWellPublishReceipt(
documentName,
bytes.Length,
serializeMilliseconds,
stopwatch.Elapsed.TotalMilliseconds,
serializeMilliseconds + stopwatch.Elapsed.TotalMilliseconds);
2026-06-01 21:27:57 +01:00
}
public async ValueTask DisposeAsync()
{
if (socket.State == WebSocketState.Open)
{
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
try
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "well-complete", cts.Token).ConfigureAwait(false);
}
catch
{
}
}
socket.Dispose();
}
}
2026-06-02 00:07:21 +01:00
internal static class MimirWellCapturePage
{
public static object Build(
MimirWellOptions options,
MimirPresentationControlState presentation,
2026-06-02 00:47:25 +01:00
MimirWellFrameBuildResult frameResult,
2026-06-02 00:25:19 +01:00
IEnumerable<MimirRollingStreamBuffer> buffers,
2026-06-02 00:07:21 +01:00
long captureSequence,
2026-06-02 00:47:25 +01:00
DateTimeOffset startedAt)
2026-06-02 00:07:21 +01:00
{
2026-06-02 00:47:25 +01:00
var frame = frameResult.Frame;
return new
{
2026-06-02 00:07:21 +01:00
type = "cultmesh-observation",
document = "mimir.well_capture_page.v1",
sourceId = "mimir-well",
nodeId = options.NodeId,
captureSequence,
wallClockUtc = DateTimeOffset.UtcNow.ToString("O"),
elapsedSeconds = (DateTimeOffset.UtcNow - startedAt).TotalSeconds,
frame = new
{
frame.PresentationTimeNs,
frame.WindowStartNs,
frame.WindowEndNs,
PresentationDelayMs = frame.PresentationDelay.TotalMilliseconds,
frame.IsComplete,
2026-06-02 00:47:25 +01:00
degradedKind = frameResult.DegradedKind,
degradedReason = frameResult.DegradedReason,
2026-06-02 00:07:21 +01:00
},
storage = new
{
bodyTransport = options.CaptureInlineBodies ? "inline-base64" : "metadata-only",
maxInlineBodyBytes = options.CaptureMaxBodyBytes,
intendedSink = "mimir-recorder-paged-cultcache",
},
configuredComposite = new
{
video = presentation.VideoFeeds.Select(feed => new
{
feed.SourceId,
feed.DisplayName,
feed.Enabled,
feed.Solo,
feed.Opacity,
feed.Layer,
}).ToArray(),
audio = presentation.AudioFeeds.Select(feed => new
{
feed.SourceId,
feed.DisplayName,
feed.Muted,
feed.Solo,
feed.Gain,
}).ToArray(),
postprocess = presentation.Postprocess,
renderedProgramBody = new
{
status = "not-published-yet",
reason = "Fensalir/OBS program-output capture is a separate producer; this page records the configured composite contract and synchronized source bodies.",
},
},
2026-06-02 00:25:19 +01:00
samples = CaptureSamples(options, captureSequence, frame, buffers)
2026-06-02 00:07:21 +01:00
.ToArray(),
};
2026-06-02 00:47:25 +01:00
}
2026-06-02 00:07:21 +01:00
2026-06-02 15:13:25 +01:00
public static IEnumerable<object> BuildStreamFrames(
MimirWellOptions options,
MimirWellFrameBuildResult frameResult,
IEnumerable<MimirRollingStreamBuffer> buffers,
long captureSequence,
DateTimeOffset startedAt)
{
var frame = frameResult.Frame;
var sliceFrames = frame.Slices
.Where(slice => slice.Sample.HasValue)
.Select(slice => CaptureStreamFrame(options, captureSequence, startedAt, slice))
.ToArray();
if (sliceFrames.Length > 0)
{
return sliceFrames;
}
return buffers
.Where(buffer => buffer.Latest.HasValue)
.Select(buffer => CaptureLatestFallbackStreamFrame(options, captureSequence, startedAt, buffer))
.ToArray();
}
2026-06-02 00:25:19 +01:00
private static IEnumerable<object> CaptureSamples(
MimirWellOptions options,
long captureSequence,
MimirSynchronizedBufferFrame frame,
IEnumerable<MimirRollingStreamBuffer> buffers)
{
var sliceSamples = frame.Slices
.Where(slice => slice.Sample.HasValue)
.Select(slice => CaptureSample(options, captureSequence, slice))
.ToArray();
if (sliceSamples.Length > 0)
{
return sliceSamples;
}
return buffers
.Where(buffer => buffer.Latest.HasValue)
.Select(buffer => CaptureLatestFallbackSample(options, captureSequence, buffer));
}
2026-06-02 00:07:21 +01:00
private static object CaptureSample(
MimirWellOptions options,
long captureSequence,
MimirSynchronizedStreamSlice slice)
{
var sample = slice.Sample!.Value;
var bodyId = $"{options.NodeId}:{captureSequence}:{sample.SourceId}:{sample.Sequence}";
return new
{
bodyId,
slice = new
{
slice.SourceId,
Kind = slice.Kind.ToString(),
Origin = slice.Origin.ToString(),
Status = slice.Status.ToString(),
slice.SourceTimestampNs,
slice.CanonicalStartNs,
slice.CanonicalEndNs,
slice.PresentationTimeNs,
slice.TimingOffsetNs,
slice.DistanceFromPresentationNs,
slice.TimingConfidence,
slice.TimingEvidenceKind,
},
sample = SampleMetadata(sample),
2026-06-02 15:13:25 +01:00
body = CaptureBody(options, sample, options.CaptureInlineBodies),
2026-06-02 00:07:21 +01:00
};
}
2026-06-02 00:25:19 +01:00
private static object CaptureLatestFallbackSample(
MimirWellOptions options,
long captureSequence,
MimirRollingStreamBuffer buffer)
{
var sample = buffer.Latest!.Value;
var bodyId = $"{options.NodeId}:{captureSequence}:{sample.SourceId}:{sample.Sequence}:latest";
return new
{
bodyId,
slice = new
{
sample.SourceId,
Kind = sample.Kind.ToString(),
Origin = sample.Origin.ToString(),
Status = "LatestUnalignedFallback",
SourceTimestampNs = sample.TimestampNs,
CanonicalStartNs = sample.TimestampNs,
CanonicalEndNs = sample.TimestampNs,
PresentationTimeNs = 0L,
TimingOffsetNs = 0L,
DistanceFromPresentationNs = 0L,
TimingConfidence = 0.0,
TimingEvidenceKind = "unsynchronized-fallback",
},
sample = SampleMetadata(sample),
2026-06-02 15:13:25 +01:00
body = CaptureBody(options, sample, options.CaptureInlineBodies),
};
}
private static object CaptureStreamFrame(
MimirWellOptions options,
long captureSequence,
DateTimeOffset startedAt,
MimirSynchronizedStreamSlice slice)
{
var sample = slice.Sample!.Value;
return CaptureStreamFrame(
options,
captureSequence,
startedAt,
sample,
new
{
slice.SourceId,
Kind = slice.Kind.ToString(),
Origin = slice.Origin.ToString(),
Status = slice.Status.ToString(),
slice.SourceTimestampNs,
slice.CanonicalStartNs,
slice.CanonicalEndNs,
slice.PresentationTimeNs,
slice.TimingOffsetNs,
slice.DistanceFromPresentationNs,
slice.TimingConfidence,
slice.TimingEvidenceKind,
});
}
private static object CaptureLatestFallbackStreamFrame(
MimirWellOptions options,
long captureSequence,
DateTimeOffset startedAt,
MimirRollingStreamBuffer buffer)
{
var sample = buffer.Latest!.Value;
return CaptureStreamFrame(
options,
captureSequence,
startedAt,
sample,
new
{
sample.SourceId,
Kind = sample.Kind.ToString(),
Origin = sample.Origin.ToString(),
Status = "LatestUnalignedFallback",
SourceTimestampNs = sample.TimestampNs,
CanonicalStartNs = sample.TimestampNs,
CanonicalEndNs = sample.TimestampNs,
PresentationTimeNs = 0L,
TimingOffsetNs = 0L,
DistanceFromPresentationNs = 0L,
TimingConfidence = 0.0,
TimingEvidenceKind = "unsynchronized-fallback",
});
}
private static object CaptureStreamFrame(
MimirWellOptions options,
long captureSequence,
DateTimeOffset startedAt,
MimirStreamSample sample,
object slice)
{
var bodyId = $"{options.NodeId}:{captureSequence}:{sample.SourceId}:{sample.Sequence}";
var transport = PreferredBodyTransport(sample);
return new
{
type = "cultmesh-observation",
document = "mimir.cultmesh_stream_frame.v1",
sourceId = "mimir-well",
nodeId = options.NodeId,
captureSequence,
wallClockUtc = DateTimeOffset.UtcNow.ToString("O"),
elapsedSeconds = (DateTimeOffset.UtcNow - startedAt).TotalSeconds,
bodyId,
stream = new
{
streamId = sample.SourceId,
verseId = "mimir-live",
ownerPeerId = options.NodeId,
kind = sample.Kind.ToString(),
origin = sample.Origin.ToString(),
preferredTransports = StreamTransports(sample),
clockDomainId = sample.SourceId,
},
frame = new
{
streamId = sample.SourceId,
sequence = sample.Sequence,
timestampNs = sample.TimestampNs,
arrivalNs = sample.ArrivalNs,
byteLength = sample.ByteLength,
bodyTransport = transport,
nativeHandle = NativeHandle(sample),
nativeHandleKind = NativeHandleKind(sample),
resourceKey = sample.VideoFrame?.ResourceKey,
producerFenceHandle = sample.VideoFrame?.ProducerFenceHandle,
producerFenceValue = sample.VideoFrame?.ProducerFenceValue ?? 0UL,
unavoidableCopyCount = sample.VideoFrame?.UnavoidableCopyCount ?? 0,
},
slice,
sample = SampleMetadata(sample),
body = CaptureBody(options, sample, options.StreamFrameInlineBodies),
2026-06-02 00:25:19 +01:00
};
}
2026-06-02 00:07:21 +01:00
private static object SampleMetadata(MimirStreamSample sample) => new
{
sample.SourceId,
Kind = sample.Kind.ToString(),
Origin = sample.Origin.ToString(),
sample.TimestampNs,
sample.ArrivalNs,
sample.Sequence,
sample.PayloadHandle,
sample.ByteLength,
video = sample.VideoFrame is null ? null : new
{
sample.VideoFrame.Width,
sample.VideoFrame.Height,
PixelFormat = sample.VideoFrame.PixelFormat.ToString(),
sample.VideoFrame.StrideBytes,
sample.VideoFrame.DeviceTimestampNs,
sample.VideoFrame.NativeHandle,
sample.VideoFrame.NativeHandleKind,
sample.VideoFrame.ResourceKey,
sample.VideoFrame.ProducerFenceHandle,
sample.VideoFrame.ProducerFenceValue,
sample.VideoFrame.UnavoidableCopyCount,
},
audio = sample.AudioBlock is null ? null : new
{
sample.AudioBlock.SampleRate,
sample.AudioBlock.Channels,
SampleFormat = sample.AudioBlock.SampleFormat.ToString(),
sample.AudioBlock.FrameCount,
sample.AudioBlock.DeviceTimestampNs,
sample.AudioBlock.NativeHandle,
sample.AudioBlock.NativeHandleKind,
},
};
2026-06-02 15:13:25 +01:00
private static string PreferredBodyTransport(MimirStreamSample sample)
{
var kind = NativeHandleKind(sample);
if (!string.IsNullOrWhiteSpace(kind))
{
return kind.Contains("d3d12", StringComparison.OrdinalIgnoreCase)
? "shared-d3d12-texture"
: kind.Contains("d3d11", StringComparison.OrdinalIgnoreCase)
? "shared-d3d11-texture"
: "native-handle";
}
return sample.Data.IsEmpty ? "metadata-only" : "inline-bytes";
}
private static string[] StreamTransports(MimirStreamSample sample)
{
var transport = PreferredBodyTransport(sample);
return transport switch
{
"shared-d3d12-texture" => ["shared-d3d12-texture", "mimir-recorder-page", "cultcache-page"],
"shared-d3d11-texture" => ["shared-d3d11-texture", "mimir-recorder-page", "cultcache-page"],
"native-handle" => ["native-handle", "mimir-recorder-page", "cultcache-page"],
"inline-bytes" => ["mimir-recorder-page", "inline-bytes", "cultcache-page"],
_ => ["metadata-only"],
};
}
private static ulong NativeHandle(MimirStreamSample sample) =>
sample.VideoFrame?.NativeHandle ?? sample.AudioBlock?.NativeHandle ?? 0UL;
private static string NativeHandleKind(MimirStreamSample sample) =>
sample.VideoFrame?.NativeHandleKind ?? sample.AudioBlock?.NativeHandleKind ?? "";
private static object CaptureBody(MimirWellOptions options, MimirStreamSample sample, bool inlineBodies)
2026-06-02 00:07:21 +01:00
{
2026-06-02 15:13:25 +01:00
if (!inlineBodies)
2026-06-02 00:07:21 +01:00
{
return new { status = "not-inline", sample.ByteLength };
}
if (sample.Data.IsEmpty || sample.ByteLength <= 0)
{
return new { status = "empty", sample.ByteLength };
}
if (sample.ByteLength > options.CaptureMaxBodyBytes)
{
return new { status = "too-large", sample.ByteLength };
}
return new
{
status = "inline",
encoding = "base64",
byteLength = sample.ByteLength,
data = Convert.ToBase64String(sample.Data.Span),
};
}
}
2026-06-02 00:47:25 +01:00
internal static class MimirWellClockDiagnostics
{
public static object Build(
IEnumerable<MimirRollingStreamBuffer> buffers,
string referenceSourceId,
MimirWellFrameBuildResult frameResult)
{
var activeBuffers = buffers
.Where(static buffer => buffer.Latest.HasValue)
.ToArray();
var referenceBuffer = activeBuffers.FirstOrDefault(buffer =>
string.Equals(buffer.Descriptor.SourceId, referenceSourceId, StringComparison.Ordinal));
var referenceEdgeNs = referenceBuffer?.Latest?.TimestampNs ?? 0L;
var referenceClockDomain = referenceBuffer?.Descriptor.EffectiveClockDomainId ?? "";
var domains = activeBuffers
.GroupBy(static buffer => buffer.Descriptor.EffectiveClockDomainId, StringComparer.Ordinal)
.Select(group => BuildDomain(group.Key, group.ToArray(), referenceClockDomain, referenceEdgeNs))
.OrderBy(domain => domain.ClockDomainId, StringComparer.Ordinal)
.ToArray();
return new
{
status = frameResult.Frame.Slices.Count > 0 ? "frame-built" : "degraded",
frameResult.DegradedKind,
frameResult.DegradedReason,
referenceSourceId,
referenceClockDomain,
referenceEdgeNs,
domainCount = domains.Length,
activeSourceCount = activeBuffers.Length,
domains,
};
}
private static ClockDomainDiagnostics BuildDomain(
string clockDomainId,
IReadOnlyList<MimirRollingStreamBuffer> buffers,
string referenceClockDomain,
long referenceEdgeNs)
{
var latestEdges = buffers
.Select(buffer => buffer.Latest?.TimestampNs ?? 0L)
.Where(static value => value > 0)
.ToArray();
var windowStarts = buffers
.Select(static buffer => buffer.OldestSampleTimestampNs > 0 ? buffer.OldestSampleTimestampNs : buffer.WindowStartNs)
.Where(static value => value > 0)
.ToArray();
var minLatest = latestEdges.Length == 0 ? 0L : latestEdges.Min();
var maxLatest = latestEdges.Length == 0 ? 0L : latestEdges.Max();
var maxWindowStart = windowStarts.Length == 0 ? 0L : windowStarts.Max();
var minWindowEnd = minLatest;
var overlapNs = minWindowEnd > 0 && maxWindowStart > 0
? minWindowEnd - maxWindowStart
: 0L;
var domainEdgeNs = maxLatest;
var provisionalOffsetToReferenceNs = referenceEdgeNs > 0 && domainEdgeNs > 0
? referenceEdgeNs - domainEdgeNs
: 0L;
return new ClockDomainDiagnostics(
clockDomainId,
buffers.Count,
buffers
.OrderBy(static buffer => buffer.Descriptor.SourceId, StringComparer.Ordinal)
.Select(buffer => new
{
buffer.Descriptor.SourceId,
Kind = buffer.Descriptor.Kind.ToString(),
Origin = buffer.Descriptor.Origin.ToString(),
buffer.Count,
buffer.WindowStartNs,
buffer.OldestSampleTimestampNs,
EdgeNs = buffer.Latest?.TimestampNs ?? 0L,
ByteLength = buffer.Latest?.ByteLength ?? 0,
})
.ToArray(),
maxWindowStart,
minLatest,
maxLatest,
overlapNs,
overlapNs >= 0,
string.Equals(clockDomainId, referenceClockDomain, StringComparison.Ordinal),
provisionalOffsetToReferenceNs,
provisionalOffsetToReferenceNs / 1_000_000.0);
}
private sealed record ClockDomainDiagnostics(
string ClockDomainId,
int SourceCount,
object[] Sources,
long MaxWindowStartNs,
long MinLatestEdgeNs,
long MaxLatestEdgeNs,
long OverlapNs,
bool HasLocalOverlap,
bool IsReferenceDomain,
long ProvisionalOffsetToReferenceNs,
double ProvisionalOffsetToReferenceMs);
}
2026-06-01 21:27:57 +01:00
internal static class MimirWellSnapshot
{
public static object Build(
MimirWellOptions options,
MimirRuntimeConfiguration runtimeConfig,
MimirSynchronizationHub hub,
MimirPresentationControlState presentation,
2026-06-02 00:47:25 +01:00
MimirWellFrameBuildResult frameResult,
2026-06-02 15:13:25 +01:00
MimirWellLatencyDecision latencyDecision,
MimirWellFeatureSignalFrame featureSignals,
2026-06-01 23:52:17 +01:00
IReadOnlyList<MimirCameraExposureControlStatus> visualCalibration,
2026-06-01 21:27:57 +01:00
IReadOnlyList<object> sourceErrors,
2026-06-02 00:47:25 +01:00
object streamPressure,
2026-06-01 21:27:57 +01:00
long sequence,
2026-06-02 00:47:25 +01:00
DateTimeOffset startedAt)
2026-06-01 21:27:57 +01:00
{
2026-06-02 00:47:25 +01:00
var frame = frameResult.Frame;
return new
{
2026-06-01 21:27:57 +01:00
type = "cultmesh-observation",
document = "mimir.well_snapshot.v1",
sourceId = "mimir-well",
nodeId = options.NodeId,
sequence,
wallClockUtc = DateTimeOffset.UtcNow.ToString("O"),
elapsedSeconds = (DateTimeOffset.UtcNow - startedAt).TotalSeconds,
ingestedSamples = hub.IngestedSamples,
configuredSources = runtimeConfig.SourceFactories.Count,
liveSources = hub.SourceCount,
sourceErrors,
buffers = hub.Buffers.Buffers.Select(BufferSnapshot).ToArray(),
synchronizedFrame = new
{
frame.PresentationTimeNs,
frame.WindowStartNs,
frame.WindowEndNs,
PresentationDelayMs = frame.PresentationDelay.TotalMilliseconds,
frame.IsComplete,
2026-06-02 00:47:25 +01:00
degradedKind = frameResult.DegradedKind,
degradedReason = frameResult.DegradedReason,
2026-06-01 21:27:57 +01:00
slices = frame.Slices.Select(SliceSnapshot).ToArray(),
},
2026-06-02 15:13:25 +01:00
latency = new
{
document = "mimir.well_latency_policy.v1",
mode = "adaptive-bounded-ceiling",
currentDelayMs = latencyDecision.PresentationDelay.TotalMilliseconds,
ceilingDelayMs = latencyDecision.CeilingDelay.TotalMilliseconds,
floorDelayMs = latencyDecision.FloorDelay.TotalMilliseconds,
retainedOverlapMs = latencyDecision.RetainedOverlap.TotalMilliseconds,
edgeSkewMs = latencyDecision.EdgeSkew.TotalMilliseconds,
latencyDecision.ReadinessConfidence,
latencyDecision.SyncConfidence,
latencyDecision.ActiveBufferCount,
latencyDecision.ReadySliceCount,
latencyDecision.TotalSliceCount,
latencyDecision.Reason,
invariant = "Five seconds is a ceiling; the Well lowers requested presentation delay when overlap, slice readiness, and sync evidence allow it.",
},
2026-06-02 00:47:25 +01:00
clockDomains = MimirWellClockDiagnostics.Build(
hub.Buffers.Buffers,
runtimeConfig.Settings.Audio.ReferenceSourceId,
frameResult),
2026-06-02 15:13:25 +01:00
canonicalClockMaps = hub.CanonicalClockMaps.Select(map => new
{
map.StreamKey,
map.OffsetNs,
offsetMs = map.OffsetNs / 1_000_000.0,
map.FirstSourceTimestampNs,
map.FirstArrivalNs,
map.LatestSourceTimestampNs,
map.LatestCanonicalTimestampNs,
map.SampleCount,
}).ToArray(),
2026-06-02 00:47:25 +01:00
streamPressure,
2026-06-02 15:13:25 +01:00
featureSignals = new
{
featureSignals.Document,
featureSignals.Sequence,
featureSignals.MeanConfidence,
featureSignals.MeanMotionPixelsPerSecond,
featureSignals.StableTrackCount,
featureSignals.FaustSignalContract,
signals = featureSignals.Signals.Select(signal => new
{
signal.SourceId,
signal.TimestampNs,
signal.Width,
signal.Height,
signal.StableTrackCount,
signal.Confidence,
signal.MeanMotionPixelsPerSecond,
signal.MotionEnergy,
signal.NormalizedCentroidX,
signal.NormalizedCentroidY,
faustControls = signal.FaustControls.Select(pair => new
{
path = pair.Key,
value = pair.Value,
}).ToArray(),
}).ToArray(),
},
2026-06-01 21:27:57 +01:00
audioSync = new
{
referenceSourceId = runtimeConfig.Settings.Audio.ReferenceSourceId,
mode = runtimeConfig.Settings.Audio.Mode.ToString(),
complexContour = hub.ComplexContourRuntimeEnabled,
states = hub.AudioSynchronizationStates.Select(state => new
{
state.SourceId,
state.ReferenceSourceId,
state.SampleRate,
state.SmoothedDelaySamples,
state.SamplingRateOffsetPpm,
state.Confidence,
evidenceKind = "audio-sync",
}).ToArray(),
reports = hub.AudioSynchronizationReports.Select(report => new
{
report.SourceId,
report.ReferenceSourceId,
report.EvidenceKind,
report.FractionalDelaySamples,
report.Confidence,
matchedEvents = report.TimelineMatchedEvents,
report.ComparedSamples,
report.AnalysisTimestampNs,
}).ToArray(),
probe = hub.LastBioacousticProbeSchedule is null
? null
: new
{
hub.LastBioacousticProbeSchedule.TimestampNs,
hub.LastBioacousticProbeSchedule.ShouldEmit,
hub.LastBioacousticProbeSchedule.ScheduledIntervalSeconds,
hub.LastBioacousticProbeSchedule.AggregateSyncConfidence,
hub.LastBioacousticProbeSchedule.AggregateFrequencyResponseConfidence,
reason = hub.LastBioacousticProbeSchedule.Reason.ToString(),
2026-06-01 23:52:17 +01:00
},
},
visualCalibration = new
{
enabled = options.VisualCalibrationEnabled,
expectedLedCount = options.VisualExpectedLedCount,
minimumLuma = options.VisualMinimumLuma,
settingSeconds = options.VisualSettingSeconds,
resweepSeconds = options.VisualResweepSeconds,
cameras = visualCalibration.Select(camera => new
{
camera.SourceId,
camera.ControlKind,
camera.SupportsExposureGain,
camera.State,
camera.CurrentSettingId,
camera.CurrentExposure,
camera.CurrentGain,
camera.BestSettingId,
camera.BestExposure,
camera.BestGain,
camera.BestScore,
camera.BestDetectedLedCount,
camera.BestUsableForCalibration,
camera.FramesScored,
camera.LastApplySucceeded,
camera.Reason,
}).ToArray(),
2026-06-01 21:27:57 +01:00
},
composite = new
{
video = presentation.VideoFeeds.Select(feed => new
{
feed.SourceId,
feed.DisplayName,
feed.Enabled,
feed.Solo,
feed.Opacity,
feed.Layer,
}).ToArray(),
audio = presentation.AudioFeeds.Select(feed => new
{
feed.SourceId,
feed.DisplayName,
feed.Muted,
feed.Solo,
feed.Gain,
}).ToArray(),
postprocess = presentation.Postprocess,
},
publication = new
{
MimirObsPublicationConfigurations.NativeProgram.Id,
MimirObsPublicationConfigurations.NativeProgram.VideoKind,
MimirObsPublicationConfigurations.NativeProgram.VideoSourceName,
MimirObsPublicationConfigurations.NativeProgram.AudioKind,
MimirObsPublicationConfigurations.NativeProgram.TargetPresentationDelaySeconds,
stems = MimirObsPublicationConfigurations.NativeProgram.AudioStems.Select(stem => new
{
stem.Id,
stem.DisplayName,
stem.ChannelCount,
stem.UserMixable,
stem.CarriesTimingWitness,
stem.Notes,
}).ToArray(),
},
};
2026-06-02 00:47:25 +01:00
}
2026-06-01 21:27:57 +01:00
private static object BufferSnapshot(MimirRollingStreamBuffer buffer) => new
{
buffer.Descriptor.SourceId,
Kind = buffer.Descriptor.Kind.ToString(),
Origin = buffer.Descriptor.Origin.ToString(),
buffer.Descriptor.Label,
buffer.Descriptor.EffectiveClockDomainId,
buffer.Count,
buffer.EdgeNs,
2026-06-02 00:47:25 +01:00
buffer.OldestSampleTimestampNs,
2026-06-01 21:27:57 +01:00
buffer.WindowStartNs,
hasLatest = buffer.Latest.HasValue,
latest = buffer.Latest.HasValue ? SampleSnapshot(buffer.Latest.Value) : null,
};
private static object SliceSnapshot(MimirSynchronizedStreamSlice slice) => new
{
slice.SourceId,
Kind = slice.Kind.ToString(),
Origin = slice.Origin.ToString(),
Status = slice.Status.ToString(),
slice.SourceTimestampNs,
slice.CanonicalStartNs,
slice.CanonicalEndNs,
slice.PresentationTimeNs,
slice.TimingOffsetNs,
slice.DistanceFromPresentationNs,
slice.TimingConfidence,
slice.TimingEvidenceKind,
sample = slice.Sample.HasValue ? SampleSnapshot(slice.Sample.Value) : null,
};
private static object SampleSnapshot(MimirStreamSample sample) => new
{
sample.SourceId,
Kind = sample.Kind.ToString(),
Origin = sample.Origin.ToString(),
sample.TimestampNs,
sample.ArrivalNs,
sample.Sequence,
sample.PayloadHandle,
sample.ByteLength,
video = sample.VideoFrame is null ? null : new
{
sample.VideoFrame.Width,
sample.VideoFrame.Height,
PixelFormat = sample.VideoFrame.PixelFormat.ToString(),
sample.VideoFrame.StrideBytes,
sample.VideoFrame.DeviceTimestampNs,
sample.VideoFrame.NativeHandle,
sample.VideoFrame.NativeHandleKind,
sample.VideoFrame.ResourceKey,
sample.VideoFrame.ProducerFenceHandle,
sample.VideoFrame.ProducerFenceValue,
sample.VideoFrame.UnavoidableCopyCount,
},
audio = sample.AudioBlock is null ? null : new
{
sample.AudioBlock.SampleRate,
sample.AudioBlock.Channels,
SampleFormat = sample.AudioBlock.SampleFormat.ToString(),
sample.AudioBlock.FrameCount,
sample.AudioBlock.DeviceTimestampNs,
sample.AudioBlock.NativeHandle,
sample.AudioBlock.NativeHandleKind,
},
};
}