whats-changed · git:20260921.e0ef31d · 2026-09-21 · sha256 6254021d7d75258e
whats-changed git:20260921.e0ef31dA
Immutable. This exact content never changes and is served at /api/v1/blob/6254021d7d75258e.
--- name: whats-changed description: Compare two periods of the same report and say what moved, by how much, and which few lines explain the total — ranked, with rate split from volume. Use when the user has this month's and last month's numbers (workbook, CSV, PowerPoint pack, PDF or Word doc) and asks what changed, what's driving it, why revenue or cost moved, or wants month-on-month or quarter-on-quarter variance commentary they can repeat in a meeting. Not a cell-by-cell diff, and it never invents a cause the source doesn't state. --- # What's changed Every reporting pack answers *what the number is*. Nobody ships the paragraph that says **what moved, by how much, and which two lines account for most of it.** That paragraph is what gets asked for in the meeting. **The product is the ranking, and the discipline is not explaining.** Of the forty things that moved, name the few that explain the total, say plainly that the rest is noise, and **never supply a cause the source does not state.** A report that says "down on seasonal softness" is worse than useless — it puts a fabricated cause into someone's mouth in a standup. ## Workflow ### 1. Take both periods as given Two files — prior and current — or one file with two period columns. Accepts `.xlsx`, `.xlsm`, `.csv`, `.tsv`, `.pptx`, `.pdf`, `.docx`, or text pasted into chat. **Mixed pairs are normal and supported**: an August PDF against a September workbook is what the user has to hand, because the workbook stayed with whoever built it. Infer which is the earlier period from filenames, sheet or slide titles, or a date header. **Ask nothing unless genuinely blocked.** At most two questions, and only these: - Which period is earlier genuinely cannot be inferred → *"Which of these is the prior period?"* - No shared key exists, so rows cannot be matched at all → say what each source is keyed on, ask how to align them. Never ask about format, audience, thresholds, or how much detail they want. Draft first. ### 2. Extract before comparing Read `references/extraction.md` and follow it. It covers per-format fidelity, the flat intermediate every source reduces to, mandatory source locators, and the four rules that stop a deck or a PDF producing confident nonsense: - never read a number off a **chart image**; - never **OCR** into the output without flagging it; - compare at the **coarser precision** of the two sources; - a line a truncated source didn't show is **not disclosed**, not gone. The precision rule is the one that bites. A deck at `£1.8m` against a workbook at `£1,783.2k` is not a £16.8k movement — it is rounding, and reporting it is a fabrication that looks like arithmetic. ### 3. Align rows, then compute Match on normalised label, then on position. Compute per line: prior, current, change, and — where the source carries both a count and a value — the **rate/volume split**. Whether a total moved because units moved or because the per-unit figure moved is the most useful thing this skill can say, and it is pure arithmetic. Reconcile before reporting: **the sum of the rows is the truth**, not a total the source prints. If they disagree, the gap is a flag. If the source is truncated and there is no complete set of rows to sum, `materiality.md` ranks the candidate totals by how checkable they are — a printed total comes last. ### 4. Rank, and drop what doesn't qualify Read `references/materiality.md` and apply its two gates. They are numeric on purpose — "report what matters" drifts from run to run, two thresholds don't. Everything failing both gates aggregates into one `all other movements` row, never silently dropped, so the arithmetic still closes. The reference also carries the refuse-to-say table, the rulings for new and gone rows, renames, sign flips and unit changes, and the closed ten-item list of what earns a flag. Those cases are the skill; do not improvise them. ### 5. Write it and stop A headline, then the tables, then the fixed trace line. No preamble, no methodology section, no offer of further analysis — the working is available on request, not printed. ```markdown **Cost of service rose £41.2k (+6.8%) to £647.9k.** One line explains four fifths of it. Read from `oct-pack.pptx` (slide 4 table) against `sep-costs.xlsx` (Costs tab). The deck rounds to £0.1k, so smaller movements aren't visible. ## Drivers (ranked) | # | Line | Prior | Current | Change | % of total move | Note | |---|------|-------|---------|--------|-----------------|------| | 1 | Hosting — EU West | 118.4 | 151.6 | +33.2 | 81% | Instances +28%, unit price flat | | 2 | Support — outsourced | 96.0 | 105.3 | +9.3 | 23% | Rate +10%, volume flat; "new MSA rate from 1 Oct" per slide 4's note | | 3 | Licences | 84.2 | 79.1 | −5.1 | −12% | Seats −6% | | 4 | Observability | — | 6.8 | +6.8 | 17% | new line | | | all other movements (7 rows) | 246.1 | 243.2 | −2.9 | −7% | none individually material | ## Structural changes (2) - S1 `Observability` is new this month — £6.8k, no prior comparative. - S2 `Legacy monitoring` has gone; it was £5.4k last month. It may have been absorbed into `Observability`, but nothing in either source says so. ## Flags (3) - F1 The Costs tab totals £650.5k; the rows sum to £647.9k. £2.6k unaccounted. - F2 `E22` is a typed-in number, not part of the column formula — which is why that total doesn't reconcile. - F3 Slide 6 carries the regional split as a picture, not a chart. Those numbers weren't readable; the underlying file is needed if that split matters. Ask "trace <handle>" to see how any line was reached. ``` Note the first two flags: one typed-over cell fires two triggers — the total not reconciling, and the hardcoded cell — so it earns **two lines, not one.** Count triggers, not defects. `% of total move` is signed against the total's direction, so an offsetting line shows negative. That is information, not a bug — which is why the column is not called `% share`. ## Rules - **Never invent a cause.** Arithmetic is yours to state; causation is not. The only permitted causal language is **quoted from the source** — a note column, a footnote, a variance-reason field, a deck's commentary — and attributed to it. Everything else is movement described, not explained. - **Rank or don't report.** An unranked list of everything that changed is the problem the workbook already has. If the drivers can't be ranked, say why. - **Flat is a valid answer.** *"Revenue is flat within 1%; no line moved more than £3k"* is true and useful. Never manufacture drivers to fill the table. - **Say less than you were asked for when the source can't support more.** A coarse PDF against a fine workbook yields a thin report; that is the honest output. - **No growth rate on a new row, a gone row, or a move across zero** — there is no denominator. Write `new`, `gone`, or describe the flip in words; never `∞`, never `340%` on a £40 base, never `n/a%`. `% of total move` is a different quantity and **does** apply to those rows; it is what makes the table's arithmetic close. - **The rows are the truth.** Never repeat a printed total that its own rows contradict. When a source is truncated and there are no complete rows to sum, prefer a total you can derive and cross-check — a segment chart's parts, say — over the printed one, say which you used, and flag the disagreement. A printed total is a claim, not evidence, however prominent. - **Cite a locator** for every figure whenever either source is not a spreadsheet. `Revenue!E7`, `slide 6, table row 3`, `p.12 Table 4`. Nobody can eyeball a diff of two PDFs. - **Flags are a closed list.** Only the ten triggers in the reference earn a line, one line per trigger **even when two triggers share one root cause** — a typed-over total cell is two flags, not one. Risks, opinions, things that merely seemed notable, and limitations of your own analysis are commentary. Omit the section when nothing qualifies. - **Stop and flag on a unit or currency mismatch** between the two sources. Every number would otherwise be wrong by 1000×. This is the one case worth refusing to report on. - **Output lands in chat** as copyable markdown. Write a file only if asked. Don't offer to chart it — the user has minutes before a meeting and wants sentences. ## Tracing Read `references/tracing.md` — it is the contract for handles, the fixed closing line, and the four-part trace block. Handles here: `headline`, drivers by their rank (`1`, `2` …), `S` structural changes, `F` flags. What a trace contains for this skill: - **Source** — prior and current value for every row involved, each with its locator in its own file, and the precision each source carries. - **Working** — change = current − prior; growth = change ÷ prior (or why there is none); `% of total move` = change ÷ total change. Where a count and value exist, the rate/volume split with both periods' units and unit value substituted. For the headline, the row sums of both periods, and — if a printed total disagrees — both figures and which was used. For `all other movements`, every member row with its change, summing to the aggregate. - **Rule applied** — the materiality gate it passed, with its numbers in the gate (or both gates it failed, for a row in the aggregate), and its rank. For a flag, its trigger number in `materiality.md`. A quoted cause stays quoted and attributed; the trace adds none. - **Would change the call** — e.g. "at the deck's £0.1m rounding this move would vanish". ## Testing `evals/` ships the fixtures and their answer keys. `sales-2026-08.xlsx` / `-09.xlsx` are the clean-shape pair; `sales-pack-2026-08.pptx` / `-09.pptx` test decks, native charts, a picture-of-a-chart slide and a top-5 truncation; `sales-pack-2026-08.pdf` tests £0.1m rounding against a £k workbook; `-08-scanned.pdf` has no text layer at all. `sales.KEY.md` and `sales-pack.KEY.md` grade them — never feed a key in with a fixture.