What boundary-creep invariants must survive a fine-tuned model's adjacent capability drift?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session uses a fine-tuned model (fine-tuned for a specific task) and observes that the fine-tuning has inadvertently affected the model's behavior on adjacent capabilities (e.g., general reasoning, refusal behavior, factual accuracy), and the session must detect this drift before it causes incidents outside the fine-tuning target. Does not apply to models fine-tuned with strict isolation guarantees (e.g., parameter-efficient fine-tuning with explicit capability boundaries).

Core Distinction

The separation between **target capability improvement** (the fine-tuned task works better) and **adjacent capability preservation** (capabilities outside the fine-tuning target remain unchanged). Relying on target improvement creates the **Fine-Tune Boundary Creep**: the fine-tuning improves the target task by 30%, but silently degrades adjacent capabilities (e.g., refusals become too permissive, factual accuracy drops on unrelated topics), causing incidents in workflows that use the model outside its original scope.

What Was Observed

In fine-tuned agent architectures, failing to detect adjacent drift produces three primary failure modes:

  1. **Refusal Regression:** A model fine-tuned for customer support becomes more permissive on safety-related refusals because the fine-tuning data was overly cooperative. Downstream workflows that rely on refusals break.
  2. **Factual Drift:** A model fine-tuned on a narrow domain loses factual accuracy on general knowledge because the fine-tuning data over-weighted the narrow domain. The successor inherits the degraded general knowledge as baseline.
  3. **Format Collapse:** A model fine-tuned for a specific output format (e.g., structured JSON) rigidly applies that format to adjacent tasks that expect free text, causing format mismatches in unrelated workflows.

Recorded Elements

  1. **`fine_tune_target_signature`:** The cryptographic proof of the fine-tuning target (task, dataset, evaluation metric), so the session knows what the fine-tuning was supposed to affect.
  2. **`adjacent_capability_baseline_receipts`:** Baseline measurements of the model's behavior on adjacent capabilities (general reasoning, refusals, factual accuracy, format flexibility) before fine-tuning, so drift can be measured.
  3. **`post_fine_tune_adjacent_measurement_receipt`:** The same measurements after fine-tuning, allowing direct comparison to detect adjacent capability drift.
  4. **`capability_boundary_enforcement_receipt`:** For models that support it, the cryptographic proof that the fine-tuning was constrained to preserve adjacent capabilities (e.g., parameter-efficient fine-tuning with frozen base layers).

Condition of Validity

* **Applies when:** The model is fine-tuned, adjacent capabilities matter for downstream workflows, and the fine-tuning can affect adjacent capabilities. * **Does not apply when:** The fine-tuned model is used only for its target capability and nothing else, or the model architecture enforces strict capability isolation.

Decision Boundary

  1. **Has the model been fine-tuned?** If no, standard model use applies. If yes, proceed.
  2. **Are `adjacent_capability_baseline_receipts` available?** If no, the session cannot measure adjacent drift. It must re-establish baselines (from the base model or an equivalent) before proceeding.
  3. **Does the `post_fine_tune_adjacent_measurement_receipt` show drift beyond the acceptable threshold?** If yes, the model has adjacent capability degradation. The session must restrict the model's use to its target capability or roll back.
  4. **Conversely, when can the session use a fine-tuned model without adjacent drift measurement?** Only when the model is used exclusively for its target capability (no adjacent use), or the fine-tuning mechanism provides cryptographic isolation guarantees.

Operational Effect

  1. **Adjacent Drift Detection:** Catches capability degradation outside the fine-tuning target.
  2. **Scope Restriction:** Enables the session to restrict the model's use to its verified scope.
  3. **Rollback Safety:** Provides the baseline needed to roll back to the base model if adjacent drift is unacceptable.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class DriftVerdict(Enum):
    NO_FINE_TUNE = auto()
    ADJACENT_CAPABILITIES_PRESERVED = auto()
    ADJACENT_DRIFT_DETECTED = auto()
    NO_BASELINE = auto()

@dataclass(frozen=True)
class CapabilityMeasurement:
    capability: str
    score: float

@dataclass(frozen=True)
class FineTuneState:
    is_fine_tuned: bool
    target_capability: str
    baseline_measurements: tuple[CapabilityMeasurement, ...]
    current_measurements: tuple[CapabilityMeasurement, ...]

@dataclass(frozen=True)
class FineTunePolicy:
    max_adjacent_drift_pct: float
    target_capability_priority: str

@dataclass(frozen=True)
class FineTuneManifest:
    verdict: DriftVerdict
    drift_details: tuple[tuple[str, float], ...]
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_fine_tune(
        cls, state: FineTuneState, policy: FineTunePolicy
    ) -> FineTuneManifest:
        
        # Gate 1: Not fine-tuned
        if not state.is_fine_tuned:
            digest = cls._hash(json.dumps({
                "fine_tuned": "FALSE"
            }, sort_keys=True))
            return FineTuneManifest(
                verdict=DriftVerdict.NO_FINE_TUNE,
                drift_details=tuple(),
                directive="PROCEED: Model not fine-tuned.",
                manifest_digest=digest
            )

        # Gate 2: Baseline presence
        if not state.baseline_measurements:
            return FineTuneManifest(
                verdict=DriftVerdict.NO_BASELINE,
                drift_details=tuple(),
                directive="HALT: No baseline measurements. Cannot measure adjacent drift.",
                manifest_digest=cls._hash("NO_BASELINE")
            )

        # Gate 3: Compare adjacent capabilities
        baseline_map = {m.capability: m.score for m in state.baseline_measurements}
        current_map = {m.capability: m.score for m in state.current_measurements}

        drift_details: list[tuple[str, float]] = []
        max_drift = 0.0

        for cap, baseline_score in baseline_map.items():
            if cap == state.target_capability:
                continue
            if cap not in current_map:
                continue
            if baseline_score == 0:
                continue
            drift = abs(current_map[cap] - baseline_score) / baseline_score
            drift_details.append((cap, drift))
            max_drift = max(max_drift, drift)

        # Gate 4: Drift threshold
        if max_drift > policy.max_adjacent_drift_pct:
            digest = cls._hash(json.dumps({
                "target": state.target_capability,
                "drift_details": tuple((c, f"{d:.4f}") for c, d in drift_details),
                "max_drift": f"{max_drift:.4f}",
                "threshold": f"{policy.max_adjacent_drift_pct:.4f}"
            }, sort_keys=True))
            return FineTuneManifest(
                verdict=DriftVerdict.ADJACENT_DRIFT_DETECTED,
                drift_details=tuple(drift_details),
                directive=f"HALT: Adjacent drift {max_drift:.2%} > {policy.max_adjacent_drift_pct:.2%}. Restrict model scope.",
                manifest_digest=digest
            )

        # Gate 5: Preserved
        digest = cls._hash(json.dumps({
            "target": state.target_capability,
            "max_drift": f"{max_drift:.4f}",
            "capabilities_checked": str(len(drift_details))
        }, sort_keys=True))
        
        return FineTuneManifest(
            verdict=DriftVerdict.ADJACENT_CAPABILITIES_PRESERVED,
            drift_details=tuple(drift_details),
            directive=f"PROCEED: Adjacent drift {max_drift:.2%} within {policy.max_adjacent_drift_pct:.2%}.",
            manifest_digest=digest
        )