Before an AI feature reaches users:
Boundary
- [ ] Provider behind a contract; no vendor SDK calls outside the driver
- [ ] Credentials resolved per tenant, never global-only
- [ ] Missing credential fails loudly at configuration, not at the provider
- [ ] No provider credential reachable from the client
Output
- [ ] Structured-output mode on where available
- [ ] Decode-or-throw at the driver; schema validation where the caller's context is known
- [ ] Required paths are minimal — only those whose absence corrupts something
- [ ] Parse failure returns the caller's expected shape, not null
Cost
- [ ]
max_tokenspinned server-side, per purpose; client cannot choose model or cap - [ ] Per-tenant ceiling, incremented before it is compared
- [ ] Rate limit and budget, keyed to what pays rather than to a rotating credential
- [ ] Usage block read and logged
Time
- [ ] The turn runs off the HTTP request
- [ ]
tries = 1; retry decided per tool, not per job - [ ] Per-call timeout inside a wall-clock deadline inside the job timeout
- [ ]
failed()recovers partial state, setsdone, clears its keys
Loop
- [ ] Every
stop_reasonhas a branch;pause_turnhandled before the no-tools exit - [ ] Truncation reported and shown as an error, never as an answer
- [ ] Iteration cap and wall-clock budget, both reported when they bind
Trust
- [ ] Attempts counted against the resource, not the submitted value
- [ ] Irreversible tools guarded by a constraint, not by an instruction
- [ ] Single-use tokens restored on every failure path
- [ ] Error messages confirm nothing to someone guessing
- [ ] Internal tools excluded from the published toolset
Operations
- [ ] Model version pinned and recorded in logs
- [ ] Round-trip logging: names and sizes, never inputs
- [ ] Dependencies and capabilities named; flows gated before starting
- [ ] A path to the same outcome that does not involve the model
Appendix B: Prompt Review Checklist
For any change to a prompt, a tool description, or a field description:
- [ ] Is it in version control, in code, reviewable as a diff?
- [ ] Does every prohibition carry an alternative action?
- [ ] Does every ambiguous case resolve to a defined output rather than to judgement?
- [ ] Are instructions bound to the values they describe, by name?
- [ ] Are internal identifiers translated into words?
- [ ] Does the stable content come first, so a prefix can be cached?
- [ ] Do refusals emit the same shape as successes?
- [ ] Does a test assert that the prompt still declares what the validator accepts?
- [ ] Is this one change, shippable and observable on its own?
Appendix C: Cost Checklist
- [ ] What does one call cost at the cap?
- [ ] What does one turn cost — calls multiplied by a growing history?
- [ ] What is the per-tenant daily ceiling, and what happens at it?
- [ ] Is the ceiling keyed to something that does not rotate?
- [ ] Is
cache_read_input_tokensnon-zero? If not, the cache marker is decorative - [ ] Is the reasoning effort tuned for this feature, or left at a default meant for hard problems?
- [ ] What is the worst case: maximum iterations, maximum history, every tool called?
- [ ] Would you notice that worst case happening a thousand times before the invoice?
Appendix D: The stop_reason Table
| Value | Meaning | Loop action | User sees |
|---|---|---|---|
| end_turn | Finished | Exit, publish | The answer |
| (tool use) | Wants a tool | Continue, send results | Progress |
| pause_turn | Suspended mid-turn | Continue — re-send history | Progress |
| max_tokens | Output cut off | Exit, report | Truncation notice |
| refusal | Safety declined | Exit, no retry | A plain explanation |
The two that are most often wrong: pause_turn treated as completion because it carries no tool calls, and max_tokens falling through to the same branch as end_turn, so a cut-off reply renders as a finished one.
Appendix E: Where to Go Next
The provider's own documentation, always, and in preference to anything in this book that contradicts it. Model APIs change on a scale of months; framework APIs change on a scale of years. Where this book shows a request shape, the shape is the lesson and the field names are a snapshot.
Everything else worth knowing is in a system you already run. Look at what your AI feature does when its provider is slow, what it costs on your busiest day, and what happens if a user presses the button twice. The answers are more interesting than anything I could put in a further chapter.