EvaluatedApplications.Prism
1.3.4
dotnet add package EvaluatedApplications.Prism --version 1.3.4
NuGet\Install-Package EvaluatedApplications.Prism -Version 1.3.4
<PackageReference Include="EvaluatedApplications.Prism" Version="1.3.4" />
<PackageVersion Include="EvaluatedApplications.Prism" Version="1.3.4" />
<PackageReference Include="EvaluatedApplications.Prism" />
paket add EvaluatedApplications.Prism --version 1.3.4
#r "nuget: EvaluatedApplications.Prism, 1.3.4"
#:package EvaluatedApplications.Prism@1.3.4
#addin nuget:?package=EvaluatedApplications.Prism&version=1.3.4
#tool nuget:?package=EvaluatedApplications.Prism&version=1.3.4
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
- Quick start
- Why this exists — the invariant every type here protects
- Prism.Lineage — the stamped journal
- Prism.Growth — grow a model correctly, with the journal stamped automatically
- Prism.Inference — the confidence-gated decode
- Gotchas and invariants
- 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:
- 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.
- 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.
- 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, andTopPare 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) andDensename the two real production choices explicitly.ResonanceSigmais 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). Themin(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 ofFloorKfixes this (it's a tail-shape problem).FloorMode.TopPfixes it by admitting on softmax probability mass instead, which has no suppressed-tail term to inherit the bug from.ResonanceSigmaitself is unchanged by this fact — switching a host toTopPis a separate, deliberate decision you make per-host, not a default this package silently changes for you.DegenGuardmust 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 duplicateGrowLayersat the same round/kind/field collapses to the first record — including itsLayerInsertIndex— so a second call with a different insert index silently returns the first record unchanged. Don't callAppend-family methods speculatively expecting the latest call to win.- An older Prism build reading a front-grown journal misreads it as an append.
LifecycleEventhas no catch-all extension-data bag for unknown fields, so a pre-front-insert reader silently dropsLayerInsertIndexand 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 anAppend*/Grow.*method and pass them in explicitly — there is no "always fresh" wiring, by design (that's the whole point of the package).FileLineageStore.AppendthrowsInvalidOperationExceptionif 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 | Versions 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. |
-
net10.0
- EvaluatedApplications.AlgFormer (>= 2.20.2)
-
net8.0
- EvaluatedApplications.AlgFormer (>= 2.20.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.