Skip to content

feat(web-search): add Yuanbao and Bocha AI output comparisons - #275

Open
lanyue-llk wants to merge 70 commits into
mainfrom
codex/yuanbao-web-search
Open

lanyue-llk wants to merge 70 commits into
mainfrom
codex/yuanbao-web-search

Conversation

@lanyue-llk

@lanyue-llk lanyue-llk commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Add Tencent Yuanbao Standard/Lite and Bocha AI Search through the existing adapter registry. Compare result lists, additional source excerpts and generated answers separately, with shared source matching and contamination checks.

Preserve native result slots and bind citations to complete local sentences. Parse rendered Markdown labels, image alternative text and HTML line breaks without treating hidden attributes or hidden subtrees as claims. Verify physical judging receipts and common inference settings, including token limits and disabled thinking. Collection retries default to zero; invalid judgment formats have bounded, explicit correction.

The maintained report renderer provides primary-metric sorting, scrollable tables, task-level method selection and consistent evidence links. Reference finalization preserves original search calls, rejects retained HTTP failures and supports supplementary cohorts. Report data and publication bindings remain outside Git.

Validation: 1,056 local Web Search tests and 77 subtests passed, together with repository lint checks. Both CI Python shards, rendered report checks and installation/packaging checks passed. Regression coverage includes native slots, hidden HTML attributes, rendered image labels, line breaks, sentence boundaries, incompatible inference settings, missing answer scopes and reference recovery.

No package or benchmark edition bump; no release tags.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 55e506e

This review found 2 issue(s), including 2 blocking issue(s).

⚠️ 1 warning(s) occurred during review.


⚠️ Warnings:

  • src/harness/web_search/adapters.py (token_budget_reached): skipped round 2 of group "src/harness/web_search/adapters.py,src/harness/web_search/comparison.py,src/harness/web_search/core.py,src/harness/web_search/messages.json,src/harness/web_search/profiles.py,src/harness/web_search/publication.py,src/harness/web_search/report.py,src/harness/web_search/runner.py": used 560851 tokens exceeds budget 500000

profile["protocol"].pop("comparison", None)
validate_profile(profile)
return profile, rows, {"certified": all(r["collection_receipt"].get("certified") for r in receipts),
"synthetic": all(r["collection_receipt"].get("synthetic") for r in receipts),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2 — Reject mixed synthetic/measured collections or preserve their synthetic classification. load_run() accepts both kinds, so composing one synthetic provider with one measured provider makes this all(...) false. _report_edition then labels the combined numbers “Measured API evaluation” (with only a diagnostic suffix), removing the synthetic warning despite fixture results contributing to the comparison. Certification still prevents publication, but the generated local report misrepresents its evidence. Reject mixed provenance before composition, or explicitly disclose it without treating the combined rows as wholly measured.

Comment thread src/harness/web_search/runner.py Outdated
)
except (ValueError, AttributeError, TypeError) as exc:
error = error or str(exc)
native_account_error = adapter_for(method["adapter"]).account_error(decoded, method)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2 — Do not apply the edition check to failed transports or HTTP error responses. With expected_response_version configured, a timeout with an empty body (or an HTML 502 response) leaves decoded = {}; account_error() then reports ResponseVersionMismatch, sets stopped, and breaks before the configured retry. A temporary network/provider failure consequently interrupts the entire collection as an account problem. Gate edition validation on a successfully received HTTP 200 response, while retaining native account-error detection and the stop behavior for genuine missing/mismatched editions.

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Re-review complete · 4361d1f

No findings in this incremental review.

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Re-review complete · a3dcd33

No findings in this incremental review.

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ℹ️ Review skipped · 6181eb1

No reviewable content was selected for this run.

@lanyue-llk lanyue-llk closed this Nov 12, 2026
@lanyue-llk lanyue-llk reopened this Nov 12, 2026
@lanyue-llk
lanyue-llk force-pushed the codex/yuanbao-web-search branch from 6181eb1 to f9c3179 Compare November 12, 2026 05:04

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Review complete · f9c3179

No findings in this review.

@lanyue-llk lanyue-llk changed the title feat(web-search): add Yuanbao Standard and Lite comparisons feat(web-search): add Yuanbao and complete comparison reports Nov 12, 2026

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Re-review complete · 24197d0

This review found 3 issue(s), including 3 blocking issue(s).

Comment thread src/harness/web_search/assets/report.js Outdated
const rows=[...table.tBodies[0].rows];
rows.sort((a,b)=>{
const x=value(a.cells[index]),y=value(b.cells[index]);
if(x.value===null||y.value===null)return x.value===y.value?original.get(a)-original.get(b):x.value===null?1:-1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

maintainability · low
P2: The null-handling expression introduces a nested ternary, which the supplied JavaScript Code Quality Checks explicitly prohibit. Use separate branches for both-null, left-null, and right-null cases, preserving original-order ties and nulls-last behavior in both directions.

Comment on lines +590 to +591
prior_call = saved
request = dict(request, messages=reference_repair_messages(p, request['messages']))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2: Use the same invalid-answer predicate when authorizing and validating a format repair. A saved answer with an exact quoted string (or a field: "url" reference) passes parse_judgments but fails _validate_judge_field_references, so this branch spends a repair call. Final verify_provenance then invokes repaired_messages, which checks only parse_judgments on the prior response and rejects it with “A valid model judgment cannot be retried as a format repair”. Subsequent resumes reject the saved repaired call too. Align the repair-provenance check with both validators used here, and add a regression for a parseable answer that violates the required title/snippet-reference format.

Comment on lines +3672 to +3675
expected = {(cid, method['id']) for cid in ids for method in profile['methods']}
actual = [(r['case_id'], r['method']) for r in relevance_scores if r['case_id'] in ids]
if len(actual) != len(expected) or set(actual) != expected:
raise ValueError('Relevance comparison requires every method and query')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · high
P1: This rejects the supported provider-scoped annotation scenario. With relevance_methods containing only the frozen providers, score_relevance() deliberately returns scores only for those methods. For an independent benchmark (or metric_kind='relevance'), this comparison instead requires every configured provider, so adding an unjudged Yuanbao configuration aborts report generation rather than rendering its relevance as unavailable. Preserve exact coverage checks within the declared annotation scope and retain unavailable values for other methods; enforce complete assessment separately when explicitly required. Add a build regression combining scoped frozen judgments with an unjudged provider.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 2be38d3

This review found 4 issue(s), including 4 blocking issue(s).

Comment thread src/harness/web_search/adapters.py Outdated
Comment on lines +29 to +30
expected = (method or {}).get("expected_response_version")
if expected is not None and not error:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2 — Edition verification silently disappears when a Yuanbao method omits expected_response_version (or sets it to null). validate_profile() accepts that configuration, and normalize_response() then accepts both a missing Response.Version and a different edition. For example, a method with output_options.edition='lite' but no expectation accepts a Standard response and can attribute its results and price to Lite. This violates the requirement to verify the returned edition on every call. Require a nonempty edition expectation for Yuanbao methods during preflight, while preserving the intentional no-version-check path for failed transports; add a regression for an omitted expectation.

const original=new Map([...table.tBodies[0].rows].map((row,index)=>[row,index]));
function value(cell){
if(cell.hasAttribute('data-sort'))return {value:Number(cell.dataset.sort),numeric:true};
if(cell.hasAttribute('data-value'))return {value:cell.dataset.value===''?null:Number(cell.dataset.value),numeric:true};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2: Text sorting is still broken on the standard overview and interpretation comparison. Their method-name cells are produced by numeric_cell(..., None, ...) (report.py lines 959 and 2928), so they carry data-value="" despite displaying provider names. This branch treats every provider as missing, and the new first-column sort button only restores original order in either direction. Render those text cells as plain <td> elements, as this PR already does in population_summary, while retaining empty numeric values as missing.

Comment thread src/harness/web_search/comparison.py Outdated
"score": query_score,
"primary": acceptance(case, row, primary_factual_metric if "reference_answer" in case else "primary", cutoff=cutoff, quality_excluded=quality_excluded, relevance_grades=[x["grade"] for x in items] if case["id"] in labels else None),
"quality": any(x["grade"] is not None and x["grade"] >= 2 for x in items) if case["id"] in labels and not quality_excluded else None,
"primary": acceptance(case, row, primary_factual_metric if "reference_answer" in case else "primary", cutoff=cutoff, quality_excluded=quality_excluded, relevance_grades=[x["grade"] for x in items] if has_labels else None),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2: Keep the primary verdict unavailable for methods outside the relevance scope. When a labeled scenario has anchors (or a site/vertical constraint), passing relevance_grades=None makes task_acceptance() fall back to source/site acceptance instead of returning None. Meanwhile, comparison.js chooses the primary verdict label from the case-wide has_relevance, so this unannotated method is displayed as “Relevant result found” or “No relevant result in top 5” and included in relevance outcome relations despite quality being unavailable. For a case with relevance labels but an out-of-scope method, set primary to None while retaining the separate source/site diagnostics. Extend the scoped-method regression to assert the primary verdict as well as score and quality.

Comment on lines +591 to +592
prior_call = saved
request = dict(request, messages=reference_repair_messages(p, request['messages']))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2 — Validate the original physical receipt before authorizing a format repair. This new branch decides that the saved answer is invalid using only saved["response"]; it never checks that this object matches the preserved response bytes. After repair, validate_model_evidence() validates only the replacement call's attempts, while repaired_messages() merely parses prior_call["response"]. Consequently, changing a previously valid saved response to an invalid judgment (without changing its raw receipt) allows --repair-format to repeat that valid call and produce evidence that passes validation. This defeats the promised audited, invalid-output-only repair boundary. Verify the prior request/attempt hashes and response-byte equality before spending, and apply the same verification to retained format_repair.prior_call during evidence validation, allowing only judgment-format validation to fail.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · f724bcb

This review found 1 issue(s), including 1 blocking issue(s).

Comment thread src/harness/web_search/core.py Outdated
Comment on lines +180 to +182
edition = method.get('output_options', {}).get('edition')
if (not isinstance(expected, str) or not expected.strip()
or edition is not None and edition != expected):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2: Validate against the effective edition when output_options.edition is omitted. tencent_wsa_request defaults that option to standard, but this condition accepts expected_response_version='lite' (or any other nonempty string) when the option is absent. Such a profile passes the preflight in run() and sends Mode=0, Cnt=10; only after the network call can runtime version checking stop it. This defeats the new pre-call edition consistency check and can spend quota on an incorrectly configured request. Default edition to standard here as well (or require an explicit edition), and cover the omitted-option mismatch in the profile-validation test.

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Re-review complete · e60e367

No findings in this incremental review.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 96a94a9

This review found 1 issue(s), including 1 blocking issue(s).

Comment on lines +2268 to +2270
for target, text in updates.items():
target.write_text(text, encoding='utf-8')
write_json(path, manifest)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2 — Make paragraph revisions recoverable across partial write failures. If one page is written successfully but a later page write or the manifest replacement fails (for example, a read-only second edition or a full disk), the report contains revised HTML with the old manifest. Retrying the same command then raises Existing authored paragraphs differ from their frozen content on the already-updated page, so the workflow cannot recover without manual restoration or rebuilding. Stage the update with retained originals and rollback/recovery state, and add a failure-injection test that verifies the report remains consistent or the same revision can resume after a mid-commit failure.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 573a806

This review found 1 issue(s), including 1 blocking issue(s).

Comment thread src/harness/web_search/report.py Outdated
'content_sha256': bytes_sha256(raw), 'provider_calls': 0,
'changed_sections': changed, 'producer': software_identity()}
manifest['authored'], manifest['content_sha256'] = revised, bytes_sha256(raw)
manifest['content_revisions'] = [*manifest.get('content_revisions', []), receipt]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2: Revision provenance is recorded but never validated. The repository search finds no consumer of content_revisions, before_manifest_sha256, or before_content_sha256 outside this writer and assertions about receipt presence. Consequently, changing a receipt's predecessor hashes, changed-section inventory, or provider-call count still passes check; a newly frozen publication plan merely binds those unchecked claims. This leaves the requested revision-provenance verification incomplete, although stale visual receipts and publication plans are correctly rejected by their manifest bindings. Validate the revision receipt schema and chain/current-content bindings in check, with negative tests for altered receipt fields; retain enough predecessor evidence to verify any historical claims the receipt makes.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Re-review complete · e3dfbaf

This review found 1 issue(s), including 1 blocking issue(s).

⚠️ 1 warning(s) occurred during review.


⚠️ Warnings:

  • src/harness/web_search/report.py (token_budget_reached): stopped group "src/harness/web_search/report.py" mid-review: used 598136 tokens exceeds budget 500000

source = item.get('source', '')
bound_quote = item.get('source_kind') == 'owner-quote' and any(
asset.get('path') == source and asset.get('sha256') for asset in content.get('assets', []))
if (item.get("currency") != "USD" or item.get("unit") not in ("1000-successful-searches", "1000-requests")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
P2 — Accepting mixed billing units here loses their meaning in the rendered comparison. catalog_price_panel, benchmark_operations, and population_summary display both units as “USD / 1,000 calls” and compare the raw amounts for winner markers; none renders item['unit'], and purchase terms are optional. For example, the mixed-unit fixture in test_report.py supplies no terms, so readers cannot distinguish a rate charged for every request from one charged only for successful searches. Render the declared billing basis per method and either normalize to an explicitly defined common workload or avoid cross-basis price winner markers. This is a correctness issue in the newly supported mixed-unit comparison, not just a wording preference.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 69a864d

This review found 5 issue(s), including 5 blocking issue(s).

Comment thread src/harness/web_search/comparison.py Resolved
Comment thread src/harness/web_search/output_levels.py Resolved
Comment thread src/harness/web_search/report.py Resolved
Comment thread src/harness/web_search/report.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Re-review complete · cfea48c

This review found 5 issue(s), including 5 blocking issue(s).

Comment thread src/harness/reporting/certified_cli.py Resolved
Comment thread src/harness/web_search/report.py Resolved
Comment thread src/harness/web_search/runner.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved
@lanyue-llk lanyue-llk changed the title feat(web-search): add Yuanbao and complete comparison reports feat(web-search): add Yuanbao and Bocha AI output comparisons Nov 13, 2026

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 4d5ee4a

This review found 6 issue(s), including 6 blocking issue(s).

Comment thread src/harness/web_search/adapters.py Resolved
Comment thread src/harness/web_search/runner.py Resolved
Comment thread src/harness/web_search/runner.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved
Comment thread src/lexbench_websearch/outputs.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 93a1b04

This review found 2 issue(s), including 2 blocking issue(s).

Comment thread src/harness/web_search/revisions.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 78b35fa

This review found 2 issue(s), including 2 blocking issue(s).

Comment thread src/harness/web_search/output_levels.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Re-review complete · daced06

No findings in this incremental review.

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 46fe8f0

This review found 1 issue(s), including 1 blocking issue(s).

Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 8779eaa

This review found 2 issue(s), including 2 blocking issue(s).

Comment thread src/harness/web_search/answers.py Resolved
Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Re-review complete · 924c29d

This review found 1 issue(s), including 1 blocking issue(s).

Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Re-review complete · 3c6514d

This review found 1 issue(s), including 1 blocking issue(s).

Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Review complete · 1d272ff

This review found 1 issue(s), including 1 blocking issue(s).

Comment thread src/lexbench_websearch/answers.py Resolved

@lexmount-ocr lexmount-ocr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Review complete · 2bf0824

No findings in this review.

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.

1 participant