Skip to content

Learn

Report & fact IDs

A number you cannot check is only a claim.

How every number in the report carries an ID that opens its SQL, its inputs and the rows it came from.

Stage 8 of 10. RENDER writes report.json (the verified data) and report.html (a self-contained page you can open offline).

A report is only as useful as your ability to check it. “Revenue fell 17.9%” in a slide is a claim; you would have to redo the work to trust it. Here every number sits next to a short ID, a fact ID, and the ID opens the exact computation behind it: the SQL and its parameters, or the function and its inputs, down to the spreadsheet rows.

RENDER · the coffee-roaster run

In

  • verified claims16
  • facts101

RENDER

  1. 1 · Fill the placeholdersEvery {{N…}} in the text becomes the fact's stored value, formatted for reading.
  2. 2 · Attach the chipsEach number keeps its fact id, which opens its SQL or function and its rows.
  3. 3 · Rank the actionsRecommendations carry an impact range made of facts and a check to run later.

Out

  • headline change−17.9%N30
  • from$44,100N12
  • to$36,200N11
  • R1 impact$3,995N350to N351, next quarter

From the verified report.json of the run.

The top finding, Revenue fell after March, driven by wholesale, as the report states it. Each figure is followed by its chip; a chip with a check mark was recomputed by the verifier. Click one: it jumps to its row in the ledger at the bottom of this page.

  1. Revenue went from $44,100N12 in 2026-03 to $36,200N11 in 2026-04 (a change of −$7,900N29, −17.9%N30). It stood at $37,000N17 in 2026-06. observed
  2. By channel, “wholesale” fell $8,500N149, more than the whole drop; “retail” rose $600N151. observed
  3. By product, the price effect was $1,181.91N175, the volume effect −$1,911.07N173 and the mix effect −$7,170.84N174. observed
  4. The hotel customer paused its standing order because of the new price list. document_supported email-0412.eml: “After the new price list we are pausing our standing order while we compare suppliers.”
  5. The wholesale price increase took effect shortly before the drop. correlated price-list.pdf: “Wholesale prices increase 12% from 15 March 2026.”
  6. The drop coincided with the price increase. correlated

The top recommendation: Offer wholesale accounts a volume-tier discount to win back paused standing orders, expected impact $3,995N350 to $7,191N351, next quarter. The impact is a scenario computed in code from facts and bounded assumptions (how much of the lost wholesale might come back, at what discount), never a number the model made up.

Following a chip down. The headline change −17.9%N30 is pct_change of two SQL facts. From the terminal, aa explain shows the same thing the chip opens:

Recorded output, offline run
$ bun run aa explain <job-id> N30
N30 = −17.9%   (I5 trend_break.v1 revenue 2026-04:change_pct)
function: pct_change
  N11 = 36,200   (revenue_2026-04)
  N12 = 44,100   (revenue_2026-03)

and one of its inputs, with the SQL, its parameters and the first input rows:

Recorded output, offline run
$ bun run aa explain <job-id> N11
N11 = 36,200   (revenue_2026-04)
definition: Revenue = sum of amount where status is empty or status is not refunded, per month, in USD (assumed)
sql:
  WITH m1 AS (SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value FROM "t_t1" WHERE NOT _is_total AND "date" IS NOT NULL AND (("status" IS NULL) OR ("status" NOT IN ($1))) AND strftime("date", '%Y-%m') BETWEEN $2 AND $3 GROUP BY ALL)
  SELECT period, value FROM m1 ORDER BY period
params: {"$1":"refunded","$2":"2026-04","$3":"2026-04","input_rows":1020}
input rows from T1 (20 shown):
  {"_row":3095,"_is_total":false,"_period":"2026-04","date":"2026-04-01T00:00:00.000Z","order_id":"CR-03094","customer":"Shop counter","channel":"retail","product":"Filter blend 250g","qty":2,"amount":32.9,"status":"paid"}
  {"_row":3096,"_is_total":false,"_period":"2026-04","date":"2026-04-01T00:00:00.000Z","order_id":"CR-03095","customer":"Online store","channel":"retail","product":"Filter blend 250g","qty":1,"amount":20.98,"status":"paid"}
  {"_row":3097,"_is_total":false,"_period":"2026-04","date":"2026-04-01T00:00:00.000Z","order_id":"CR-03096","customer":"Online store","channel":"retail","product":"Filter blend 250g","qty":1,"amount":35.88,"status":"paid"}
… (7 more lines)

Click a citation to see what it points at (from the build’s own run of the example):

Click a citation · Revenue fell after March, driven by wholesale

Revenue went from 44,100 in 2026-03 to 36,200 in 2026-04 (a change of −7,900, −17.9%). It stood at 37,000 in 2026-06.observed
By channel, “wholesale” fell 8,500, more than the whole drop; “retail” rose 600.observed
By product, the price effect was 1,181.91, the volume effect −1,911.07 and the mix effect −7,170.84.observed
The hotel customer paused its standing order because of the new price list.document_supported
The wholesale price increase took effect shortly before the drop.correlated

Every number above is a fact computed by SQL; every citation opens what it points at.

Provenance is the record of where something came from. Every fact has it (its computation and cited rows), every quote has it (file, page, character span), every web statement has it (URL and fetch time). A claim without provenance is not allowed in report.json.

The text in the report was written with {{N12}}-style placeholders. Rendering replaces each with the fact’s stored value, formatted for reading: rounding happens only on screen, the stored value keeps full precision. That is why the report and aa explain always agree.

report.html carries its own data and script, makes no network requests, and works from a USB stick. report.json follows a published schema, so other tools can read it.

Run the first tutorial, then open the report and click any number:

Terminal
AA_DEMO_MODEL=scripted bun run aa analyze examples/coffee-roaster --yes --embedder hash --today 2026-07-01 --currency USD --open

Go deeper: Your first report and the report schema.

FactValueWhat it isHow it was computedVerified
N11 $36,200 revenue_2026-04
SQL, run in DuckDB
WITH m1 AS (SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value FROM "t_t1" WHERE NOT _is_total AND "date" IS NOT NULL AND (("status" IS NULL) OR ("status" NOT IN ($1))) AND strftime("date", '%Y-%m') BETWEEN $2 AND $3 GROUP BY ALL)
SELECT period, value FROM m1 ORDER BY period

parameters: {"$1":"refunded","$2":"2026-04","$3":"2026-04","input_rows":1020}

recomputed
N12 $44,100 revenue_2026-03
SQL, run in DuckDB
WITH m1 AS (SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value FROM "t_t1" WHERE NOT _is_total AND "date" IS NOT NULL AND (("status" IS NULL) OR ("status" NOT IN ($1))) AND strftime("date", '%Y-%m') BETWEEN $2 AND $3 GROUP BY ALL)
SELECT period, value FROM m1 ORDER BY period

parameters: {"$1":"refunded","$2":"2026-03","$3":"2026-03","input_rows":1050}

recomputed
N17 $37,000 revenue_2026-06
SQL, run in DuckDB
WITH m1 AS (SELECT strftime("date", '%Y-%m') AS period, sum("amount") AS value FROM "t_t1" WHERE NOT _is_total AND "date" IS NOT NULL AND (("status" IS NULL) OR ("status" NOT IN ($1))) AND strftime("date", '%Y-%m') BETWEEN $2 AND $3 GROUP BY ALL)
SELECT period, value FROM m1 ORDER BY period

parameters: {"$1":"refunded","$2":"2026-06","$3":"2026-06","input_rows":1040}

recomputed
N29 −$7,900 I5 trend_break.v1 revenue 2026-04:change delta N11 N12 recomputed
N30 −17.9% I5 trend_break.v1 revenue 2026-04:change_pct pct_change N11 N12 recomputed
N149 $8,500 contribution.v1 revenue 2026-04 by channel:magnitude:wholesale abs N144 recomputed
N150 1 contribution.v1 revenue 2026-04 by channel:exceeds:wholesale abs_exceeds N144N146 recomputed
N151 $600 contribution.v1 revenue 2026-04 by channel:magnitude:retail abs N145 recomputed
N173 −$1,911.07 pvm.v1 revenue 2026-04 by product:pvm:volume pvm.v1 N115N163N116N164N117N165N118N166N119N167N120N168N121N169N122N170N123N171N124N172 recomputed
N174 −$7,170.84 pvm.v1 revenue 2026-04 by product:pvm:mix pvm.v1 N115N163N116N164N117N165N118N166N119N167N120N168N121N169N122N170N123N171N124N172 recomputed
N175 $1,181.91 pvm.v1 revenue 2026-04 by product:pvm:price pvm.v1 N115N163N116N164N117N165N118N166N119N167N120N168N121N169N122N170N123N171N124N172 recomputed
N350 $3,995 scenario impact.v1:recover_share:impact_low impact.v1:recover_share N144N349N347 recomputed
N351 $7,191 scenario impact.v1:recover_share:impact_high impact.v1:recover_share N144N349N348 recomputed