AI at the Boundary: Generating Adapters Safely In short: An adapter is two known types and a mapping — the best-shaped task in this whole course to delegate. It is also the one place a model will confidently invent a business rule and give it a plausible name. Chapter 3 argued that strict contracts turn generation from invention into translation. Adapters are the purest case of that: the input type is fixed, the output type is fixed, and the function is pure. They are also where the one genuinely dangerous mistake lives. Why adapters delegate well Four properties, all rare together: Both types are written down. and are real interfaces the model can read. The function is pure. No injection, no lifecycle, no DOM. It is trivially testable. Input object, expected output object. Mistakes are contained. A wrong adapter affects one screen, and it is reversible in a commit — unlike Chapter 4's exports. Compare with "build the dashboard", where the model has to invent requirements. Here it only has to connect two things you already defined. The prompt Give it both types and be explicit about what is not its decision: The last line is the important one, and the rest of this lesson is about why. The failure that matters Every other mistake here is caught by the compiler. This one is not. Ask for an adapter without specifying the rules and you get something like: It compiles. Types are correct. The test the model also wrote asserts exactly this behaviour, so the suite is green. It renders, and it looks entirely reasonable. And it is wrong in ways nobody will notice for a while: is not the agreed wording. Now the dashboard and the printed report disagree. 200,000 somatic cells is a real-sounding threshold that nobody set. It is not in any requirement. Deliveries will be flagged amber on a number invented from training data about dairy quality. silently blocks approval for small collections, which is a business rule with money attached that no one decided. The reason this is the dangerous case: an invented business rule is indistinguishable from a correct one by reading the code. A hallucinated Angular API fails to compile. A hallucinated threshold ships. Three controls 1. Supply the rules, or demand a stop. The prompt above does both. "List them and stop" is more useful than any instruction to be careful, because it gives the model a legal way to not know something. 2. Make the compiler carry the states. means a new backend status is a build failure rather than a silent fallthrough: This turns "did the model handle every case?" from a review question into a compile check. 3. Review the constants, not the code. The structure will be fine. Read only the literal values — every string a user sees, every number, every threshold. Those are the decisions. Ten seconds, and it is the whole risk. The rules file block That last line is worth repeating in the rules file even though the linter enforces it, because a model that knows the rule proposes a better design instead of writing code that gets rejected. Facades are a different risk Facades delegate less well. They involve subscriptions, lifetimes, and error policy — and the two things models get wrong are worth naming. Provider scope. A model will reach for or because that is what most training data shows. For feature state that is wrong, and it is Chapter 1's bug: the dashboard's error message survives navigating away and comes back stale. Error messages. Same problem as adapter constants — a model will write a plausible message that does not match your product's voice or your support team's vocabulary. Review the strings. The boundary rules do the rest Everything in Chapter 7's architecture is already enforced by the lint config from lesson five. That config does not care who wrote the import: An agent that runs step 2 discovers its own boundary violation. This is Chapter 2's principle holding: automate the objective rules and they apply to everyone. "But I thought a good test suite would catch an invented rule" This is the natural defence, and for almost every other category of bug it works. Tests catch regressions, wrong types, broken edge cases. Why not this? Because of where the tests come from. When you ask a model for an adapter and its tests in one go, the tests are generated from the implementation it just wrote , not from your requirements. It invented , so it writes: The test passes. It will keep passing forever. It is a faithful description of behaviour nobody asked for — and worse, it now documents the invented rule, so the next developer treats 200,000 as a requirement and defends it in review. Even tests written independently do not help, because a test can only check a rule someone stated. If nobody wrote down what the threshold should be, no test knows it is wrong. Failure Caught by types Caught by tests Caught by review --- --- --- --- Missing field on the model Yes Yes Yes Wrong type assigned Yes Yes Yes Unhandled status (with ) Yes Maybe Maybe Adapter in t…