Dados B3 › Transparency
Transparency
Transparency — how you check the numbers yourself
Data version 2026-09-27-reapresentacao-agreg · page generated 2026-09-27 06:52 UTC. If these do not match /saude, you are reading a cached copy.
What is checked, before every publication — 479 automated tests, collected live
0 are DATA invariants (does the number tie out?) and 120 are product tests — access gate, navigation, language, AI connector. Calling all 479 'invariants' would be inflating it: the split is checkable in the list itself. Not a hand-picked highlight reel: every test below was found by introspecting the actual test files just now, the same way pytest --collect-only would. Grouped by what it protects against, not by which file it lives in.
Level 1 — Integrity: does the data tie out? (0)
Level 2 — Semantics: does the account mean what the calculation assumes? (0)
Level 3 — Economic: is the result possible in the real world? (0)
Other product tests (15)
Access gate, navigation and the MCP connector — they test whether the product works, not whether a number is right, so they don't fit the 3 levels above by design. Still counted, still listed:
AUD01— The coordinates we hand an external auditor really do lead to the line. Three of the five external audit attempts died on the same rock: the reviewer's tooling cannot open a zip archive, so they read the published cases and could never compare against the source. Serving our own extracted CSV would have been worthless, since the auditor would then be checking our number against our own extraction, so we publish coordinates instead: the exact file inside the archive and the three-column filter that isolates the row. This test opens the archive, applies the published filter, and checks that exactly one row comes back and that its raw value times its declared scale equals what we serve. A wrong coordinate does not return nothing, it returns a real row belonging to a different account, and the auditor then reports a discrepancy against a correct database, which is the worst possible outcome of an audit.AUD02— The instructions do not promise a check that the source makes impossible. The first draft said to compare the archive checksum and that it must match. Running our own instruction before publishing showed it failing: the regulator REPUBLISHES these archives, and the one for 2024 was modified two days after we read it. Any auditor downloading today would get a different checksum and conclude we had tampered with the data. Publishing a check that fails by design is worse than publishing nothing, because it carries the appearance of rigor while manufacturing a false accusation against our own database. The checksum is still published, but as a statement of which snapshot we read, never as a byte-for-byte proof.AUD03— The route states its own limit instead of leaving it implicit. Two admissions have to survive any rewrite: the currency-scale conversion is OURS, and it is the one step in the chain the auditor cannot see; and anyone whose tooling can open the archive should read the original file rather than trust our coordinates. Without the second, a convenience for limited tooling quietly becomes an invitation to audit our own copy, which is the circularity this whole effort exists to avoid.AUD04— End-to-end check on the route external auditors actually use, which builds its coordinates by a different code path than the lineage does, so one passing does not imply the other. It found a real defect on its first run: the statement of changes in equity carries an extra dimension, so the three-column filter isolates one row in the balance sheet and income statement but returned SIX there, one per equity column. We would have published an ambiguous coordinate for every item sourced from it, the auditor would have picked one of six in the dark, found a number that genuinely exists, and reported a discrepancy against a correct database.AUD05— The methodology says what happens WHEN the reporting basis changes. I claimed the rule was undocumented and I was wrong: I searched the HTML shell and a content directory that does not exist, while the text lives in the sources-and-standardization page and has been live all along. Concluding absence from my own bad search is the same mistake an external reviewer made with a cached page on the same day. What was genuinely missing is the CONSEQUENCE at the boundary: that comparing two years there compares two different consolidation perimeters. This test now requires the rule, the flag name, and the concrete case to all appear in both languages, because an abstract rule with no example is exactly what let this boundary go unnoticed for months.AUD06— A comparison that straddles a change of reporting basis is marked as such. One company published a 268 percent revenue increase because its consolidated figure for one year was compared against its individual figure for the year before; on a consistent basis revenue had actually fallen by a quarter, and the number carried no flag at all. The instructive part is why the existing protection missed it: the routine that picks the restated comparative denominator deliberately matches on the aggregation level, but that only guarantees the DENOMINATOR is internally consistent and never compares the denominator's basis against the NUMERATOR's. The guard was correct and in the wrong place. We mark rather than recompute, because recomputing on the individual basis would discard the consolidated statements, which are the right basis for the year they exist in.AUD07— A browser gets a page; an agent that asks for JSON gets JSON. This is the fourth external audit attempt stopped by the same kind of door: the reviewer read the 47 KB home page and could not read the audit sample route at all. The route answered correctly in under two seconds — the problem was that it was 142 KB of raw JSON, a format browsing tools truncate or refuse. Half that weight was my own defect from the same day: the coordinate block repeated all twenty-odd accounts of the company for an indicator that consumes three, and a coordinate for an account the formula never touches does not help anyone audit, it just pushes what matters past the tool's reading limit. Trimming brought it to 60 KB; serving HTML closes it. Same remedy as the connector endpoint that used to answer 406 in a browser: someone arriving by browser is not speaking the protocol, they are trying to READ.AUD08— The audit sample route is named in llms.txt and the home page links to the audit protocol. The fifth external attempt produced the sharpest diagnosis yet: the reviewer picked its own seed, composed the URL, and its own reading tool REFUSED it, because that tool only opens URLs that already appeared in the conversation or in a search result, and no search engine had indexed the domain, so there was no path by link. Checking that turned up two defects of ours: the home page did not link to the audit protocol at all, and llms.txt — the file we publish precisely so that AI agents can find their way around — never mentioned the audit route, which lives only in the sitemap, a file reading tools do not consult. Publishing a door and hanging no sign on it is the same as having no door, for anyone who does not already know it is there. The file now also lists a concrete indexed URL, because a tool that cannot compose a URL cannot use a template.AUD09— Amortization of debt issuance cost is kept out of the depreciation figure that feeds EBITDA. This is the first data finding to come from an external auditor since the earlier successful one, and it started from a single case worth 0.34 percent: one company added a line labelled amortization of transaction cost to its depreciation and amortization, and the reviewer flagged it as a methodological caveat rather than declaring a discrepancy, because he could not open the source file to show the account. He was right, and the cause was systemic: the matcher accepted any label containing the word amortization. Measured across the base: 279 company-years affected, 226 inflated EBITDA figures, 107 of them by more than one percent and 35 by more than five, with the worst at nearly 39 percent. EBITDA is operating earnings plus depreciation and amortization OF ASSETS, and financing cost is not that, so this is a correction rather than a mark: the rule about marking instead of rewriting applies when the source is ambiguous, and a line that says cost of raising debt is not ambiguous. Half of this test guards the opposite error: amortization of the fair-value step-up from a business combination IS asset amortization and belongs in EBITDA, and the first exclusion pattern I wrote would have silently removed it from 89 lines.AUD10— The audit protocol declares the conflict of interest instead of pretending it away. The prompt used to open with a sentence saying the person asking is not the owner of the database and has no stake in the result — and the people who paste this prompt are overwhelmingly us. The fifth external auditor caught it: the audit opened with a claim of independence and the outcome arrived in the first person, ours, admitting fault and announcing the fix. His finding survives the conflict, because the account he checked sits in an audited financial statement rather than in his trust of whoever asked. But a protocol whose entire thesis is honesty cannot begin with a false sentence, and that sentence was mine, written to sound neutral. Declaring the tie is stronger than hiding it: an auditor who knows who asked calibrates his skepticism, while one who finds out afterwards discounts the whole result, and is right to.AUD11— The sample cache makes a retry instant and never serves a sample built from an older database. Six external attempts have now ended on transport rather than arithmetic: measured in production, the same route ranged from under two seconds to nearly fifty across six consecutive calls, with one exceeding a sixty-second ceiling, while locally it answers in 136 milliseconds. That is not the algorithm, it is contention on a half-CPU instance serving a 1.8 GB database from network-attached disk. Every audit tool retries the URL after a timeout, and the three that tried reported the same symptom under different names: a gateway error, a cache miss, an unavailable endpoint. Caching turns the second attempt into five milliseconds. The danger of the cache is precisely the defect it imitates: one auditor spent twelve reads looking at a frozen snapshot from the previous day and reported that the correction was not live. If WE served a stale sample after a rebuild we would be the cause of that, with the aggravation that the number would be wrong rather than merely old — so the database version is part of the cache key, and this test attacks by removing it.AUD12— For a bank, the generic list of source accounts is not presented as though it applied. The sixth external auditor found that one bank case declared one pair of account codes while the accounts actually used were a different pair entirely: declared did not match used. He classified it precisely as an audit-trail defect rather than a numerical one, and refused to turn a documentation inconsistency into a claim that the ratio was wrong — the accounts actually used are the correct banking structure. But 1,407 indicators, 2.2 percent of the base, were published that way, and the placement is the worst part: the banking chart of accounts is exactly the surface our own prompt tells auditors to attack. A field called declared that does not describe what was used looks auditable and is not. The chart varies even between banks, so swapping in another fixed list would only change whose statement is wrong; the honest output says the generic list does not apply here and points at the field that does.AUD13— An auditor can redo the ORDERING, not merely the individual scores. This is the finest objection we have received: having checked every published sample score and found them all correct, the auditor observed that this proves the key reproduces the scores shown, but not that those are the smallest scores in the whole population, because he never received the population to sort. He is right, and the distinction is subtle — checking each published score detects a fabricated key, but it cannot detect OMISSION. A case with a smaller score could have been left out and nothing in what he received would reveal it, so the claim that the sample is the smallest N rested on our word. A new route publishes the population keys, and this test does exactly what he would do: download them, score all of them, sort, and compare. Its first version had the same blind spot one level up — an attack that dropped one arbitrary line PASSED, because an arbitrary line is almost never in the top N — so the count of published keys is now checked against the table itself.AUD14— The published population declares an arithmetic that has to reconcile against a different route. The external auditor had just proved, independently, that the sample is the top of the ordering over the population file — but the SIZE of that population was still a bare assertion: the health endpoint published one indicator count and the population file delivered a smaller number of keys, with a gap of several thousand that appeared nowhere. He could verify that the sample was the top, and could not verify that the population was the population. Publishing the count of suppressed indicators closes the arithmetic across the two routes. This does not remove the dependency on us, since both numbers come from here, but it replaces an assertion with a SUM, and a sum that has to reconcile is attackable: dropping a key from the population now requires editing the health endpoint too. The attack truncates the population file without touching the other route.AUD15— The excluded depreciation lines are published, not only the ones that were summed. Without this the new rule was not falsifiable from outside: we published which accounts ENTERED the depreciation figure and nothing about which stayed out, so an auditor wanting to attack the exclusion of debt-issuance cost — a change that moved 232 EBITDA values — could see neither what was excluded nor why. The rule matches the NATURE of the label rather than the account code, since the same numeric code is transaction cost at one company and amortization of a sales stand at another, and a rule like that can only be defended by showing the label that triggered it, which means it can only be ATTACKED the same way. The auditor named three companies as targets; checking them showed the rule does not even fire at two of them, so the route exists for him to find the cases where it does fire on his own, rather than depending on the audited party to point at the battlefield.
Reconstruct it yourself — net margin across 5 companies, 4 sectors
We don't ask you to trust the numbers. Here's the net margin of five companies in four different sectors, each rebuilt straight from its annual report (DFP) at the CVM — net income ÷ revenue, matching the published figure exactly. For ANY indicator, of any company, the whole chain down to the line in CVM's file is at /linhagem:
| Company · sector | Net income (CVM acct) | Revenue (CVM acct) | Margin =÷ |
|---|---|---|---|
| WEGE3 · industrial | R$ 6.78 bn DRE:3.11 | R$ 40.80 bn DRE:3.01 | 16.6% |
| VALE3 · mining | R$ 11.81 bn DRE:3.11 | R$ 213.59 bn DRE:3.01 | 5.5% |
| PETR4 · oil & gas | R$ 110.61 bn DRE:3.11 | R$ 497.55 bn DRE:3.01 | 22.2% |
| ITUB4 · bank | R$ 45.85 bn DRE:3.09 | R$ 387.12 bn DRE:3.01 | 11.8% |
| BBAS3 · bank | R$ 16.78 bn DRE:3.11 | R$ 319.46 bn DRE:3.01 | 5.3% |
Download any of these DFPs from the CVM, take the income and revenue accounts, divide — you get the same number. Banks use interest income as revenue (what makes sense for a bank), so the reconciliation is sector-aware; the others use sales revenue. Figures are the latest fiscal year.
Why we may differ from another site (and it's not an error)
A difference between two sites usually isn't one being wrong — it's a method choice. We disclose ours:
- Average vs ending capital: ROE and ROIC use average equity/capital (this year + last ÷ 2), not the ending balance — so they're not a naive single-year division.
- Controlling vs consolidated: we state which one each item uses.
- TTM vs annual: quarterly multiples use trailing-twelve-months earnings.
- IFRS 16, goodwill, cash, exceptional tax: each handled explicitly and flagged when it distorts.
Do the tests bite? Yes — real cases the suite has caught
A test that never fails could mean perfect data — or a weak test. These were born from real errors that slipped through, and now fail — only shown for tests that actually exist in the collected suite above:
- I-B16 · banks' P/E = 0: the CVM reports share count sometimes in units, sometimes in thousands (varying by company and year); market cap came out 1000× too small and P/E was zero. I-B16 (price × shares recomputed) caught it — we fixed 661 annual and 2,027 quarterly multiples.
- I-B24 · the vanishing profit: the profit/equity account varies by bank (Itaú 3.09, BB 3.11); if the label search fails, the number vanishes silently and ROE is born wrong. I-B24 makes that hole fail.
- H-B23 · the 800% dividend yield: old B3 dividends carry a price not adjusted for splits; without H-B23 the yield would look absurdly real. The flag keeps the record and warns.
- I-B20 · the missing COTAHIST 2023: on the first deploy one year of prices failed to download silently; the API shipped with ~50k fewer prices and the suite passed, because nothing checked coverage. We added I-B20 — a year without prices now fails the build loudly.
- I-B33 · Oil & Gas at −89.6% in one week: COTAHIST isn't split-adjusted; a 10:1 split read as a −90% weekly return and stayed in the cumulative return forever, with nothing failing (a blind amplitude filter didn't fix it either — it just flipped which direction was wrong). I-B33 (no sector week beyond ±35%, the ruler is the exchange itself) stops the build.
- I-B31 · 364 of 865 sector-index weeks frozen: extending the series back to 2010, a sector with no company carrying a market cap that week turned into a factor of 1.0 — a flat line that the cumulative return read as 'market stood still', and the 'since 2010' return came out fictional (+527%). I-B31 fails on any week repeated to the cent.
- I-E05 · EMBRAER's 2010 P/E priced with 2025 data: the point-in-time price lookup fell forward with no ceiling whenever the current ticker had no price at balance-sheet time (ticker change, share-class migration); the multiple came out priced 15 years into the future, in 22% of annual and quarterly rows, silently. The 45-day window (and I-E05) blocks it: no session inside the deadline, no multiple computed.
- I-E04 · AZUL at R$ 1.67 quadrillion market cap: the balance sheet carried 54.7 trillion shares from the judicial recovery issuance, but the price used was already on the post-reverse-split (1:150,000) basis — two ends measured on different bases, market cap wrong by orders of magnitude. I-E04 (market cap never above Brazil's GDP) fails the build on that absurdity.
How far back each block of data goes
No asterisks here: this is coverage year by year, counted right now. Indicators (ROE, ROIC, margins, growth) come from the filings alone and cover the whole series. Multiples (P/E, P/BV, EV/EBITDA) need a price and a share count — and the share count comes from CVM's reference form, which the further back you go the fewer companies filed in a usable format. The gap between the two columns is a source limit, not an ingestion hole. If you look for an old P/E and do not find it, it is because nobody has it — not because we hid it. The same numbers as JSON: /cobertura.
| Year | Companies with indicators | Companies with multiples |
|---|---|---|
| 2025 | 438 | 290 |
| 2024 | 444 | 296 |
| 2023 | 442 | 298 |
| 2022 | 429 | 295 |
| 2021 | 423 | 296 |
| 2020 | 410 | 274 |
| 2019 | 371 | 164 |
| 2018 | 326 | 164 |
| 2017 | 317 | 162 |
| 2016 | 311 | 152 |
| 2015 | 303 | 143 |
| 2014 | 301 | 139 |
| 2013 | 292 | 130 |
| 2012 | 291 | 111 |
| 2011 | 284 | 97 |
| 2010 | 277 | 34 |
Live coverage
456 companies · 876,076 price points · 8,654 recorded restatements · last refresh 2026-09-27 00:20:28. Full live counts at /saude.
Sources: CVM (open data, ODbL) and B3 (COTAHIST). Not affiliated with B3 or the CVM. Not investment advice.
Numbers on this page are live. Data version 2026-09-27-reapresentacao-agreg · page generated 2026-09-27 06:52 UTC. If this does not match /saude, you are reading a cached copy.