Skip to content

fix(api): casefold message roles and tool/function types over HTTP - #716

Closed
seonghobae wants to merge 44 commits into
mainfrom
feat/tool-type-role-casefold-http-honesty-20260817110052
Closed

fix(api): casefold message roles and tool/function types over HTTP#716
seonghobae wants to merge 44 commits into
mainfrom
feat/tool-type-role-casefold-http-honesty-20260817110052

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

  • Strip + casefold chat message roles (User / ASSISTANTuser / assistant); developer / function still fail closed after casefold with migration errors.
  • Strip + casefold tools[].type, tool_choice.type, and assistant tool_calls[].type to function for form/JS SDK parity.
  • HTTP honesty tests on chat + responses; tip substrate ≥ fix(api): coerce message weight digits and tool strict/prefix bool forms #715 (message weight digit coerce + tool strict/prefix bool coerce).

Test plan

  • python -m pytest tests -q → 1192 passed locally
  • CI Full unit + Semgrep product gates
  • Independent non-author APPROVE (seonghobae cannot self-approve); auto-merge squash armed

seonghobae and others added 30 commits August 16, 2026 21:18
…closed otherwise

Chat history: message-level audio and legacy function_call are null/empty omit
no-ops; non-empty fail closed with named errors (including tools passthrough).
Tip substrate from #577 assistant refusal/annotations honesty. Local full unit:
940 passed.
…ed otherwise

OpenAI fine-tune style message weight is not applied on this gateway.
Accept null/0/1 as honest no-ops; reject other types and values with
invalid_message_weight. Tip substrate from #578. Local full unit: 943 passed.
…ion role

Reject unsupported message keys with named unknown_message_fields (not silent
strip or tools-passthrough smuggle). Reject legacy function role with
invalid_message_role migration to tool. Tip substrate from #579. Local full
unit: 947 passed.
OpenAI partial-assistant prefix flag is not applied on this gateway.
null/false are honest no-ops; true and non-booleans fail closed with
invalid_message_prefix. Tip substrate from #580. Local full unit: 950 passed.
…therwise

Named invalid_max_tool_calls on /v1/chat/completions instead of opaque
unknown_fields. Aligns with Responses max_tool_calls honesty; gateway has
no multi-step tool loop.
…losed otherwise

Legacy /v1/completions treated max_tool_calls as unknown_fields. Accept the
key for named invalid_max_tool_calls (null/empty/whitespace omit-equivalent),
matching chat/Responses honesty so SDKs get a clear migration path.
SDK clients often send include_usage/include_obfuscation as JSON null.
Drop null flag values before validation so null (and null+false mixes)
match omit / all-false no-ops on chat, Completions, and Responses.
True flags remain fail-closed with invalid_stream_options.
…or Responses parallel true

SDK optional defaults often send function.strict and json_schema.strict as
null — treat as omit rather than type errors. Align Responses
parallel_tool_calls=true with chat by requiring a non-empty tools array.
SDK optional defaults often send description and parameters as JSON null.
Treat null as omit rather than type errors; non-null non-string/object
values remain fail-closed with invalid_tools.
OpenAI-style tool descriptions are at most 1024 characters. Over-long
descriptions fail closed with named invalid_tools so SDKs never believe a
truncated description was accepted.
SDK optional participant name blanks ("" / whitespace) are omit-equivalent
like JSON null. Non-string, over-long, and invalid charset names remain
fail-closed with invalid_message_name.
SDK optional defaults serialize omitted tool.function description/parameters/strict
as JSON null. Accepting those keys without popping them is not omit-equivalent:
proxy_completion forwards the body and several providers reject null parameters.
Pop in place so passthrough matches omit; keep non-null wrong types on invalid_tools.
Also pop response_format.json_schema.strict null. Tip substrate from #614.
Local full unit: 989 passed.
Null flag values on allowed keys (include_usage / include_obfuscation) stay
omit-equivalent. Dropping nulls before the allow-list made {unknown: null}
look empty and silently omit — dishonest for buyers. Fail closed with
invalid_stream_options on chat, Completions, and Responses. Tip substrate
from #638. Local full unit: 996 passed.
…ix/mode/metadata)

Parallel tip #653 lacked later omit seams. Restore top_logprobs empty-string
omit, tool_calls arguments null→empty string, Responses instructions
blank omit, Completions whitespace suffix omit, mode strip, and metadata
null value key-omit. Fail-closed paths for nonzero/non-string remain.
#668 restored accept-path 200s but left omit-equivalent keys on the
proxied body. Write back empty tool_calls arguments, pop blank
Responses instructions, persist cleaned metadata, and hoist chat
logprobs/top_logprobs before tools passthrough so providers see the
omit-equivalent payload.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
str.isalnum() accepted Unicode letters and digits (café, 名前,
Arabic-Indic digits), so the documented [a-zA-Z0-9_-]{1,64} check still
forwarded illegal names and buyers saw an opaque provider 400.

Require name.isascii() on tool.function.name, tool_calls function.name,
message name, and response_format.json_schema.name (plus 64-char cap on
json_schema.name). HTTP honesty locks Unicode reject and legal keep on
chat and Responses. Request-body fuzz exercises both validators.

Re-lands parallel tip #685/#669 seams onto the highest #686 substrate.
The gateway rejected all non-empty text as invalid_text, so official SDK
defaults (text.format.type=text) and structured json_object/json_schema
never reached the provider. Accept the official plane, pop null/blank
optionals, fail-closed on verbosity and dual-plane text+response_format,
and require ASCII [a-zA-Z0-9_-]{1,64} on flat json_schema names.

Mock echo includes text so HTTP honesty locks forward shape. Re-lands
parallel tip #681 onto the #687 substrate.
OpenAI SDKs send truncation auto/disabled; this gateway has no multi-turn
conversation window to truncate, so those values are omit-equivalent.
Unknown truncation strings remain fail-closed with invalid_truncation.
Also align conversation-controls tests with official text.format text.
Pop null/blank description and null strict inside response_format.json_schema
before passthrough, and fail closed on unknown nested keys — parity with
Responses text.format structured-output honesty.
Fail closed when tool_choice=required is sent without a non-empty tools
array (chat + Responses), matching parallel_tool_calls=true honesty so
clients cannot mandate tool use with no tools declared.
Reject blank metadata keys on chat/Responses so cost and observability
surfaces never index empty labels; non-empty keys keep the existing
16-entry and length contracts.
…nals

SDK clients send service_tier as " AUTO " and routing optionals as null.
Casefold after strip so auto/default match; treat routing channel/priority
empty and latency_tolerant null as omit. flex/priority and non-boolean
latency_tolerant remain fail-closed.
…seed

JS SDKs often send 0/1 for booleans and integer seeds as strings. Accept
int 0/1 (not True/False via int subclass) for store, stream, and
parallel_tool_calls; parse digit strings for seed (Responses passthrough;
Completions still fail-closed after type check as unsupported).
Assistants-style tool_resources must not surface as opaque unknown_fields.
Accept the key for named invalid_tool_resources; JSON null and empty object
are treat-as-omit on chat, Completions, and Responses.
Coerce digit-string n and best_of (write back int) on Completions/chat/
Responses. Accept JS int 0/1 for echo, background, and logprobs via the
shared optional-bool helper; digit-string top_logprobs "0" is omit.
Tip-substrate from #697; local unit: 1091 passed.
Form/query JS SDKs send store/stream/parallel as \"true\"/\"false\" and
sampling knobs as digit strings. Extend optional bool coerce for those
strings and int/float digit-string coerce for max_tokens and sampling
penalties/temperature/top_p. Non-numeric strings remain fail-closed.
…ws omit

JS JSON often serializes integers as 1.0. Coerce whole-number floats (and
digit strings for Responses max_output_tokens) on n/best_of/seed/max_* paths.
Treat chat stop whitespace as omit-equivalent like empty string.
Tip substrate from #703. Local full unit: 1111 passed.
…probs 0 omit

Accept FLOAT/Float as float on embeddings; coerce Responses stream false/"0"
like chat; treat Completions logprobs 0/false string forms as omit no-ops.
Tip substrate from #704. Local full unit: 1117 passed.
SDK clients send padded/uppercase tool_choice and function_call control
strings. Strip and casefold so none/auto remain omit-equivalent without
tools and required matches with tools; non-control values stay fail-closed.
Buyer SDKs and form clients send padded/uppercase enum strings. Treat
reasoning_effort none (chat/completions), response_format.type and
text.format.type (text/json_object/json_schema), and modalities ["text"]
as case-insensitive omit-equivalent or accepted controls; write back
lowercased types/modalities. Fail-closed for non-none effort and non-text
modalities remains.
…ttribution values

SDK form/query clients send "true"/"false"/0/1 for include_orchestration_trace;
route them through _coerce_optional_bool (parity with stream/store). Known
attribution dimensions with null or blank values omit rather than stringify.
…ings

SDK form/query clients send "true"/"false"/0/1 for routing.latency_tolerant
and stream_options flags; route them through _coerce_optional_bool. Empty
response_format.type alone omits. Responses top_logprobs accepts digit strings
when logprobs is true.
…ons digits

SDK clients send ROUTE/CONDUCT/AUTO and padded aliases; normalize via
strip+casefold. Embeddings dimensions digit strings type-check then still
fail closed as unsupported (not applied).
…ons digits

Strip+lower orchestration mode aliases so SDK-padded ROUTE/Conduct match.
Coerce embeddings dimensions digit strings and whole floats before the
existing fail-closed unsupported reject (type-honest invalid path).
SDK clients send 0/"0" when no tool rounds are requested; treat as omit
(parity with top_logprobs 0). Nonzero values still fail closed as
unsupported; bool is not an integer count.
Accept "1.0"/"0.0" in _coerce_optional_int so JS form encodings match
native 1.0 floats. top_logprobs and max_tool_calls zero omit use digit
coerce then nonzero reject (parity with tip #711). HTTP honesty coverage
for n/best_of/seed/top_logprobs/max_tool_calls float strings.

Local unit: 1161 passed.
…, dim 0

Responses reasoning with effort=none (casefold) is an honest no-op. Empty
text.format.type alone omits. Completions logprobs whole-float zero strings
omit. Embeddings dimensions 0 is omit-equivalent (not applied).
Accept float 0.0/1.0 and whole-float strings ("0.0"/"1.0") in
_coerce_optional_bool so stream/store/parallel_tool_calls/logprobs/echo
and related controls match int 0/1 and "0"/"1" honesty. Non-whole floats
remain fail-closed.
SDK form/JS clients send weight as "0"/"1"/"0.0" and strict/prefix as
0/1/0.0/"true"/"false". Coerce via shared helpers; prefix=true still
fail-closed (unsupported).
Form/JS SDKs send User/Function with incidental whitespace. Strip+casefold
message roles and tools/tool_choice/tool_calls type to function; developer
and function roles still fail closed after casefold with migration errors.
@seonghobae
seonghobae enabled auto-merge (squash) August 17, 2026 02:21
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

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.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 183 files, which is 83 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e2c5e481-93af-4f3d-a29c-88d4c196232b

📥 Commits

Reviewing files that changed from the base of the PR and between 6841b71 and d93b8c9.

📒 Files selected for processing (183)
  • conductor/tracks.md
  • contextual_orchestrator/cost_ledger.py
  • contextual_orchestrator/orchestrator.py
  • contextual_orchestrator/server.py
  • docs/architecture.md
  • evidence/cycle_bool_whole_float_zero_one_coerce.txt
  • evidence/cycle_iot_bool_coerce_attr_omit.txt
  • evidence/cycle_max_tool_calls_zero_omit.txt
  • evidence/cycle_mode_casefold_dimensions_coerce.txt
  • evidence/cycle_mode_casefold_embeddings_dimensions_coerce.txt
  • evidence/cycle_reasoning_none_text_logprobs_dim_omit.txt
  • evidence/cycle_routing_latency_stream_options_bool_coerce.txt
  • evidence/cycle_tool_type_role_casefold.txt
  • evidence/cycle_weight_strict_prefix_bool_coerce.txt
  • evidence/cycle_whole_float_string_int_coerce.txt
  • fuzz/targets.py
  • tests/test_analytics_runtime.py
  • tests/test_assistant_refusal_annotations_http_honesty.py
  • tests/test_assistant_tool_calls_null_noop_http_honesty.py
  • tests/test_audio_websearch_reasoning_null_noop_http_honesty.py
  • tests/test_background_reasoning_reject_http_honesty.py
  • tests/test_batch_embeddings.py
  • tests/test_batch_embeddings_encoding_dimensions_http_honesty.py
  • tests/test_batch_embeddings_endpoint_http_honesty.py
  • tests/test_batch_embeddings_routing_http_honesty.py
  • tests/test_batch_embeddings_user_http_honesty.py
  • tests/test_bool_01_seed_str_http_honesty.py
  • tests/test_bool_whole_float_zero_one_coerce_http_honesty.py
  • tests/test_budget_enforcement.py
  • tests/test_chat_assistant_tool_calls_http_honesty.py
  • tests/test_chat_attribution_routing_http_honesty.py
  • tests/test_chat_audio_web_search_reject_http_honesty.py
  • tests/test_chat_developer_multimodal_content_http_honesty.py
  • tests/test_chat_empty_user_system_content_http_honesty.py
  • tests/test_chat_include_orchestration_trace_http_honesty.py
  • tests/test_chat_include_reject_http_honesty.py
  • tests/test_chat_logit_bias_http_honesty.py
  • tests/test_chat_max_completion_tokens_http_honesty.py
  • tests/test_chat_max_tool_calls_http_honesty.py
  • tests/test_chat_message_name_http_honesty.py
  • tests/test_chat_modalities_http_honesty.py
  • tests/test_chat_n_gt1_http_honesty.py
  • tests/test_chat_openai_metadata_http_honesty.py
  • tests/test_chat_orchestration_mode_http_honesty.py
  • tests/test_chat_parallel_tool_calls_http_honesty.py
  • tests/test_chat_penalties_http_honesty.py
  • tests/test_chat_prediction_http_honesty.py
  • tests/test_chat_reasoning_effort_http_honesty.py
  • tests/test_chat_reasoning_object_reject_http_honesty.py
  • tests/test_chat_response_format_http_honesty.py
  • tests/test_chat_response_format_json_schema_omit_real_http_honesty.py
  • tests/test_chat_service_tier_http_honesty.py
  • tests/test_chat_store_http_honesty.py
  • tests/test_chat_stream_options_http_honesty.py
  • tests/test_chat_temperature_top_p_http_honesty.py
  • tests/test_chat_tool_call_id_http_honesty.py
  • tests/test_chat_tool_choice_functions_http_honesty.py
  • tests/test_chat_tools_shape_http_honesty.py
  • tests/test_chat_top_logprobs_http_honesty.py
  • tests/test_chat_unknown_fields_http_honesty.py
  • tests/test_commercial_readiness.py
  • tests/test_completions_chat_era_fields_reject_http_honesty.py
  • tests/test_completions_empty_tools_noop_http_honesty.py
  • tests/test_completions_include_reject_http_honesty.py
  • tests/test_completions_legacy_knobs_http_honesty.py
  • tests/test_completions_max_completion_tokens_http_honesty.py
  • tests/test_completions_max_tokens_http_honesty.py
  • tests/test_completions_max_tool_calls_http_honesty.py
  • tests/test_completions_metadata_service_tier_http_honesty.py
  • tests/test_completions_prompt_shape_http_honesty.py
  • tests/test_completions_response_format_audio_null_http_honesty.py
  • tests/test_completions_response_format_reject_http_honesty.py
  • tests/test_completions_sampling_knobs_http_honesty.py
  • tests/test_completions_seed_http_honesty.py
  • tests/test_completions_stop_http_honesty.py
  • tests/test_completions_store_http_honesty.py
  • tests/test_completions_stream_options_http_honesty.py
  • tests/test_completions_stream_reject_http_honesty.py
  • tests/test_completions_tool_choice_function_call_noop_http_honesty.py
  • tests/test_completions_tools_noop_extensions_http_honesty.py
  • tests/test_completions_tools_reject_http_honesty.py
  • tests/test_completions_top_logprobs_reject_http_honesty.py
  • tests/test_cost_review_server.py
  • tests/test_digit_n_bool01_echo_logprobs_http_honesty.py
  • tests/test_embeddings_blank_input_http_honesty.py
  • tests/test_embeddings_encoding_format_http_honesty.py
  • tests/test_embeddings_metadata_http_honesty.py
  • tests/test_embeddings_model_pool_http_honesty.py
  • tests/test_embeddings_null_optional_noop_http_honesty.py
  • tests/test_embeddings_routing_http_honesty.py
  • tests/test_embeddings_user_field_http_honesty.py
  • tests/test_empty_modalities_prediction_noop_http_honesty.py
  • tests/test_empty_stop_array_noop_http_honesty.py
  • tests/test_empty_stream_options_include_noop_http_honesty.py
  • tests/test_empty_string_controls_noop_http_honesty.py
  • tests/test_empty_string_encoding_tool_choice_endpoint_noop_http_honesty.py
  • tests/test_empty_string_numeric_controls_noop_http_honesty.py
  • tests/test_empty_string_reasoning_text_include_noop_http_honesty.py
  • tests/test_empty_string_stop_noop_http_honesty.py
  • tests/test_empty_tools_array_http_honesty.py
  • tests/test_encoding_stream_logprobs_http_honesty.py
  • tests/test_function_call_reasoning_empty_noop_http_honesty.py
  • tests/test_functions_null_max_tool_calls_null_http_honesty.py
  • tests/test_include_orchestration_trace_bool_coerce_http_honesty.py
  • tests/test_include_orchestration_trace_null_noop_http_honesty.py
  • tests/test_int_float_max_output_stop_ws_http_honesty.py
  • tests/test_json_schema_name_charset_http_honesty.py
  • tests/test_ledger_execution_identity_http_honesty.py
  • tests/test_max_tool_calls_zero_omit_http_honesty.py
  • tests/test_message_audio_function_call_http_honesty.py
  • tests/test_message_name_empty_omit_http_honesty.py
  • tests/test_message_name_null_noop_http_honesty.py
  • tests/test_message_prefix_http_honesty.py
  • tests/test_message_unknown_fields_http_honesty.py
  • tests/test_message_weight_http_honesty.py
  • tests/test_metadata_key_nonempty_http_honesty.py
  • tests/test_mode_casefold_http_honesty.py
  • tests/test_multimodal_content_parts_shape_http_honesty.py
  • tests/test_multimodal_message_content_http_honesty.py
  • tests/test_openai_models_listing_http.py
  • tests/test_openai_passthrough.py
  • tests/test_openai_sdk_control_fields_reject_http_honesty.py
  • tests/test_openai_user_field_http_honesty.py
  • tests/test_prediction_modalities_model_strip_http_honesty.py
  • tests/test_prompt_cache_retention_reject_http_honesty.py
  • tests/test_reasoning_effort_none_store_stream_empty_noop_http_honesty.py
  • tests/test_reasoning_format_modalities_casefold_http_honesty.py
  • tests/test_reasoning_none_text_empty_logprobs_zero_http_honesty.py
  • tests/test_responses_attribution_routing_http_honesty.py
  • tests/test_responses_conversation_controls_http_honesty.py
  • tests/test_responses_instructions_reasoning_http_honesty.py
  • tests/test_responses_logit_bias_logprobs_http_honesty.py
  • tests/test_responses_max_output_tokens_http_honesty.py
  • tests/test_responses_max_tokens_http_honesty.py
  • tests/test_responses_max_tool_calls_reject_http_honesty.py
  • tests/test_responses_metadata_http_honesty.py
  • tests/test_responses_modalities_prediction_http_honesty.py
  • tests/test_responses_model_required_http_honesty.py
  • tests/test_responses_n_http_honesty.py
  • tests/test_responses_parallel_tool_calls_http_honesty.py
  • tests/test_responses_penalties_http_honesty.py
  • tests/test_responses_response_format_http_honesty.py
  • tests/test_responses_seed_stop_http_honesty.py
  • tests/test_responses_service_tier_http_honesty.py
  • tests/test_responses_store_http_honesty.py
  • tests/test_responses_stream_options_http_honesty.py
  • tests/test_responses_stream_reject_http_honesty.py
  • tests/test_responses_temperature_top_p_http_honesty.py
  • tests/test_responses_text_format_http_honesty.py
  • tests/test_responses_tools_shape_http_honesty.py
  • tests/test_responses_user_field_http_honesty.py
  • tests/test_routing_latency_stream_options_bool_coerce_http_honesty.py
  • tests/test_sales_readiness.py
  • tests/test_sdk_null_legacy_controls_noop_http_honesty.py
  • tests/test_sdk_null_object_optional_noop_http_honesty.py
  • tests/test_sdk_null_optional_noop_http_honesty.py
  • tests/test_security_hardening.py
  • tests/test_service_tier_encoding_format_strip_http_honesty.py
  • tests/test_service_tier_routing_null_omit_http_honesty.py
  • tests/test_stream_null_noop_http_honesty.py
  • tests/test_stream_options_false_tool_choice_empty_noop_http_honesty.py
  • tests/test_stream_options_null_flags_noop_http_honesty.py
  • tests/test_stream_options_unknown_null_reject_http_honesty.py
  • tests/test_streaming.py
  • tests/test_string_bool_numeric_coerce_http_honesty.py
  • tests/test_tip_reland_sdk_omit_http_honesty.py
  • tests/test_tip_reland_sdk_omit_persist_http_honesty.py
  • tests/test_tool_choice_auto_without_tools_noop_http_honesty.py
  • tests/test_tool_choice_function_call_casefold_http_honesty.py
  • tests/test_tool_choice_required_requires_tools_http_honesty.py
  • tests/test_tool_choice_strip_modalities_text_noop_http_honesty.py
  • tests/test_tool_description_length_http_honesty.py
  • tests/test_tool_description_parameters_null_noop_http_honesty.py
  • tests/test_tool_function_name_charset_http_honesty.py
  • tests/test_tool_function_null_fields_pop_http_honesty.py
  • tests/test_tool_resources_named_reject_http_honesty.py
  • tests/test_tool_strict_null_noop_http_honesty.py
  • tests/test_tool_type_role_casefold_http_honesty.py
  • tests/test_top_logprobs_zero_omit_noop_http_honesty.py
  • tests/test_true_streaming.py
  • tests/test_user_null_omit_noop_http_honesty.py
  • tests/test_weight_strict_bool_coerce_http_honesty.py
  • tests/test_whole_float_string_int_coerce_http_honesty.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before 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 head d93b8c9f37025c7c7b66696b155e6508ce9cd0d0.

  • Head SHA: d93b8c9f37025c7c7b66696b155e6508ce9cd0d0

  • Workflow run: 32166986448

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  Evidence["OpenCode evidence"] --> Review["Current PR review path"]
  Review --> Verify["Required checks"]
Loading

@opencode-agent

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: d93b8c9f37025c7c7b66696b155e6508ce9cd0d0
  • Workflow run: 32166986448
  • Workflow attempt: 1
  • Gate result: REQUEST_CHANGES (approval step)

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 success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before 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 head d93b8c9f37025c7c7b66696b155e6508ce9cd0d0.

  • Head SHA: d93b8c9f37025c7c7b66696b155e6508ce9cd0d0

  • Workflow run: 32166986448

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  Evidence["OpenCode evidence"] --> Review["Current PR review path"]
  Review --> Verify["Required checks"]
Loading

@opencode-agent
opencode-agent Bot disabled auto-merge August 18, 2026 19:00
@seonghobae

Copy link
Copy Markdown
Contributor Author

Superseded by #759. The current head is included in the published http-honesty integration tree (integration commit c1aa96a; published tree fdf2fbec), and this PR has no commit outside that integrated stack.

@seonghobae seonghobae closed this Aug 19, 2026
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.

2 participants