dicechess.engine.model

Members list

Type members

Classlikes

final class FeatureSchema

One feature-extraction contract of this engine: the id a model manifest names, the column layout that id promises, and the extractor that produces a row.

One feature-extraction contract of this engine: the id a model manifest names, the column layout that id promises, and the extractor that produces a row.

This is what makes a manifest's featureSchema field actionable rather than documentation. A host that loads a model no longer hardcodes which extractor to pair with it — the artifact declares its schema, this registry resolves it, and a model trained on a different layout fails to load instead of silently receiving a vector in which every column means something else. That failure mode is the reason the field exists: two schemas of equal width (there is no such pair today, but nothing prevents one) would otherwise be indistinguishable at run time.

The engine is the single source of truth for the values themselves — every extractor here is the same code the training enrichment calls — so train == serve holds by construction rather than by a Python reimplementation.

Value parameters

columnNames

the layout in extract's order; its length is the input width a conforming model must declare

extract

(state, color) => row, from color's perspective and independent of state's active color and dice pool

id

the extractor's own schemaId, never a string repeated here

Attributes

Companion
object
Source
FeatureSchema.scala
Supertypes
class Object
trait Matchable
class Any
object FeatureSchema

Attributes

Companion
class
Source
FeatureSchema.scala
Supertypes
class Object
trait Matchable
class Any
Self type
final case class ModelCalibration(temperature: Double = ..., brierScore: Option[Double] = ..., logLoss: Option[Double] = ..., calibratedOn: Option[String] = ...)

Calibration metadata of a probability-valued model. Advisory — the engine records it and never applies it, because scaling a score the search only ever compares against other scores of the same model changes nothing.

Calibration metadata of a probability-valued model. Advisory — the engine records it and never applies it, because scaling a score the search only ever compares against other scores of the same model changes nothing.

Field names and the temperature default mirror the deployed evaluation service's calibration metadata, so one artifact's manifest is readable by both without a translation step.

Attributes

Source
ModelManifest.scala
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
final case class ModelManifest(manifestVersion: String, modelId: String, modelSha256: String, modelRole: String, featureSchema: String, featureCount: Int, inputName: String, outputName: String, perspective: String, engineCompatibility: String, evaluationProfile: Option[String] = ..., calibration: ModelCalibration = ..., provenance: Map[String, String] = ...)

The versioned description of one trained ONNX artifact: what it is for, what it consumes, what it emits, which engines may serve it, and which bytes it describes.

The versioned description of one trained ONNX artifact: what it is for, what it consumes, what it emits, which engines may serve it, and which bytes it describes.

Every field is here because its absence has a silent failure mode. A model in the wrong ModelRole answers a different question; a model on the wrong featureSchema receives a vector in which every column means something else; a model whose tensors are named or shaped differently either fails deep inside a JNI call or — worse — is fed by index and scored anyway; a model served by an engine whose feature extractors have moved on is scored on out-of-distribution inputs; and a model whose bytes no longer match the manifest is simply a different model. None of those show up as a crash. They show up as a bot that plays worse than it measured, which is the most expensive defect this project can ship.

Validation is therefore fail-closed and happens before a session is created (ModelManifest.validate, ModelManifest.verifyDigest) and before any row reaches the model (OnnxModelContract.validate).

Versions

  • 1.0.0 — the manifest the evaluation service and the training repository's kcp-13 serving contract already produce. It has no role, perspective or tensor-name fields; this engine reads such a manifest as ModelRole.PositionValue on the mover-perspective convention with the contract's input/output tensor names, which is exactly what those artifacts are.
  • 1.1.0 — adds modelRole and perspective as required fields and inputName/outputName as optional ones. A model for the search's chance-collapse or pre-ranking hooks can only be described by this version, since 1.0.0 cannot say which of them it is.

Unknown fields are ignored on purpose: a newer producer may add metadata this engine has no use for, and refusing to load over it would make every manifest addition a breaking change. A field a declared version does not define is the opposite case and is refused: a 1.0.0 manifest carrying modelRole would mean one thing here and another to every reader that only knows 1.0.0.

Value parameters

engineCompatibility

space-separated MAJOR.MINOR.PATCH comparators (=, >, >=, =0.12.0 <1.0.0. The syntax is the deployed evaluator's, deliberately not re-invented

modelSha256

64 hex characters over the ONNX file's bytes — the manifest describes exactly one file and can be pinned in a preregistered experiment record

perspective

whose point of view the feature row and the output take; see ModelManifest.MoverPerspective

provenance

free-form producer metadata (training run, dataset digest, commit); never interpreted here

Attributes

Companion
object
Source
ModelManifest.scala
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object ModelManifest

Attributes

Companion
class
Source
ModelManifest.scala
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
final case class ModelPackage(modelPath: Path, manifest: ModelManifest, role: ModelRole, schema: FeatureSchema)

A validated model package: an ONNX file, the manifest that describes it, and the two things the manifest's ids resolve to — the ModelRole the model may be wired into and the FeatureSchema whose rows it must be fed.

A validated model package: an ONNX file, the manifest that describes it, and the two things the manifest's ids resolve to — the ModelRole the model may be wired into and the FeatureSchema whose rows it must be fed.

Holding this value is the proof that the checks ran. A host that has one can wire a search hook without re-deciding which extractor to use or whether the artifact fits: ModelPackage.extract is the only correct extractor for these bytes, and the role is the only correct place to put them.

Loading is deliberately cheap and session-free: it reads the manifest, digests the model file, and stops. The graph itself is checked once a session exists, through ModelPackage.validateSession — the one check that needs onnxruntime to open the file.

Attributes

Companion
object
Source
ModelPackage.scala
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object ModelPackage

Attributes

Companion
class
Source
ModelPackage.scala
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
object ModelRole

Attributes

Companion
enum
Source
ModelRole.scala
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type
ModelRole.type
enum ModelRole(val id: String)

What a trained model is used for, declared by its manifest and checked before the model is wired into a search.

What a trained model is used for, declared by its manifest and checked before the model is wired into a search.

The role is not cosmetic metadata: the three roles below answer different questions about different objects, and feeding one where another is expected produces a bot that runs, reports no error, and plays badly. Tensor width cannot tell them apart — two roles may share a feature schema and therefore an identical [batch, F] input — so the role is the only thing that can.

  • ModelRole.PositionValue — P(the evaluated color wins) for a position whose next roll is unknown. The leaf evaluator of every ONNX bot here, and the root rescorer, are this role.
  • ModelRole.ChanceCollapse — the expectation a chance node would compute for the position reached by a turn, i.e. a learned replacement for expanding all 56 weighted dice outcomes. Trained against a deeper search's value, not against game outcomes, so its scale is an expectation and not a win probability.
  • ModelRole.MovePreRank — a score per candidate turn, used only to choose which candidates a search expands. Ordering is all that is consumed; the absolute value is never compared against a value-model score.

The ids are the strings a manifest carries and match the role inventory of the training repository's train/serve contract, so one artifact describes itself the same way on both sides.

Attributes

Companion
object
Source
ModelRole.scala
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all

Checks that a loaded ONNX graph is the graph its manifest promises, before a single row is scored.

Checks that a loaded ONNX graph is the graph its manifest promises, before a single row is scored.

The engine feeds a session by name (session.run takes a name → tensor map) and reads the first output by position, so a graph whose input is called something else fails inside the runtime with a message about a missing input, and a graph whose output is a different tensor than expected is scored anyway — the observed cause of the Python/JVM disagreement this contract exists to end (the repository's own older fixtures name their output variable, which the JVM reads by index and the contract now rejects by name).

A width mismatch is the other half: [batch, 27] fed 13 floats is an error, [batch, 13] fed a 13-column row from the wrong schema is not — which is why the schema id is checked in the manifest and the width here. Both must hold.

Attributes

Source
OnnxModelContract.scala
Supertypes
class Object
trait Matchable
class Any
Self type
final case class OnnxTensorContract(name: String, dataType: OnnxJavaType, shape: Vector[Long])

One tensor of a loaded ONNX graph, as the runtime reports it. Separated from the checks below so the shape rules can be tested without a real session — every dimension and dtype branch is reachable from a value, not from a fixture.

One tensor of a loaded ONNX graph, as the runtime reports it. Separated from the checks below so the shape rules can be tested without a real session — every dimension and dtype branch is reachable from a value, not from a fixture.

Value parameters

shape

dimensions as ONNX Runtime states them: a negative entry is a dynamic (symbolic) axis

Attributes

Source
OnnxModelContract.scala
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all