Skip to content

feat (CritPt): improve AA scoring recovery and add key rotation - #1944

Merged
martinagvilas merged 12 commits into
NVIDIA-NeMo:mainfrom
martinagvilas:mgonzalezvil/FEP1075-critpt-judge-resilience
Jul 13, 2026
Merged

feat (CritPt): improve AA scoring recovery and add key rotation#1944
martinagvilas merged 12 commits into
NVIDIA-NeMo:mainfrom
martinagvilas:mgonzalezvil/FEP1075-critpt-judge-resilience

Conversation

@martinagvilas

Copy link
Copy Markdown
Contributor

Summary

This MR improves CritPt resilience around Artificial Analysis scoring failures.

  • On-disk scoring cache: persist submitted solutions, AA batch responses, and partial metrics for each run.
  • Replay recovery: add resources_servers.critpt.replay to rescore cached submissions later without rerunning inference, if AA key fails.
  • AA key rotation: support multiple AA keys in both live scoring and replay, rotating on rate limits.
  • Run isolation: write each server launch to its own cache subdirectory so independent runs do not share metrics.

Testing

  • python -m pytest resources_servers/critpt/tests/ -q
  • Manual smoke/full CritPt rollout against NVIDIA OpenAI-compatible endpoint
  • Manual replay validation with multiple AA keys

@copy-pr-bot

copy-pr-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

…s; replay tool

Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
…reshed per-batch is sufficient

Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
- Isolate cache files per server launch.
- Anchor relative CRITPT_CACHE_DIR to the repo root.
- Add replay --fire-after support for smoke runs.
- Document replay recovery and add focused tests.

Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
@martinagvilas
martinagvilas force-pushed the mgonzalezvil/FEP1075-critpt-judge-resilience branch from 9cb872a to b7f25bc Compare July 7, 2026 11:12
return key

# ──────────────────────────────────────────────────────────
# Persistence helpers (cache_dir-gated; no-op when unset)

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.

Can we add unit tests for the caching + replay paths?

  1. verify() test with cache_dir set that fires a batch and checks the 3 files get written correctly (submissions.jsonl, aa_responses.jsonl, partial_metrics.json)
  2. main_async() test that seeds a temp cache, checks it skips already-scored submissions and ships only pending batch, returns right exit codes, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. Added unit coverage for both paths:

  • verify() with cache_dir set now fires a mocked batch and asserts submissions.jsonl, aa_responses.jsonl, and partial_metrics.json are written with the expected contents.
  • replay.main_async() now has temp-cache tests for skipping already-scored submissions, shipping only pending batches, and the expected exit codes for success/nothing pending, missing cache, and quota exhaustion.

f"timeout_rate={response.get('timeout_rate')}"
)

print(f"Replay complete. Rejudged {rejudged} batches.")

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.

(non-blocking) This is minor but should we call _refresh_partial_metrics() again here? It might be confusing if a replay results in another incomplete run. We might have to move it out of the resource server class and into the module if so. If it is not worth the effort we can leave it as is since it's mostly cosmetic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point, thanks. I addressed this by moving the metrics refresh logic into a module-level refresh_partial_metrics(cache_dir) helper and reusing it from both the resource server and replay tool.

replay.py now refreshes partial_metrics.json after successful replay completion, and also on quota exhaustion if at least one batch was scored before the 429. That keeps the metrics file aligned with the on-disk submissions.jsonl / aa_responses.jsonl state even after an incomplete replay.

Add unit tests for the on-disk scoring cache and replay paths:
- verify() writes submissions.jsonl, aa_responses.jsonl, and
  partial_metrics.json on a full batch
- replay ships only pending submissions and skips already-scored ones
- replay exit codes: 0 (nothing pending/success), 2 (missing cache),
  3 (AA quota exhausted, no response appended)

Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
Signed-off-by: Martina G. Vilas <mgonzalezvil@nvidia.com>
@martinagvilas
martinagvilas merged commit f58563b into NVIDIA-NeMo:main Jul 13, 2026
8 checks passed
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