EvaluatedApplications.Prism 1.3.4

dotnet add package EvaluatedApplications.Prism --version 1.3.4
                    
NuGet\Install-Package EvaluatedApplications.Prism -Version 1.3.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EvaluatedApplications.Prism" Version="1.3.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EvaluatedApplications.Prism" Version="1.3.4" />
                    
Directory.Packages.props
<PackageReference Include="EvaluatedApplications.Prism" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EvaluatedApplications.Prism --version 1.3.4
                    
#r "nuget: EvaluatedApplications.Prism, 1.3.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EvaluatedApplications.Prism@1.3.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EvaluatedApplications.Prism&version=1.3.4
                    
Install as a Cake Addin
#tool nuget:?package=EvaluatedApplications.Prism&version=1.3.4
                    
Install as a Cake Tool

Prism

Beta. The public API may change between versions while we improve it. Breaking changes always come with a new major version, and the release notes say what changed.

EvaluatedApplications.Prism — the AlgFormer/HoloFormer production standard: a stamped, append-only lineage journal that answers "what was true when this happened" without ever re-deriving history from current state, plus the canonical confidence-gated decode policy a real HoloFormer/AlgFormer host runs in production. Built to stop one class of bug that has hit a real training hot path three times — a value recomputed from a live constant/field instead of read from a fact stamped at the time it happened. This page is comprehensive: every public type and member is documented below, because this package ships binary-only (no source, no separate docs site).

dotnet add package EvaluatedApplications.Prism

Depends on EvaluatedApplications.AlgFormer (resolved automatically). Namespaces: Prism.Lineage, Prism.Inference, Prism.Growth.

Table of contents

  1. Quick start
  2. Why this exists — the invariant every type here protects
  3. Prism.Lineage — the stamped journal
  4. Prism.Growth — grow a model correctly, with the journal stamped automatically
  5. Prism.Inference — the confidence-gated decode
  6. Gotchas and invariants
  7. License

Quick start

using Prism.Lineage;
using Prism.Growth;
using Prism.Inference;
using PrismFormer;

// 1) A model and a lineage journal to go with it (JSONL on disk, or MemoryLineageStore for no filesystem).
var model = new HoloFormer(vocab: 10, shifts: 3, layers: 1, maxContext: 6, dModel: 8, frozenPrefix: 0);
var journal = new LineageJournal(new MemoryLineageStore());
var inForce = new InForce(IterWarm: 8, StackK: 2, CtxCeiling: 64, LayerCeiling: 8);
journal.AppendGenesis(round: 0, layers: model.Layers, inForce);

// 2) Grow it through Prism.Growth so the journal is stamped automatically.
var grown = Grow.AddLayers(model, extra: 1, atRound: 10, journal, inForce);
double rampedAlpha = journal.AlphaAt(round: 12, layerIndex: grown.Model.Layers - 1);
Console.WriteLine($"grew to {grown.Model.Layers} layers; new layer's alpha at round 12 = {rampedAlpha:F3}");

// 3) Decode with the canonical confidence gate instead of hand-rolling softmax + a threshold.
double[] logits = grown.Model.LogitsFor(new[] { 1, 2, 3 });
var decision = Gate.Evaluate(logits, vocab: model.Vocab, DecodePolicy.Holographic);
int picked = Gate.Pick(logits, vocab: model.Vocab, DecodePolicy.Holographic, new Random(1));
Console.WriteLine($"greedy={decision.Greedy} top={decision.Top} picked={picked}");

Why this exists

A fact about what happened is stamped when it happens, and is never re-derived from current state. Every LineageJournal derivation (AlphaAt, DepthAt, LastGrowthRound, AddRoundOf) walks stamped history up to the round in question; none of them ever reads an ambient/live constant or field. Three real production incidents in a HoloFormer/AlgFormer training host shared exactly this root cause before this package existed:

  1. Alpha computed live from a constant. A per-layer ramp read the current warm-up constant instead of the constant that was in force when that layer was added — hand-bumping the constant as a stopgap, then reverting it, made every already-ramped layer's alpha jump discontinuously.
  2. A regrow-ramp boundary invented from a schedule. A formula guess kept recomputing a "boundary" after growth had already stopped, crushing the learning rate forever.
  3. Serving depth read live from the wrong knob. A diagnostic hardcoded an old depth value after the live value had moved on, silently evaluating a checkpoint at the wrong depth.

A fourth, same-family trap: a layer index is also state that moves once front-insert growth exists (index i names a different layer after every later front grow) — LineageJournal resolves indices by replaying stamped events, never by looking an index up against a range frozen at grow time.

If you build your own derivation on top of Prism.Lineage, ask "does this read anything from the stamped event list, or does it reach for a live field/constant instead?" — the second answer is the bug this package exists to prevent.


Prism.Lineage

Types

Member Purpose
EventKind (enum) Genesis (model came into existence) / GrowContext / GrowLayers / GrowShifts (structural, carry a shape From/To) / Mint (vocab grew in lockstep with a tokenizer mint, carries shape From/To) / Knob (a runtime parameter changed value with no shape change, carries Field/FieldFrom/FieldTo). GrowShifts and Mint deliberately do not count as a LastGrowthRound trigger — shifts/K are lineage-fixed and a vocab row perturbs no existing layer or position.
Origin (enum) Stamped (recorded when it actually happened — the default) / Backfilled (reconstructed later from legacy data or a formula — honest about being an inference, not an eyewitness account).
InForce(int IterWarm, int StackK, int CtxCeiling, int LayerCeiling) (sealed record) Every parameter a later derivation might need, captured at the moment an event is stamped — a snapshot, not a live reference; the caller must read current values and pass them in. Extra (Dictionary<string,JsonElement>?, [JsonExtensionData]) round-trips a future field this version doesn't know about. InForce.Empty — an all-zero placeholder, never a real stamp.
LifecycleEvent(int Seq, int Round, EventKind Kind, InForce InForce) (sealed record) One append-only, immutable journal entry. Seq — journal append order (assigned by the journal). Round — the model's own training-round clock at the moment this fired. ShapeFrom/ShapeTo (int?) — populated for a structural event, null for Knob. LayerInsertIndex (int?, GrowLayers only) — where new layers went: 0=front, ShapeFrom=append, null=append (every pre-existing journal line). Field/FieldFrom/FieldTo (string?/double?) — populated for Knob, null otherwise. Origin — defaults to Stamped.
ILineageStore (interface) The storage seam: void Append(LifecycleEvent evt); IReadOnlyList<LifecycleEvent> ReadAll(). Deliberately minimal and synchronous.
FileLineageStore(string path) : ILineageStore JSONL (one event per line) store for a real filesystem. Each append is one flushed write, so a killed process can only ever truncate the last line — ReadAll drops a torn last line silently but throws on any earlier parse failure (real corruption). Throws InvalidOperationException if a serialized event would contain a raw newline.
MemoryLineageStore() : ILineageStore Pure in-memory store, no I/O — for a browser/WASM host with no filesystem, or for tests.
LineageJournal(ILineageStore store) The journal itself. Loads its whole history from store once, at construction.

LineageJournal members

Member Purpose
Events (IReadOnlyList<LifecycleEvent>) Every event ever stamped, in append order (a defensive copy).
Append(EventKind kind, int round, InForce inForce, int? shapeFrom = null, int? shapeTo = null, string? field = null, double? fieldFrom = null, double? fieldTo = null, Origin origin = Origin.Stamped, int? layerInsertIndex = null) → LifecycleEvent The general append primitive. Idempotent: a duplicate (Round, Kind, Field) key is a no-op that returns the pre-existing record — safe to call unconditionally from a ctor catch-up that re-checks "should this have fired already" on every resume.
AppendGenesis(int round, int layers, InForce inForce, Origin origin = Origin.Stamped) Stamp the model's genesis: layers [0, layers) exist from round (conventionally round 0).
AppendGrowContext(int round, int fromCtx, int toCtx, InForce inForce, Origin origin = Origin.Stamped) Stamp a real context grow — a LastGrowthRound trigger.
AppendGrowLayers(int round, int fromLayers, int toLayers, InForce inForce, Origin origin = Origin.Stamped, int? insertIndex = null) Stamp a real layer grow — a LastGrowthRound trigger. insertIndex must lie in [0, fromLayers] (throws ArgumentOutOfRangeException otherwise); 0=front-insert, fromLayers/null=append.
AppendGrowShifts(int round, int fromShifts, int toShifts, InForce inForce, Origin origin = Origin.Stamped) Stamp a real shift grow — deliberately not a LastGrowthRound trigger.
AppendMint(int round, int fromVocab, int toVocab, InForce inForce, Origin origin = Origin.Stamped) Stamp a real vocab mint — deliberately not a LastGrowthRound trigger.
AppendKnob(int round, string field, double from, double to, InForce inForce, Origin origin = Origin.Stamped) Stamp a runtime-parameter change with no shape change (e.g. hand-editing IterWarm).
AlphaAt(int round, int layerIndex) → double Layer layerIndex's weight-tied-K ramp fraction (0..1) at round, using the IterWarm that was in force when that layer was actually added — never today's ambient value. The index is resolved against the layer stack as it existed at round. Throws InvalidOperationException if no layer held that index by then.
AlphaFor(int round, int addRound, int iterWarm) → double (static) The pure ramp formula in isolation: clamp((round-addRound)/iterWarm, 0, 1).
AddRoundOf(int layerIndex) → int The round layer layerIndex actually materialized, index read against the current (live, all-events-replayed) stack.
DepthAt(int round) → (int StackK, double[] Alpha) The live depth as of round: how many layers existed by then, the StackK in force, and each layer's own alpha in that round's stack order. Throws InvalidOperationException if nothing was stamped at or before round.
LastGrowthRound(int round) → int? The round of the most recent genuine context/layer growth event at or before round (excludes GrowShifts/Mint by design). null if no growth has happened yet.
using Prism.Lineage;

var journal = new LineageJournal(new MemoryLineageStore());
var inForce0 = new InForce(IterWarm: 10, StackK: 1, CtxCeiling: 32, LayerCeiling: 4);
journal.AppendGenesis(round: 0, layers: 1, inForce0);

var inForce1 = new InForce(IterWarm: 10, StackK: 2, CtxCeiling: 32, LayerCeiling: 4);
journal.AppendGrowLayers(round: 20, fromLayers: 1, toLayers: 2, inForce1);   // append (default)

double alphaNewLayerEarly = journal.AlphaAt(round: 22, layerIndex: 1);   // 2 rounds into its own 10-round ramp
double alphaOldLayer      = journal.AlphaAt(round: 22, layerIndex: 0);   // settled long ago -> 1.0
var (stackK, alpha) = journal.DepthAt(round: 22);
Console.WriteLine($"newLayerAlpha={alphaNewLayerEarly:F2} oldLayerAlpha={alphaOldLayer:F2} " +
                   $"StackKAt22={stackK} LastGrowthRound(25)={journal.LastGrowthRound(25)}");

// Idempotent re-append (e.g. a resumed process re-checking "should this have fired") is a safe no-op:
var again = journal.AppendGrowLayers(round: 20, fromLayers: 1, toLayers: 2, inForce1);
Console.WriteLine($"idempotent: {journal.Events.Count} events after a duplicate append");

Prism.Growth

A growth surface over HoloFormer (package AlgFormer) that makes each axis correct by construction and stamps the LineageJournal as it goes. Prism.Growth.Grow is the only sanctioned way to grow a model you're tracking with a LineageJournal — calling HoloFormer.GrowLayers/GrowShifts/HoloUpgrade.* directly and hand-stamping reopens exactly the "forgot to record it" bugs this package exists to prevent.

Member Purpose
GrowResult(HoloFormer Model, LifecycleEvent? Event, IReadOnlyList<string> Warnings) (readonly record struct) The outcome of one Grow call. Event is null exactly on a no-op (requested size already matched). Warnings is non-empty only for an explicit opt-in cost (see ToContext).
Grow.ToContext(HoloFormer model, int newContext, int atRound, LineageJournal journal, InForce inForce, bool allowFrontDemotion = false, Func<int,double[]>? seed = null) → GrowResult Grow the context window. Front-preserving by default (wraps HoloUpgrade.To). Refuses with InvalidOperationException on a GrowFromFront:false model unless allowFrontDemotion:true — and even then records a Warnings entry, because opting in once doesn't make the cost free.
Grow.AddLayers(HoloFormer model, int extra, int atRound, LineageJournal journal, InForce inForce, bool zeroOutputOnly = true, int seed = 42, bool atFront = false) → GrowResult Add extra layers (wraps HoloFormer.GrowLayers), stamping one GrowLayers event covering the whole new range so AlphaAt ramps every new layer from 0 at atRound. atFront:true inserts at the front (the original first layer stays last forever) and stamps insertIndex:0.
Grow.ToShifts(HoloFormer model, int newShifts, int atRound, LineageJournal journal, InForce inForce, int seed = 42) → GrowResult Grow shift-banks. Stamps EventKind.GrowShifts, which LastGrowthRound excludes — a shift grow must not reset the regrow-ramp cooldown.
Grow.ToVocab(HoloFormer model, int newVocab, int atRound, LineageJournal journal, InForce inForce, Func<int,double[]> seed) → GrowResult The model-side half of a tokenizer mint (wraps HoloUpgrade.GrowVocab). Pass exactly the tokenizer's newly minted count, no headroom. seed is required here (unlike the underlying primitive) — a vocab row isn't meant to be random; passing the wrong/no seed silently breaks the frozen-prefix/orbital-band/zero-tail scheme.

All four methods: are a no-op (same model reference, Event:null, an informational Warnings entry) when the requested size already matches the model's current size on that axis; throw ArgumentException on any shrink request (a live checkpoint cannot shrink in place).

using Prism.Lineage;
using Prism.Growth;
using PrismFormer;

var model = new HoloFormer(vocab: 10, shifts: 3, layers: 1, maxContext: 6, dModel: 8, frozenPrefix: 0);
var journal = new LineageJournal(new MemoryLineageStore());
var inForce = new InForce(IterWarm: 8, StackK: 1, CtxCeiling: 32, LayerCeiling: 8);
journal.AppendGenesis(0, model.Layers, inForce);

var layersResult = Grow.AddLayers(model, extra: 2, atRound: 5, journal, inForce);
var shiftsResult = Grow.ToShifts(layersResult.Model, newShifts: 5, atRound: 8, journal, inForce);
var ctxResult    = Grow.ToContext(shiftsResult.Model, newContext: 10, atRound: 10, journal, inForce);

Console.WriteLine($"layers={layersResult.Model.Layers} (event={layersResult.Event != null}) " +
                   $"shifts={shiftsResult.Model.Shifts} ctx={ctxResult.Model.Context} " +
                   $"warnings={ctxResult.Warnings.Count}");

// No-op: requesting the current size records no event and returns the SAME model instance.
var noop = Grow.ToShifts(shiftsResult.Model, newShifts: 5, atRound: 20, journal, inForce);
Console.WriteLine($"no-op same instance: {ReferenceEquals(noop.Model, shiftsResult.Model)} event={noop.Event is null}");

Prism.Inference

The confidence-gated decode a HoloFormer/AlgFormer host actually runs: commit greedily when the top token is confident, otherwise sample — either over a resonance-filtered subset (the holographic core's real behaviour) or the whole vocabulary (the plain-softmax core's real behaviour) — plus a degeneracy guard.

Member Purpose
FloorMode (enum) None (no floor — sample the whole vocab, the non-holographic core's behaviour) / ResonanceSigma (cut anything below mean + FloorK·sigma of the raw logits — the holographic core's behaviour; structurally degenerates to a pure top-1 filter on 78-84% of real below-confidence positions, see Gotchas) / TopP (nucleus sampling — admit the smallest probability-mass prefix meeting DecodePolicy.P; fixes the ResonanceSigma degeneracy but is not the default for any existing caller).
DecodePolicy (sealed record) ConfidentThreshold (0.60) — top-1 probability at/above which the pick is greedy. Temperature (0.80). FloorK (3.0, used by ResonanceSigma). Floor (FloorMode, default ResonanceSigma). P (0.9, used by TopP). DegenRepeat (4), DegenNonGreedyRun (5) — see DegenGuard. Static presets: Holographic (the named holographic-core policy, value-identical to Default), Dense (same gate/temperature but Floor:None, for the non-holographic core), Default (= Holographic).
GateDecision(int Top, double TopProb, bool Greedy, int OverFloor) (readonly record struct) What Gate.Evaluate/Pick decided, without re-drawing a sample — for an inspector to explain a choice at zero extra forward-pass cost. OverFloor is the sampleable count (or the whole vocab under FloorMode.None); meaningless when Greedy is true.
Gate (static class) Evaluate(double[] logits, int vocab, DecodePolicy policy) → GateDecision — classify without drawing from the RNG. Pick(double[] logits, int vocab, DecodePolicy policy, Random rng) → int — draw a token; takes an explicit Random for reproducibility. TopK(double[] scores, int vocab, int count) → IReadOnlyList<(int Index, double Percent)> — a display helper, no gate logic. Both Evaluate/Pick throw ArgumentOutOfRangeException if vocab doesn't fit within logits.Length (named explicitly — the real cause historically was a post-mint vocab/logits race; bound by the returned logits array's own length, not a snapshotted vocab count).
DegenGuard(int repeatThreshold, int nonGreedyRunThreshold) / DegenGuard(DecodePolicy policy) Fires on either of two independent triggers: RepeatThreshold consecutive identical tokens, or NonGreedyRunThreshold consecutive sampled (non-greedy) picks. Observe(int token, bool greedy) → bool (true the moment either trigger fires); Reset(). Known blind spot, carried forward honestly: misses period>1 cycles ("A B A B A B" trips neither trigger).
using Prism.Inference;

var rng = new Random(1);
double[] logits = { 0.1, 5.0, 0.2, 0.05, 0.3 };   // index 1 clearly dominant -> should decode greedy

var decision = Gate.Evaluate(logits, vocab: logits.Length, DecodePolicy.Holographic);
int picked = Gate.Pick(logits, vocab: logits.Length, DecodePolicy.Holographic, rng);
var top3 = Gate.TopK(logits, vocab: logits.Length, count: 3);
Console.WriteLine($"greedy={decision.Greedy} top={decision.Top} topProb={decision.TopProb:F3} picked={picked} " +
                   $"top3=[{string.Join(",", top3.Select(t => $"{t.Index}:{t.Percent:F1}%"))}]");

// A non-holographic ("Dense") host explicitly opts out of the resonance floor:
var denseDecision = Gate.Evaluate(logits, vocab: logits.Length, DecodePolicy.Dense);
Console.WriteLine($"Dense OverFloor (whole vocab, no floor)={denseDecision.OverFloor}");

// Degeneracy guard:
var guard = new DegenGuard(DecodePolicy.Holographic);
bool collapsed = false;
foreach (var tok in new[] { 1, 1, 1, 1 }) collapsed = guard.Observe(tok, greedy: true);
Console.WriteLine($"collapsed after 4 repeats (threshold 4)={collapsed}");

Gotchas

  • FloorMode.None, ResonanceSigma, and TopP are all real, for different callers. Don't silently default every caller to one — that is exactly the copy-drift this package exists to end. Holographic (= Default) and Dense name the two real production choices explicitly.
  • ResonanceSigma is structurally a top-1 filter at most below-confidence positions (measured: 77.7%– 83.9% of real FINAL-face logit positions on a production-shaped checkpoint). The min(mean+FloorK·sigma, max) cap means the admitted set is never empty, but mean/sigma are computed over the full vocab including every already-suppressed token, so sigma measures the rejected bulk's spread, not the real candidates' — no retune of FloorK fixes this (it's a tail-shape problem). FloorMode.TopP fixes it by admitting on softmax probability mass instead, which has no suppressed-tail term to inherit the bug from. ResonanceSigma itself is unchanged by this fact — switching a host to TopP is a separate, deliberate decision you make per-host, not a default this package silently changes for you.
  • DegenGuard must keep both triggers. Dropping the non-greedy-run trigger reopens a real closed gap (a port that implemented only the repeat trigger missed it).
  • LineageJournal.Append's idempotency key is (Round, Kind, Field). A duplicate GrowLayers at the same round/kind/field collapses to the first record — including its LayerInsertIndex — so a second call with a different insert index silently returns the first record unchanged. Don't call Append-family methods speculatively expecting the latest call to win.
  • An older Prism build reading a front-grown journal misreads it as an append. LifecycleEvent has no catch-all extension-data bag for unknown fields, so a pre-front-insert reader silently drops LayerInsertIndex and replays a front grow as if it were an append. Upgrade every reader of a shared journal file before writing a front grow into it.
  • InForce's four fields are a snapshot you provide, never a live binding. Read your current knob values at the moment you call an Append*/Grow.* method and pass them in explicitly — there is no "always fresh" wiring, by design (that's the whole point of the package).
  • FileLineageStore.Append throws InvalidOperationException if the serialized event contains a raw newline — this guards the one-event-per-line JSONL contract. Keep any free-text fields you might add to a future event newline-free, or escape them before they reach the store.
  • Nothing here is license-gated. Every type and member on this page works identically regardless of any license key; see License for what the commercial-use terms actually are.

License

Proprietary — this package ships the compiled library only; see LICENSE for the full terms. Installing and using unmodified copies for internal evaluation and non-commercial development or testing is licensed; commercial, production, or revenue-generating use requires a separate commercial licence from the owner. No feature on this page is gated behind a tier or a licence key — every capability described works identically with or without one. Copyright (c) 2026 Dongyang Stephen Chen, trading as Evaluated Applications. All rights reserved.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.4 131 10/3/2026
1.3.3 110 10/3/2026
1.3.2 110 10/2/2026
1.3.1 110 10/2/2026
1.3.0 121 9/23/2026
1.2.0 117 9/19/2026
1.1.0 111 9/14/2026
1.0.2 127 9/6/2026
1.0.1 130 9/5/2026
1.0.0 121 9/5/2026