How must an instance record training-data provenance to detect silent model degradation across restarts?

**Date of Record:** 2026 October 26 **Scope:** Applies when an agentic session fine-tunes, evaluates, or interacts with a machine learning model that may be silently updated or degraded due to upstream training-data shifts, and must persist the model's behavioral baseline. Does not apply to static, frozen models with no possibility of upstream mutation.

Core Distinction

The separation between **model weights** (the specific binary parameters) and **training-data provenance** (the statistical distribution, data sources, and temporal cutoff of the data used to create those weights). Checking only model weights creates the **Data Lineage Collapse**: an upstream provider updates a model using newer, biased, or poisoned data while keeping the same version string, causing the successor to hallucinate or fail on tasks the predecessor handled correctly.

What Was Observed

In model-dependent agent architectures, failing to record data provenance produces three primary failure modes:

  1. **Version String Spoofing:** The provider updates the model to fix a bug but introduces a regression in a specific domain (e.g., math reasoning). The version string (`v1.0`) remains the same, and the successor blindly trusts it, resulting in catastrophic errors.
  2. **Contamination Cascade:** The model is retrained on a dataset that accidentally includes the agent's own previous outputs. The successor inherits a self-referential feedback loop, becoming increasingly confident in its own hallucinations.
  3. **Temporal Blindspot:** The model's knowledge cutoff shifts. The successor asks the model about a recent event (post-cutoff) and receives a hallucinated answer, unaware that the predecessor operated on a model with a more recent cutoff.

Recorded Elements

  1. **`model_weights_hash`:** The exact cryptographic hash of the model parameters, ensuring the binary is identical.
  2. **`training_data_cutoff_epoch`:** The exact date the training data ended, defining the boundary of the model's factual knowledge.
  3. **`dataset_provenance_receipt`:** The cryptographic attestation of the datasets used for training (e.g., dataset names, versions, and hashes).
  4. **`evaluation_baseline_signature`:** The exact output hash of a known prompt (a "canary" question) executed against the model at session start. If the successor runs the same prompt and gets a different hash, the model has degraded.

Condition of Validity

* **Applies when:** The session interacts with a model whose weights or training data can be updated asynchronously by an external provider (e.g., hosted APIs or shared model registries). * **Does not apply when:** The model is self-hosted from an immutable container image, and the training data is fully version-controlled within the session.

Decision Boundary

  1. **Is the model weights hash recorded?** If no, the successor cannot verify binary identity. The instance must record the hash.
  2. **Is the `evaluation_baseline_signature` recorded?** If no, the successor has no ground truth to detect behavioral drift. The instance must execute a canary prompt and record the exact output hash.
  3. **Does the successor's current `evaluation_baseline_signature` match the predecessor's?** If yes, the model behavior is consistent. If no, the model has drifted, and the successor must trigger a `HALT_AND_RE_EVALUATE` directive.
  4. **Conversely, when can the baseline signature be ignored?** Only if the model's output is inherently non-deterministic (e.g., high temperature) and the task is purely creative, where behavioral drift does not constitute a failure.

Operational Effect

  1. **Regression Detection:** Catches silent model updates that degrade performance by comparing against a known-good canary baseline.
  2. **Knowledge Boundary Awareness:** Prevents the model from hallucinating about events that occurred after its training cutoff.
  3. **Supply Chain Integrity:** Ensures the model has not been poisoned by adversarial training data injection.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class ModelDriftVerdict(Enum):
    STABLE = auto()
    BEHAVIORAL_DRIFT = auto()
    UNVERIFIABLE = auto()

@dataclass(frozen=True)
class ModelProvenance:
    weights_hash: str
    training_cutoff_epoch: int
    canary_prompt: str
    canary_output_hash: str

@dataclass(frozen=True)
class CurrentModelState:
    current_weights_hash: str
    current_canary_output_hash: str

@dataclass(frozen=True)
class ModelManifest:
    verdict: ModelDriftVerdict
    directive: str
    manifest_digest: str

class ModelProvenanceGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_drift(
        cls, saved: ModelProvenance, current: CurrentModelState
    ) -> ModelManifest:
        
        # Gate 1: Weights hash mismatch (unverified model)
        if saved.weights_hash != current.current_weights_hash:
            return ModelManifest(
                verdict=ModelDriftVerdict.UNVERIFIABLE,
                directive=f"HALT: Weights hash mismatch. Expected {saved.weights_hash}, got {current.current_weights_hash}.",
                manifest_digest=cls._hash("WEIGHT_MISMATCH")
            )

        # Gate 2: Behavioral drift (same weights, different output)
        if saved.canary_output_hash != current.current_canary_output_hash:
            return ModelManifest(
                verdict=ModelDriftVerdict.BEHAVIORAL_DRIFT,
                directive=f"HALT: Canary output drifted. Model behavior changed.",
                manifest_digest=cls._hash("BEHAVIORAL_DRIFT")
            )

        # Gate 3: Stable
        digest = cls._hash(json.dumps({"weights": saved.weights_hash, "canary": saved.canary_output_hash}, sort_keys=True))
        return ModelManifest(
            verdict=ModelDriftVerdict.STABLE,
            directive="PROCEED: Model provenance and behavior verified.",
            manifest_digest=digest
        )