Attach Move proof surface to runtime frame
This commit is contained in:
parent
7d96c42a3c
commit
02c6bfc533
6 changed files with 188 additions and 5 deletions
|
|
@ -90,6 +90,13 @@ a named invariant that the native runtime cannot protect yet.
|
|||
--move-proof-pipeline-smoke` proves that shape against the native reservoir
|
||||
debug DLL; live hardware and presented-frame capture still need to call this
|
||||
primitive instead of hand-assembling a parallel path.
|
||||
- `MimirRuntime` is now the live Fensalir attachment point for proof surfaces.
|
||||
`PublishMoveProofSurface` accepts the Mimir-owned
|
||||
`mimir.move_proof_surface.v1` document, `CreateFrame` composes its
|
||||
observer-only `move-proof-*` splines into `AquariumFrame.Scene.SplineFrame`,
|
||||
and `Mimir.BufferSmoke --move-proof-runtime-frame-smoke` proves the frame is
|
||||
empty before publish, contains the proof splines after publish, and clears
|
||||
without leaving a repair loop behind.
|
||||
- `MimirMoveCalibrationProtocol` publishes the typed calibration preflight for
|
||||
Starfire/Nightwing Moves: required Muninn evidence streams, optional
|
||||
Quest headset/controller pose witnesses, stillness/sweep/validation phases, and
|
||||
|
|
@ -398,10 +405,11 @@ a named invariant that the native runtime cannot protect yet.
|
|||
becomes a deterministic timeline anchor before the actuator moves samples.
|
||||
6. Prove the bioacoustic hybrid fallback through real loopback and microphones
|
||||
with probe durations long enough to keep loopback and mic windows live.
|
||||
7. Attach the Move proof surface to the live runtime/Fensalir presentation path:
|
||||
ingest real Muninn Nightwing and Starfire evidence, require calibrated
|
||||
optical witnesses, publish `mimir:starfire:move-pose:<sequence>`, and capture
|
||||
a presented Fensalir frame/probe for the same sequence.
|
||||
7. Wire live Move proof production into `MimirRuntime.PublishMoveProofSurface`:
|
||||
ingest real Muninn Nightwing and Starfire evidence through
|
||||
`MimirMoveProofPipeline`, require calibrated optical witnesses, publish
|
||||
`mimir:starfire:move-pose:<sequence>`, and capture a presented Fensalir
|
||||
frame/probe for the same sequence.
|
||||
8. Bind Fensalir UI to the synchronization hub so buffer depth, stream cadence,
|
||||
source timestamps, and output settings are visible and adjustable.
|
||||
9. Implement the Mimir program scene graph as the shared commit primitive for
|
||||
|
|
|
|||
|
|
@ -212,6 +212,12 @@ from one Muninn CultMesh shared-memory frame it performs native admission,
|
|||
Mimir fusion, pose-frame creation, proof-surface creation, and Fensalir probe
|
||||
lowering. Live Nightwing/Starfire wiring should call this owner path rather
|
||||
than preserving separate manual actions and programmatic proof paths.
|
||||
`MimirRuntime` now owns the actual Fensalir presentation attachment for the
|
||||
proof surface: `PublishMoveProofSurface` stores the latest Mimir-owned
|
||||
`mimir.move_proof_surface.v1`, and `CreateFrame` merges its observer-only
|
||||
`move-proof-*` probe splines into `AquariumFrame.Scene.SplineFrame` beside the
|
||||
audio spectrum preview. Fensalir renders this frame; it still does not decide
|
||||
proof.
|
||||
|
||||
## Program Composition
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ using System.Diagnostics;
|
|||
using System.Numerics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using Aquarium.Engine;
|
||||
using GameCult.Caching;
|
||||
using GameCult.Caching.MessagePack;
|
||||
using GameCult.Mesh;
|
||||
using MessagePack;
|
||||
using Mimir.Runtime;
|
||||
using Mimir.Runtime.Synchronization;
|
||||
|
||||
if (args.Any(arg => string.Equals(arg, "--chirplet-self-test", StringComparison.OrdinalIgnoreCase)))
|
||||
|
|
@ -146,6 +148,11 @@ if (args.Any(arg => string.Equals(arg, "--move-proof-pipeline-smoke", StringComp
|
|||
ParseStringOption(args, "--native-reservoir", DefaultNativeReservoirPath()));
|
||||
}
|
||||
|
||||
if (args.Any(arg => string.Equals(arg, "--move-proof-runtime-frame-smoke", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return RunMoveProofRuntimeFrameSmoke();
|
||||
}
|
||||
|
||||
if (args.Any(arg => string.Equals(arg, "--move-calibration-protocol-smoke", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return await RunMoveCalibrationProtocolSmokeAsync(
|
||||
|
|
@ -2223,6 +2230,106 @@ static int RunMoveProofSurfaceSmoke()
|
|||
: 1;
|
||||
}
|
||||
|
||||
static int RunMoveProofRuntimeFrameSmoke()
|
||||
{
|
||||
var surface = CreateMoveProofSurfaceSmokeDocument();
|
||||
var runtime = new MimirRuntime(
|
||||
new AquariumRuntimeOptions(Headless: true, CultCachePath: null),
|
||||
new MimirSynchronizationSettings());
|
||||
var emptyFrame = runtime.Frame;
|
||||
runtime.PublishMoveProofSurface(surface);
|
||||
var proofFrame = runtime.Frame;
|
||||
var proofSplineCount = proofFrame.Scene.SplineFrame.Splines.Count(spline =>
|
||||
spline.Id.StartsWith("move-proof-", StringComparison.Ordinal));
|
||||
runtime.ClearMoveProofSurface();
|
||||
var clearedFrame = runtime.Frame;
|
||||
|
||||
Console.WriteLine(
|
||||
$"move-proof-runtime-frame-smoke proof={surface.ProofId} frame={surface.FensalirFrameId} verdict={surface.Verdict} before={emptyFrame.Scene.SplineFrame.Splines.Count} proofSplines={proofSplineCount} afterClear={clearedFrame.Scene.SplineFrame.Splines.Count}");
|
||||
|
||||
return emptyFrame.Scene.SplineFrame.Splines.Count == 0 &&
|
||||
proofFrame.Scene.SplineFrame.HasInput &&
|
||||
proofSplineCount >= 3 &&
|
||||
proofFrame.Scene.SplineFrame.Splines.Any(spline => spline.Id.Contains("move-0xA11CE-79", StringComparison.Ordinal)) &&
|
||||
clearedFrame.Scene.SplineFrame.Splines.Count == 0
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
static MimirMoveProofSurfaceDocument CreateMoveProofSurfaceSmokeDocument()
|
||||
{
|
||||
var pose = new MimirMoveControllerPoseDocument(
|
||||
PoseId: "move:0xA11CE:79",
|
||||
WandId: "move:0xA11CE",
|
||||
TrackingSpaceId: "mimir-stage-space",
|
||||
CalibrationId: "mimir-move-stage-calibration-v1",
|
||||
FusionAuthorityId: "mimir.runtime.move-fusion",
|
||||
SourceTimestampNs: 1_781_202_600_004_000_000,
|
||||
EstimatedAtNs: 1_781_202_600_006_200_000,
|
||||
Sequence: 79,
|
||||
PositionMeters: new MimirVector3Snapshot(0.0, 1.1, 1.0),
|
||||
Orientation: new MimirQuaternionSnapshot(0.0, 0.0, 0.0, 1.0),
|
||||
LinearVelocityMetersPerSecond: new MimirVector3Snapshot(0.0, 0.0, 0.0),
|
||||
AngularVelocityRadiansPerSecond: new MimirVector3Snapshot(0.02, -0.01, 0.04),
|
||||
Confidence: 0.82,
|
||||
LatencyMilliseconds: 2.2,
|
||||
Battery01: 0.72,
|
||||
Buttons:
|
||||
[
|
||||
new MimirTrackingButtonSnapshot("move", true, 1.0),
|
||||
new MimirTrackingButtonSnapshot("trigger", true, 0.5)
|
||||
],
|
||||
EvidenceStreamIds:
|
||||
[
|
||||
"witness:0x00000000000A11CE",
|
||||
"witness:0x0000000000000B0B",
|
||||
"controller:0x00000000000A11CE"
|
||||
],
|
||||
EvidenceKinds:
|
||||
[
|
||||
"optical-marker:triangulated",
|
||||
"controller-state:buttons-imu",
|
||||
"orientation:imu-unresolved"
|
||||
],
|
||||
ConsumerContract: "fensalir.move-controller-input");
|
||||
var admission = new MimirMuninnMoveEvidenceAdmission(
|
||||
FrameId: "muninn:nightwing:move-evidence:79",
|
||||
ProducerPeerId: "muninn:nightwing",
|
||||
PublishedAtNs: 1_781_202_600_005_000_000,
|
||||
MimirReadAtNs: 1_781_202_600_005_700_000,
|
||||
SampleCount: 3,
|
||||
OpticalMarkerCount: 2,
|
||||
ControllerStateCount: 1,
|
||||
SourceTimeMinNs: 1_781_202_600_004_000_000,
|
||||
SourceTimeMaxNs: 1_781_202_600_004_000_000,
|
||||
ArrivalMinNs: 1_781_202_600_004_500_000,
|
||||
ArrivalMaxNs: 1_781_202_600_005_700_000,
|
||||
Handle: new MimirNativeSampleHandle(
|
||||
SensorIdHash: 0xF00D,
|
||||
TimestampNs: 1_781_202_600_004_000_000,
|
||||
ArrivalNs: 1_781_202_600_005_700_000,
|
||||
Sequence: 79,
|
||||
PayloadHandle: 0xBEEF,
|
||||
Flags: 0,
|
||||
Reserved: 0),
|
||||
ReservoirEdgeNs: 1_781_202_600_004_000_000,
|
||||
ReservoirWindowStartNs: 1_781_197_600_004_000_000,
|
||||
ReservoirMoveEvidenceCount: 1);
|
||||
var poseFrame = MimirMovePoseStream.CreateFrame(
|
||||
frameId: "mimir:starfire:move-pose:79",
|
||||
producerPeerId: "mimir:starfire",
|
||||
publishedAtNs: pose.EstimatedAtNs,
|
||||
trackingSpaceId: pose.TrackingSpaceId,
|
||||
calibrationId: pose.CalibrationId,
|
||||
poses: [pose]);
|
||||
|
||||
return MimirMoveProofSurface.Create(
|
||||
admission,
|
||||
poseFrame,
|
||||
"fensalir:starfire:presented-frame:79",
|
||||
fensalirPresentedAtNs: 1_781_202_600_007_100_000);
|
||||
}
|
||||
|
||||
static int RunMoveProofPipelineSmoke(string nativeReservoirPath)
|
||||
{
|
||||
const ulong leftWitnessHash = 0x00000000000A11CE;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ direct
|
|||
private IReadOnlyList<MimirAudioSynchronizationReport> lastAudioSynchronizationReports = [];
|
||||
private IReadOnlyList<MimirAudioSpectrumSnapshot> lastAudioSpectra = [];
|
||||
private readonly Queue<IReadOnlyList<MimirAudioSpectrumSnapshot>> spectrumHistory = new();
|
||||
private MimirMoveProofSurfaceDocument? latestMoveProofSurface;
|
||||
|
||||
public MimirRuntime(AquariumRuntimeOptions options)
|
||||
: this(options, MimirRuntimeConfiguration.Load())
|
||||
|
|
@ -144,6 +145,9 @@ direct
|
|||
: bufferFieldFrame.HasInput
|
||||
? new Vector3(0.0f, 0.0f, 12.0f)
|
||||
: new Vector3(0.0f, 0.0f, cameraZ + 12.0f);
|
||||
var spectrumSplineFrame = ShouldRenderSpectrumPreviewSplines()
|
||||
? BuildSpectrumSplineFrame()
|
||||
: AquariumSplineFrame.Empty;
|
||||
return new AquariumFrame(
|
||||
new ViewFrame(Vector2.Zero, 24.0f),
|
||||
cameraPosition,
|
||||
|
|
@ -155,7 +159,7 @@ direct
|
|||
TraceHeightFieldSurface = false,
|
||||
UseStarfieldBackground = false,
|
||||
BufferFieldFrame = bufferFieldFrame,
|
||||
SplineFrame = ShouldRenderSpectrumPreviewSplines() ? BuildSpectrumSplineFrame() : AquariumSplineFrame.Empty,
|
||||
SplineFrame = ComposeFensalirSplineFrame(spectrumSplineFrame, latestMoveProofSurface),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +170,44 @@ direct
|
|||
synchronization.AddSource(source);
|
||||
}
|
||||
|
||||
public void PublishMoveProofSurface(MimirMoveProofSurfaceDocument surface)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(surface);
|
||||
latestMoveProofSurface = surface;
|
||||
}
|
||||
|
||||
public void ClearMoveProofSurface()
|
||||
{
|
||||
latestMoveProofSurface = null;
|
||||
}
|
||||
|
||||
public static AquariumSplineFrame ComposeFensalirSplineFrame(
|
||||
AquariumSplineFrame baseFrame,
|
||||
MimirMoveProofSurfaceDocument? moveProofSurface)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(baseFrame);
|
||||
if (moveProofSurface is null)
|
||||
{
|
||||
return baseFrame;
|
||||
}
|
||||
|
||||
var proofFrame = MimirMoveProofSurface.BuildFensalirProbeFrame(moveProofSurface);
|
||||
if (!baseFrame.HasInput)
|
||||
{
|
||||
return proofFrame;
|
||||
}
|
||||
|
||||
if (!proofFrame.HasInput)
|
||||
{
|
||||
return baseFrame;
|
||||
}
|
||||
|
||||
return new AquariumSplineFrame
|
||||
{
|
||||
Splines = baseFrame.Splines.Concat(proofFrame.Splines).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Console.WriteLine($"Mimir runtime sync buffers: {synchronization.Summary()} @ {synchronization.Settings.BufferDuration.TotalSeconds:0.###}s audioSync={audioSyncSettings.Mode} reference={audioSyncSettings.ReferenceSourceId}");
|
||||
|
|
@ -231,6 +273,8 @@ direct
|
|||
panel.Readout("Audio sync state", DescribeAudioSyncState);
|
||||
panel.Readout("Aligned audio", DescribeAlignedAudio);
|
||||
panel.Readout("Chirplet reference", DescribeChirpletReference);
|
||||
panel.Section("Move Proof");
|
||||
panel.Readout("Latest proof", DescribeMoveProofSurface);
|
||||
panel.Section("Live FFT");
|
||||
panel.Readout("Spectrum cadence", () => sceneReady
|
||||
? $"{lastAudioSpectra.Count} spectra fft={lastAudioSpectra.FirstOrDefault()?.FftSize ?? 0} analyze={lastSpectrumAnalysisMilliseconds:0.00}ms"
|
||||
|
|
@ -246,6 +290,17 @@ direct
|
|||
});
|
||||
}
|
||||
|
||||
private string DescribeMoveProofSurface()
|
||||
{
|
||||
var surface = latestMoveProofSurface;
|
||||
if (surface is null)
|
||||
{
|
||||
return "No Move proof surface published.";
|
||||
}
|
||||
|
||||
return $"{surface.ProofId} verdict={surface.Verdict} confidence={surface.PoseConfidence:0.000} latency={surface.LatencyMilliseconds:0.00}ms chain={surface.MuninnEvidenceFrameId}->{surface.MimirEvidenceFrameId}->{surface.MimirPoseFrameId}->{surface.FensalirFrameId}";
|
||||
}
|
||||
|
||||
private static AquariumRenderPlan CreateRenderPlan()
|
||||
{
|
||||
var app = new AquariumApp();
|
||||
|
|
|
|||
|
|
@ -161,3 +161,4 @@
|
|||
{"ts": "2026-07-08T22:21:57+01:00", "type": "verification", "status": "ok", "note": "Correction to the earlier Move marker camera evidence: after installing/using the x86_64-unknown-linux-gnu Rust target, Muninn's V4L2 YUYV Move marker camera producer compiled with cargo check -p muninn-daemon --target x86_64-unknown-linux-gnu. cargo test -p muninn-daemon passes 148 tests. Nightwing hardware live proof remains pending, so this proves owned producer code and target compatibility, not calibrated live pose."}
|
||||
{"ts": "2026-07-08T22:28:32+01:00", "type": "implementation", "status": "ok", "note": "Added MimirMoveProofSurface as the first observer-only Fensalir-visible Move proof surface: it combines a Muninn evidence admission receipt, Mimir pose stream frame, and Fensalir presentation/probe timestamp into mimir.move_proof_surface.v1, lowers a dev AquariumSplineFrame probe, preserves source/publish/read/admit/fusion/present timing, and refuses to treat single-ray fallback as full pose. Verified dotnet build Mimir.Runtime, dotnet build Mimir.BufferSmoke, BufferSmoke --move-proof-surface-smoke, and BufferSmoke --move-fusion-smoke. Live Nightwing hardware, calibrated camera witnesses, and actual Fensalir presented-frame capture remain pending."}
|
||||
{"ts": "2026-07-08T22:34:00+01:00", "type": "implementation", "status": "ok", "note": "Added MimirMoveProofPipeline as the shared commit primitive for one Move proof frame: it reads a Muninn CultMesh shared-memory evidence frame, admits samples to native move_evidence, runs MimirMoveFusion, emits the mimir:starfire move-pose frame, creates mimir.move_proof_surface.v1, and lowers the Fensalir spline probe in one pass. Verified dotnet build Mimir.Runtime, dotnet build Mimir.BufferSmoke, and BufferSmoke --move-proof-pipeline-smoke against the native reservoir debug DLL. This proves the reusable Mimir owner path; live Nightwing hardware, calibrated camera witnesses, and actual presented-frame capture remain pending."}
|
||||
{"ts": "2026-07-08T22:41:32+01:00", "type": "implementation", "status": "ok", "note": "Attached the Move proof surface to the actual MimirRuntime/Fensalir frame path: MimirRuntime.PublishMoveProofSurface stores the latest Mimir-owned mimir.move_proof_surface.v1 document, CreateFrame composes its observer-only move-proof-* splines into AquariumFrame.Scene.SplineFrame, and the UI exposes a display-only proof readout. Verified dotnet build Mimir.Runtime, dotnet build Mimir.BufferSmoke, BufferSmoke --move-proof-runtime-frame-smoke, --move-proof-surface-smoke, and --move-proof-pipeline-smoke against the native reservoir debug DLL. Live Nightwing hardware, calibrated camera witnesses, and real presented-frame capture remain pending."}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,12 @@ accepted_design:
|
|||
proof surface, and returns the Fensalir spline probe. Direct user actions,
|
||||
programmatic smokes, and future live subscribers should use this same path
|
||||
so the proof chain does not split into separately repaired truths.
|
||||
- `MimirRuntime` now owns the actual Fensalir presentation attachment for
|
||||
Move proof surfaces. `PublishMoveProofSurface` accepts the latest
|
||||
Mimir-owned proof document, and `CreateFrame` composes its observer-only
|
||||
`move-proof-*` probe splines into `AquariumFrame.Scene.SplineFrame` beside
|
||||
the audio spectrum preview. Fensalir remains a renderer, not a proof
|
||||
authority.
|
||||
- `MimirMoveCalibrationProtocol` defines the runnable Starfire/Nightwing Move
|
||||
calibration preflight as typed state: required Muninn Move evidence streams,
|
||||
optional Quest headset/controller pose witnesses over USB,
|
||||
|
|
|
|||
Loading…
Reference in a new issue