Skip to content
Draft
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
76be330
fix(tests): update 3 tests stale after intentional orchestrator/free …
claude Sep 1, 2026
a065431
ci: pin available Linux runner
seonghobae Sep 1, 2026
a32c736
ci: pin fuzz Linux runner
seonghobae Sep 1, 2026
62479a9
ci: pin security Linux runner
seonghobae Sep 1, 2026
f3ef3dc
test: preserve mixed spend evidence semantics
seonghobae Sep 1, 2026
25ec482
test: isolate spend source from optional judge dependency
seonghobae Sep 1, 2026
fd9aac5
fix: reject non-empty all-zero served_usage as reported spend evidence
claude Sep 1, 2026
3c8373b
test(accounting): isolate provider usage capture
seonghobae Sep 1, 2026
903aa4f
test(judge): distinguish provider zero usage provenance
seonghobae Sep 1, 2026
1f97228
test(judge): probe usage provenance aliases and TOCTOU
seonghobae Sep 1, 2026
934fdb0
chore: apply one-shot usage provenance repair
seonghobae Sep 1, 2026
9556fc8
ci(repair): move usage provenance one-shot off saturated Linux queue
seonghobae Sep 1, 2026
1fac323
fix(judge): preserve provider usage provenance
claude Sep 1, 2026
c4d46b7
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
8b2ff71
ci(repair): make usage provenance writer single-flight
seonghobae Sep 1, 2026
9447030
fix(judge): preserve provider usage provenance
github-actions[bot] Sep 1, 2026
39736e7
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
917ce40
test(judge): cover Responses zero usage fields
seonghobae Sep 1, 2026
238a880
ci(repair): apply usage counter family fix once
seonghobae Sep 1, 2026
9ab8c59
ci(repair): move usage counter writer to Linux
seonghobae Sep 1, 2026
4351a04
ci(temp): repair Responses usage alias accounting
seonghobae Sep 1, 2026
82cb7ed
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
589210a
fix(repair): make usage alias writer executable
seonghobae Sep 1, 2026
6eafe23
fix(judge): accept Responses usage counters in both accounting helpers
claude Sep 1, 2026
dfc04d8
ci(repair): remove superseded usage counter writer
seonghobae Sep 1, 2026
06e6369
ci: remove temporary usage repair workflow
seonghobae Sep 1, 2026
e53e92f
ci(temp): execute bounded Responses usage repair
seonghobae Sep 1, 2026
c1bf375
ci(repair): apply Responses usage alias fix with locked test env
seonghobae Sep 1, 2026
bd8f8f8
ci: remove failed one-shot usage repair workflow
seonghobae Sep 1, 2026
2f5f84e
ci: remove queued one-shot usage repair workflow
seonghobae Sep 1, 2026
d9ceca4
ci(repair): retry Responses alias repair with minimal writer
seonghobae Sep 1, 2026
bcc7d18
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
ebb087b
chore: remove now-fulfilled usage alias repair retry workflow
claude Sep 1, 2026
c499516
ci(repair): trigger Responses alias repair on PR events
seonghobae Sep 1, 2026
8f9fd87
Merge remote-tracking branch 'origin/fix/orchestrated-responses-strea…
claude Sep 1, 2026
2253866
test(batch): add exact-head worker usage fixture repair driver
seonghobae Sep 2, 2026
cbf5860
ci(test): run exact-head batch usage fixture repair
seonghobae Sep 2, 2026
22f665c
chore(test): mark current-main convergence intent
seonghobae Sep 2, 2026
44dcb0a
chore(test): add exact current-main merge helper
seonghobae Sep 2, 2026
c8bff9a
chore(test): stage non-destructive current-main merge
seonghobae Sep 2, 2026
338464a
merge current main into PR 1002 without rewriting history
seonghobae Sep 2, 2026
61384c5
test(batch): isolate provider usage fixture from optional judge
Sep 2, 2026
2f325e8
docs(tests): close CodeRabbit's diff-scoped docstring coverage gap
claude Sep 2, 2026
cef6214
Merge remote-tracking branch 'origin/main' into pr1002-work
claude Sep 2, 2026
02b61e4
Merge remote-tracking branch 'origin/main' into pr1002-work
claude Sep 3, 2026
65f5a03
fix(tests): wait for provider embedding batch completion before asser…
claude Sep 3, 2026
91ef087
fix: capture judge usage provenance atomically, immune to pool races
claude Sep 3, 2026
27b6ba5
Merge branch 'main' into fix/orchestrated-responses-stream-and-spend-…
opencode-agent[bot] Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ concurrency:
jobs:
pytest:
name: Full unit and contract suite
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand All @@ -39,7 +39,7 @@ jobs:

nim_benchmark_quality:
name: NIM benchmark coverage, docstrings, and package smoke
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
# Always-on, cross-platform property tests. Fast, deterministic, no native deps.
property_tests:
name: Hypothesis property tests
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand All @@ -45,7 +45,7 @@ jobs:
# so CI stays cheap; schedule/dispatch runs use a longer budget.
coverage_guided:
name: Atheris coverage-guided
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
codeql_analysis:
name: CodeQL analysis
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
actions: read
contents: read
Expand All @@ -49,7 +49,7 @@ jobs:

python_supply_chain:
name: Python supply chain
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/source-fix-1002-batch-usage-fixture.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Source fix PR1002 batch usage fixture

on:
push:
branches:
- fix/orchestrated-responses-stream-and-spend-analytics-20260901
paths:
- scripts/source_fix_1002_batch_usage_fixture.py
- .github/workflows/source-fix-1002-batch-usage-fixture.yml

permissions:
contents: write
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Outdated

jobs:
repair:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
ref: fix/orchestrated-responses-stream-and-spend-analytics-20260901
fetch-depth: 0
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
with:
python-version: '3.12'
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d
with:
version: '0.12.5'
- name: Apply exact fixture repair
run: python scripts/source_fix_1002_batch_usage_fixture.py
- name: Verify focused accounting contract
run: uv run --locked --extra api --extra db --extra queue --group dev python -m pytest -q tests/test_batch_optimizer.py tests/test_model_judge_usage_provenance_regression.py tests/test_provider_usage_capture.py tests/test_spend_analytics.py
- name: Remove one-shot artifacts and push
shell: bash
run: |
set -euo pipefail
rm -f scripts/source_fix_1002_batch_usage_fixture.py .github/workflows/source-fix-1002-batch-usage-fixture.yml
git config user.name 'CWL source-fix'
git config user.email 'actions@users.noreply.github.com'
git add tests/test_batch_optimizer.py scripts/source_fix_1002_batch_usage_fixture.py .github/workflows/source-fix-1002-batch-usage-fixture.yml
git diff --cached --check
git commit -m 'test(batch): isolate provider usage fixture from optional judge'
git fetch origin fix/orchestrated-responses-stream-and-spend-analytics-20260901
remote_head="$(git rev-parse origin/fix/orchestrated-responses-stream-and-spend-analytics-20260901)"
if [ "$remote_head" != "$(git rev-parse HEAD^)" ]; then
git merge --no-edit "$remote_head"
uv run --locked --extra api --extra db --extra queue --group dev python -m pytest -q tests/test_batch_optimizer.py tests/test_model_judge_usage_provenance_regression.py tests/test_provider_usage_capture.py tests/test_spend_analytics.py
fi
git push origin HEAD:fix/orchestrated-responses-stream-and-spend-analytics-20260901
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Outdated
104 changes: 80 additions & 24 deletions contextual_orchestrator/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ class _FastMLSIJudgeAdapter:
served_agent_id: str | None = None
served_model: str | None = None
served_usage: dict[str, Any] | None = None
served_usage_source: str | None = None
served_output: str | None = None
mode: str = "auto"
allowed_agent_ids: set[str] | None = None
Expand All @@ -381,6 +382,17 @@ def client(self) -> ModelClient:
"""Expose the existing gateway client capability to fast-mlsirm."""
return self.orchestrator.client

@staticmethod
def _usage_source_for_agent(agent: ModelAgent, usage: Any) -> str | None:
"""Classify transport-boundary usage without guessing from token counts."""
if not isinstance(usage, dict):
return None
return (
"synthetic_mock"
if agent.base_url.startswith("mock://")
else "provider_reported"
)

def complete(self, messages: list[ChatMessage], mode: str | None = None) -> dict[str, Any]:
"""Return one judge completion through the constrained adapter."""
if mode is not None and (type(mode) is not str or mode not in {"auto", "route", "conduct"}):
Expand All @@ -394,6 +406,17 @@ def complete(self, messages: list[ChatMessage], mode: str | None = None) -> dict
eligibility_role="verifier",
excluded_agent_ids=self.excluded_agent_ids,
)
# _invoke may fail over to a candidate outside this orchestrator's own
# pool (e.g. a test double standing in for the served agent);
# unresolvable provenance must fail closed to unknown (None, treated
# as unmeasured downstream) rather than raise and drop this
# otherwise-successful call's accounting entirely.
try:
served_agent = self.orchestrator._agent(served_id)
except KeyError:
self.served_usage_source = None
else:
self.served_usage_source = self._usage_source_for_agent(served_agent, usage)
Comment thread
seonghobae marked this conversation as resolved.
Outdated
return self._completion_payload(
output, served_id, served_model, usage, self.mode if mode is None else mode
)
Expand Down Expand Up @@ -434,8 +457,12 @@ def complete_structured(
# must survive validation failing on how to interpret its result.
self.served_agent_id = agent.id
self.served_model = agent.model
response_usage = response.get("usage")
self.served_usage = (
response.get("usage") if isinstance(response.get("usage"), dict) else None
dict(response_usage) if isinstance(response_usage, dict) else None
)
self.served_usage_source = self._usage_source_for_agent(
agent, self.served_usage
)
output = ModelClient._response_content(agent, response)
return self._completion_payload(
Expand All @@ -453,7 +480,8 @@ def _completion_payload(
"""Build the bounded adapter response shared by normal and structured calls."""
self.served_agent_id = served_id
self.served_model = served_model
self.served_usage = usage
usage_snapshot = dict(usage) if isinstance(usage, dict) else None
self.served_usage = usage_snapshot
self.served_output = output
trace = [
{
Expand All @@ -464,8 +492,8 @@ def _completion_payload(
"output": output,
}
]
if usage is not None:
trace[0]["usage"] = usage
if usage_snapshot is not None:
trace[0]["usage"] = dict(usage_snapshot)
Comment thread
seonghobae marked this conversation as resolved.
return {
"answer": output,
"mode": mode,
Expand Down Expand Up @@ -8165,18 +8193,14 @@ def _model_judge_verification(
"judge": "model",
}
verification.update(self._judge_adapter_accounting_fields(judge_adapter))
# The adapter's provider-boundary capture is authoritative for
# usage. fast-mlsirm aggregates a missing trace usage into a
# non-empty zero-token mapping, which must not turn an unmeasured
# call into provider-reported zero spend here.
result_usage_has_positive_evidence = isinstance(result.usage, Mapping) and any(
type(result.usage.get(key)) is int and result.usage[key] > 0
for key in ("prompt_tokens", "completion_tokens", "total_tokens")
)
if result.usage and (
judge_adapter.served_usage is not None or result_usage_has_positive_evidence
# Prefer the adapter's transport-boundary snapshot, including an
# authoritative all-zero provider report. Only fall back to a
# positive fast-mlsirm aggregate when no boundary usage survived.
if (
"judge_usage" not in verification
and self._usage_has_positive_evidence(result.usage)
):
verification["judge_usage"] = result.usage
verification["judge_usage"] = dict(result.usage)
verification["judge_orchestration_mode"] = result.orchestration_mode
# The provider call has already completed by this point (result
# is a real response, with judge_agent_id/judge_model/judge_usage
Expand Down Expand Up @@ -8243,6 +8267,35 @@ def _model_judge_verification(
**self._judge_adapter_accounting_fields(judge_adapter),
}

@staticmethod
def _usage_has_positive_evidence(usage: Any) -> bool:
"""Return whether Chat or Responses usage reports a positive token count.

This remains the compatibility rule for aggregate usage whose origin
is unknown. A provider-boundary zero measurement is handled separately
by ``_usage_is_reported_token_mapping`` plus explicit provenance.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"""
if not isinstance(usage, Mapping):
return False
counts = (
usage.get("prompt_tokens", usage.get("input_tokens")),
usage.get("completion_tokens", usage.get("output_tokens")),
usage.get("total_tokens"),
)
return any(type(value) is int and value > 0 for value in counts)

@staticmethod
def _usage_is_reported_token_mapping(usage: Any) -> bool:
"""Validate complete non-negative Chat or Responses token counters."""
if not isinstance(usage, Mapping):
return False
counts = (
usage.get("prompt_tokens", usage.get("input_tokens")),
usage.get("completion_tokens", usage.get("output_tokens")),
usage.get("total_tokens"),
)
return all(type(value) is int and value >= 0 for value in counts)

@staticmethod
def _judge_adapter_accounting_fields(
judge_adapter: "_FastMLSIJudgeAdapter | None",
Expand All @@ -8267,15 +8320,18 @@ def _judge_adapter_accounting_fields(
fields["judge_agent_id"] = judge_adapter.served_agent_id
if judge_adapter.served_model is not None:
fields["judge_model"] = judge_adapter.served_model
if judge_adapter.served_usage:
# A falsy served_usage (missing/invalid response usage) is left
# genuinely absent rather than fabricated as reported-zero
# (Devin review on #961, on this same fix): judge_agent_id/
# judge_model above already keep a completed-but-unmeasured call
# attributable, and downstream budget/spend consumers derive an
# honest estimated fallback from the judge's own served_output
# text instead of trusting a fabricated "reported" usage dict.
fields["judge_usage"] = judge_adapter.served_usage
if TaskOrchestrator._usage_has_positive_evidence(
judge_adapter.served_usage
) or (
judge_adapter.served_usage_source == "provider_reported"
and TaskOrchestrator._usage_is_reported_token_mapping(
judge_adapter.served_usage
)
):
# Positive aggregate usage remains backward-compatible. Exact
# provider-boundary zero usage is accepted only with explicit
# provenance; synthetic mock/fast-mlsirm zero remains unmeasured.
fields["judge_usage"] = dict(judge_adapter.served_usage)
if judge_adapter.served_output is not None:
# The judge's own generated text, not the verifier_output text
# it was judging (Devin review on #961, on this same fallback
Expand Down
22 changes: 22 additions & 0 deletions scripts/source_fix_1002_batch_usage_fixture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Repair the batch-worker usage fixture after transport-provenance hardening."""

from __future__ import annotations

from pathlib import Path


TARGET = Path("tests/test_batch_optimizer.py")
OLD = '''def test_batch_route_persists_runs_with_usage() -> None:\n client = _CountingClient()\n orchestrator = _orch(client)\n records = orchestrator.batch_route([t["prompt"] for t in TASKS])\n\n assert len(records) == 3\n'''
NEW = '''def test_batch_route_persists_runs_with_usage() -> None:\n client = _CountingClient()\n orchestrator = _orch(client)\n # This regression measures the worker Batch API usage contract only. The\n # full CI environment installs fast-mlsirm, whose optional model-judge call\n # is a separate spend source; allowing it into this fixture would make the\n # aggregate usage source correctly mixed/unavailable and stop testing the\n # worker provenance this case is named for.\n with patch.object(orchestrator_module, "_resolve_fast_mlsirm_components", return_value=None):\n records = orchestrator.batch_route([t["prompt"] for t in TASKS])\n\n assert len(records) == 3\n'''


def main() -> None:
text = TARGET.read_text(encoding="utf-8")
count = text.count(OLD)
if count != 1:
raise SystemExit(f"expected exactly one worker-usage fixture target, found {count}")
TARGET.write_text(text.replace(OLD, NEW), encoding="utf-8")
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Outdated


if __name__ == "__main__":
main()
65 changes: 64 additions & 1 deletion tests/test_model_judge.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,65 @@ def count_messages(self, messages: list[dict], model: str = "") -> int:
assert budget_contribution["model-x"] > 0


def test_judge_adapter_zero_aggregate_served_usage_is_not_treated_as_reported() -> None:
"""A non-empty-but-all-zero ``served_usage`` must stay genuinely absent.

Devin review on `contextual-orchestrator#1002`: unlike `result.usage`
(fast-mlsirm's own aggregate, already guarded), `_FastMLSIJudgeAdapter`'s
`served_usage` comes straight from `ModelClient`'s provider-boundary
capture -- for the `mock://` transport that is exactly
`{"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}`
(`ModelClient._mock_response`'s chat.completion branch), a non-empty
dict that is truthy in Python even though every count is 0. The plain
`if judge_adapter.served_usage:` check this function used to run
treated that as genuine reported-zero evidence, disagreeing with the
sibling `result.usage` guard a few lines above for the identical
fabricated shape. `_judge_adapter_accounting_fields` must reject it
exactly like `result.usage` already does.
"""
adapter = orchestrator_module._FastMLSIJudgeAdapter(
orchestrator=None, # type: ignore[arg-type]
text="task",
judge="model",
served_agent_id="general_agent",
served_model="model-x",
served_usage={"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0},
served_output="judge rationale text",
)

fields = TaskOrchestrator._judge_adapter_accounting_fields(adapter)

assert fields["judge_agent_id"] == "general_agent"
assert fields["judge_model"] == "model-x"
assert "judge_usage" not in fields
assert fields["judge_output_text"] == "judge rationale text"


def test_judge_adapter_positive_served_usage_is_still_reported() -> None:
"""A genuine positive token count in ``served_usage`` must still count.

The zero-aggregate guard above must not overcorrect into dropping real
provider-reported usage.
"""
adapter = orchestrator_module._FastMLSIJudgeAdapter(
orchestrator=None, # type: ignore[arg-type]
text="task",
judge="model",
served_agent_id="general_agent",
served_model="model-x",
served_usage={"prompt_tokens": 12, "completion_tokens": 34, "total_tokens": 46},
served_output="judge rationale text",
)

fields = TaskOrchestrator._judge_adapter_accounting_fields(adapter)

assert fields["judge_usage"] == {
"prompt_tokens": 12,
"completion_tokens": 34,
"total_tokens": 46,
}


def test_free_conduct_keeps_model_judge_inside_zero_cost_pool() -> None:
class _RecordingClient(_ScriptedClient):
def __init__(self) -> None:
Expand Down Expand Up @@ -504,7 +563,11 @@ def __init__(self, criterion_id: str, description: str, weight: float) -> None:
# candidate pool -- "backup_judge" is not a real pool member here.
assert result["judge_model"] == "backup-model"
assert result["judge_orchestration_mode"] == "route"
assert result["judge_usage"] == {"prompt_tokens": 4, "completion_tokens": 3, "total_tokens": 7}
# The adapter's own transport-boundary capture (_invoke's returned usage)
# is now preferred over fast-mlsirm's result.usage aggregate when both
# carry evidence, so this reflects served_usage exactly as _invoke
# returned it -- not backfilled from result.usage's fuller breakdown.
assert result["judge_usage"] == {"total_tokens": 7}
assert result["judge_criterion_scores"] == {"evidence_quality": 0.8, "risk_signal": 0.9}
assert result["judge_irt_item_type"] == "dichotomous"
assert result["judge_irt_row"] == [1, 1]
Expand Down
Loading
Loading