diff --git a/public/sitemap.xml b/public/sitemap.xml
index 1d27c71..96ff2a1 100644
--- a/public/sitemap.xml
+++ b/public/sitemap.xml
@@ -1 +1 @@
-https://refactron.dev/weekly1.0https://refactron.dev/blogweekly0.9https://refactron.dev/aboutmonthly0.6https://refactron.dev/changelogweekly0.7https://refactron.dev/securitymonthly0.5https://refactron.dev/researchmonthly0.5https://refactron.dev/privacy-policyyearly0.3https://refactron.dev/terms-of-serviceyearly0.3https://refactron.dev/blog/i-ran-refactron-on-djangos-codebasemonthly0.8https://refactron.dev/blog/refactron-vs-cursor-vs-codeantmonthly0.8https://refactron.dev/blog/why-we-built-verification-engine-firstmonthly0.8https://refactron.dev/blog/legacy-code-ai-refactoringmonthly0.8https://refactron.dev/blog/refactron-on-requests-librarymonthly0.8https://refactron.dev/blog/real-cost-of-not-refactoringmonthly0.8https://refactron.dev/blog/refactron-on-fastapimonthly0.8https://refactron.dev/blog/how-to-safely-refactor-python-code-you-didnt-writemonthly0.8https://refactron.dev/blog/why-refactron-runs-locallymonthly0.8https://refactron.dev/blog/refactron-is-now-a-nodejs-packagemonthly0.8
\ No newline at end of file
+https://refactron.dev/weekly1.0https://refactron.dev/blogweekly0.9https://refactron.dev/aboutmonthly0.6https://refactron.dev/changelogweekly0.7https://refactron.dev/securitymonthly0.5https://refactron.dev/researchmonthly0.6https://refactron.dev/research/perf-01yearly0.5https://refactron.dev/research/comparison-01yearly0.5https://refactron.dev/privacy-policyyearly0.3https://refactron.dev/terms-of-serviceyearly0.3https://refactron.dev/blog/i-ran-refactron-on-djangos-codebasemonthly0.8https://refactron.dev/blog/refactron-vs-cursor-vs-codeantmonthly0.8https://refactron.dev/blog/why-we-built-verification-engine-firstmonthly0.8https://refactron.dev/blog/legacy-code-ai-refactoringmonthly0.8https://refactron.dev/blog/refactron-on-requests-librarymonthly0.8https://refactron.dev/blog/real-cost-of-not-refactoringmonthly0.8https://refactron.dev/blog/refactron-on-fastapimonthly0.8https://refactron.dev/blog/how-to-safely-refactor-python-code-you-didnt-writemonthly0.8https://refactron.dev/blog/why-refactron-runs-locallymonthly0.8https://refactron.dev/blog/refactron-is-now-a-nodejs-packagemonthly0.8
\ No newline at end of file
diff --git a/scripts/generate-sitemap.js b/scripts/generate-sitemap.js
index 8e11baf..356c693 100644
--- a/scripts/generate-sitemap.js
+++ b/scripts/generate-sitemap.js
@@ -19,7 +19,9 @@ const staticRoutes = [
{ url: '/about', changefreq: 'monthly', priority: 0.6 },
{ url: '/changelog', changefreq: 'weekly', priority: 0.7 },
{ url: '/security', changefreq: 'monthly', priority: 0.5 },
- { url: '/research', changefreq: 'monthly', priority: 0.45 },
+ { url: '/research', changefreq: 'monthly', priority: 0.6 },
+ { url: '/research/perf-01', changefreq: 'yearly', priority: 0.5 },
+ { url: '/research/comparison-01', changefreq: 'yearly', priority: 0.5 },
{ url: '/privacy-policy', changefreq: 'yearly', priority: 0.3 },
{ url: '/terms-of-service',changefreq: 'yearly', priority: 0.3 },
// blog posts added dynamically below
diff --git a/scripts/prerender.js b/scripts/prerender.js
index 4834909..43c9531 100644
--- a/scripts/prerender.js
+++ b/scripts/prerender.js
@@ -32,6 +32,8 @@ const PAGES = [
'/changelog',
'/security',
'/research',
+ '/research/perf-01',
+ '/research/comparison-01',
'/privacy-policy',
'/terms-of-service',
...blogSlugs.map(slug => `/blog/${slug}`),
diff --git a/src/App.tsx b/src/App.tsx
index c69690b..2472bc6 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -26,12 +26,15 @@ import AuthApp from './components/AuthApp';
import NotFoundPage from './components/NotFoundPage';
import ErrorBoundary from './components/ErrorBoundary';
import SkipToMain from './components/SkipToMain';
+import ScrollToTop from './components/ScrollToTop';
import usePerformanceMonitoring from './hooks/usePerformanceMonitoring';
import useAccessibility from './hooks/useAccessibility';
import PageLayout from './components/PageLayout';
import Changelog from './components/Changelog';
import SecurityPage from './components/SecurityPage';
import ResearchPage from './components/ResearchPage';
+import ResearchPerf01Page from './components/ResearchPerf01Page';
+import ResearchComparison01Page from './components/ResearchComparison01Page';
import StatusPage from './components/StatusPage';
import { ThemeProvider } from './contexts/ThemeContext';
@@ -91,6 +94,7 @@ function App() {
+
{isDocsHost ? (
} />
@@ -161,6 +165,22 @@ function App() {
}
/>
+
+
+
+ }
+ />
+
+
+
+ }
+ />
} />
(
.rfn-die-core { animation: rfn-die-pulse 2.6s ease-in-out infinite; }
`}
- {/* Surrounding mono labels */}
-
+ {/* Surrounding mono labels — sit OUTSIDE the chip body in the safe
+ gutter. Bumped from neutral-600/700 to neutral-400/500 so they
+ actually read against the page bg instead of disappearing. */}
+
+ {/* Bottom-left product label. The chip die above is bright on hover
+ of the eye, so labels need real contrast or they get read as part
+ of the dot grid. */}
+
+
REFACTRON
+
ENGINE
{/* Bottom-right status LEDs — first one pulses (active) */}
@@ -843,13 +847,21 @@ const AboutPage: React.FC = () => {
});
return (
-
+
{/* ─── Hero ────────────────────────────────────────────────────── */}
-
+ {/* Top padding pushes content clear of the fixed navbar (~5rem tall);
+ bottom padding gives the hero room to breathe before section #2. */}
+
{sectionFades}
-
+ Refactron vs the{' '}
+ codemod baseline. A
+ head-to-head.
+
+
+ Two transforms, four other tools, identical inputs. We measured
+ speed, coverage, and safety against the existing
+ deterministic-codemod technology. The result is mixed in exactly
+ the way an honest benchmark should be.
+
+ Refactron is the slowest tool we measured. It is also the only
+ one that is top-coverage on both transforms while never
+ producing a single unsafe rewrite. The two pure codemod tools
+ that ship no verification step run sub-second and write code
+ that does not compile.
+
+
+ That tension is the paper. Speed without verification bought
+ broken code in every cell where it was measured. The benchmark
+ builds on the deterministic-refactoring tradition
+ — behaviour preservation checked, not assumed.
+
+
+
+ {/* 01 · Why */}
+
+ 01 · Why this study
+
The engineering baseline, not the competitors.
+
+ jscodeshift and LibCST are codemod frameworks — you
+ author codemods with them. Comby is a structural search/replace
+ DSL. ESLint --fix is a linter's autofix. None of
+ them is the product a team weighs Refactron against.
+
+
+ But they are the existing technology that performs deterministic
+ source-to-source transformation — exactly what Refactron's
+ engine does. A new approach earns credibility by being measured
+ against the established one on identical inputs. This is
+ "transform + verify versus transform only," not "our product
+ versus theirs."
+
+
+
+ {/* 02 · Setup */}
+
+ 02 · Setup
+
Identical inputs, three axes.
+
+
+
+
+
+
+ Each tool runs the equivalent codemod, authored the way a
+ competent engineer would and committed to the repo for audit.
+ LibCST uses Instagram's reference{' '}
+ ConvertFormatStringCommand
+ ; ESLint runs its stock prefer-const{' '}
+ + no-var rules.
+
+
+ {[
+ {
+ t: 'Speed',
+ d: 'Wall-clock for the whole invocation, process startup included. What a user actually waits for.',
+ },
+ {
+ t: 'Coverage',
+ d: 'Per-site exact classification — correct, missed, wrong, broken — by stable anchor, not line proximity.',
+ },
+ {
+ t: 'Safety',
+ d: "tsc --noEmit / py_compile plus the fixture's own test suite, run against the tool's output.",
+ },
+ ].map(x => (
+
+
+ {x.t}
+
+
{x.d}
+
+ ))}
+
+
+
+ {/* 03 · Results */}
+
+ 03 · Results
+
Coverage and safety move together.
+
+ Figure 1. Correct-rewrite coverage per tool. Bar
+ colour encodes safety — green compiled and passed tests, red
+ did not.
+ >
+ }
+ >
+
+
+
+
+ var → const/let
+
+
+ TypeScript · 126 planted sites
+
+
+
+
+ format → f-string
+
+
+ Python · 108 planted sites
+
+
+
+ Table 1. Median of five runs. Refactron and ESLint
+ convert every site correctly and safely; the pure codemod tools
+ emit dozens of wrong rewrites that fail to compile.
+
+
+
+ {/* 04 · The split */}
+
+ 04 · The split
+
+ Careful tools are safe. Unguarded tools are fast and broken.
+
+
+ Figure 2. Every measured cell, speed against
+ coverage. Safe results (green) sit in a high-coverage band;
+ unsafe results (red) sit below 50%.
+ >
+ }
+ >
+
+
+
+
+ Refactron is top-coverage on both transforms — a tie with
+ ESLint at 100% on var → const/let, an outright
+ win at 99.1% vs LibCST's 57.4% on{' '}
+ format → f-string — and never emits an unsafe
+ rewrite. No other tool here is top-coverage on both.
+
+
+ Refactron is the slowest tool measured — ~8× slower than
+ ESLint on var → const/let. This is not an
+ optimization gap to apologize for; it is the pipeline.
+ Refactron applies a transform, re-parses every changed file,
+ resolves every import, runs the full test suite on a shadow
+ tree, then writes atomically. The 5.22s figure is{' '}
+ that pipeline.
+
+
+
+ The honest claim is not "Refactron is fastest." It is: Refactron
+ is the only tool measured here that never wrote broken code —
+ and that guarantee has a price denominated in seconds.
+
+
+ These are frameworks and linters, not Refactron's commercial
+ alternatives. Cursor, SonarQube, and the LLM tools belong in a
+ separate, categorical study.
+
+
+ Refactron ships ten. These two were chosen for tool overlap,
+ not because they are the hardest cases.
+
+
+ Ten files per transform with planted patterns. Real codebases
+ are messier. The fixtures are published so the methodology can
+ be challenged.
+
+
+ We authored them and committed them for audit. If an expert
+ shows us a better visitor, we rerun and republish.
+
+
+
+
+ {/* 07 · How it was built */}
+
+ 07 · How this benchmark was built
+
It embarrassed us first.
+
+ The first run reported Refactron at 27% coverage on{' '}
+ var → const/let. Investigation found two real bugs
+ in Refactron's own transform — a scope-unaware reference scan
+ and a missed AST node kind. They were fixed (27% → 100%) before
+ publication
+ . The benchmark also caught a precision flaw in
+ its own checker that was miscounting every tool; that was
+ corrected too. A benchmark you publish should be one that has
+ already embarrassed you in private.
+
+
+
+
+
+
+ {/* References */}
+
+ References
+
+
+ Comparison bench — fixtures, per-tool codemods, harness, raw
+ results.{' '}
+
+ github.com/Refactron-ai · bench/comparison
+
+
+
+ Instagram / LibCST. ConvertFormatStringCommand — the
+ reference Python format codemod benchmarked here.
+
+
+ Opdyke, W. F. (1992).{' '}
+ Refactoring Object-Oriented Frameworks. PhD thesis,
+ University of Illinois Urbana-Champaign — the
+ precondition-checking foundation behaviour-preserving
+ refactoring rests on.
+
+
+ The var_to_const_let scope-correctness fix and the
+ printf-grammar percent converter.{' '}
+
+ Refactron_Lib_TS · PR #27
+
+
+
+ Refactron 0.2.0 performance report —{' '}
+
+ research paper #01
+
+ .
+
+
+
+
+ );
+};
+
+export default ResearchComparison01Page;
diff --git a/src/components/ResearchPage.tsx b/src/components/ResearchPage.tsx
index 3f5fd08..bf10758 100644
--- a/src/components/ResearchPage.tsx
+++ b/src/components/ResearchPage.tsx
@@ -1,152 +1,376 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { motion } from 'framer-motion';
-import { Lock, Sparkles } from 'lucide-react';
import useSEO from '../hooks/useSEO';
+/* ─── Tokens shared with ResearchPerf01Page ──────────────────────── */
+
+const eyebrow =
+ 'text-[10px] font-mono uppercase tracking-[0.28em] text-neutral-500';
+
+const fadeUp = {
+ initial: { opacity: 0, y: 18 },
+ whileInView: { opacity: 1, y: 0 },
+ viewport: { once: true, margin: '-80px' },
+ transition: { duration: 0.55 },
+};
+
+/* ─── Paper index ────────────────────────────────────────────────── */
+
+type PaperStatus = 'live' | 'planned';
+
+interface Paper {
+ no: string;
+ status: PaperStatus;
+ date: string;
+ title: string;
+ abstract: string;
+ href?: string;
+ external?: boolean;
+}
+
+const PAPERS: Paper[] = [
+ {
+ no: '01',
+ status: 'live',
+ date: '2026-05-15',
+ title:
+ 'Refactron 0.2.0. A measured look at deterministic refactoring at scale.',
+ abstract:
+ 'Wall-clock benchmarks for analyze, plan, and the 3-gate verifier on synthetic and real Python fixtures. 45% faster on 100k LOC vs the 0.1 baseline. All scripts and raw runs in the public repo.',
+ href: '/research/perf-01',
+ },
+ {
+ no: '02',
+ status: 'live',
+ date: '2026-05-15',
+ title:
+ 'Refactron vs the codemod baseline. A head-to-head on var → const/let and format → f-string.',
+ abstract:
+ 'Two transforms, measured against jscodeshift, Comby, ESLint --fix, and LibCST on identical inputs across speed, coverage, and safety. The unverified codemod tools run sub-second and write code that does not compile; Refactron is the slowest tool measured and the only one that is top-coverage on both transforms while never unsafe.',
+ href: '/research/comparison-01',
+ },
+ {
+ no: '03',
+ status: 'planned',
+ date: 'Target 2026-06',
+ title:
+ 'Legacy patterns in the wild. An empirical survey of the top 100 PyPI packages.',
+ abstract:
+ 'How prevalent are the patterns Refactron transforms target? Which packages would benefit most from a deterministic refactoring pass? Distribution by transform, by package age, and by test coverage.',
+ },
+ {
+ no: '04',
+ status: 'planned',
+ date: 'Target 2026-06',
+ title:
+ 'Cross-file preconditions for callback_to_async_await. A method paper.',
+ abstract:
+ 'Why this transform is the hardest of the ten and how the precondition set is constructed. Walks through the call-graph, the safety constraints, and the cases the transform deliberately refuses.',
+ },
+];
+
+/* ─────────────────────────────────────────────────────────────── */
+
const ResearchPage: React.FC = () => {
useSEO({
title: 'Research | Refactron',
description:
- 'Refactron’s internal research on deterministic refactoring and verification is private today. Public notes, benchmarks, and write-ups are coming soon.',
+ "Refactron's research stream. Performance reports, comparison studies, and method papers on deterministic refactoring with verification-first guarantees.",
canonical: 'https://refactron.dev/research',
robots: 'index, follow',
});
return (
-
-
-
-
- Research
-
-
- We are doing serious work here.
-
- Not everything is ready to share yet.
-
-
-
- Our work on safe, deterministic refactoring, including verification
- design, transform pipelines, and how we benchmark against real
- codebases, is handled as{' '}
- internal research for now.
- Not everything belongs in a landing page; we'll publish what we
- can, when it's ready.
-
+ What we measure,{' '}
+
+ why we measure it, what we found.
+
+
+
+
+ Refactron's thesis is that refactoring belongs to deterministic
+ tools with formal safety guarantees, not to text generators.
+ These papers are how we hold that claim to scrutiny: published
+ benchmarks, published methodology, published source.
+
+ Refactron 0.2.0. A measured look at{' '}
+ deterministic{' '}
+ refactoring at scale.
+
+
+ We measured Refactron 0.2.0 on the work users actually do —
+ analyze a tree, plan a refactor, then verify and apply it. Every
+ number on this page is a wall-clock measurement. Every script that
+ produced it lives in the repo.
+
+
+
+ {/* ═══════════════ TWO-COLUMN: TOC + PAPER BODY ═══════════════ */}
+
+
+ {/* ── Sticky TOC ── */}
+
+
+ {/* ── Paper body ── */}
+
+
+
+ {/* 00 · Abstract */}
+
+ 00 · Abstract
+
+ Refactron 0.2.0 analyzes a 100k-LOC tree in a median 11.13
+ seconds — 45% faster than 0.1.0-beta.2, with run-to-run variance
+ compressed by 65%. On a real Python project the full analyze →
+ plan → apply loop, including the 3-gate verifier running pytest
+ on a shadow tree, completes in roughly five seconds.
+
+
+ This report measures the cost of safety-first deterministic
+ refactoring
+ . Every figure is wall-clock; every harness is
+ public.
+
+ vs 0.1.0-beta.2. Median dropped from 20.58s to 11.13s, and the
+ long-tail variance compressed by 65% — predictable enough to
+ drop into a pre-commit hook.
+
+
+ Figure 1. Every measured run on 100k LOC; the
+ horizontal bar is the median. Both spread and centre
+ collapse from v0.1 to v0.2.
+ >
+ }
+ >
+
+
+
+
+
+
+ {/* 02 · Methodology */}
+
+ 02 · Methodology
+
Reproducible by design.
+
+ Each measurement is the wall-clock real time reported by{' '}
+ /usr/bin/time -p, captured over five runs after a
+ single warm-up. We report median, min, and max — never a single
+ best case. For the apply step, the fixture is freshly copied per
+ iteration because the command mutates the tree.
+
+ Synthetic fixtures generated fresh per run from{' '}
+ bench/gen-fixture.ts
+ — mixed Python and TypeScript with every legacy
+ pattern Refactron's ten transforms target. This isolates the
+ analyze step.
+
+
+
+
+
+ Table 1. Median over five runs. Bars show the spread of
+ all five measured runs; min and max in the same row. Δ% is the
+ v0.1 → v0.2 median improvement.
+
+
+
+ {/* 04 · Pipeline */}
+
+ 04 · The full pipeline
+
Real fixture, real test suite.
+
+ Synthetic numbers isolate the analyze step. Real users run the
+ whole loop. We measure against{' '}
+
+ python-legacy-mini
+
+ — 9 files, 189 LOC, with a pytest suite that
+ exercises every function the transforms touch.
+
+
+ Figure 2. The three pipeline stages and their
+ measured median wall-clock.
+ >
+ }
+ >
+
+
+
+
+
+
+
+
+ Table 2. Median wall-clock per step, five runs each,
+ fresh fixture copy per apply. End-to-end:{' '}
+
+ ~5.2s
+ {' '}
+ from scan to atomically-written refactor.
+
+ Of the 3.38-second apply budget on this fixture, roughly 3s is
+ the test gate — pytest cold-start dominates at 9 files. On
+ larger projects the ratio inverts: the test gate becomes bound
+ by your suite, while plan and verification overhead stay roughly
+ constant.
+
+
+ Figure 3. Every refactor passes three gates before
+ any byte is written. Any failure drops to the rejected state
+ — your tree never changes, so there is nothing to roll back.
+ >
+ }
+ >
+
+
+
+
+ {/* 06 · Discussion */}
+
+ 06 · Discussion
+
What this report does and doesn't claim.
+
+
+ A fair head-to-head against jscodeshift, Comby, and{' '}
+ eslint --fix is its own study — now published as{' '}
+
+ research paper #02
+
+ .
+
+
+ Wall-clock only at v0.2. Peak RSS during the 100k LOC analyze
+ is in the next pass.
+
+
+ Apple M2 only. Linux x86 and Windows numbers when the bench
+ moves into CI.
+
+
+ Fixture generation alone takes ~30s and pushes 8 GB. The bench
+ script supports{' '}
+ SIZES=500000 bash bench/run-bench.sh; we don't
+ publish until we can run it with headroom.
+
+
+ Both bench scripts ship in the public repo. No special hardware,
+ no proprietary fixtures, no telemetry. If your numbers come out
+ meaningfully different on Apple Silicon, please open an issue.
+
+
+
+
+
+
+
+ {/* References */}
+
+ References
+
+
+ Synthetic fixture generator and timing harness.{' '}
+
+ bench/gen-fixture.ts
+
+
+
+ Real Python fixture with pytest suite.{' '}
+
+ fixtures/python-legacy-mini
+
+
+
+ Opdyke, W. F. (1992).{' '}
+ Refactoring Object-Oriented Frameworks. PhD thesis,
+ University of Illinois Urbana-Champaign — the foundation
+ behaviour-preserving refactoring rests on.
+
+
+ Per-file parallelization PR — the source of the 45% win.{' '}
+
+ Refactron_Lib_TS · PR #23
+
+
+
+ Refactron vs the codemod baseline —{' '}
+
+ research paper #02
+
+ .
+
+
+
+
+);
+
+export default ResearchPerf01Page;
diff --git a/src/components/ScrollToTop.tsx b/src/components/ScrollToTop.tsx
new file mode 100644
index 0000000..b114d5d
--- /dev/null
+++ b/src/components/ScrollToTop.tsx
@@ -0,0 +1,28 @@
+import { useEffect } from 'react';
+import { useLocation } from 'react-router-dom';
+
+/**
+ * Scroll the window to the top whenever the route pathname changes.
+ *
+ * React Router does not reset scroll position on navigation by default,
+ * so links from a deep page (e.g. /research) into another page (e.g.
+ * /research/perf-01) inherit the scroll offset of the page that was just
+ * left. Mount this component once inside to fix that.
+ *
+ * If the URL contains a `#hash` we leave scroll alone so in-page anchors
+ * keep working.
+ */
+export const ScrollToTop: React.FC = () => {
+ const { pathname, hash } = useLocation();
+
+ useEffect(() => {
+ if (hash) return;
+ // Use 'auto' (instant) — 'smooth' looks broken on long pages because the
+ // browser scrolls past content before the new page has finished mounting.
+ window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
+ }, [pathname, hash]);
+
+ return null;
+};
+
+export default ScrollToTop;