fix: measure local input after provider cleanup

This commit is contained in:
Ouroboros 2026-09-13 03:48:57 +03:00 • committed by Ouroboros
parent ea5f8ea7c8
commit c27340d07f
2 changed files with 50 additions and 2 deletions

View file

@ -267,8 +267,19 @@ class _LocalLaneMixin:
"""
from ouroboros.local_model import get_manager
target["local_input_measurement"] = get_manager().measure_prepared_input(payload)
return _finalized_physical_candidate(target, payload, "chat.completions")
manager = get_manager()
measure = getattr(manager, "measure_prepared_input", None)
# Bind the provider-clean physical payload before measuring. Host-only
# metadata must not affect the measured input or candidate hash.
candidate = _finalized_physical_candidate(target, payload, "chat.completions")
if callable(measure):
evidence = measure(candidate)
if isinstance(evidence, dict) and evidence.get("supported"):
target["local_input_measurement"] = evidence
# Rebuild from the original prepared source so the exact
# measured input and output cap are sealed together.
candidate = _finalized_physical_candidate(target, payload, "chat.completions")
return candidate
def _chat_local(
self, messages: List[Dict[str, Any]], tools: Optional[List[Dict[str, Any]]],

View file

@ -1,5 +1,6 @@
"""The owned server counts with its actual formatter and never invokes inference."""
import asyncio
import copy
import os
from types import SimpleNamespace
@ -40,6 +41,42 @@ def test_selected_formatter_tokenizer_and_serving_capacity_are_used(native_model
assert "actual rendered template" not in str(result)
def test_measurement_fingerprint_is_after_host_metadata_scrubbing(native_model):
payload = {"model": "local-model", "messages": [
{"role": "user", "content": "exact", "_context_capsule": "host-only"},
], "tools": []}
clean = {**payload, "messages": [{"role": "user", "content": "exact"}], "tools": []}
result = measure_chat_input(native_model, clean)
assert result["native_input_sha256"] == input_fingerprint(clean)
assert result["native_input_sha256"] != input_fingerprint(payload)
def test_finalize_measures_the_provider_clean_candidate_not_the_caller_payload(monkeypatch):
from ouroboros import llm_local
client = object.__new__(llm_local._LocalLaneMixin)
payload = {"model": "local-model", "messages": [
{"role": "user", "content": "exact", "_context_capsule": "host-only"},
], "max_tokens": 256}
clean = {"model": "local-model", "messages": [{"role": "user", "content": "exact"}], "max_tokens": 256}
seen = []
monkeypatch.setattr(llm_local, "_finalized_physical_candidate", lambda target, value, surface: clean)
monkeypatch.setattr("ouroboros.local_model.get_manager", lambda: SimpleNamespace(
measure_prepared_input=lambda value: seen.append(copy.deepcopy(value)) or {
"supported": True, "input_is_exact": True, "input_tokens": 8,
"context_window": 81920, "process_id": 1,
"native_input_sha256": input_fingerprint(value),
"output_limit_enforced": True,
"reasoning_included_in_limit": True,
"tokenizer_template_provenance": {"source": "fixture"},
}))
target = {"provider": "local", "resolved_model": "local-model", "usage_model": "local-model"}
assert client._finalize_local_candidate(target, payload) == clean
assert seen == [clean]
assert target["local_input_measurement"]["native_input_sha256"] == input_fingerprint(clean)
def test_unrecognized_handler_is_not_called_to_guess_its_behavior(native_model):
native_model.chat_handler = lambda **kwargs: pytest.fail("Opaque handler was invoked")
result = measure_chat_input(native_model, {"messages": []})