Ster/Docs

Steering artifact

A steering artifact is Ster's durable, model-bound collection of one or more layer directions. train and optimize write it; inspect, evaluate, and generate read it. The file is compact JSON, not Safetensors, and carries enough identity and

Overview#

A steering artifact is Ster's durable, model-bound collection of one or more layer directions. train and optimize write it; inspect, evaluate, and generate read it. The file is compact JSON, not Safetensors, and carries enough identity and shape information to refuse a plausible vector on the wrong model, and enough provenance to say when a direction is being read in a space it was not fitted in.

Schema 1#

SteeringArtifact in src/artifact.rs has this complete wire shape:

json
{
  "schema_version": 1,
  "product": "ster",
  "model": "toy-llama",
  "model_revision": null,
  "precision": "f32",
  "chat_template": "absent",
  "trait_name": "calm",
  "method": "caa",
  "hidden_size": 64,
  "vectors": [
    {
      "layer": 2,
      "values": [0.14712493, 0.16871634, -0.061927322],
      "train_margin": 0.76135504,
      "train_accuracy": 0.875
    }
  ],
  "metadata": {}
}

The displayed values array is shortened; the executed file has 64 values. Every field is required on read except metadata, precision, and chat_template: metadata defaults to {}, and the two provenance fields default to null, for schema-1 files that omit them.

FieldContract
schema_versionMust equal the build's ARTIFACT_SCHEMA_VERSION, currently 1.
productMust be exactly "ster".
modelThe exact --model string used for training; runtime matching is string equality.
model_revisionResolved Hub commit SHA; for local directories, the supplied revision or null.
precisionThe dtype the base weights were mapped at when this direction was fitted, spelled exactly as --precision spells it: "f32", "f16", or "bf16". #[serde(default)], so null means an artifact written before the field existed.
chat_templateWhether the pairs this direction was fitted from were read through the model's own chat template: "applied", "absent", or "off" — the same three words an adapter sidecar records at train.chat_template (chat template). #[serde(default)], so null means an artifact written before the field existed.
trait_nameCopied verbatim from the pair set; may be empty.
methodCanonical caa, pca, or logistic.
hidden_sizeModel residual width; must be non-zero and match every vector and the runtime model.
vectorsNon-empty array of layer vectors. train keeps every selected layer; optimize keeps one.
metadataString-to-string map. optimize records the search that produced the artifact, for example selection: "chosen over 12 candidates on a 2-pair holdout, then refitted on all 8 pairs"; train leaves it empty.

A LayerVector contains a 0-based layer, exactly hidden_size finite F32 values, and the training-set train_margin and train_accuracy. Artifact validation does not independently bound the scores or reject duplicate layer numbers; the commands create well-formed, sorted vectors, and generation's BTreeMap plan would let the last duplicate replace an earlier one. Do not hand-author duplicates.

precision and chat_template are additive and defaulted, which is why the schema version does not move: an artifact written before they existed loads with both null and is not a mismatch with anything. They exist because evaluate --precision had always told the operator it should match the run that trained the artifact, and until the artifact recorded it, nothing could check the claim — it was advice with no evidence behind it. ster vector evaluate and ster generate now compare both against the run reading the direction and warn on a difference, using the same helper the tune half uses on an adapter sidecar.

They are deliberately not metadata entries. metadata is where an operator's own notes go, and provenance the product wrote has to stay distinguishable from notes a person wrote. Of the two, chat_template is the sharper: precision moves where a direction points by a few ulps, while format changes what the residual stream contains, because a templated prompt is a user turn the assistant is about to answer and a raw one is a document being continued.

Lifecycle#

  • SteeringArtifact::new stamps schema 1 and product ster, and records the run's precision and chat_template.
  • save validates, creates parent directories, serializes compact JSON, and writes the file.
  • load reads, deserializes, and validates.
  • `ster vector inspect` is the model-free CLI for the same load-and-validate path, and then prints the summary — identity, precision, chat_template, metadata, and per layer layer, width, norm, train_accuracy, train_margin — rather than the vectors.
  • evaluate adds an exact artifact-model-string gate before scoring, and a warning, not a gate, when the recorded precision or chat_template differs from the run doing the reading.
  • generate adds model string, model width, and model layer-count gates before constructing an intervention.

Refusals#

Validation is fail-closed:

  • artifact schema <N> is unsupported; this Ster build reads schema 1
  • artifact belongs to product "<PRODUCT>", not Ster
  • artifact has no steering vectors
  • layer <L> has vector width <ACTUAL>, expected <HIDDEN_SIZE>
  • layer <L> contains a non-finite value

Handing the loader the other product's document is refused by name rather than by serde. A LoRA adapter sidecar offered to --vector used to fail as a missing field somewhere past column two hundred thousand; it now refuses as direction.json is a LoRA adapter sidecar, not a steering artifact: it carries rank and targets where a steering artifact carries trait_name and vectors, and the mirror refusal comes back from --adapter handed a steering artifact (runbook).

I/O adds failed to read steering artifact <PATH>, invalid steering artifact JSON in <PATH>, failed to create <PARENT>, and failed to write steering artifact <PATH>. Runtime mismatch sentences are in the runbook.

Schema 1 is versioned but Ster is pre-1.0: do not infer forward compatibility. Keep the original model revision and pair set beside a release artifact when reproducibility matters.