A million tokens of context changed less about coding than the price cut did

A million tokens of context changed less about coding than the price cut did

On this page

    Two things happened to frontier models in 2026 that got very different amounts of attention. Context windows reached one million tokens, which got a lot. Prices fell by around eighty percent on several frontier models, which got less.

    The second one changed my work substantially. The first one mostly did not, and the reason is worth spelling out, because it says something about where the actual constraint sits.

    What a million tokens does not solve

    The pitch for a huge context window is that you can put an entire codebase into a single prompt. That is true, and I have done it, and the result is usually worse than a well-chosen twenty thousand tokens.

    Ad space, reserved

    Relevance does not scale with volume. If you paste an entire WordPress plugin into context to ask why one function returns null, you have not given the model more information about that function. You have given it several hundred opportunities to notice something else. The signal you care about is now a smaller fraction of what it is reading.

    The practical version: when I am debugging, the most useful thing I do is decide what to leave out. That skill did not get less important when the window grew. It got more important, because the tooling stopped forcing me to do it.

    Where the big window genuinely helps

    There is one category where it is transformative, and it is not writing code. It is answering questions about a system that has no single owner.

    Where is this option actually read? Which of these forty template files produces this markup? Is this function called from anywhere, or is it dead? Those are questions where the answer requires having seen everything, and where a human would spend an hour grepping. Those got dramatically better.

    So the distinction is roughly this. Large context is good at questions of the form where and whether, and no better than before at questions of the form why.

    Why the price cut mattered more

    An eighty percent price reduction does not make any individual call better. It changes which calls you are willing to make at all.

    At the old prices, running a model over every commit was an expense you had to justify. At the new ones it is cheaper than the CI minutes it runs alongside. That moves a whole class of work from occasional and manual to automatic and boring, which is where useful tooling actually lives.

    Here is a small thing I now run on every diff rather than on request. It is deliberately unclever: it collects only the files a diff touched, and refuses to grow past a budget.

    // build-review-context.js
    // Collect only what a diff touched, and stop at a hard budget.
    
    import { execSync } from 'node:child_process';
    import { readFileSync, statSync } from 'node:fs';
    
    const BUDGET_CHARS = 60000; // roughly 15k tokens, deliberately small
    const SKIP = /.(png|jpe?g|gif|svg|webp|woff2?|zip|min.js|min.css)$/i;
    
    function changedFiles(base) {
      const out = execSync('git diff --name-only ' + base + '...HEAD', { encoding: 'utf8' });
      return out
        .split('n')
        .map(function (s) { return s.trim(); })
        .filter(Boolean)
        .filter(function (f) { return !SKIP.test(f); });
    }
    
    export function buildContext(base) {
      const files = changedFiles(base || 'origin/main');
      const parts = [];
      const skipped = [];
      let used = 0;
    
      for (const file of files) {
        let size;
        try {
          size = statSync(file).size;
        } catch (e) {
          continue; // deleted in this diff
        }
    
        if (used + size > BUDGET_CHARS) {
          skipped.push(file);
          continue;
        }
    
        parts.push('--- ' + file + ' ---' + readFileSync(file, 'utf8'));
        used += size;
      }
    
      return { context: parts.join('nn'), usedChars: used, skipped: skipped };
    }

    The important line is the one that pushes a file into skipped rather than growing the payload. Returning that list matters too. A review that silently ignored four files is worse than no review, because you will trust it.

    Agents changed the failure mode, not the failure rate

    The other shift this year is agentic tooling. Claude Code, Copilot agent mode, and Cursor will read a codebase, plan a change across several files, run the tests, and iterate on failures without being prompted at each step.

    This is real and useful. What I did not expect is how it changes what going wrong looks like. A model that writes one bad function gives you one bad function, and you notice, because you are reading it. An agent that makes twelve coordinated edits gives you something that looks finished. The bad one is buried among eleven good ones, and the surrounding correctness is exactly what stops you looking closely.

    I learned this the direct way. An agent working on this site wrote a theme file across several sequential appends. One append did not complete. The file was left mid-statement, the site returned a fatal error on every route, and the interface being used to fix it ran through the same broken WordPress install.

    Nothing malfunctioned. Each individual step did what it said. The mistake was structural: a sequence of writes where every intermediate state is invalid, and no check between them. The fix is not better prompting. It is writing to a temporary path, validating, and renaming into place, so the live file goes from one valid state to another in a single operation.

    // Never let a live PHP file exist in a half-written state.
    
    $target = get_stylesheet_directory() . '/functions.php';
    $tmp    = $target . '.tmp';
    
    file_put_contents( $tmp, $new_source );
    
    try {
        // Throws ParseError on invalid syntax, without executing anything.
        token_get_all( file_get_contents( $tmp ), TOKEN_PARSE );
    } catch ( ParseError $e ) {
        unlink( $tmp );
        throw new RuntimeException( 'Refusing to install: ' . $e->getMessage() );
    }
    
    rename( $tmp, $target ); // atomic on the same filesystem

    That token_get_all call with the TOKEN_PARSE flag is worth knowing generally. It parses without executing, so you can validate generated PHP before it becomes loadable code. It is the cheapest safety check available and almost nobody uses it.

    A footnote on publishing this post

    This article would not save. It went through the block editor pipeline three times and came back empty each time, while three other posts written in the same session saved without trouble.

    The editor reported success on every attempt. The content simply was not there afterwards. In the end it had to be written straight to the database, bypassing the editor save path entirely.

    Which is the same lesson as the rest of the post. The dangerous failures are not the ones that throw errors. They are the ones that return a success code and quietly do nothing.

    What I would tell someone starting now

    Do not chase the context number. Chase the cost, because cost determines whether you can afford to run something on every change instead of when you remember to.

    And assume anything writing files on your behalf will fail partway at some point. Design for the partial failure now, while the stakes are a personal blog, rather than later.

    Sources

    Ad space, reserved

    Similar Posts

    Leave a Reply

    Your email address will not be published. Required fields are marked *