Skip to content

fix(rubric): redact hostile iterable failures - #801

Merged
seonghobae merged 3 commits into
mainfrom
fix/rubric-iterable-redaction-green
Aug 13, 2026
Merged

fix(rubric): redact hostile iterable failures#801
seonghobae merged 3 commits into
mainfrom
fix/rubric-iterable-redaction-green

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Rubric collection materialization fails closed on hostile iterable setup/iteration exceptions.
  • Preserves MemoryError resource signals.
  • Stacked on fitstats/docs fail-closed base for product CI.

Supersedes

Test plan

  • tests/test_rubric_iterable_error_boundary.py
  • docs + fitstats fail-closed smoke

Summary by CodeRabbit

  • New Features

    • Added cumulative-threshold categorization for LLM evaluations, including strict Boolean validation and explicit category counts.
    • Evaluation results now record the selected categorization method.
    • Added stricter validation for judge inputs, text, usage data, and traces.
  • Bug Fixes

    • Improved handling of hostile rubric iterables with stable errors while preserving memory failures.
    • Improved model-comparison error redaction.
    • Improved optimizer convergence detection and recovery reliability.
  • Documentation

    • Expanded guidance for calibration, security boundaries, optimizer recovery, documentation governance, and research references.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6fd06749-f314-445e-9d70-140df6d47499

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds cumulative-threshold LLM-judge categorization and strict input validation, hardens rubric iterable error boundaries, updates L-BFGS convergence behavior, adds Rust optimizer recovery tests, and expands governance, licensing, and research documentation.

Changes

LLM judge validation and categorization

Layer / File(s) Summary
Judge input and result contracts
python/fast_mlsirm/llm_judge.py
Validation now requires exact built-in types for judge inputs, scores, usage, modes, identifiers, and text. Results serialize the selected category_method.
Cumulative-threshold evaluation flow
python/fast_mlsirm/llm_judge.py, tests/test_llm_judge.py
The judge supports direct and cumulative_threshold modes. Cumulative mode validates monotone Boolean threshold arrays and derives category levels.
Judge evidence and decision record
tests/test_llm_judge.py, tests/test_llm_judge_description_boundary.py, docs/adr/0014-bounded-llm-judge-category-inputs.md, docs/adr/README.md, README.md
Tests cover malformed inputs, runtime subclasses, response boundaries, category methods, and IRT projection. ADR-0014 and the README document the contract and calibration requirements.

Rubric iterable error boundaries

Layer / File(s) Summary
Rubric iterable failure handling
python/fast_mlsirm/rubric/models.py, tests/test_rubric_iterable_error_boundary.py, docs/changelog.d/783-rubric-iterable-error-boundary.md, CHANGELOG.md
Iterator setup and iteration failures become stable package-owned errors. MemoryError remains unchanged. Regression tests cover both failure phases.

Native optimizer validation

Layer / File(s) Summary
L-BFGS convergence and recovery validation
crates/mlsirm-core/src/jmle_opt.rs, tests/test_jmle_optimizer_recovery.py, docs/doctoring/jmle_optimizer_recovery_evidence.md
L-BFGS now checks relative objective reduction. Tests cover large-offset convergence, optimizer statuses, deterministic recovery, objective traces, and public Rust modes.
Fit-statistics ownership evidence
tests/test_cov_c_fitstats.py, tests/test_fitstats_infit_outfit_allocations.py, docs/doctoring/fitstats_sx2_person_rust_required.md
Coverage text and verification lists describe Rust ownership and fail-closed behavior for incomplete native fit-statistics APIs.

Documentation governance and research references

Layer / File(s) Summary
Architecture and documentation status
docs/adr/0013-continuous-execution-and-documentation-governance.md, docs/documentation_coverage.md
Documentation now separates target registry architecture from protected-main initialization and export paths.
Paper provenance and licensing records
docs/papers/README.md, docs/papers/directive-irt-coverage.md, docs/papers/oa-pdf-manifest.md
Paper policies now record redistribution terms, citation-only sources, preserved PDF metadata, and interpretation boundaries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant ContextualOrchestratorJudge
  participant Model
  participant IRTProjection
  Caller->>ContextualOrchestratorJudge: submit category_method and category_count
  ContextualOrchestratorJudge->>Model: request direct categories or Boolean thresholds
  Model-->>ContextualOrchestratorJudge: return structured judgment
  ContextualOrchestratorJudge->>IRTProjection: validate and derive categories
  IRTProjection-->>Caller: return serialized LLMJudgeResult
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. 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 and concisely describes the main change: redacting hostile iterable failures during rubric handling.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rubric-iterable-redaction-green

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.

@seonghobae
seonghobae marked this pull request as draft August 12, 2026 07:22
@seonghobae
seonghobae changed the base branch from main to fix/fitstats-m2-infit-docs-green August 12, 2026 07:22
@seonghobae
seonghobae marked this pull request as ready for review August 12, 2026 08:14
Base automatically changed from fix/fitstats-m2-infit-docs-green to main August 12, 2026 08:14
@seonghobae
seonghobae force-pushed the fix/rubric-iterable-redaction-green branch from ae5c879 to c678e90 Compare August 12, 2026 10:02

Copy link
Copy Markdown
Contributor Author

@OpenCode address

Bounded current-head repair for exact branch head 96951ec5d5efd13dda1e17d867aa1c3021578795 over protected main b4f39da310d63056e12d4fcb5390254b6b4e5287. Refetch both refs and comments before writing; abort if either moved or another writer appeared.

The branch now correctly contains only the rubric production/test delta plus authoritative fragment docs/changelog.d/783-rubric-iterable-error-boundary.md, but the repository's deterministic changelog contract treats fragments as authoritative and requires root CHANGELOG.md to be rendered from them. Run the existing repository renderer (scripts/render_changelog_fragments.py --update using its supported CLI), commit only the deterministic root CHANGELOG.md synchronization if needed, then run the focused changelog contract and rubric iterable regression plus the applicable full suite. Do not change the rubric implementation/test/fragment, dependencies, workflows, review/merge state, protection, or any other PR. Preserve current protected-main entries such as the merged #800 scoring item. Stop immediately if head/base/writer state changes.

@seonghobae
seonghobae enabled auto-merge (squash) August 12, 2026 11:03
@seonghobae
seonghobae force-pushed the fix/rubric-iterable-redaction-green branch from 96951ec to 2a79e97 Compare August 12, 2026 11:22

@coderabbitai coderabbitai 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.

Actionable comments posted: 6

🧹 Nitpick comments (2)
tests/test_cov_c_fitstats.py (1)

191-191: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the tests to match the fail-closed behavior.

test_sx2_numpy_fallback_realistic, test_sx2_numpy_fallback_spatial_and_dim_floors, test_person_fit_numpy_fallback, and test_infit_outfit_numpy_fallback now patch an incomplete core and expect RuntimeError. They no longer test NumPy fallback behavior. The spatial test also no longer exercises the dimension floors because execution stops at the missing native entry point.

Rename the tests to describe incomplete-core fail-closed coverage. Keep separate native-core tests for any retained floor behavior.

Proposed renames
-def test_sx2_numpy_fallback_realistic(monkeypatch):
+def test_sx2_incomplete_core_fails_closed_realistic(monkeypatch):

-def test_sx2_numpy_fallback_spatial_and_dim_floors(monkeypatch):
+def test_sx2_incomplete_core_fails_closed_spatial(monkeypatch):

-def test_person_fit_numpy_fallback(monkeypatch):
+def test_person_fit_incomplete_core_fails_closed(monkeypatch):

-def test_infit_outfit_numpy_fallback(monkeypatch):
+def test_infit_outfit_incomplete_core_fails_closed(monkeypatch):

Also applies to: 208-208, 221-221, 231-231

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_cov_c_fitstats.py` at line 191, Rename the four tests currently
named test_sx2_numpy_fallback_realistic,
test_sx2_numpy_fallback_spatial_and_dim_floors, test_person_fit_numpy_fallback,
and test_infit_outfit_numpy_fallback to names describing incomplete-core
fail-closed behavior and their expected RuntimeError. Remove the misleading
NumPy-fallback and dimension-floor wording; preserve any dimension-floor
coverage only in separate native-core tests.
docs/doctoring/jmle_optimizer_recovery_evidence.md (1)

31-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

State which stopping rule produces the "converged" status.

This PR adds a relative objective-reduction stopping rule to the Rust L-BFGS loop. That rule can set "converged" while the gradient norm is still above 1e-5. Record this in the evidence document, so a reader does not read "convergence remains a mandatory gate" as gradient-norm convergence only.

📝 Suggested addition
-The initial 500-iteration evidence reached the configured iteration ceiling for L-BFGS and the hybrid mode rather than satisfying their convergence contract. The follow-up evidence expands the optimizer budget to 2,000 iterations without relaxing the `1e-5` tolerance or any recovery threshold; convergence remains a mandatory gate.
+The initial 500-iteration evidence reached the configured iteration ceiling for L-BFGS and the hybrid mode rather than satisfying their convergence contract. The follow-up evidence expands the optimizer budget to 2,000 iterations without relaxing the `1e-5` tolerance or any recovery threshold; convergence remains a mandatory gate.
+
+The Rust L-BFGS loop reports `converged` from either the gradient-norm rule or the relative objective-reduction rule added in this change. Record which rule terminated each mode when the evidence is regenerated, because the objective-reduction rule can stop the loop while the gradient norm is still above the configured tolerance.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/doctoring/jmle_optimizer_recovery_evidence.md` at line 31, Update the
evidence document’s convergence statement to explicitly identify the relative
objective-reduction stopping rule in the Rust L-BFGS loop as capable of
producing the "converged" status, including when the gradient norm remains above
1e-5; clarify that the mandatory gate uses this rule rather than implying
gradient-norm convergence only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/mlsirm-core/src/jmle_opt.rs`:
- Around line 361-376: Update lbfgs_accepts_relative_objective_convergence to
match the corrected stopping behavior: do not assert a converged status while
stopping at x[0] == 0.5 for an objective whose minimum is x[0] == 1.0. Assert
the distinct status or tolerance-driven outcome introduced by the stopping-rule
change, and make the assertions explicitly validate objective-reduction
convergence rather than reaching the minimum.
- Around line 173-181: Separate the objective-reduction tolerance from the
gradient tolerance in the optimizer’s stopping logic around the L-BFGS iteration
flow, and require the function-reduction criterion to hold on consecutive
iterations before stopping. Return a distinct non-“converged” status for
objective-based termination, while reserving “converged” for the gradient
criterion; update the NumPy L-BFGS reference path to use the same tolerance
semantics, consecutive-iteration rule, and status string, preserving Rust/NumPy
parity.

In `@docs/adr/0013-continuous-execution-and-documentation-governance.md`:
- Around line 68-76: Update the “Current review finding and remediation” section
in ADR-0013 to remove references to the active review and active PR, preserving
only the durable requirement that the documentation matrix separately describe
the target architecture and protected-main behavior until ADR-0011 is
implemented.

In `@docs/papers/README.md`:
- Around line 50-52: Update the paper title in the bibliography entry for Zheng
et al. to hyphenate the compound modifier as “multiple-choice selectors,”
preserving the rest of the citation unchanged.
- Around line 50-62: In the citation-only entries for Zheng et al. and Samejima
in the papers README, add one concise scope-summary sentence to each: describe
Zheng et al. as addressing selector/order sensitivity, and Samejima as defining
ordered cumulative boundaries for graded categories. Preserve the existing
licensing explanations and the stated limits on prompt-fairness and positive-K
claims.

In `@tests/test_jmle_optimizer_recovery.py`:
- Around line 123-146: Add module-level pytest.importorskip for
fast_mlsirm._core with reason “compiled Rust core required” in
tests/test_jmle_optimizer_recovery.py, before tests execute. Keep the explicit
backend="rust" configuration in
test_rust_jmle_optimizer_modes_recover_known_parameters unchanged.

---

Nitpick comments:
In `@docs/doctoring/jmle_optimizer_recovery_evidence.md`:
- Line 31: Update the evidence document’s convergence statement to explicitly
identify the relative objective-reduction stopping rule in the Rust L-BFGS loop
as capable of producing the "converged" status, including when the gradient norm
remains above 1e-5; clarify that the mandatory gate uses this rule rather than
implying gradient-norm convergence only.

In `@tests/test_cov_c_fitstats.py`:
- Line 191: Rename the four tests currently named
test_sx2_numpy_fallback_realistic,
test_sx2_numpy_fallback_spatial_and_dim_floors, test_person_fit_numpy_fallback,
and test_infit_outfit_numpy_fallback to names describing incomplete-core
fail-closed behavior and their expected RuntimeError. Remove the misleading
NumPy-fallback and dimension-floor wording; preserve any dimension-floor
coverage only in separate native-core tests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d1772f1-994d-496b-ab1c-97b9bb634b4c

📥 Commits

Reviewing files that changed from the base of the PR and between 5231438 and 2a79e97.

⛔ Files ignored due to path filters (3)
  • docs/papers/papers/li-2025-evaluating-scoring-bias-llm-as-a-judge.pdf is excluded by !**/*.pdf
  • docs/papers/papers/pezeshkpour-hruschka-2024-option-order-sensitivity.pdf is excluded by !**/*.pdf
  • docs/papers/papers/sharma-2023-sycophancy.pdf is excluded by !**/*.pdf
📒 Files selected for processing (21)
  • CHANGELOG.md
  • README.md
  • crates/mlsirm-core/src/jmle_opt.rs
  • docs/adr/0013-continuous-execution-and-documentation-governance.md
  • docs/adr/0014-bounded-llm-judge-category-inputs.md
  • docs/adr/README.md
  • docs/changelog.d/783-rubric-iterable-error-boundary.md
  • docs/doctoring/fitstats_sx2_person_rust_required.md
  • docs/doctoring/jmle_optimizer_recovery_evidence.md
  • docs/documentation_coverage.md
  • docs/papers/README.md
  • docs/papers/directive-irt-coverage.md
  • docs/papers/oa-pdf-manifest.md
  • python/fast_mlsirm/llm_judge.py
  • python/fast_mlsirm/rubric/models.py
  • tests/test_cov_c_fitstats.py
  • tests/test_fitstats_infit_outfit_allocations.py
  • tests/test_jmle_optimizer_recovery.py
  • tests/test_llm_judge.py
  • tests/test_llm_judge_description_boundary.py
  • tests/test_rubric_iterable_error_boundary.py
💤 Files with no reviewable changes (1)
  • tests/test_fitstats_infit_outfit_allocations.py

Comment thread crates/mlsirm-core/src/jmle_opt.rs Outdated
Comment thread crates/mlsirm-core/src/jmle_opt.rs Outdated
Comment thread docs/adr/0013-continuous-execution-and-documentation-governance.md Outdated
Comment thread docs/papers/README.md Outdated
Comment thread docs/papers/README.md Outdated
Comment thread tests/test_jmle_optimizer_recovery.py Outdated
@opencode-agent
opencode-agent Bot disabled auto-merge August 12, 2026 11:30
@seonghobae
seonghobae force-pushed the fix/rubric-iterable-redaction-green branch from 2a79e97 to 7a19649 Compare August 12, 2026 11:35
Fail closed on hostile iterable setup/iteration with package-owned
messages while preserving MemoryError. Rebuilt on current main after
@seonghobae
seonghobae force-pushed the fix/rubric-iterable-redaction-green branch from 43245ac to a03bad3 Compare August 12, 2026 18:14

@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 a03bad35a57755394d9eb223951bb263533782c7.

  • Head SHA: a03bad35a57755394d9eb223951bb263533782c7

  • Workflow run: 31632747083

  • 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 (2 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (2 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: 783-rubric-iterable-error-boundary.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: 783-rubric-iterable-error-boundary.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test: test_rubric_iterable_error_boundary.py"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test: test_rubric_iterable_error_boundary.py"]
  R3 --> V3["targeted test run"]
Loading

@opencode-agent

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: a03bad35a57755394d9eb223951bb263533782c7
  • Workflow run: 31632747083
  • 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 a03bad35a57755394d9eb223951bb263533782c7.

  • Head SHA: a03bad35a57755394d9eb223951bb263533782c7

  • Workflow run: 31632747083

  • 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 (2 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (2 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: 783-rubric-iterable-error-boundary.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: 783-rubric-iterable-error-boundary.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test: test_rubric_iterable_error_boundary.py"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test: test_rubric_iterable_error_boundary.py"]
  R3 --> V3["targeted test run"]
Loading

@seonghobae
seonghobae dismissed opencode-agent[bot]’s stale review August 13, 2026 01:22

Dismissing stale coverage-evidence request; required coverage-evidence is green on current tip.

@seonghobae
seonghobae merged commit 21e9774 into main Aug 13, 2026
35 checks passed
@seonghobae
seonghobae deleted the fix/rubric-iterable-redaction-green branch August 13, 2026 01:43
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