Try CodeDelta

The Code Delta ‘Data Centre’: every scan saved in one industry-standard SQL database.

In CodeDelta 2.6.4 · macOS (Apple silicon), Windows, Linux

Versions of source code flowing into a database of lines, statements, additions, deletions and moves, with SQL queries on a screen and a notebook headed Ask anything

Every CodeDelta scan writes its measurements to one SQLite file: projects, scans, per-file churn, the statements behind the diff viewer and AI scores. History, Trend, the executive summary and every comparison read from that file.

Lose the file and the history is gone. The Data Centre backs it up, checks it and shows what it holds.

Download free WHAT IT CAN TELL YOU →

What it can tell you

QuestionAnswer from
What changed in each scan, and by how much?History tab: one row per scan, click for its report.
Is churn falling before the release?Trend tab: CRN_SLOC and CRN_LLOC over time.
What does management need to see?trend: a one-page summary with trend arrows and charts.
Which files keep being reworked?The per-file rows: one per file, per scan.
How have the AI scores moved?The AI scores kept for every AI code scan.
Anything else?Export scans (CSV), or query the file with any SQLite tool.

An example: five years of Erlang/OTP

Erlang is a programming language. Erlang/OTP is its open-source runtime, standard library and tools, originally developed at Ericsson: the platform behind telecom infrastructure and some of the world’s largest messaging systems. More: Scanning Erlang/OTP.

Five releases, 25.0 (May 2022) to 29.0 (May 2026), were scanned in pairs. Releases 26.0 to 29.0 each hold 3.1 to 3.9 million lines of code in 11,000 to 13,200 measured files. The four scans require a 12 MB database space: only measurements are stored, not the original code.

Across the four scans: 2,286,965 churned statements, of which 324,657 are in generated files, so true churn (TRUE_CHURN) is 1,962,308.

Which files changed in every release? 632 of them. The ten with the most churn:

FileKindChurned statements (CRN_LLOC)
lib/stdlib/src/erl_parse.erlGenerated42,752
lib/kernel/test/socket_SUITE.erlHand-written42,027
lib/stdlib/src/unicode_util.erlGenerated26,149
erts/preloaded/src/erlang.erlHand-written9,217
lib/ssl/src/ssl.erlHand-written7,224
lib/kernel/src/socket.erlHand-written5,713
erts/configureGenerated4,876
lib/wx/src/gen/gl.erlGenerated4,269
lib/stdlib/src/gen_statem.erlHand-written4,013
lib/kernel/test/gen_tcp_misc_SUITE.erlHand-written3,837

CodeDelta marks four of them as generated from the stamp in their first lines (erl_parse.erl says it is built from erl_parse.yrl), so their churn counts as generated churn, not true churn.

# files changed in every scan, most churn first sqlite3 otp.db " SELECT f.rel_path, COUNT(*) AS releases, SUM(f.crn_lloc) AS churn FROM file_metrics f JOIN run r ON r.id = f.run_id WHERE r.project_id = (SELECT id FROM project WHERE name = 'Erlang/OTP') AND f.crn_lloc > 0 GROUP BY f.rel_path ORDER BY releases DESC, churn DESC LIMIT 10;"

What was deleted, and when?

ReleaseFiles deletedStatements deleted
OTP 26.0196133,908
OTP 27.02,5801,061,764
OTP 28.014440,559
OTP 29.07511,476
# deleted files per release sqlite3 otp.db " SELECT r.new_label, COUNT(*) AS files, SUM(f.del_lloc) AS statements FROM file_metrics f JOIN run r ON r.id = f.run_id WHERE f.status = 'D' GROUP BY r.id ORDER BY r.id;"

OTP 27.0: what was deleted? Mostly XML documentation: 2,281 of the 2,288 XML files sat in doc/ folders.

Kind of fileFiles deleted
XML2,288
Unclassified text144
Make82
Erlang34
# what: deleted files by kind sqlite3 otp.db " SELECT f.lang, COUNT(*) AS files FROM file_metrics f JOIN run r ON r.id = f.run_id WHERE r.new_label = 'OTP-27.0' AND f.status = 'D' GROUP BY f.lang ORDER BY files DESC LIMIT 4;"

Where? The eight folders with the most deleted files:

FolderFiles deleted
lib/wx729
lib/stdlib228
system/doc167
lib/kernel140
lib/snmp120
erts/doc106
lib/erl_docgen101
lib/common_test94
# where: deleted files by folder (first two levels) sqlite3 otp.db " SELECT substr(f.rel_path, 1, instr(f.rel_path, '/') + instr(substr(f.rel_path, instr(f.rel_path, '/') + 1), '/') - 1) AS folder, COUNT(*) AS files FROM file_metrics f JOIN run r ON r.id = f.run_id WHERE r.new_label = 'OTP-27.0' AND f.status = 'D' GROUP BY folder ORDER BY files DESC LIMIT 8;"

Scanned with CodeDelta 2.6.4 from the release downloads on github.com/erlang/otp.

What can we make for you?

The database already keeps the statements of every scanned version, every file’s measurements in every scan, and every AI score. New tools can be built on it, for example:

We have all the code data. What else do you need? Tell us what we can make for you.

Saved and protected

What it holds

The card shows project names, scans, file measurements, AI scores, size and the last scan. Hover any figure for the details from your own database: each project’s scan count, scans in the last 7 and 30 days, the largest project.

Projects… lists the size of each project. Remove old scans keeps the latest ones and makes a backup first; Compact gives the space back to the disk.

Commands

CommandWhat it does
data-centre infoWhat the database holds, its copies, the next backup.
data-centre checkHealth check.
data-centre backupCheck, then copy now.
data-centre restore --copy N --yesRestore copy N (1 = newest).
data-centre projectsSize of each project.
data-centre remove --project NAME --keep N --yesKeep the latest N scans, after a backup.
data-centre compact --yesGive the space back to the disk.
data-centre export --out FILE.csvOne row per scan.
scan --backup-folder DIR --backup-every weekly --backup-keep 3Backup settings for a command-line scan.

Each command runs as codedelta_server.py data-centre …. Without --yes, restore, remove and compact show what they would do.

Appendix: a fix this page exposed

Creating this page exposed an edge case in the engine, fixed in CodeDelta 2.6.4. Checking the page’s figures meant scanning large public code bases again, and npm/cli 10.9.0 → 11.0.0, scanned three times with nothing changed, gave three different totals: 5,892, 5,894 and 5,896 churned statements.

The cause was huge statements: whole test snapshots, each one statement of more than 64 KB. CodeDelta keeps the first 64 KB of a statement as text. In JavaScript, TypeScript, Dart, Perl, Ada and Oracle PL/SQL the byte after that text was left unset, so two identical statements could compare as different on one run and equal on the next. And in 18 languages a change past the first 64 KB was not counted at all; only the C family had been fixed, in July.

CodeDelta 2.6.4 fingerprints everything past 64 KB in every language, and the same input gives the same result on every run: npm/cli scores 5,887 churned statements every time. A test covering all 18 languages fails on 2.6.3, passes on 2.6.4, and runs before every release. The same exercise taught the engine more generated-file stamps, such as “Generated by GNU Autoconf”, so that output is counted as generated churn, not authored.

All parsing tools have bugs; continuous, extreme testing is how CodeDelta aims to have the fewest. Its test scans include Chromium (43.5 million lines), Erlang/OTP, Kubernetes and FFmpeg. Do other vendors push the boat out like this? Ask them.

Read more

User guide: Data Centre · Management brief · Downloads · Papers

SEE THE RISK. PREVENT THE DISASTER.

Mac, Windows and Linux — or straight into your CI.

Try CodeDelta All tools