fix(routing): word-bound verify verdicts and stream redaction - #622
fix(routing): word-bound verify verdicts and stream redaction#622cursor[bot] wants to merge 13 commits into
Conversation
Closes the test-time-compute-allocation gap between what Fugu, Conductor,
and TRINITY (docs/architecture.md, arXiv:2512.04695, arXiv:2512.04388) call
for and what main actually does: reasoning_effort was accepted at the HTTP
edge but silently dropped on the orchestrated route/conduct path, and there
was no way to get a single checked judgment without paying for the full
four-step conduct() workflow.
- ModelClient.chat/stream_chat forward reasoning_effort (OpenAI-compatible
minimal/low/medium/high) to the provider payload when set, omitted
otherwise -- unaffected for providers/callers that never opt in.
- reasoning_effort threads through the whole call chain (server body ->
CostRoutingCoordinator.complete -> TaskOrchestrator.run/complete/_dispatch
-> route_once/conduct/route_and_verify -> _invoke -> ModelClient.chat),
including the plan-generation and model-judge calls, and is folded into
the response cache key so a cached low-effort answer can't be served for
a high-effort request. Batch-channel requests intentionally drop it today
(BatchRequest has no such field) -- documented, not silently wrong.
- New mode="verify" (TaskOrchestrator.route_and_verify): one worker call
plus one checked verifier judgment, for adjudication-shaped requests
("does B follow from A?") that need a verified verdict without the
thinker/worker/verifier/synthesizer workflow's cost.
- _client_chat() call-site helper keeps every existing ModelClient-shaped
test double/subclass in this repo working unchanged when reasoning_effort
is unset (the default) -- no test double needed touching.
Tests: tests/test_paper_contracts.py (reasoning_effort reaches every
provider call in a conduct() run; omitted by default; verify mode's trace
shape and reasoning_effort propagation) and a new
tests/test_reasoning_effort_and_verify_mode.py (HTTP-level: verify mode,
invalid/valid reasoning_effort validation). Full suite: 307 passed.
Does not touch any of the ~20 other open PRs' surface (OpenAI-compat
headers, security/session hardening, pricing/routing) -- verified no
existing open PR claims reasoning_effort or a partial-conduct mode before
starting this.
…s diff This PR's Semgrep check failed on 5 findings, none introduced by this change (line numbers only shifted because earlier edits in this branch added lines above them): - cost_ledger.py:586,605,625 (sqlalchemy-execute-raw-query): already bandit-suppressed (# nosec B608) with the same rationale -- the interpolated pieces are a DB-API placeholder character and fixed internal column-name constants, never request data; actual values always go through the parameterized second argument. Semgrep doesn't read bandit's nosec syntax, so it re-flags what bandit already accepted. Added the matching # nosemgrep suppression alongside the existing nosec comment -- no SQL construction logic changed. - orchestrator.py (unverified-ssl-context, dynamic-urllib-use-detected): same pattern -- both already carry a bandit nosec with an accepted rationale (verify_tls=False is an explicit opt-in dev-only argument, not a default; the request URL is validated by _provider_url()/ _validate_provider() -- https-only, path-injection-safe, private/ loopback/link-local/reserved-IP-rejecting -- before urlopen is ever reached). Added the matching # nosemgrep suppression with the same rationale spelled out for the urllib case. Verified locally: 'semgrep --config auto --severity WARNING --severity ERROR --error' now reports 0 findings on both files (was 5). Full test suite still 307 passed (comment-only change, no behavior touched).
The later quality-cost staging scripts were collected by pytest because stage_quality_cost_policy_test.py matches *_test.py. Importing that module wrote tests/test_quality_cost_adaptive_default.py during collection, which then failed the Full unit suite. The apply workflow also used contents:write (Scorecard Token-Permissions) and regex-patched orchestrator.py into a U+0001 SyntaxError on red-green-verify. Keep the already-landed reasoning_effort + verify mode and adaptive route/verify/conduct dispatch. Ignore scripts/ during collection so helper modules cannot inject tests again. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
A scripts/*_test.py helper was collected as a test and wrote a failing file into tests/ during import. Keep collect_ignore covering scripts/ and fuzz/, and document why so the Full unit suite cannot pick up staging helpers again. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
mode=verify no longer fallback-accepts a neutral verifier report or returns a rejected worker answer as a normal completion. Auto verify hints drop ambiguous check/review/confirm tokens and match ASCII terms on word boundaries. The chat surface echoes routing_decision and applied-or-dropped reasoning_effort; batch 202 reports the drop. Architecture notes now say request-level only and leave issue #568 open. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
The ledger counted only the public completion text, so a two-call verify invoice looked like a single route. Sum worker and verifier outputs (and any multi-step trace) before recording usage. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
password, looks good, and negated accept no longer rubber-stamp a verifier report. Auto-mode drops leftover validate/judge/확인/평가 bills. run() echoes applied reasoning_effort so the HTTP path matches complete(). Stream chunks redact verification and echo routing knobs. The ledger prefers step usage tokens and does not collapse a two-step trace with one empty output back to the public envelope. Rejected conduct returns the same rejection envelope as verify. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
There was a problem hiding this comment.
Stale comment
Do not merge this PR. It is a parallel verify-honesty slice of the same residuals already landed on #618 (
aa188cb).#618 is the landing vehicle: first-line ACCEPT/REJECT,
require_explicit_verdicton conduct, reasoning-token invoicing, and the same SSE/HTTP effort echo. Review and merge #618. Close #612 and this PR after #618 lands.Do not start issue #568 on this branch. Do not open another overlapping honesty PR.
Sent by Cursor Automation: Fix Issues
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Do not merge this PR. Review and land #634 (62cb671) instead.
#622 at 1ec6a76 still bills a paying caller for a checked judgment and then rubber-stamps it. Runtime on this head:
The tests pass.,This is a confirmed fact in the sources., andI haven't accepted this.accept and serve the worker text.- A leading
ACCEPTorI accept this.false-rejects a good worker answer. - Neutral
conduct()returnsfallback acceptance from available planner and worker outputand serves the worker text. - Isolated
Verify this answer.selectsverify, butPlease verify the security of this change.andAnalyze and verify the plan.auto-selectconduct.
What this head does get right: password and I have not accepted this no longer accept; leftover auto validate / judge / 확인 / 평가 / 검토 stay route; run() echoes applied reasoning_effort; framed SSE redacts Bearer tokens in verification; the ledger prefers step completion_tokens and does not collapse an empty verifier step.
#634 is the successor on the #618 tip: first-line or whole-report ACCEPT/REJECT only, incidental body accepted fails closed, and rejected conduct uses the same public envelope as rejected verify.
Close #612, #618, and this PR after #634 lands. Do not start issue #568 on this branch — #631 already holds that draft. This automation cannot merge or self-approve. Independent non-author review of #634 is the next action.
Sent by Cursor Automation: Fix Issues
| conduct_hint_threshold: int = 2 | ||
| verifier_required: bool = True | ||
| verifier_positive_terms: tuple[str, ...] = ("verified", "accepted", "confirmed", "pass", "good", "ok") | ||
| verifier_positive_terms: tuple[str, ...] = ("verified", "accepted", "confirmed", "pass") |
There was a problem hiding this comment.
Whole-word pass and confirmed still accept. Runtime on this head: The tests pass. and This is a confirmed fact in the sources. both return accepted=True and serve worker says yes.
Do not patch this list here. #634 accepts only a first-line or whole-report ACCEPT/REJECT. Review that head.
| @@ -1421,17 +1652,21 @@ def last_output(role: str) -> str: | |||
| upstream = last_output("thinker") or outputs.get(steps[0].id, "") | |||
| verification = self._judge_verifier_output(last_output("verifier"), upstream, last_output("worker")) | |||
There was a problem hiding this comment.
conduct() still calls _judge_verifier_output without require_explicit_verdict=True. A silent verifier plus thinker+worker output returns fallback acceptance from available planner and worker output and serves the worker text as a normal completion.
#634 passes require_explicit_verdict=True on both generated and template conduct. Land that instead of adding a third honesty commit here.
| return False | ||
| if any("\uac00" <= character <= "\ud7a3" for character in term): | ||
| return True | ||
| negated = rf"(?<![\w])(?:not|never|cannot|can't|don't|do not)\s+{re.escape(term)}(?![\w])" |
There was a problem hiding this comment.
| @@ -1599,10 +1902,29 @@ def _needs_workflow(self, text: str) -> bool: | |||
| hits = sum(1 for hint in self.COMPLEX_HINTS if hint in lowered) | |||
There was a problem hiding this comment.
COMPLEX_HINTS still treats verify and 검증 as raw substrings, and _needs_workflow wins before _needs_verification. Runtime: Please verify the security of this change. and Analyze and verify the plan. auto-bill the four-step workflow.
A paying caller who said verify should get bounded verify, not a surprise conduct invoice. Fix that on the #634 tip if it is still open there; do not open a fifth overlapping honesty PR.
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head1ec6a765ee00c88effef8c3819e5fc78b7210bda. -
Head SHA:
1ec6a765ee00c88effef8c3819e5fc78b7210bda -
Workflow run: 32138297903
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (7 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (7 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Docs: architecture.md"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs: architecture.md"]
R2 --> V2["docs review"]
Evidence --> S3["Test (6 files)"]
S3 --> I3["regression suite"]
I3 --> R3["Review risk: Test (6 files)"]
R3 --> V3["targeted test run"]
OpenCode Review Overview
Pull request overviewOpenCode cannot approve yet because required coverage evidence did not pass. Review outcome1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
Coverage evidenceCoverage evidence job did not run or did not publish coverage evidence. Changed-File Evidence Mapflowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (7 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (7 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Docs: architecture.md"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs: architecture.md"]
R2 --> V2["docs review"]
Evidence --> S3["Test (6 files)"]
S3 --> I3["regression suite"]
I3 --> R3["Review risk: Test (6 files)"]
R3 --> V3["targeted test run"]
|
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head1ec6a765ee00c88effef8c3819e5fc78b7210bda. -
Head SHA:
1ec6a765ee00c88effef8c3819e5fc78b7210bda -
Workflow run: 32148157069
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (7 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (7 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Docs: architecture.md"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs: architecture.md"]
R2 --> V2["docs review"]
Evidence --> S3["Test (6 files)"]
S3 --> I3["regression suite"]
I3 --> R3["Review risk: Test (6 files)"]
R3 --> V3["targeted test run"]


Landing vehicle for verify-mode honesty. Supersedes #612 (
95393a0) with the residual fail-close defects that still billed or rubber-stamped a paying caller.What to do next
Review this PR instead of #612. Do not merge #612. After this lands, the next buyer-facing gap is issue #568 (per-role
reasoning_effortprofiles and equal-budget ablation).Buyer-visible fixes on top of #612
password,looks good, andI have not accepted thisno longer accept a worker answer.validate/judge/확인/평가/검토. Explicitverify/adjudicate/검증/심사still select verify.TaskOrchestrator.run()(the HTTP/coordinator path) echoes appliedreasoning_effort.chat.completion.chunkframes redact verification and echo routing/effort the same way as the sync completion.step["usage"].completion_tokensand does not collapse a two-step trace with one empty output back to the public envelope.conduct()returns the same rejection envelope as verify. Worker text stays on the trusted trace.ACCEPT/REJECTtoken, soI DO NOT ACCEPTcannot override a reject.Evidence
python3 tests/test_verify_mode_honesty.py— pass, including the new residual cases.python3 tests/test_model_judge.py— pass after the conduct-reject envelope change.Grounding
Nielsen, S., Cetin, E., Schwendeman, P., Sun, Q., Xu, J., & Tang, Y. (2025). Learning to orchestrate agents in natural language with the Conductor. arXiv. https://arxiv.org/abs/2512.04388
Xu, J., Sun, Q., Schwendeman, P., Nielsen, S., Cetin, E., & Tang, Y. (2025). Trinity: An evolved LLM coordinator. arXiv. https://arxiv.org/abs/2512.04695
Sakana AI. (2026). Fugu technical report. https://github.com/SakanaAI/fugu/blob/main/Fugu_technical_report.pdf
Issue #568 remains open. This PR does not claim per-role allocation.