Skip to content

Entry-resolution tasks: name the protein, not the id - #6

Merged
dbolser merged 5 commits into
mainfrom
feat/resolve-tasks
Oct 6, 2026
Merged

dbolser merged 5 commits into
mainfrom
feat/resolve-tasks

Conversation

@dbolser

@dbolser dbolser commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Every MVS task hands the model the PDB id. Real users don't. The first evaluator prompt to fail on the preview site was "I wanna see a structure of PDE5A", answered with 1UJ7 — an entry that does not exist. Probing 12 named-protein prompts on Haiku found the quieter version too: 0 non-existent ids but 3 real ids for the wrong protein (a SARS-CoV-2 RBD for "nanobody bound to GFP", DR5 for PCSK9, a plant Toc75 domain for CFTR).

Changes

  • tasks/mvs_resolve/ — six tasks (PDE5A, PCSK9, CFTR, GFP, sperm whale myoglobin, HEWL). Prompts are verbatim/near-verbatim from the evaluator corpus and the probe. Each carries accepted_ids: every PDB entry whose polymer maps to the protein's UniProt accession (RCSB search, 50–1398 entries, recorded under provenance), plus a minimal polymer-cartoon reference on one canonical entry so the task measures resolution, not styling. scripts/generate_resolve_tasks.py regenerates them.
  • Grader — grade_mvs(…, accepted_refs=…) folds any accepted id in the prediction onto the reference's canonical id before matching. A made-up id (1UJ7) is left alone and mismatches the download segment as before. Runner and escalating_grade pass the task's set through. No change for tasks without accepted_ids.
  • Tests (+4, 22 pass): accepted-set sanity for every resolve task; any accepted entry scores 1.0; the 1UJ7 case scores below it and identically with/without the fold; multi-structure references are untouched.
  • ROADMAP — B4 (this, plus an exists sub-metric to separate "made-up" from "wrong-but-real"), B5 (colour-scheme prompt drift from the chat-driver), B6 (structured outputs experiment).

Corpus goes 84 → 90 tasks; the live leaderboard is unaffected until a re-run.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added six structure-resolution tasks covering CFTR, GFP, lysozyme, myoglobin, PCSK9, and PDE5A.
    • Grading recognizes accepted alternate structure entries as equivalent to the reference for applicable tasks, while continuing to penalize unaccepted entries.
  • Documentation
    • Added roadmap items for structure resolution, color themes, and structured outputs.

…ll its entries

Every MVS task handed the model the PDB id. Real users don't: the first evaluator
prompt to fail live was "I wanna see a structure of PDE5A", answered with 1UJ7 —
an entry that does not exist. Probing found the quieter failure too: real ids for
the wrong protein (a SARS-CoV-2 RBD for "nanobody bound to GFP").

- tasks/mvs_resolve/: six tasks (PDE5A, PCSK9, CFTR, GFP, myoglobin, lysozyme),
  each with `accepted_ids` = every PDB entry mapped to the protein's UniProt
  accession (RCSB search, recorded under provenance) and a minimal polymer-cartoon
  reference on one canonical entry. scripts/generate_resolve_tasks.py regenerates.
- grade_mvs(accepted_refs=…): any accepted id in the prediction is folded onto the
  reference's; anything else (1UJ7) mismatches as before. Runner and escalation
  pass the task's set through.
- Tests: accepted set sanity, any-accepted-entry == 1.0, the 1UJ7 case scores
  below it, multi-structure references are left alone. 22 pass.
- ROADMAP: B4 resolution, B5 colour-scheme prompt drift, B6 structured outputs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 50 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b5f6a6cf-fdb0-48da-9772-d60b2691589c
📥 Commits

Reviewing files that changed from the base of the PR and between abf4225 and 4df4c99.

📒 Files selected for processing (3)
  • scripts/build_leaderboard.py
  • scripts/generate_resolve_tasks.py
  • tasks/mvs_resolve/res-gfp.json

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a7666126-582b-4d35-8e5f-d4f5abb4e98a
📥 Commits

Reviewing files that changed from the base of the PR and between ca9d864 and abf4225.

📒 Files selected for processing (5)
  • molbench/escalate.py
  • molbench/mvs.py
  • scripts/generate_resolve_tasks.py
  • tasks/mvs_resolve/res-cftr.json
  • tests/test_harness.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The grader now accepts configured alternate structure IDs for single-ID references. The runner passes accepted IDs to grading and escalation. Six resolution tasks and a task-generation script are added. The roadmap also records plans for color-theme grading and structured-output evaluation.

Changes

Entry Resolution

Layer / File(s) Summary
Accepted-reference grading
molbench/mvs.py, molbench/escalate.py, molbench/runner.py, tests/test_harness.py
The grader folds accepted predicted download IDs to the reference ID when the reference contains one distinct download ID. The runner passes task accepted_ids to normal and escalation grading. Tests cover accepted and unaccepted IDs, multi-download references, malformed downloads, and escalation reference handling.
Resolve task generation and records
scripts/generate_resolve_tasks.py, tasks/mvs_resolve/*
The script queries UniProt and RCSB, checks for each canonical ID, and writes task records with accepted IDs, reference workflows, metadata, and provenance. Six task records are added.

Roadmap Updates

Layer / File(s) Summary
Phase B roadmap items
ROADMAP.md
The roadmap adds items on entry resolution, color-theme grading, and JSON-schema constrained-decoding evaluation.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Runner as run_mvs_task
  participant Grader as grade_mvs
  participant Escalation as escalating_grade
  Runner->>Grader: Pass reference, prediction, accepted_ids
  Runner->>Escalation: Pass reference, prediction, accepted_ids
  Escalation->>Grader: Grade with accepted_refs
  Escalation->>Escalation: Adjust copied reference for rendering when IDs match accepted IDs
Loading

Merge Risk: ⚪ Minimal · up to abf42

The reviewed changes have no identified issue that needs resolution before merge.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to ca9d8

The reviewed changes alter scoring without allowing predictions to choose the accepted-ID policy or gain additional execution, network, or file authority. Task generation uses fixed destinations and local output paths. No material security risk was identified in these changes.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed authority is bounded to repository-local task authoring and benchmark scoring. Predictions cannot select the accepted set through the runner, and accepted IDs do not create new execution, file, or network operations in the grader. Existing optional rendering and judge capabilities remain separately configured.

Trust Boundaries and Controls

  • observed — The new external-data trust transition occurs during authoring: RCSB identifiers become repository task policy. Canonical membership is checked before each write, and remote identifiers remain JSON data rather than output filenames. The script does not independently verify every returned identifier's protein mapping beyond the RCSB query result.
  • observed — The runner separates prediction data from scoring policy. Although direct API callers can deliberately supply their own accepted_refs, the new runner calls obtain that value from task metadata, not from the prediction.

Resilience and Maintainability Implications

  • inferred — Generator interruption and concurrency can affect local policy-file consistency and loader availability. Fixed filenames and data-only consumption contain the observed failure mode; no evidence connects it to cross-tenant access, privilege escalation, or insecure deployed configuration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.13% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 5 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding protein entry-resolution tasks that identify structures by protein rather than by a single entry ID.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 39.13% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 5 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces entry-resolution tasks where prompts name a protein instead of a specific PDB ID, allowing grading against multiple accepted structure IDs mapped to a UniProt accession. It adds a generation script, several new resolve tasks, and updates the grading logic in molbench/mvs.py to fold accepted predicted IDs onto the reference's canonical ID. Feedback on the changes highlights potential IndexError crashes in _fold_accepted_refs when handling malformed trees with empty tuples, suggesting the addition of tuple length checks to ensure robustness.

Comment thread molbench/mvs.py Outdated
Comment on lines +183 to +184
ref_ids = {seg[1][1] for path in ref_paths for seg in path
if seg[0] == "download" and isinstance(seg[1], tuple) and seg[1][0] == "ref"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If the reference or predicted tree contains a download node with empty or malformed parameters, seg[1] can be an empty tuple (). Accessing seg[1][0] without verifying the length of the tuple will raise an IndexError, potentially crashing the entire evaluation run. Adding a length check ensures robustness against malformed trees.

Suggested change
ref_ids = {seg[1][1] for path in ref_paths for seg in path
if seg[0] == "download" and isinstance(seg[1], tuple) and seg[1][0] == "ref"}
ref_ids = {seg[1][1] for path in ref_paths for seg in path
if seg[0] == "download" and isinstance(seg[1], tuple) and len(seg[1]) == 2 and seg[1][0] == "ref"}

Comment thread molbench/mvs.py Outdated
Comment on lines +191 to +192
if seg[0] == "download" and isinstance(seg[1], tuple) and seg[1][0] == "ref" \
and seg[1][1] in accepted:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If the predicted tree contains a download node with empty parameters, seg[1] will be (). Accessing seg[1][0] directly will raise an IndexError and crash the grading process. Adding a length check prevents this crash when evaluating malformed model outputs.

Suggested change
if seg[0] == "download" and isinstance(seg[1], tuple) and seg[1][0] == "ref" \
and seg[1][1] in accepted:
if seg[0] == "download" and isinstance(seg[1], tuple) and len(seg[1]) == 2 and seg[1][0] == "ref" \
and seg[1][1] in accepted:

@dbolser

dbolser commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-06T18:50:54.593229Z 782c7a1 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca9d864fa2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/test_harness.py
Comment on lines +201 to +204
# --- entry resolution (tasks/mvs_resolve) ------------------------------------------

def _resolve_tasks():
return [t for t in load_tasks(["mvs"]) if t.get("source") == "resolve"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include the resolution tests in the direct test runner

The repository CI runs PYTHONPATH=. python tests/test_harness.py, but all four new resolution tests are defined after the existing if __name__ == "__main__" block and are never called by that block. Consequently, the CI command exits successfully without exercising the accepted-ID behavior or validating the generated task sets. Move the main block below these definitions and invoke the new tests, or change CI to run pytest.

Useful? React with 👍 / 👎.

…download node without params

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@dbolser

dbolser commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Thanks both — fixed in 4312683:

  • Tests not run by CI (Codex): the __main__ block now sits at the end and calls the five resolution tests, so python tests/test_harness.py exercises them. Verified both ways (direct run + pytest, 23 pass).
  • IndexError on a download node without params (Gemini): segment checks go through a _download_id() helper that requires a 2-tuple ("ref", id); added a test with a bare download node in both prediction and reference.

@dbolser

dbolser commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

@codex review — please re-review including the fix commit 4312683.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 431268369a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/generate_resolve_tasks.py Outdated
Comment on lines +56 to +58
"attribute": "rcsb_polymer_entity_container_identifiers."
"reference_sequence_identifiers.database_accession",
"operator": "exact_match", "value": accession}},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter accepted IDs by task-level structure coverage

For res-cftr, the prompt asks for the CFTR channel, but this accession-only query accepts every entry containing any P13569-mapped polymer. The generated set consequently includes entries such as 1XMI and 2BBO, which are isolated NBD1 domains rather than channel structures; grade_mvs then folds those IDs to the full-length 5UAK reference and awards a matching scene full credit. Add sequence-coverage/domain constraints or curate accepted IDs per prompt so fragment-only answers do not corrupt the resolution score.

Useful? React with 👍 / 👎.

Comment thread molbench/escalate.py
accepted_refs: set[str] | list[str] | None = None,
) -> dict[str, Any]:
g = grade_mvs(reference_tree, predicted_tree)
g = grade_mvs(reference_tree, predicted_tree, accepted_refs=accepted_refs)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize accepted entries before rendering escalation

When --escalate is enabled and a prediction uses a noncanonical accepted ID but differs elsewhere in the tree (for example, an equivalent all selector instead of polymer), this call folds the ID only for tree scoring. The visual tiers still render the canonical reference structure against the alternate accepted structure, so structural differences can dominate the pixel comparison and the VLM is explicitly asked whether both images contain the same structure, preventing an otherwise equivalent visualization from being rescued. Render a reference rewritten to the prediction's accepted ID, or otherwise carry the accepted-entry equivalence through T1/T2.

Useful? React with 👍 / 👎.

…alation renders the accepted entry; CI runs every test

- generate_resolve_tasks: optional per-task min coverage (entity-level RCSB query);
  res-cftr drops isolated-domain entries such as 1XMI/2BBO.
- escalate: the visual tiers re-point the reference at the accepted entry the
  prediction loaded, as the tree tier already does.
- test_harness: the __main__ block runs every test_* function, so CI (which runs
  this file directly) can no longer skip a newly added test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@dbolser

dbolser commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Codex: both fixed in abf4225.

  • CFTR fragments: res-cftr now needs one polymer entity covering at least 70% of P13569 (an entity-level RCSB query). That leaves 24 entries; 1XMI and 2BBO are gone. The other tasks are unchanged.
  • Escalation: T1/T2 render the reference re-pointed at the accepted entry the prediction loaded.
  • Also: tests/test_harness.py's __main__ now runs every test_* function, so CI can't silently skip new tests again.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: abf4225170

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

task = {
"id": f"res-{slug}",
"category": "mvs",
"source": "resolve",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Map resolution tasks outside the clinical regime

When the leaderboard is regenerated with these tasks, scripts/build_leaderboard.py::_regime_of recognizes only generated/curated and grounded, then classifies every other source as Clinical (SIFTS/ClinVar). Consequently, all six new source: "resolve" tasks will be included in the clinical counts, means, and difficulty-spread claims even though they do no clinical or SIFTS grounding. Add an explicit resolution regime (including it in the displayed regime lists) or deliberately map this source to an existing non-clinical regime.

Useful? React with 👍 / 👎.

… unknown sources fail loudly

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@dbolser

dbolser commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Codex: fixed in 782c7a1. Sources now map to regimes through an explicit table. resolve gets its own Resolution (by name) regime, shown in the per-regime table but kept out of Finding 03's difficulty gradient. An unknown source now raises an error instead of silently landing in Clinical.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 782c7a12e2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/build_leaderboard.py Outdated

# How a task's `source` maps to a difficulty regime, ordered easy -> hard.
REGIMES = ["Translation", "Grounded (ligand/SS)", "Clinical (SIFTS/ClinVar)"]
REGIMES = ["Translation", "Grounded (ligand/SS)", "Clinical (SIFTS/ClinVar)", "Resolution (by name)"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep resolution out of the difficulty ordering

When the leaderboard is rebuilt, regime_table() iterates this entire list while its heading and description still present the rows as an easy-to-hard difficulty gradient and assert that later regimes separate models more. Appending Resolution here therefore tells readers that name resolution is harder than Clinical, even though the adjacent comment and Finding 03 explicitly treat only the first three regimes as the gradient. Use a separate list for displayed, non-ordered regimes or update the table copy so the new row is clearly orthogonal.

Useful? React with 👍 / 👎.

Comment thread scripts/generate_resolve_tasks.py Outdated
Comment on lines +46 to +47
("gfp", "show green fluorescent protein", "P42212", "1ema",
"The starter chip's target; the model tends to be right here — a control."),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Disambiguate GFP before restricting it to one accession

For the generic prompt show green fluorescent protein, the generator accepts only entries mapped to UniProt P42212 because entries_for() performs an exact accession match. A model can therefore select a valid GFP structure from another organism or accession and be graded as wrong even though the prompt provides no species or accession constraint. Specify Aequorea victoria/P42212 in the prompt or include the other GFP accessions that satisfy this wording.

Useful? React with 👍 / 👎.

…culty gradient; GFP prompt names the species

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@dbolser
dbolser merged commit f300ecb into main Oct 6, 2026
3 checks passed
dbolser pushed a commit that referenced this pull request Oct 6, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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