Code that depends on unwritten invariants — `const tax = base * rate;` that assumes rate > 0, with no enforcement and only a stale comment if any.
Code that depends on unwritten invariants the agent must reconstruct from context; bugs that violate the invariant surface far from the source.
Invariants the code assumes are stated explicitly; readers don't need to deduce them.
Invariants live in code as runtime checks; the agent reads the assertion as a typed constraint that downstream code can take as a precondition without re-deriving it from caller context.
Before the refactoring
// rate must be positiveconst tax = base * rate;
After the refactoring
if (rate <= 0) throw new Error('rate must be positive');const tax = base * rate;
Bugs that violate the invariant bubble out as mysterious downstream errors; readers must reconstruct the invariant from context; the assumption drifts silently as the code evolves.
The agent must reconstruct invariants from surrounding code; bugs surface far from the source and tracing them costs reasoning hops.
Assertions used as control flow couple production behavior to debug-mode invariants — keep them as runtime contracts that should never fire.
Assertions used as control flow couple production behavior to debug-mode invariants; the agent that conflates the two ships a flow-dependent change disguised as documentation.
Bugs that violate the invariant fail loudly at the source instead of bubbling out as mysterious downstream errors.
Invariants fail loudly at the source; the agent's debugging traces are short; assumptions become enforceable contracts.
Using assertions as control flow — production code that depends on the assertion firing or not firing becomes coupled to debug-mode behavior.
Coupling production behavior to assertion presence/absence — the agent reads them as documentation but the runtime depends on them firing or not.