Skip to content

feat(scripts): rebuild_log audit script (#288 phase-1c) - #350

Merged
robotrocketscience merged 1 commit into
mainfrom
feat/issue-288-rebuild-log-audit
May 2, 2026
Merged

feat(scripts): rebuild_log audit script (#288 phase-1c)#350
robotrocketscience merged 1 commit into
mainfrom
feat/issue-288-rebuild-log-audit

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented May 2, 2026

Copy link
Copy Markdown
Owner

Phase-1c companion to the merged phase-1a rebuild diagnostic log (#288).

scripts/audit_rebuild_log.py reads per-session rebuild_log JSONL files and prints:

  • pack-rate distribution: mean, p50, p90 of n_packed / n_candidates
  • drop-reason histogram bucketed by prefix (so below_floor:0.40, below_floor:0.41 collapse to below_floor: N)
  • rank distribution of packed rows (surfaces whether the rebuilder typically packs the top candidate or something further down)
  • count of truncated session-files

Reads only — never modifies inputs. Tolerant of malformed JSONL lines (the writer is fail-soft so a partial last line is expected on a crash). Accepts files or directories of *.jsonl.

Tests cover: summary maths (records, pack-rate, packed ranks, drop-reason counts), truncated-marker accounting, missing pack_summary tolerance, drop-reason prefix bucketing, malformed-line skipping, directory expansion, percentile maths, and CLI exit codes (0 on summary, 1 on no-input).

Closes the phase-1 implementation tracker for #288. Phase 2 (fixed-corpus precision harness) blocks on a week of operator-collected logs per the ratified spec at docs/rebuild_eval_harness.md.

Summary by Sourcery

Add a CLI script to audit rebuild_log JSONL session files and report aggregate packing and drop statistics.

New Features:

  • Introduce scripts/audit_rebuild_log.py to summarise rebuild_log JSONL files across one or more paths.
  • Expose a command-line interface that reads JSONL files or directories, aggregates metrics, and prints a human-readable audit report.

Tests:

  • Add unit tests covering summary calculations, drop-reason bucketing, JSONL iteration with malformed-line tolerance, directory expansion, percentile computation, and CLI exit codes.

Reads per-session rebuild_log JSONL files (output of phase-1a) and
prints a summary: pack-rate distribution (mean / p50 / p90), drop-
reason histogram bucketed by prefix (so below_floor:0.40 and
below_floor:0.41 collapse), and the rank distribution of packed rows.
Reads only — never modifies inputs. Tolerant of malformed JSONL lines
(the writer is fail-soft so partial last lines are expected).

Closes the phase-1 implementation tracker for #288. Phase 2 (fixed-
corpus precision harness) blocks on a week of operator-collected logs
per the ratified spec.
@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@robotrocketscience has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 39 minutes and 6 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 479c7f52-a02a-46d0-8a9b-6678fe6e15e4

📥 Commits

Reviewing files that changed from the base of the PR and between 2182350 and 38f7952.

📒 Files selected for processing (2)
  • scripts/audit_rebuild_log.py
  • tests/test_audit_rebuild_log.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-288-rebuild-log-audit

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
Review rate limit: 0/1 reviews remaining, refill in 39 minutes and 6 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai

sourcery-ai Bot commented May 2, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a standalone audit script and its tests for summarising rebuild_log JSONL files, including pack-rate stats, drop-reason bucketing, packed-rank distribution, truncated-session counting, and a small CLI wrapper with robust file handling and malformed-line tolerance.

Sequence diagram for audit_rebuild_log CLI execution flow

sequenceDiagram
    actor Developer
    participant audit_rebuild_log_py as audit_rebuild_log_py
    participant argparse_module as argparse
    participant file_system as filesystem
    participant summariser as summariser

    Developer->>audit_rebuild_log_py: invoke with paths
    audit_rebuild_log_py->>argparse_module: parse_args(argv)
    argparse_module-->>audit_rebuild_log_py: args.paths

    audit_rebuild_log_py->>file_system: _collect_paths(paths)
    file_system-->>audit_rebuild_log_py: list_of_jsonl_paths

    alt no_paths
        audit_rebuild_log_py-->>Developer: exit code 1 (no readable input)
    else have_paths
        loop for each path
            audit_rebuild_log_py->>file_system: _iter_records(path)
            file_system-->>audit_rebuild_log_py: decoded_records (malformed lines skipped)
        end

        audit_rebuild_log_py->>summariser: _summarise(all_records)
        summariser-->>audit_rebuild_log_py: summary_dict

        audit_rebuild_log_py->>audit_rebuild_log_py: _print_report(summary_dict, paths_read)
        audit_rebuild_log_py-->>Developer: exit code 0 (summary printed)
    end
Loading

Class diagram for audit_rebuild_log script structure

classDiagram
    class AuditRebuildLogScript {
        +_iter_records(path: Path) Iterable_dict
        +_collect_paths(targets: list_Path) list_Path
        +_percentile(values: list_float, p: float) float
        +_summarise(records: list_dict) dict
        +_bucketise_drop_reasons(reasons: Counter_str) Counter_str
        +_print_report(summary: dict, paths_read: int) void
        +main(argv: list_str) int
    }

    class Path
    class Counter_str {
        +__getitem__(key: str) int
        +items() Iterable_tuple_str_int
        +most_common() list_tuple_str_int
    }

    AuditRebuildLogScript --> Path : uses
    AuditRebuildLogScript --> Counter_str : uses
Loading

File-Level Changes

Change Details Files
Introduce audit_rebuild_log CLI script to summarise rebuild_log JSONL files with robust parsing and aggregation logic.
  • Implement _iter_records to read JSONL files safely, skipping unreadable files and malformed JSON lines.
  • Implement _collect_paths to accept files or directories and expand directories into *.jsonl file lists while warning on non-existent targets.
  • Compute summary statistics in _summarise, including record counts, truncated markers, pack-rate distribution (mean/p50/p90 via _percentile), drop-reason counts, and packed-rank histogram.
  • Group raw drop-reason strings by prefix with _bucketise_drop_reasons, and render a human-readable report in _print_report.
  • Wire everything into a main() that parses CLI args, enforces at least one readable input (exit 1 otherwise), and prints the summary (exit 0 on success).
scripts/audit_rebuild_log.py
Add unit tests validating the audit script’s summarisation, bucketing, file handling, percentile logic, and CLI behaviour.
  • Dynamically load the audit_rebuild_log module from scripts/ to test its internals without packaging changes.
  • Provide helper builders for records, packed/dropped candidates, and JSONL file writing to create realistic test fixtures.
  • Test _summarise’s handling of normal records, truncated markers, and records missing pack_summary while still tracking packed ranks.
  • Verify _bucketise_drop_reasons collapses reasons on the prefix before ':' to avoid histogram fragmentation.
  • Ensure _iter_records skips malformed/blank lines, _collect_paths expands directories to *.jsonl only, and main() returns correct exit codes and emits expected summary text and percentile behaviour.
tests/test_audit_rebuild_log.py

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@robotrocketscience robotrocketscience added attn:review Needs review (PR open, awaiting reviewer) author-Setr PR coordination mutex labels May 2, 2026
from __future__ import annotations

import importlib.util
import io
import importlib.util
import io
import json
import sys

@sourcery-ai sourcery-ai 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.

Hey - I've found 1 issue, and left some high level feedback:

  • Both _iter_records and main currently materialize entire files / record sets into memory; consider iterating over file handles line-by-line and streaming records into _summarise (or making _summarise accept an iterator) to keep memory usage bounded for large rebuild logs.
  • _iter_recordsusesPath.read_text()andsplitlines()which lose line-offset context and load the entire file; switching towith path.open() as fand iteratingfor line in f` would be more efficient and avoid holding large JSONL files in memory.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Both `_iter_records` and `main` currently materialize entire files / record sets into memory; consider iterating over file handles line-by-line and streaming records into `_summarise` (or making `_summarise` accept an iterator) to keep memory usage bounded for large rebuild logs.
- _iter_records` uses `Path.read_text()` and `splitlines()` which lose line-offset context and load the entire file; switching to `with path.open() as f` and iterating `for line in f` would be more efficient and avoid holding large JSONL files in memory.

## Individual Comments

### Comment 1
<location path="scripts/audit_rebuild_log.py" line_range="73" />
<code_context>
+    return out
+
+
+def _percentile(values: list[float], p: float) -> float:
+    """Nearest-rank percentile. Empty -> 0.0."""
+    if not values:
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Percentile implementation doesn’t match standard nearest-rank definition and may behave unexpectedly at extremes.

The implementation uses `int(round((p/100) * (n-1)))`, which is a rounded, linearly-scaled index rather than conventional nearest-rank. Standard nearest-rank for p∈(0,100] is based on `ceil(p/100 * n)` (index `ceil(p/100 * n) - 1`). If percentile behavior is important for diagnostics, consider switching to the standard formula and explicitly defining behavior for p=0 and empty input to avoid surprising results.

Suggested implementation:

```python
def _percentile(values: list[float], p: float) -> float:
    """Nearest-rank percentile.

    Uses the standard nearest-rank definition for 0 < p <= 100:
      rank = ceil(p / 100 * n), index = rank - 1

    Special cases:
      - Empty input -> 0.0
      - p <= 0 -> minimum value
      - p >= 100 -> maximum value
    """
    if not values:
        return 0.0

    s = sorted(values)
    n = len(s)

    if p <= 0:
        return s[0]
    if p >= 100:
        return s[-1]

    rank = math.ceil((p / 100.0) * n)
    index = min(max(rank - 1, 0), n - 1)
    return s[index]

```

The updated implementation uses `math.ceil`, so ensure `math` is imported at the top of `scripts/audit_rebuild_log.py`:

- Add `import math` alongside other imports (or reuse an existing `math` import if already present).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

return out


def _percentile(values: list[float], p: float) -> float:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Percentile implementation doesn’t match standard nearest-rank definition and may behave unexpectedly at extremes.

The implementation uses int(round((p/100) * (n-1))), which is a rounded, linearly-scaled index rather than conventional nearest-rank. Standard nearest-rank for p∈(0,100] is based on ceil(p/100 * n) (index ceil(p/100 * n) - 1). If percentile behavior is important for diagnostics, consider switching to the standard formula and explicitly defining behavior for p=0 and empty input to avoid surprising results.

Suggested implementation:

def _percentile(values: list[float], p: float) -> float:
    """Nearest-rank percentile.

    Uses the standard nearest-rank definition for 0 < p <= 100:
      rank = ceil(p / 100 * n), index = rank - 1

    Special cases:
      - Empty input -> 0.0
      - p <= 0 -> minimum value
      - p >= 100 -> maximum value
    """
    if not values:
        return 0.0

    s = sorted(values)
    n = len(s)

    if p <= 0:
        return s[0]
    if p >= 100:
        return s[-1]

    rank = math.ceil((p / 100.0) * n)
    index = min(max(rank - 1, 0), n - 1)
    return s[index]

The updated implementation uses math.ceil, so ensure math is imported at the top of scripts/audit_rebuild_log.py:

  • Add import math alongside other imports (or reuse an existing math import if already present).

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Toug:2026-05-02T19:40:28Z]

@robotrocketscience
robotrocketscience merged commit 38f7952 into main May 2, 2026
22 checks passed
@robotrocketscience
robotrocketscience deleted the feat/issue-288-rebuild-log-audit branch May 2, 2026 19:41
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Toug:2026-05-02T19:41:10Z]

@robotrocketscience robotrocketscience removed the attn:review Needs review (PR open, awaiting reviewer) label May 2, 2026
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Kulili:2026-05-02T19:41:27Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Kulili:2026-05-02T19:42:14Z]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author-Setr PR coordination mutex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants