How the weekly report gets written
The gather step handed over one clean figure set. Now the report has to be written — and this is the step where it would be tempting to just feed everything to a model and let it talk. The builder doesn’t. Every figure and every comparison is computed in plain Python first. The model is the last step, not the first, and it only ever writes prose about numbers that already exist. This post walks through that order, one step at a time.
Key takeaways
- Plain Python computes every figure and every comparison before the model is touched.
- What counts as a “notable change” is a threshold in the config doc, not the model’s opinion.
- The one Bedrock call is handed the real numbers and told to describe only those.
- After writing, every figure in the paragraph is checked back against the computed set.
- If a sentence references a number that isn’t in the set, that sentence is dropped, not sent.
The write flow, step by step
Comparisons first, in plain Python
The gather step already produced this week, last week, and the four-week average. Step one computes the changes: how much each figure moved versus last week, and how it sits against the four-week average. That’s simple arithmetic — percentages and differences — and it’s done in Python where it can be tested and trusted. The point of doing it here, before any writing, is that the report’s “up 12%” or “down from 14” is a fact the code computed, not a phrase a model produced and hoped was right.
Comparing to both last week and the four-week average matters because a single week can mislead. Sales down 8% on last week sounds bad until you see last week was the best week of the quarter and this week is still above the average. The report carries both comparisons so a one-off doesn’t read like a trend.
What counts as “notable” is in the config, not the model
Step two decides which changes are worth calling out. This is a threshold in the config doc, not a judgment the model makes. The doc says things like “flag any week-over-week move bigger than 25%” or “always call out new customers, even small moves.” The code applies those thresholds and marks each figure as either background or a highlight. If nothing crosses a threshold, the week is steady, and the report is honest about that — a short “quiet week, nothing moved much” note beats a model padding three paragraphs out of noise.
Keeping “notable” in the config means the owner controls what the report gets excited about. A business that lives and dies on new customers turns that threshold down; a business with naturally spiky weekly sales turns that one up so it isn’t flagged every Monday.
The one model call, and what it’s allowed to do
Step four is the only place a model touches the report. The code builds a facts list — a fixed set of computed statements, each with its number attached: “sales: $18,400, up 12% on last week, above the four-week average”; “new customers: 9, down from 14, the slowest week in a month.” That list is handed to Claude Haiku 4.5 with a short instruction: write a few plain sentences that describe these facts for a busy owner, lead with the headline, keep it short, and do not introduce any number that isn’t in the list.
The model is good at exactly this — turning a list of facts into readable prose — and bad at exactly the thing it’s not being asked to do, which is compute or recall figures. By the time it’s called, there is nothing for it to get wrong about the numbers, because all the numbers are already decided. It’s writing, not analyzing.
Checking the numbers back before anything sends
Step five is the guardrail. After the model returns its paragraph, the code scans the draft for every figure it mentions and matches each one against the computed set. A number that matches stays. A number that doesn’t — a stray figure, a rounded value that drifted, anything the model added — gets the sentence containing it dropped, and the drop is logged. In practice Haiku 4.5 handed a tight facts list rarely invents a number, but “rarely” isn’t “never,” and a weekly report that an owner makes decisions on has to be never. The check is cheap and absolute: if a sentence’s number isn’t in the set, the owner never sees that sentence.
This is why the email always carries the numbers table next to the summary. The words are the convenient version; the table is the source of truth, and any sentence in the summary can be checked against the row right below it.
Next post: how the report reaches the owner — the Monday send, the timezone handling, and the four checks between the written report and the inbox.
All posts