Domain concepts represented as raw strings, numbers, or booleans — phone number is a string, money is a number, status is a code.
Function signatures use raw strings and numbers where domain concepts hide; the agent cannot tell from the type whether an argument is the right kind of thing.
Each domain concept has a small typed home — Money, PhoneNumber, OrderId, Status — that knows its rules.
Each domain concept has its own typed wrapper; the agent's type checker catches wrong-primitive-in-wrong-slot mistakes before runtime.
Smellier version
function priceFor(cents, currency) {// ...}
Fresher version
class Money { /* amount + currency, with arithmetic */ }function priceFor(money) {// ...}
Validation and formatting scatter across every consumer; the type system can't catch wrong primitives in the wrong slot.
The agent must inspect call-site context (variable names, surrounding code) to verify a primitive is the right kind; validation and formatting logic scatters across consumers.
Each wrapper class adds construction ceremony at every entry point; for one-off primitives that never carry domain rules, the wrapper is overhead with no return.
Each wrapper is a class the agent must load and instantiate; for primitives used in only one place, the wrapper is more code than the original concern warranted.
Misuse becomes a type error; behavior accretes around the concept; refactoring is local to the wrapper.
Wrong-primitive misuse becomes a type error the agent catches without runtime testing; behavior and rules accrete around the concept where the agent expects to find them.
Wrapping every primitive on principle — Name, Title, Description as separate classes whose only methods are toString() — adds typing ceremony without enforcing any domain rule.
Wrapping every primitive — including ones with no domain rules or behavior — adds boilerplate the agent must navigate at every signature with no reasoning benefit.