There is a particular kind of engineer right now who measures their day in token throughput, runs a dozen agents in parallel, checks their state on the phone and feels genuine anxiety when they have unused compute at month-end. They have not debugged by hand in months, their CLI tokens and passwords to systems long expired. They feel faster than ever. They are almost certainly wrong about that last part, and the cost of being wrong is compounding in ways that will not be visible until it matters most.
This is about that engineer. It might be you. It might be half of your team.
The Term Everyone Has Borrowed
“AI psychosis” - yes, that one. You have heard it. Semi-official definition: the triggering or amplification of existing mental health conditions through sycophantic AI feedback loops. Real people, real harm, caused by software designed to flatter and validate without limits. That definition matters and should not be diluted.
What happened is that the phrase got borrowed, and with enough credibility that it stuck. We all hear the stories: I have not written a single line of code since X. I have 16-hour work days just orchestrating agent swarms. Genuine anxiety, though.
And those are not random voices on the internet. These are the people your engineers look up to. They are framing sleep deprivation, compulsive tool usage, and inability to stop as evidence of being at the frontier. As something to aspire to rather than something to correct. That is the cultural transmission vector. That is why you are seeing it in your teams. I feel it myself, quite often.
The Data That Should Have Killed The Narrative
There was a rigorous randomised controlled trial: 16 experienced open-source developers, 246 tasks, half with AI tools available and half without. Before the study, developers predicted AI would make them 24% faster. After completing it, they estimated they had been 20% faster.
They were actually slower. Measurably, significantly, and without knowing it. This is the most important finding in the study and the least discussed: the perception gap.
Developers on high-AI-adoption teams touch 10% more tasks and 50% more pull requests per day. For most of engineering history, that pattern of high context switching and high task fragmentation has been a negative indicator correlated with cognitive overload. In 2025 we rebranded it as “throughput” and called it progress.
The more precise explanation for the productivity paradox is not that AI makes engineers slower. It is that AI makes engineers differently busy in ways that do not show up as business value.
Engineers hit genuine velocity on greenfield work and immediately fill the freed time with the backlog that was never prioritised: tech debt, undocumented behaviour, refactoring deferred for eighteen months. All legitimate. All genuinely valuable. None of it net new capability delivery. The business looks at its AI investment and sees the same feature throughput, a slightly cleaner codebase, and an ROI slide that does not close. There is a reason for this. AI tooling lowers the activation energy for previously invisible work. Tech debt persists in backlogs forever because starting it is hard: understand the mess, devise the approach, write the boilerplate. AI removes that friction. Suddenly the refactor that felt impossible feels approachable. So it gets done. Nobody budgeted for it, nobody is measuring it, and its value is entirely negative-space, a “things that did not break later” column that does not survive a quarterly review.
My take on the AI versus ROI debate is this: AI did not increase output, just yet. It changed what output gets produced.
The organisations winning on AI ROI are the ones who deliberately redirected the freed capacity. Who said explicitly: we will use this to ship X by date Y, and held that as a constraint. Not the ones who let engineers self-direct into available work, which will always trend towards the satisfying and invisible. AI produces redirect-able capacity, not additive capacity. Redirection requires intent. Intent requires someone making a deliberate choice. Which turns out to be the same constraint we will keep returning to throughout this writeup.
The AI-JIT Thought Experiment
Set the empirical debates aside and run the following thought experiment.
Assume the inference cost of generating software is lower than the cost of compiling it. Accuracy is 99% or better. Tokens are effectively free and you pay only for latency. We are good at building resilient systems from unreliable components. Distributed systems taught us that much.
Given all of this: now what?
The first question worth asking is what the SDLC was actually for. Requirements exist because humans forget. Tests exist because code rots and humans make mistakes. Code review exists because one person’s judgment is insufficient and knowledge needs to spread. CI/CD exists because integration is expensive. Documentation exists because context decays.
If AI-JIT generation is cheap, most of those rationales weaken considerably. But not all of them. The ones that survive are the interesting ones.
Intent specification survives and becomes the entire job. The requirements document was always a proxy for intent. In the AI-JIT world it becomes the only durable artefact. The problem is that requirements are hard not because writing them down is hard, but because humans do not fully know what they want until they see what they do not want. That is not a tooling problem. AI-JIT generation accelerates the feedback loop, which helps. The loop still exists.
The 1% failure rate is not what you think. We know how to build resilient systems from unreliable components, but those failure modes are characterisable. A node goes down. A network partitions. You can reason about the failure envelope and design around it. A 99%-accurate AI-JIT-generated behaviour has a failure mode that is semantically unpredictable. The 1% is not random noise. It is correlated with edge cases, novel inputs, and precisely the conditions where correctness matters most. That is qualitatively different from a flaky network link, and the engineering intuitions that work for one do not transfer to the other.
Audit, compliance, and liability do not go away. Who owns the behaviour of an AI-JIT-generated system that caused a financial loss? A medical error? The ability to say “this is exactly what ran at 14:32:07 on 3rd March” is a legal requirement in regulated industries. Ephemeral generation breaks that requirement by default, and the proposed solution to this problem is more interesting than it first appears.
The attack surface moves rather than shrinks. You no longer attack the code. You attack the prompt context, the intent specification, the training distribution. Prompt injection, today a nuisance, becomes the primary attack vector in an AI-JIT world. The threat model needs rebuilding from the specification layer down.
Why The Obvious Audit Design Breaks
The naive audit model for an AI-JIT world looks reasonable at first glance. Hash the spec. Hash the generated code. Hash the inputs and outputs. Chain them together. Tamper-evident, reproducible, done.
Well, In the AI-JIT world, the code is almost always different. Same spec, different code, every run. Hardware variance, batching differences, and floating point ordering all introduce drift. The hash of the code is not a stable identity. It is noise.
Repeatable builds, as a concept, may simply not survive the AI-JIT era. The classical guarantee of same source, same binary, always, assumed a deterministic compilation step. That assumption is gone. Trying to preserve it in a generative world is like insisting on a mutex in a distributed system: the abstraction is fighting the underlying reality.
The anchor the audit chain actually needs is this: stop hashing the code and start hashing the behaviour.
Code is an implementation detail. It always was. What regulators care about, what consistency protocols care about, what post-incident reviews care about is observable behaviour. Does the system do what the spec said it would do, repeatably, verifiably, independent of which code instantiation is currently running?
The stable artefact is the behavioural contract: the explicit, verifiable statement of what the system must accept, must produce, must guarantee, and must refuse. That is deterministic. It is derived from the spec through reduction, not generation. Different code variants are simply different valid instantiations of the same contract. The audit record anchors to intent, not implementation.
The record then says: at time T, spec S produced contract C. Input I produced output O. Output O was verified to satisfy contract C. Code never appears in the audit trail. Code is a transient execution vehicle, not an auditable artefact. This is a stronger guarantee than the classical model, not a weaker one, because you are auditing intent satisfaction rather than binary reproducibility, which is what audits actually care about but could never easily measure before.
One hard problem remains. Contracts themselves drift. Business rules change. Regulations change. The solution is to treat contracts as an event log: immutable, versioned, append-only, so that any audit record can always be read against the contract version that was current when it was generated. The specs and contracts are the durable history. The code is an ephemeral projection of that history at a point in time. The log is the truth. The code is just the current materialised view.
The Haskell Slide
At some point in any open conversation about specification precision, someone asks: why not just write it in Haskell? The question sounds like a troll. It is only partially a troll.
Haskell’s type system is the closest thing mainstream programming has to an executable formal specification. A Haskell type signature does not document intent; it constrains the possibility space of valid implementations. The compiler rejects entire categories of semantic error before runtime exists. Requirements ambiguity shrinks considerably when your specification is expressed in a language where “subject to interpretation” has a checkable meaning.
Haskell’s purity gives you something else: referential transparency by default. Same inputs, same outputs, guaranteed. The hash chain that breaks in an imperative world becomes reproducible. The non-determinism problem that poisons the naive audit model largely dissolves in the pure functional core.
The architecture this implies is real and worth taking seriously. The human writes precise types as the specification layer. The AI-JIT system generates implementations that satisfy those types. The compiler rejects everything that does not. The IO boundary, where the system meets the real world, is kept minimal and explicitly logged. The type signature is the contract. The compiler is the consistency protocol.
Why this does not fully solve it? A perfectly type-correct Haskell function can charge the wrong account, sort a list in the wrong order, or violate a business rule that was never encoded in the type. At that point you are writing formal specifications, which is harder than writing Haskell, which is already harder than writing Python.
Which is the real point. The tools to do this correctly have existed for decades. The formal specification layer is available and has been available. The market has consistently chosen the faster wrong answer over the slower right one. That choice is not changing because LLMs arrived. It is only accelerating.
The Constraint That Never Goes Away
Back to reality from this experiment. The binding constraint in the AI-JIT software world is not compute, nor power. Compute scales horizontally. Power scales too, just slower. You can buy more tomorrow.
The binding constraint is talent, specifically the capacity and ability to evaluate whether what was generated is correct, whether the spec captured what was intended, whether the system being built is the right system to be building at all. That capacity does not scale with hardware. It accumulates slowly, through deliberate practice, through time spent in the failure space developing the pattern recognition that distinguishes “this output is plausible” from “this output is correct.”
The uncomfortable implication: AI tooling is most valuable in the hands of the most talented engineers, because they have the evaluation depth to use it correctly. It is most dangerous in others. The technology amplifies the talent gap rather than compressing it. This is the precise opposite of the democratisation narrative the market is selling. And that is why we all are back to hiring senior talent.
There is also the loop that closed-loop advocates consistently underestimate. A self-correcting system corrects towards a fixed objective. The objective itself drifts. Business rules change. Regulations change. Products pivot.
Who detects that the old constraints are now wrong? Who updates the intent specification when the world it was modelling has moved? That is not a software problem, and it requires humans with domain context, judgment, and accountability. None of those can be generated on demand.
SaaS in a box. Closed loop. Self-correcting. The answer is still no. The loop that does not close is the human one.
Why Slow Is Good
Speed is not the scarce resource. In the AI-JIT world it becomes almost irrelevant. The scarce resource is judgment, and judgment atrophies when not exercised. This is not metaphor. It is how cognitive skills work.
The engineers spending sixteen hours a day in generation loops are actively degrading the one capability that the AI-JIT world makes more valuable, not less. The evaluation muscle weakens through disuse, and you do not notice it weakening until you need it under pressure: in an incident, in an architecture review, in a moment where there is no prompt to fall back on.
Slow is good because slow builds that muscle. Debugging without assistance, reading an unfamiliar implementation critically: these are not nostalgia exercises. They are the training regime for the judgment that separates an engineer who can evaluate agent output from one who can only generate it.
Slow forces specification precision. When generation is fast, the temptation is to iterate towards correctness rather than specify towards it. Rapid iteration feels like progress. It is often just expensive search through the wrong part of the solution space, producing cognitive debt that compounds silently until you are three weeks into a project you cannot remember why you started.
Slow exposes failure modes. You develop a nose for it only by spending time in the failure space: reading the wrong outputs, understanding why they are wrong, building the pattern recognition that eventually lets you evaluate at speed without losing accuracy.
Slow preserves reasoning. A decision made slowly leaves artefacts: notes, comments, architecture decision records, the working-out that explains the why. A decision made fast in a generation loop leaves a prompt and a hash. The reasoning is gone. In regulated environments, in post-incident reviews, in the architecture discussion three years from now, the reasoning is what matters.
How to Detect This in Your Team?
The signal is not enthusiasm. Enthusiasm for new tooling is healthy and worth encouraging. The signal is substitution.
Watch for tool-first problem framing. “We should use an agent for this” before anyone has asked what “this” actually is. The same pattern as “we should put it in the cloud” in 2013. The technology arrived before the requirement.
Watch for token burn without artefacts. Extensive prompting, visible iteration, nothing shippable at sprint end. The loop has become the product. When you ask what they built, they describe what they explored.
Watch for demo anxiety: the compulsion to show AI-augmented workflow in standups. The performance as a substitute for output.
Watch for justification inflation. “This is where the industry is going” is not an engineering decision. The decision was made from FOMO and backfilled with reasoning.
Watch for framework half-life decay: context-switching to a new framework every few sprints. Each new framework resets the learning clock and feels like progress. Remember the “no new frameworks were introduced during this project” mantra.
Watch for the velocity illusion. Everybody feels faster. They will tell you confidently they are faster. The data says this perception is systematically wrong for experienced engineers in familiar codebases. Do not argue with the subjective experience. Measure actual cycle time and defect rate. The gap between felt velocity and measured velocity is the diagnostic.
The tell that cuts deepest: ask an engineer to do something without the tool. Debug manually. Read a codebase cold. Explain a system architecture without generating a diagram first. If the response is genuine uncertainty rather than mild inconvenience, that is not inefficiency. That is atrophy. The capability loss is already structural, not merely behavioural.
The reason formal specification does not happen at scale is not technical. The reason is that the market consistently chooses the faster partially correct answer over the slower right one.
That dynamic drove every hype cycle before this one. Each time: cargo-cult adoption, activity mistaken for progress, post-mortems concluding “we need better requirements.” Each time, the useful thing and the shiny thing had a significant lag between them, and the engineers who understood that lag had better outcomes than the ones who did not.
The engineers who will have the actual moat in the AI-JIT era are not the ones maximising token throughput. They are the ones who can evaluate what the tokens produced: who have the domain depth, and possess the disciplined slowness to catch the 1% before it reaches production.
Writing software is easy. Shipping is hard. Fast is easy. Easy is rarely correct. Slow is how you know the difference.