Skip to content

add one-time script to trim score_details_v3 crps_data to totals#274

Closed
Thykof wants to merge 1 commit into
mainfrom
chore/trim-score-details-v3
Closed

add one-time script to trim score_details_v3 crps_data to totals#274
Thykof wants to merge 1 commit into
mainfrom
chore/trim-score-details-v3

Conversation

@Thykof

@Thykof Thykof commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

PR #273 changed the live writer to keep only the per-interval "Total" rows, an aggregate "Gaps"/"Total" row, and the "Overall"/"Total" row in detailed_crps_data, dropping the verbose per-increment entries.

This adds verify/trim_score_details_v3.py to rewrite the historical miner_scores.score_details_v3 rows into that same shape so the column is uniform and far smaller. The aggregate gap total is reconstructed by summing the per-interval "Total" of every interval whose name ends with "_gaps" — the same value the new writer accumulates.

Keyset-paginated by id, idempotent (re-running recomputes the identical list and skips the write), and dry-run by default (--apply to persist).

PR #273 changed the live writer to keep only the per-interval "Total"
rows, an aggregate "Gaps"/"Total" row, and the "Overall"/"Total" row in
detailed_crps_data, dropping the verbose per-increment entries.

This adds verify/trim_score_details_v3.py to rewrite the historical
miner_scores.score_details_v3 rows into that same shape so the column is
uniform and far smaller. The aggregate gap total is reconstructed by
summing the per-interval "Total" of every interval whose name ends with
"_gaps" — the same value the new writer accumulates.

Keyset-paginated by id, idempotent (re-running recomputes the identical
list and skips the write), and dry-run by default (--apply to persist).

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

Copilot AI 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

Adds a one-time, keyset-paginated migration script to shrink historical miner_scores.score_details_v3["crps_data"] to the same “totals-only (+ optional Gaps aggregate + Overall)” shape, plus unit tests for the trimming helper.

Changes:

  • Added verify/trim_score_details_v3.py CLI to scan/update MinerScore.score_details_v3 in batches (dry-run by default, --apply to persist).
  • Implemented trim_crps_data() to drop per-increment entries, keep per-interval Total rows, reconstruct the Gaps aggregate, and keep the final Overall total.
  • Added unit tests for trimming behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
verify/trim_score_details_v3.py Implements the trimming logic and a batch migration runner for historical DB rows.
tests/test_trim_score_details_v3.py Adds unit tests validating trimming order, gap reconstruction, and idempotency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


from synth.db.models import MinerScore, get_engine

load_dotenv()
Comment on lines +36 to +45
def trim_crps_data(crps_data: list[dict]) -> list[dict]:
"""Reduce a verbose ``crps_data`` list to the post-#273 shape.

Keeps the per-interval ``Total`` rows, appends a reconstructed
``Gaps``/``Total`` aggregate, then the ``Overall``/``Total`` row — matching
the order the live writer produces. Error payloads (e.g.
``[{"error": ...}]``) and anything without ``Total`` rows are left as-is.
"""
if not isinstance(crps_data, list):
return crps_data
Comment on lines +55 to +66
gap_total = sum(
d["CRPS"]
for d in totals
if str(d.get("Interval", "")).endswith("_gaps")
)

overall = [d for d in totals if d.get("Interval") == "Overall"]
trimmed = [d for d in totals if d.get("Interval") != "Overall"]
if gap_total > 0:
trimmed.append(
{"Interval": "Gaps", "Increment": "Total", "CRPS": gap_total}
)
Comment on lines +101 to +107
if apply:
for score_id, new_details in updates:
connection.execute(
update(MinerScore)
.where(MinerScore.id == score_id)
.values(score_details_v3=new_details)
)
twice = trim_crps_data(once)

self.assertEqual(once, twice)


Historical rows stored a verbose ``crps_data`` list with one entry per scoring
increment (``Increment`` = 1, 2, 3, ...) alongside the per-interval ``Total``
rows. PR #273 changed the live writer (``crps_calculation.py``) to keep only:
Comment on lines +71 to +73
def main(apply: bool, batch_size: int) -> None:
engine = get_engine()
after_id = 0
@Thykof Thykof marked this pull request as draft June 4, 2026 21:18
@Thykof Thykof closed this Jun 5, 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