Skip to main content

Release

v0.2.2: Rollback, Bordered Output, and a document Step That Finally Scales

Om SherikarMay 18, 2026

Three things you will notice the moment you upgrade. Bordered boxes everywhere — analyze, run, and dry-run all render structured output instead of running together. A rollback command that actually undoes an apply. And a document step that finishes in minutes instead of dragging on for half an hour on real codebases. All in one release.

Bordered output

The analyze command now renders one bordered box per file, followed by boxed tables for TRANSFORMS, BY TRANSFORM, and SUMMARY. The run --dry-run command matches the pattern with a CHANGES table and a four-sided diff box per modified file. The output reads cleanly in a 200-row terminal scrollback, which is where most evaluation happens.

This is not a cosmetic change. Before v0.2.2, the output of a real run on a real codebase blurred into a wall of unstructured text — file paths bled into diffs bled into summaries, and finding the file you cared about meant searching for a specific path. With the bordered output, each file is a visually distinct unit. You can scan the report and locate the file you want without reading every line.

Rollback

The rollback command finally exists. It performs a journal-based LIFO undo of the most recent run --apply or document --apply operation. Three flags shape its behavior:

  • --all reverts every journaled refactor in sequence, walking back to a clean state.
  • --force skips the drift check, which we will explain in a moment.
  • --dry-run shows what rollback would do without writing.

What rollback does not do: replace git. If you have already committed and pushed the refactor, rollback will not unwind your remote. Rollback is for the in-between state — the state where you have applied a refactor, opened the diff, looked at it, and decided to walk it back before commit. That state is where the previous workflow had no good answer, and where rollback now does.

The drift check is the one piece worth flagging. If a file that the refactor touched has been edited since the refactor was applied, rollback refuses by default. The reason is obvious: if you have edited the file by hand and rollback overwrites it with the pre-refactor version, you lose your edits. Pass --force if you have already inspected the situation and want the rollback anyway.

Live progress on run --apply

The apply step now reports its progress gate by gate, with per-file detail on the verify and apply phases. The refactor runs as a batch first — all files together, all gates together — and falls back to a per-file path only when the batch fails. The per-file fallback isolates the bad file rather than killing the entire refactor over one transform that mis-fired.

The previous behavior was a single spinner that ran for two minutes and then either printed success or a stack trace. The current behavior tells you which gate is running, which file is being verified, and which file just passed apply. When the refactor fails, you know exactly where it failed.

The silent document bug we fixed

The document step had a bug that produced zero docstrings on large files. The cause was a batch sizer that capped only the input tokens. As long as the prompt stayed under the input budget, the batch was sent. But the model's response — the docstrings for every function in the batch — frequently overran the completion-token cap, and the JSON came back truncated. The truncated JSON failed to parse, the batch was discarded, and the document step moved on to the next batch without writing anything.

The fix has two parts. First, batches are now also capped by the projected response size, so the model is never asked to generate more than it can return in a single completion. Second, when a response is truncated despite the cap — model behavior varies, sometimes the projection is off — the response is salvaged entry by entry rather than discarded wholesale. The entries that parsed cleanly are kept; the truncated tail is dropped and the affected functions are retried in a smaller batch.

The cost curve

The document step is no longer O(symbols) — one LLM call per function was the original prototype's behavior and it scaled badly. It is now O(source tokens / batch budget) with bounded concurrency and token-aware rate limiting. On a real codebase — LibCST itself, around 50K Python LOC — that change reduces the number of LLM calls by roughly eight times.

The practical effect: documenting a real codebase used to take twenty minutes or more, with frequent rate-limit stalls. It now finishes in two to three minutes on the same hardware against the same API.

Smaller things you might miss

A handful of fixes and behavior changes that did not warrant their own section:

  • analyze now exits with a non-zero status code when it finds issues. Previously it always exited zero, which made CI integration awkward.
  • A full report is saved to .refactron/reports/ after every run, regardless of whether the run was a dry-run or an apply.
  • run --apply now short-circuits cleanly with an explicit message when no test runner is detected. The previous behavior silently skipped the test gate, which violated the safety contract.
  • The document step no longer produces six-quote docstrings on rare edge cases. The bug was a string-escape issue at the boundary of triple-quoted strings; the fix is in the docstring composer.
  • deprecated_api_requests_to_httpx now refuses files where the requests API is not a safe httpx drop-in. The previous version emitted runtime-broken code in those cases.
  • Report and CHANGELOG paths are normalized to forward slashes on Windows, so links in generated artifacts work in any markdown renderer.

Upgrading

One command:

npm install -g refactron@0.2.3

Python users can upgrade with pip install --upgrade refactron. There are no breaking changes from v0.2.0 or v0.2.1. Existing configuration files continue to work without modification.

v0.2.2ReleaseCLI UXRollbackDocumentation
0 views0 clicks