SwapAI

Training

Create one immutable candidate from one dataset revision without switching production traffic.

Request a bounded run

const result = await relevance.requestTraining();

if (result.status === "not_ready") {
  console.table(result.deficits);
  return;
}

console.log(result.trainingRunId, result.datasetRevisionId);

This is the only modern API operation that starts training. classify(), logClassification(), startup and deployment never start a trainer.

Before starting a provider, SwapAI freezes a dataset revision and records a durable training run. A retry cannot silently train different data under the same ID.

Runner contract

Local and remote providers use the same versioned job contract:

job manifest + training data

model artifact + metadata + hashes

The manifest identifies the classifier, generation, dataset revision, result contract, runner version and SHA-256 digest of every expected input file. SwapAI rejects a missing or changed expected file.

The runner returns a manifest that hashes the complete artifact. For numeric models this includes both the Needle model and its number-label sidecar. SwapAI verifies everything before evaluation.

Protected evaluation stays local

The provider receives only examples whose purpose is training. Validation, representative-test and coverage-test rows—and their hashes—stay in the controlling SwapAI process. All three protected purposes are evaluated locally only after the artifact has been verified.

If a candidate cannot classify a protected example, that prediction contributes an error of 1.0. Evaluation continues across the remaining protected examples, and the candidate is rejected with durable per-purpose and per-result-bin metrics. A bad model is therefore a measured rejected outcome; provider, runtime and storage faults remain failed runs.

Outcomes

requestTraining() returns one of:

  • not_ready with exact deficits; no provider was started;
  • candidate with immutable run and dataset revision IDs;
  • rejected when protected evaluation fails.
  • already_running when the same current dataset revision already has a live run;
  • already_promoted when that exact revision is already active;
  • already_failed when that exact revision and provider already produced a failed or rejected terminal run.

An aggregate protected-purpose shortage is reported with resultBin: null. requestTraining() returns not_ready with that exact deficit before checking or contacting the provider, so an empty protected set cannot spend money or create remote infrastructure.

A repeated request can also return the existing candidate instead of paying to train the same dataset revision again. Every terminal outcome is deduplicated.

An intentional paid retry must name the failed or rejected run:

const retry = await relevance.retryTraining(failedTrainingRunId);

retryTraining() returns a new candidate or rejected result. It accepts only a failed or rejected run for the same current dataset revision and provider, and refuses the retry until provider cleanup has been reconciled.

A candidate remains inactive until explicit promotion.

Concurrency

A durable lease prevents two processes from training the same classifier generation simultaneously. Run status survives a process restart. A provider-specific run ID is recorded as soon as remote infrastructure exists, allowing reconciliation to target the exact resource.