The code ran. The tests were green. You shipped it, and for three weeks nothing happened. Then the bill for one service climbs with no matching climb in users. Or a page that loaded instantly takes four seconds, and only for your oldest customers. Or two people open the same screen at the same moment and see different numbers.
Nobody wrote a bug. There is no stack trace, no failing test, no line in the diff that looks wrong. Go back and read the change that caused it and you find something small, tidy and entirely reasonable. That is the shape of the problem this piece is about, and it has one cause: a decision was made in your repository by something that was not you, and nothing about it looked like a decision at the time.
Productize reads the vibe coding vs agentic coding split as a question of ownership rather than of skill. This is the second half of a reading of Andrew Ng's AI engineering skills map: Part 1 covered the map and the AI-specific skills on it. This one covers the software half, where the silent decisions live.
Part 1The clause the whole essay rests on
Ng's essay on software fundamentals opens with a question and answers it in one sentence. That sentence does two jobs, and most people read only the first.
Even when you use a coding agent to write all your code, understanding software fundamentals is important for steering your agent to make the tradeoffs you want
or to even know what tradeoffs exist to be made.
The first half is the familiar argument: know enough to point the agent in the right direction. The second half is a stranger claim. The dangerous case is not being wrong about a tradeoff. It is not knowing one was there.
A missing answer is recoverable, because you can see the gap. A missing question is not, because it has already been answered. If you do not know how to configure a cache, you notice, look it up, decide. If you do not know a cache has to be invalidated, nothing prompts you. The agent picked a value, the tests pass, the page is fast, and the wrongness is scheduled for three weeks out.
Ng names the mechanism plainly: the novice who vibe codes gets working simple applications and, with them, bad tradeoffs, because "the developer didn't know such tradeoffs even existed and therefore did not steer the agent to make the right decisions for their application context". He gives the vocabulary once and never returns to it: "latency, availability, consistency, reliability, maintainability, simplicity, and/or cost". Those seven are what every decision below trades against each other.
Part 2Does agentic coding enable you, or conscript you?
It conscripts you. Ng frames the widening of your role as an opportunity, and that framing is too gentle for what happens in a repository.
His version: "Agentic coding enables many developers who previously played more specialized roles (like front-end developer or mobile developer) to play a broader, full-stack role." As a description of capability, true and cheering.
Ng does not say the next part; we do. Enables implies you could decline. You cannot. The cache-invalidation decision and the state-placement decision land in your repository whether or not you know they exist, because the agent has to write something and it will not stop to ask. There is no version of using a coding agent where you decline the decision. There is only a version where you make it without looking. Which changes the advice. Not you may now expand your role, but the expansion already happened, so the only question is whether you are watching.
An agent's lean when nobody is watching is predictable: toward whatever is most written about. The tutorial answer, the single-user answer, the one-process answer. Silence from you is not deferral. It is a decision made by whatever the model has read most of.
Here is what that looks like. You ask for a faster dashboard. The agent adds a five-minute cache in front of the summary query, held in the app's own memory. On your laptop it is correct: one copy of the app, one user. In production there are four copies behind a load balancer. A user edits a record, the write lands on copy two, and the next request routes back to copy one, where the edit has not happened. So they do it again. Now there are two records. Nothing errored.
The tell is cruel: severity scales with how many copies you run, so it worsens right after you scale up, sending everyone into the scaling change instead of the caching one. The instruction that would have prevented it is not be careful with caching. It is: name the write that invalidates this cache, implement it in the same change, and never keep shared state in one process's memory.
Part 3Why is data the one pillar that fails in silence?
Because its failure has no output. Every other part of the stack eventually produces something loud: a timeout, an error page, a bill. A data architecture that is missing something produces a confident, plausible answer, and nothing in the system looks different from success.
Ng gives data a privilege the other pillars do not get. He calls it "a foundation that software is built on top of, that is relatively hard to change (even if agents help with migrations)", then makes the essay's one AI-era claim: "Your AI systems will get their own input context from your data source, so if data architecture is chosen poorly, the AI doesn't know what it doesn't know."
The mechanism is stronger than the usual complaint that bad data gives bad answers. A model's output is a function of its context, and its context is assembled by code running against your data layer. So the outer edge of what the system can know is the edge of what that layer can return, and nothing inside the model can see that edge from the inside. A person who does not know something can notice the gap. A model handed a truncated context does not experience a truncation. It experiences a complete context.
The sharpest form of this is one sentence long. An empty result set is the same bytes whether the answer is genuinely none, or the question was never answerable from that schema. No query language can express the difference, because the distinction lives in the collection history, and the collection history is not in the database.
This is the exact opposite of the failure we wrote about in why your AI agent lies to you. There the model invents something that was not in front of it. Here it invents nothing: it answers correctly, over a smaller world, with no signal that the world was smaller. Which is why a better model does not fix it. A better model given the same context reaches the same answer with more polish. It is a data problem that presents as a model problem, so teams misdiagnose it and spend months tuning prompts at it.
Four ways a fact becomes invisible, worth naming on sight:
- Never modelled. The fact was never a field. There is
amountbut noreason. The system answers how much and never why, and no result hints that why was ever answerable. - Deleted by retention. A ninety-day window on interaction history means an agent asked whether this customer has raised this before is structurally unable to say yes about anything older. It will not say it can see ninety days. It will say no. The people who chose that window were balancing storage cost against a compliance rule; nobody in that room was deciding the memory horizon of a system that did not exist yet.
- Not reachable. The row exists and the retrieval path cannot get to it: a filter excluded it, a permission scope hid it, the field was not indexed, a chunk boundary split the sentence that mattered. The system behaves in every observable way as though the data were not there.
- Not resolved. Two records describe the same customer and nothing links them. The answer is about half a person, and half is not a shape that shows up in an answer. The most dangerous of the four, because the output is not empty. It is partial and plausible.
The everyday version of all four is NULL. In real schemas it stands in for at least five meanings: not applicable, unknown, not yet collected, collected and genuinely empty, and lost in a migration. A model reading a NULL cannot tell them apart. Mostly, neither can we. Which makes one review question unusually productive on a generated schema: what does NULL mean in this column, and is it more than one thing?
Ng states the problem and prescribes nothing, leaving a warning about an invisible failure with no instrument attached. The best instrument we know sits at the boundary where an agent reads. A retrieval tool asked to filter on a dimension the source does not have should return an explicit this field is not available here, never an empty list. That converts a silent absence into a token in the context, which the model can read, report and route around.
Then prove that instrument can fire. Ask something whose answer you know lies outside the retained window, and assert that the system reports it cannot see that far. A retrieval layer that has never once reported a limit has not shown it can detect one.
Part 4The rest of the map, in one story
Architecture is where the essay makes its quietest good point: "the right architecture is a moving target, depending on the phase of the project". The prototype shape is not the first-production shape, and "that too may change as the application scales". Cheap generation is an argument for committing later, not bigger.
Ng stops there. The part we would add is where irreversibility actually sits. One-way doors are not spread evenly through a system. They cluster at its edges. A published URL, an API shape a second client adopted, an ID a user can see, the tenant key in the first migration, where the bytes physically live, what you promised to delete. Internals stay reversible far longer than people assume, and interfaces become irreversible far sooner. The rule that falls out: spend deliberation at the edges, speed in the middle.
Prototypes are the trap inside that rule, because they feel disposable. Their code is. Their published URLs and the real user data they ingested are not: the moment a prototype touches personal data it picks up obligations that outlive every line that created them.
Underneath it is an asymmetry agentic coding created and did not advertise. Generation got dramatically cheaper. Migration got a little cheaper, since an agent rewrites call sites but cannot negotiate a contract change with consumers you do not control. Operating cost did not move at all: it is a function of surface area, and surface area does not care how the code was authored. So cheap generation did not make good architecture cheaper. It made wrong architecture cheaper to acquire and left it exactly as expensive to own. Nobody hand-built seven services for a prototype, because nobody had the weekend. The friction of typing was acting as a limiter on ambition, and removing the friction removed the limiter, not the cost.
The last two pillars fail the same way, and we have written about both, so only the shape here. Ng asks for a testing strategy. The failure we keep meeting is not too few tests but tests that cannot go red, and checks that report green for the wrong reason. In production, an alert that has never fired and an alert that is broken look identical from outside, because both produce silence. Neither is a knowledge gap. Both are the cache question again: what would have to be true for this to tell me something?
Part 5What can you ask of a diff tomorrow?
Ask questions you can answer by reading, without running anything. Every one is recognition rather than implementation, which makes the skill acquirable on work you already do. If you cannot answer one from the code in front of you, that is the finding, and the agent's default stands.
- Where does this cached value live: this process, a shared store, the CDN, the browser? If this process, how many processes will there be?
- Which write invalidates it, and is that line in this same change?
- Is this authorization check running on the server, or is the server trusting a value the client sent?
- Does this session survive a restart, and a second instance?
- Is this endpoint paginated, and what happens when a customer's list has ten thousand rows?
- For each nullable column: what does
NULLmean here, and is it more than one thing? - What is the retention period here, who decided it, and what does an AI layer lose at that boundary?
- Which consumers outside this repository read these columns, and how were they enumerated? Searching one repo is not an enumeration.
- When a question falls outside what this source holds, does the tool return an empty result or an explicit unsupported?
- What one-line change to the source would make this new test go red?
None of those requires you to write the implementation yourself. That is the point: these fundamentals are learnable at review time, not only in a curriculum.
Ng closes by saying developers who deeply understand how software works "vastly outperform those who vibe code without understanding". He attributes it to an internal study and publishes no figures, so take it as a considered position rather than a measured result. Our version is narrower and harder to argue with: the agent makes the decision either way, and the only variable is whether anyone looked.
Part 1 covered the other half of the map: the AI-specific skills sitting on top of these fundamentals. Read it here.
- Andrew Ng, AI Engineering Skills Map: Software engineering fundamentals, LinkedIn, 28 Aug 2026. Title, author, date and opening paragraphs verified against the live page on 30 Aug 2026. Later quotations rest on a single copy of the full text.
§