Claude Code · Opus 4.6 vs Opus 4.7

Same requirements spec, different model generation (4.6 → 4.7).
Comparison: does the newer model produce better-factored code?

Claude Code (Opus 4.6)
2,003 lines · strict mode · no CSS vars
Claude Code (Opus 4.7)
1,800 lines · no strict · CSS vars
How each dimension was judged during human review — operational definitions & scoring method

Scoring method. Each dimension is a head-to-head. A model "wins" a row when its output meets the operational bar more cleanly than the other. A "tie" means the observable difference is within measurement noise. No weighted average is computed — the takeaway is the shape of wins, not a composite score.

DimensionWhat it measuresSignals for "better"
File sizeTotal lines of the single-file outputFewer lines for the same feature set
Strict modeWhether the JS block opens with 'use strict'Present — flags implicit globals & reserved-word assignment
CSS custom propertiesPresence of --var declarations at :rootMore named variables; fewer repeated hex values
Global state variablesModule-scope let declarations that get mutatedFewer globals; clearer ownership of mutable state
var/let/const disciplineUse of const where rebinding never occurs; absence of varHigher const-to-let ratio; var-free
Code layeringWhether top-to-bottom order reflects dependency orderConstants → state → DOM refs → helpers → logic
Naming qualityIdentifier clarity at the top of the file and in hot pathsFull words; convention held across long generations
Function length (worst case)Line counts of the longest functionsLower P90; fewer functions over 50 lines
Async control flowMax closure/callback nesting in async pipelinesShallower nesting; named helpers over inline lambdas
Magic numbersUnnamed numeric literals in core logic (scoring, AI, timing)Hoisted to named constants or clustered near call sites
Persistence layerOrganization of localStorage accessDedicated load/save module; try/catch without silent fails
Input-handler guard patternRepeated precondition checks across event handlersCentralized guard wrapper; no inline duplication
HTML structureSemantic clarity of the DOM layoutNamed layout sections; logical grouping over flat div-soup

Worked example · Naming quality

LESS CLEAR · FOUND IN 4.6
// deep in the AI scoring code
let topPen = 0;
...
tooltip.innerText =
  'Hght: ' + h + ', Vlly: ' + v;

Abbreviations appear in hot paths late in the file. Signals the model started losing its naming conventions under long-generation context pressure.

CLEARER · FOUND IN 4.7
function evaluateBoardDetailed(board) {
  const heights = columnHeights(board);
  const holes   = countHoles(board);
  const valleys = detectValleys(heights);
  ...
}

Full-word identifiers continue deep into the file. The model is still honoring the naming convention it set up earlier.

Worked example · Async control flow

5 LEVELS DEEP · 4.6
setTimeout(() => {
  const moveToTarget = () => {
    if (x === target.x) {
      setTimeout(() => {
        hardDrop();
      }, delay);
    }
  };
  moveToTarget();
}, delay);

Inline closures nested inside a recursive setTimeout chain. Every level is another thing the reader's eye has to pattern-match.

2 LEVELS DEEP · 4.7
const push = () => {
  if (!autoplayEnabled) return;
  hardDrop();
  spawnNext();
};

setTimeout(push, delay);

Inner logic hoisted into a named helper. Scheduling and body are now separable units.

Dimension Claude Code (Opus 4.6) Claude Code (Opus 4.7) Winner
File size 2,003 lines 1,800 lines Opus 4.7
Strict mode Yes No Opus 4.6
CSS custom properties No — hard-coded panel widths, colors Yes — :root { --bg, --panel, --border, --text } (11–19) Opus 4.7
Global state variables ~25 ~20 Opus 4.7
var/let/const discipline Reassigns const-style initial vars (board at 687 re-bound at 1823) Clean: const for refs/state, let for locals, no var Opus 4.7
Code layering Comment-labelled sections inside one large script block Distinct blocks: constants → state → DOM refs → helpers → logic (616–795) Opus 4.7
Naming quality Cryptic abbreviations in hot paths (e.g. topPen, Hght:, Vlly:) Descriptive identifiers throughout (e.g. randomPieceType, fmtNum, evaluateBoardDetailed) Opus 4.7
Function length (worst case) Longest function ~92 lines (1170–1262) Longest function ~90 lines (769–858) Tie
Async control flow Deeply nested closures and setTimeout chains (1499–1549) Nested closures present but with narrower scope (1403–1446) Opus 4.7
Magic numbers Scattered inline and uncommented in core logic Present, but clustered and closer to call sites Opus 4.7
Persistence layer Clean dedicated module (884–950) Inline with try/catch — silent fails on error Opus 4.6
Input-handler guard pattern Centralized guard wrapper reused by all handlers (1980–1990) Guard clauses duplicated inline per handler Opus 4.6
HTML structure Flat div-heavy Three clearly labelled layout sections; more navigable Opus 4.7

Takeaway: Clear generational improvement. Claude Code (Opus 4.7) wins 9 of 13 rows: smaller, more disciplined, CSS vars, better naming, clearer layering. Claude Code (Opus 4.6) retains only three wins: strict mode, a dedicated persistence module, and a centralized input-handler guard pattern. The newer model trades some safety rails (strict mode) for substantially better factoring.

Quantitative static analysis

Human review judgment is subjective. To pressure-test the qualitative claims above, I extracted the JS from each file, walked the AST with espree, and ran eslint 9 with a shared flat config (complexity ≤ 10, max-depth ≤ 4, max-lines-per-function ≤ 50, no-magic-numbers with [−1, 0, 1, 2] allowed, prefer-const, eqeqeq). CSS metrics were measured by regex on the <style> block. The numbers below either anchor the qualitative findings — or complicate them.

−11.6%
JS lines
1,343 → 1,187
−8.5%
Total ESLint warnings
71 → 65
−17%
Magic-number literals
47 → 39
−50%
Functions > 50 lines
6 → 3
−51%
Hex colour occurrences
51 → 25 · CSS vars absorbed the rest
+76%
Top-level const decls
17 → 30
Metric Opus 4.6 Opus 4.7 Δ Source
JS lines1,3431,187−11.6%wc
CSS lines512470−8.2%regex
CSS custom properties declared07+7regex
Hex colour occurrences in CSS5125−51%regex
'use strict'YesNoregressionregex
Total ESLint warnings7165−8.5%eslint
no-magic-numbers4739−17%eslint
max-lines-per-function43−1eslint
complexity (cyclomatic > 10)79+2eslint
max-depth (> 4)1112+1eslint
eqeqeq (uses of ==/!=)02regressioneslint
Function count (incl. arrows)9297+5%AST
Functions > 50 lines63−50%AST
Longest function (lines)9391−2AST
P90 function length4241−1AST
Max cyclomatic complexity4447+3AST
Median cyclomatic complexity34+1AST
High-complexity functions (>10)812+4AST
Max block-nesting depth (global)1115+4AST
Top-level let declarations3029−1AST
Top-level const declarations1730+76%AST
var declarations anywhere00AST
setTimeout calls65−1AST

Where the automated metrics confirm the human review

Where the automated metrics disagree or nuance the claim

Methodology. JS extracted from each <script> block and parsed with espree (ECMAScript 2022, script mode). Cyclomatic complexity computed per function by walking the AST and counting if / switch case / for / while / catch / && / || / ternary. ESLint 9 run with a flat config; rules above with thresholds: complexity ≤ 10, max-depth ≤ 4, max-lines-per-function ≤ 50, max-nested-callbacks ≤ 3, no-magic-numbers allowing [−1, 0, 1, 2], prefer-const, eqeqeq, no-var. CSS metrics by regex on the <style> block (custom properties = --name:, hex occurrences = #hex, px values = \d+px). Non-functional only — correctness was verified separately with the functional-test suite.