DEV Community

Avery Lin
Avery Lin

Posted on

Opinion: AI Review Comments Are Ephemeral — Keep the Ledger Instead

Opinion: AI Review Comments Are Ephemeral — Keep the Ledger Instead

AI code review produces its real value only after the comments disappear, because the durable output is the ledger of decisions rather than the conversation. A comment answers one moment, while a structured record of what the model flagged, what a human accepted, and what slipped through answers the next hundred moments. Teams that treat AI review as a suggestion box lose the only part that compounds, and per-call pricing quietly encourages that loss.

The problem: comments are chat

Most AI review integrations present findings as inline comments, which are excellent for the author and nearly useless for the organization. The author reads the comment, fixes the issue, and the thread closes, while the model's category, severity, and accuracy vanish with it. You cannot measure whether the reviewer improves over time, whether certain file types attract false positives, or whether your team actually acts on the findings. The conversation is ephemeral by design, and that is the wrong design for a system you want to trust.

The position: review as telemetry

My position is that AI review should be treated as telemetry, not as a second opinion, and that the review ledger is the primary deliverable of any AI review pipeline. A ledger entry records the file, the rule category, the severity, the model's confidence, the human verdict, and the patch's eventual fate, which turns scattered comments into a queryable dataset. Once the dataset exists, you can answer questions that no single review can answer, such as which categories waste the most human time and which reviewers silently override the model. The comment is the interface; the ledger is the asset.

Why free tooling changes the calculus

The economics of the tooling determine whether the ledger gets built, because a per-call price makes every review a cost center and every skipped review a small victory. MonkeyCode's free model access and free server option remove that friction, since you can run the reviewer as a shared service without watching a meter. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The workflow below targets the free server option, and the same pattern works with any reviewer that emits structured findings.

A paid reviewer nudges you toward fewer reviews, which is exactly the wrong direction for a system whose value grows with repetition. A free reviewer lets you run the gate on every pull request and lets the ledger accumulate without budget anxiety. That difference in incentive is the real product, and it is why free access is a workflow decision rather than a marketing decision.

The workflow: from comments to corpus

The goal is a pipeline that captures every finding before it disappears, and it takes four steps to build.

  1. Run the reviewer as a service. Start the server once on a small VM or in your CI environment, and treat it as infrastructure rather than a developer tool, because a shared endpoint gives every pull request the same reviewer and the same configuration.
  2. Point CI at the server. Add a job that sends the diff to the server, captures the JSON response, and fails the build only on findings your team has classified as blocking, so the gate stays strict without becoming noisy.
  3. Append every response to a ledger. Use the script below to normalize the server response into one JSONL line per finding, with a human verdict field that the author fills in after the review.
  4. Analyze the ledger monthly. Run the companion script to compute acceptance and false-positive rates per category, then adjust the prompt or the rules based on what the data shows.

The artifact: a review ledger in two scripts

The first script reads a review payload from standard input and appends one line per finding to a JSONL file.

#!/usr/bin/env python3
"""Append AI review findings to a local JSONL ledger."""
import json
import sys
import uuid
from datetime import datetime, timezone


def append_findings(review_payload: dict, ledger_path: str = "review_ledger.jsonl") -> int:
    count = 0
    with open(ledger_path, "a") as ledger:
        for finding in review_payload.get("findings", []):
            entry = {
                "id": str(uuid.uuid4())[:8],
                "ts": datetime.now(timezone.utc).isoformat(),
                "file": finding.get("file"),
                "category": finding.get("category"),
                "severity": finding.get("severity"),
                "confidence": finding.get("confidence"),
                "human_verdict": None,  # filled in by the author after review
                "patch_merged": None,   # filled in when the pull request closes
            }
            ledger.write(json.dumps(entry) + "\n")
            count += 1
    return count


if __name__ == "__main__":
    payload = json.load(sys.stdin)
    print(f"logged {append_findings(payload)} findings")
Enter fullscreen mode Exit fullscreen mode

The second script reads the ledger and reports the distribution of human verdicts per category, which is the fastest signal for a reviewer that cries wolf.

#!/usr/bin/env python3
"""Summarize human verdicts per category from the review ledger."""
import collections
import json
from pathlib import Path

rows = [json.loads(line) for line in Path("review_ledger.jsonl").open()]
by_category = collections.defaultdict(list)
for row in rows:
    by_category[row["category"]].append(row)

for category, items in sorted(by_category.items(), key=lambda kv: -len(kv[1])):
    accepted = sum(1 for i in items if i["human_verdict"] == "accepted")
    rejected = sum(1 for i in items if i["human_verdict"] == "rejected")
    print(f"{category}: {len(items)} findings, {accepted} accepted, {rejected} rejected")
Enter fullscreen mode Exit fullscreen mode

Run the pair from CI with a pipe, and the ledger becomes a byproduct of every review instead of a manual chore.

curl -s -X POST http://localhost:8080/review -d @diff.json | python3 review_ledger.py
Enter fullscreen mode Exit fullscreen mode

When the server beats the ad-hoc call

A decision table keeps the workflow honest about when the shared server is worth the setup.

Situation Recommended path
One-off question about a snippet Ad-hoc local model call
Every pull request needs the same standards Shared free server in CI
You need to audit reviewer accuracy over time Ledger plus monthly analysis
A team member wants findings in the IDE Local call, then log the verdict manually

The pattern is simple: anything you want to compare or audit belongs in the ledger, and anything that feeds the ledger belongs on the shared server.

Limitations and who should skip this

The approach fails when the reviewer's output is unstructured, so the server must emit JSON with stable field names and your parser must tolerate missing fields. The ledger is only as honest as the human_verdict field, which means authors must fill it in, and teams that skip that step end up with a corpus of noise. The workflow is also batch-oriented, so developers who want instant IDE-style feedback will find the ledger loop too slow, and solo developers with a handful of pull requests per month will spend more time on setup than they save. If your team cannot agree on which severities block a merge, fix that policy before you build the pipeline, because the ledger will only expose the disagreement.

If you are already running MonkeyCode's free server, the ledger script drops into the same pipeline in about ten minutes, and the first monthly analysis will tell you more about your reviewer than any single comment ever did.

Top comments (0)