Gliner/Packaging/GlinerPackagingProbe.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Cryptography;
using Sandbox;
using Sandbox.Diagnostics;
namespace GlinerPoc.Packaging;
/// <summary>
/// Phase 2 packaging probe. Loads the root GLiNER model resource through
/// normal s&box APIs, validates the SBGLI1 manifest and shard identities,
/// reads selected tensor bytes and compares them against values generated
/// from the deterministic Python export, and records memory/timing at each
/// stage. Performs NO neural inference.
///
/// Also runs the C# parser negative-path checks (bad magic, bad version,
/// truncated payload, chunk out of bounds) before the happy path.
/// </summary>
[Title( "GLiNER Packaging Probe" )]
[Category( "GLiNER" )]
public sealed class GlinerPackagingProbe : Component
{
[Property]
public bool RunOnStart { get; set; } = true;
[Property]
public GlinerModelResource ModelResource { get; set; }
private int _failures;
private long _bytesTouched;
protected override void OnStart()
{
if ( RunOnStart )
{
_ = RunAsync();
}
}
private async Task RunAsync()
{
Log.Info( "[GLI:PACK] probe start" );
var sw = Stopwatch.StartNew();
LogStage( "baseline", sw );
RunNegativeChecks( ModelResource.MetadataData?.Bytes );
try
{
if ( ModelResource is null )
{
throw new InvalidOperationException(
"[GLI:ERROR] Probe has no GlinerModelResource assigned." );
}
var root = ModelResource;
// ---- root identity -------------------------------------------------
if ( root.FormatMagic != GlinerModelResource.ExpectedMagic )
{
throw new InvalidOperationException(
$"[GLI:ERROR] Root magic expected '{GlinerModelResource.ExpectedMagic}', found '{root.FormatMagic}'." );
}
if ( root.FormatVersion != GlinerModelResource.ExpectedFormatVersion )
throw new InvalidOperationException( "[GLI:ERROR] Unexpected root format version." );
// ---- runtime config (parsed once, validated against contract) ------
var config = Json.Deserialize<Dictionary<string, object>>( root.RuntimeConfigJson );
Expect( config, "hidden_size", 384.0 );
Expect( config, "num_hidden_layers", 12.0 );
Expect( config, "num_attention_heads", 6.0 );
Expect( config, "intermediate_size", 1536.0 );
Expect( config, "vocab_size", 128011.0 );
Expect( config, "position_buckets", 256.0 );
Expect( config, "layer_norm_eps", 1e-7 );
Expect( config, "classification_temperature", 1.0 );
Log.Info( "[GLI:PACK] PASS runtime_config contract (hidden/layers/heads/ffn/vocab/buckets/eps/temperature)" );
// tokenizer identity
string tokenizerSha = Sha256Hex( root.TokenizerData?.Bytes );
if ( tokenizerSha != root.TokenizerSha256 )
throw new InvalidOperationException( "[GLI:ERROR] Tokenizer bytes SHA-256 mismatch." );
Log.Info( $"[GLI:PACK] PASS tokenizer identity bytes={root.TokenizerByteCount:N0}" );
LogStage( "root_metadata_parsed", sw );
// ---- SBGLI1 manifest parse ------------------------------------------
var manifest = Sbgli1Manifest.Parse( root.MetadataData.Bytes );
_bytesTouched += root.MetadataData.Bytes.Length + root.TokenizerData.Bytes.Length;
Log.Info( $"[GLI:PACK] PASS manifest tensors={manifest.TensorCount} " +
$"chunks={manifest.ChunkCount} shards={manifest.ShardCount}" );
if ( manifest.CheckpointSha256 != root.CheckpointSha256 )
throw new InvalidOperationException( "[GLI:ERROR] Checkpoint SHA-256 identity mismatch (root vs manifest)." );
if ( manifest.RuntimeConfigSha256 != root.RuntimeConfigSha256 )
throw new InvalidOperationException( "[GLI:ERROR] Runtime config SHA-256 identity mismatch." );
// ---- shard identity (typed references vs manifest) -------------------
// Eager-loading observation: report whether shard payloads are already
// materialized merely by the root resource having loaded.
int eagerCount = 0;
long eagerBytes = 0;
foreach ( var r in root.Shards )
{
var bytes = r.Shard?.Payload?.Bytes;
if ( bytes is { Length: > 0 } )
{
eagerCount++;
eagerBytes += bytes.Length;
}
}
Log.Info( $"[GLI:PACK] OBSERVE eager_materialized_shards={eagerCount}/{root.Shards.Count} " +
$"bytes={eagerBytes:N0} (root loaded without explicit shard access)" );
if ( root.Shards.Count != manifest.ShardCount )
throw new InvalidOperationException( "[GLI:ERROR] Shard reference count != manifest shard count." );
for ( int i = 0; i < root.Shards.Count; i++ )
{
var r = root.Shards[i];
if ( r.ShardIndex != i )
throw new InvalidOperationException( $"[GLI:ERROR] Shard reference at position {i} declares index {r.ShardIndex}." );
if ( r.Shard is null )
throw new InvalidOperationException( $"[GLI:ERROR] Shard reference {r.ShardIndex} is null." );
if ( r.Shard.ShardIndex != r.ShardIndex )
throw new InvalidOperationException( $"[GLI:ERROR] Shard {r.ShardIndex} index mismatch." );
var srec = manifest.Shards[r.ShardIndex];
if ( r.Shard.ByteCount != srec.ByteCount || r.ByteCount != srec.ByteCount )
throw new InvalidOperationException( $"[GLI:ERROR] Shard {r.ShardIndex} byte count mismatch." );
if ( r.Shard.Sha256 != srec.Sha256 )
throw new InvalidOperationException( $"[GLI:ERROR] Shard {r.ShardIndex} SHA-256 metadata mismatch." );
}
Log.Info( "[GLI:PACK] PASS shard references match manifest (count/size/sha)" );
// ---- shard payload verification (all shards, staged timing/memory) ---
var shardData = new byte[manifest.ShardCount][];
for ( int i = 0; i < root.Shards.Count; i++ )
{
var bytes = root.Shards[i].Shard.Payload?.Bytes;
if ( bytes is not { Length: > 0 } )
throw new InvalidOperationException( $"[GLI:ERROR] Shard {i} payload not materialized on access." );
if ( bytes.Length != manifest.Shards[i].ByteCount )
throw new InvalidOperationException( $"[GLI:ERROR] Shard {i} payload length mismatch." );
string sha = Sha256Hex( bytes );
if ( sha != manifest.Shards[i].Sha256 )
throw new InvalidOperationException( $"[GLI:ERROR] Shard {i} payload SHA-256 mismatch." );
shardData[i] = bytes;
_bytesTouched += bytes.Length;
if ( i == 0 )
{
LogStage( "one_shard_verified", sw );
}
}
LogStage( "all_shards_verified", sw );
// ---- representative tensor reads vs Python-exported expectations ----
int checkedValues = 0;
foreach ( var sample in ExpectedTensorSamples.All )
{
byte[] tensorBytes = manifest.ReadTensorBytes( sample.Tensor, shardData );
var rec = manifest.GetRequiredTensor( sample.Tensor );
int rowElems = 1;
for ( int d = 1; d < rec.Rank; d++ ) rowElems *= rec.Shape[d];
int rowBytes = rowElems * 4;
int take = Math.Min( 4, rowElems );
int rowOffset = sample.Row * rowBytes;
for ( int k = 0; k < take; k++ )
{
float actualFirst = BitConverter.ToSingle( tensorBytes, rowOffset + k * 4 );
if ( actualFirst != sample.First[k] )
throw new InvalidOperationException(
$"[GLI:ERROR] Tensor '{sample.Tensor}' row {sample.Row} first[{k}]: expected {sample.First[k]}, read {actualFirst}." );
float actualLast = BitConverter.ToSingle( tensorBytes, rowOffset + rowBytes - (take - k) * 4 );
if ( actualLast != sample.Last[k] )
throw new InvalidOperationException(
$"[GLI:ERROR] Tensor '{sample.Tensor}' row {sample.Row} last[{k}]: expected {sample.Last[k]}, read {actualLast}." );
checkedValues += 2;
}
}
_bytesTouched += checkedValues * 4;
Log.Info( $"[GLI:PACK] PASS tensor byte comparisons values={checkedValues} " +
"samples=ExpectedTensorSamples.All (exact FP32)" );
LogStage( "tensors_compared", sw );
// ---- release stage ---------------------------------------------------
shardData = null;
LogStage( "references_released", sw );
Log.Info( $"[GLI:PACK] probe complete failures={_failures} total_ms={sw.ElapsedMilliseconds} PASS" );
}
catch ( Exception error )
{
_failures++;
Log.Error( $"[GLI:PACK] FAIL: {error.Message}" );
Log.Error( $"[GLI:PACK] probe complete failures={_failures}" );
}
}
private void RunNegativeChecks( byte[] valid )
{
ExpectRejected( "bad magic", valid, d => d[0] = (byte)'X' );
ExpectRejected( "wrong version", valid, d => d[8] = 99 );
ExpectRejected( "corrupted records", valid, d => d[Sbgli1Manifest.HeaderBytes + 8] ^= 0xFF );
Log.Info( "[GLI:PACK] PASS parser negative-path checks" );
}
private static void ExpectRejected( string label, byte[] valid, Action<byte[]> mutate )
{
byte[] d = new byte[valid.Length];
for ( int i = 0; i < valid.Length; i++ )
{
d[i] = valid[i];
}
mutate( d );
try
{
Sbgli1Manifest.Parse( d );
}
catch ( InvalidOperationException )
{
Log.Info( $"[GLI:PACK] negative detected: {label}" );
return;
}
throw new InvalidOperationException(
$"[GLI:ERROR] Negative check '{label}' was not rejected by the parser." );
}
private static void Expect( Dictionary<string, object> config, string key, double expected )
{
if ( !config.TryGetValue( key, out var raw ) )
{
throw new InvalidOperationException( $"[GLI:ERROR] Runtime config missing '{key}'." );
}
// s&box Json.Deserialize yields System.Text.Json.JsonElement boxes.
double actual = raw is System.Text.Json.JsonElement element
? element.GetDouble()
: Convert.ToDouble( raw );
if ( Math.Abs( actual - expected ) > 1e-9 )
{
throw new InvalidOperationException(
$"[GLI:ERROR] Runtime config '{key}' expected {expected}, found {actual}." );
}
}
// NOTE: GC.GetTotalMemory and Environment.WorkingSet are whitelist-blocked
// (SB1000, engine 26.09.15) - in-process memory metrics are unavailable.
// Memory evidence comes from explicit byte accounting (_bytesTouched) plus
// external process working-set measurement recorded in the Phase 2 report.
private void LogStage( string stage, Stopwatch sw )
{
Log.Info( $"[GLI:PACK] stage={stage} elapsed_ms={sw.ElapsedMilliseconds} " +
$"payload_bytes_touched={_bytesTouched:N0}" );
}
private static string Sha256Hex( byte[] bytes )
{
if ( bytes is null || bytes.Length == 0 )
{
return "";
}
return Convert.ToHexString( SHA256.HashData( bytes ) ).ToLowerInvariant();
}
}