Skip to content

test(routing): lock HTTP/SSE echo of unchecked conduct - #683

Closed
cursor[bot] wants to merge 16 commits into
mainfrom
cursor/bc-0c62fe5c-1773-495d-b574-cdba241ae934-fe31
Closed

test(routing): lock HTTP/SSE echo of unchecked conduct#683
cursor[bot] wants to merge 16 commits into
mainfrom
cursor/bc-0c62fe5c-1773-495d-b574-cdba241ae934-fe31

Conversation

@cursor

@cursor cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown

Summary

Successor to #664. Keep omitted-verifier answer_status=unchecked, empty-verifier fail-closed rejected, and rejected-envelope gating. Close the buyer-visible hole #664 left green.

#664 at a448732 persisted unchecked from run() and locked rejected-verify HTTP/SSE framing. A later accepted|rejected allowlist on the buyer envelope could stay green while dropping the only field that distinguishes “served but not checked” from a verified accept.

This head:

  • Asserts complete(mode="conduct") on an omitted-verifier generated plan echoes orchestration.answer_status == unchecked on HTTP and the final SSE chunk.
  • Asserts the synthesizer text is still served (not the rejection envelope) and verification.accepted is not True on both surfaces.
  • Documents that persist, HTTP, and SSE echo unchecked.
  • Leaves issue [Product Gap] Provider-neutral role reasoning-effort profiles with equal-budget ablation #568 open for per-role reasoning_effort_profile and equal-budget ablation.

Do not merge #149 at e3f7588, #612 at 95393a0, #618 at aa188cb, #622 at 1ec6a76, #634 at 62cb671, or #664 at a448732. Prefer this successor. Independent non-author approval is still required.

Test plan

  • python3 tests/test_generated_workflow.py — omitted verifier is unchecked on conduct(), run(), and complete() HTTP/SSE; empty verifier step fails closed.
  • python3 tests/test_verify_mode_honesty.py — architecture names persist/HTTP/SSE unchecked; rejected verify persist and framing stay locked.
  • python3 tests/test_paper_contracts.py test_model_judge.py test_reasoning_effort_and_verify_mode.py test_streaming.py test_conventions.py test_api_contract.py test_self_check.py

Closes the leftover #664 honesty gap. Does not close #568.

Open in Web View Automation 

seonghobae and others added 16 commits August 13, 2026 10:08
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>
mode=verify still accepted password/looks good/not accepted via substring
terms, run() dropped reasoning_effort so HTTP never echoed it, and SSE
shipped raw verification. Invoice every trace step, including an empty
verifier plus a long worker. Conduct no longer serves the worker answer
on reject. Everyday validate/judge/확인/평가 stay on the single-worker
route. Per-role profiles remain issue #568.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
#618 still accepted "the password was accepted" as a verdict and served
the synthesizer after a rejected conduct run. Require first-line or
whole-report ACCEPT, echo answer_status on HTTP/SSE, and keep worker
or synthesizer text on the trace only.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
#634 still stamped answer_status=accepted when a generated plan
omitted a verifier, and treated an empty verifier step as omitted.
Serve the synthesizer only when no verifier step exists, fail-close
a present-but-empty verifier, and persist the status from complete().

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
#664 persisted omitted-verifier status and locked rejected-verify
framing, but a later accepted|rejected allowlist could drop
unchecked from the buyer envelope while those tests stayed green.
Assert complete() HTTP and SSE echo answer_status=unchecked and
still serve the synthesizer.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@seonghobae
seonghobae marked this pull request as ready for review August 16, 2026 17:05
@seonghobae
seonghobae self-requested a review as a code owner August 16, 2026 17:05
@seonghobae
seonghobae enabled auto-merge (squash) August 16, 2026 17:05
@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Author

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.

@seonghobae seonghobae closed this Aug 16, 2026
auto-merge was automatically disabled August 16, 2026 18:23

Pull request was closed

@seonghobae

Copy link
Copy Markdown
Contributor

Superseded by tip #691 (cumulative honesty substrate ≥ #689). Closing to free Full unit + Semgrep runners.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Product Gap] Provider-neutral role reasoning-effort profiles with equal-budget ablation

2 participants