Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

statements package

Overview

Package statements turns a chart of accounts into classified financial statements, where the section, the sign and every total are functions of each account's kind and none of them is supplied by the caller.

A realm holds the chart — p/journal keeps one, and a realm wrapping it publishes one — and asks this package what the statements say. Nothing here reads the chain, holds state, or decides what an account is: it takes journal.Account rows and returns figures.

Example
1rows := []journal.Account{ /* ascending by Code */ }
2st, err := Derive(rows)
3// st.Assets, st.Claims, st.CumulativeNet, st.Abnormal

The three-bucket partition

journal partitions the five kinds in two, by normal balance. A statement partitions them in three, by where the figure is presented:

Example
1SectionAssets      : {Asset}                 balance sheet, debit side
2SectionClaims      : {Liability, Equity}     balance sheet, credit side
3SectionPerformance : {Revenue, Expense}      income statement

SectionOf is the whole mapping and it is fail-closed: a Kind outside 1..5 is ErrInvalidKind, never a bucket. The zero Kind matters here because journal.Kind.IsDebitNormal reports it as credit-normal, so a silent fallthrough would not drop the row — it would file it under claims and produce a statement that balances and is wrong.

There is no Balances method, and the reason is the product's own arithmetic

Write A, L, Q, R and X for the natural-sign totals of the five kinds, each the sum of journal.Account.Balance over its kind, and NI = R - X. For any single account, Balance() is RawDelta() for a debit-normal kind and its negation otherwise, so

Example
1sum over every account of RawDelta  =  A - L - Q - R + X

and in a balanced book that sum is totalDebits - totalCredits = 0. Hence

Example
1A = L + Q + NI

which is the balance sheet identity. The consequence is uncomfortable and is stated here rather than discovered by a reader: **over a chart drawn from a journal.Book the identity is a constant true**, algebraically identical to `totalDebits == totalCredits`, which the Book enforces on every Post. It is true of a chart whose every account is classified backwards. A `Balances()` returning that comparison would be a check that cannot fail, which this project has shipped before and does not ship again — see DISCOVERY.md § 4.

The identity is NOT vacuous over this package's own input domain, because rows may come from anywhere and a hand-built set need not sum to zero. That scope is the whole content of the claim, and dropping a scope is the documentation defect this project has recorded most often. So:

  • [Statement.Assets] and [Statement.Claims] are both reported, as figures.
  • Their equality is asserted in the tests, in both directions: held over a Book-derived chart, and shown to survive a chart miscoded on purpose, which is what makes it vacuous there rather than reassuring.
  • Nothing in the API offers that comparison as a verdict.

What ships instead: the abnormality census

journal.Account.Balance is natural-sign and journal's own doc says a negative result is "a real signal (a contra position)". What did not exist is the roll-up: finding an abnormal account meant already knowing to look at it. [Statement.Abnormal] lists every row whose balance runs against its kind, and Statement.AbnormalIn counts them per section. It survives a balanced book, which the identity does not.

It is the only partial answer in this portfolio to journal's obligation 7 — "a Kind set wrongly at Open time is undetectable here and undetectable anywhere else in this package" — and it is sound but incomplete, with the incompleteness exactly characterisable:

  • It CATCHES a misclassification that crosses the debit/credit-normal boundary and whose account has a non-zero balance. A payables account coded as an asset accumulates credits and reads negative.
  • It CANNOT CATCH a misclassification that stays on the same side: Liability <-> Equity <-> Revenue, or Asset <-> Expense. Both subtotals move, no balance goes negative, and nothing anywhere detects it. Obligation 7 is narrowed, not closed.
  • It has a FALSE-POSITIVE MODE that is not a defect: a genuine contra account — accumulated depreciation under assets, a sales return under revenue — is legitimately abnormal-signed. The census is a finding to read, never a verdict.

The income statement is cumulative and can be nothing else

journal.Book.Close is a backdating seal: it refuses entries dated at or before a cutoff and does not sweep nominal accounts into equity. There is no retained-earnings account and no closing entry, so revenue and expense accumulate from the book's first posting forever. The field names carry the word — [Statement.CumulativeRevenue], [Statement.CumulativeExpenses], [Statement.CumulativeNet] — because a reader who takes them for a period figure misreads every statement this package produces.

[Statement.Claims] therefore includes CumulativeNet as an explicit reconciling line. A reader who checks Liabilities + Equity against Assets and finds it short by exactly CumulativeNet is not looking at a bug. A period income statement needs entry-level data and is out of scope; so is a cash-flow statement, which needs a cash-vs-accrual classification journal.Posting does not carry.

What this package does not claim

  • **Nothing about money.** A statement is a report about a book, and a book is a set of claims by its owner with no custody behind it. This package never sees a coin. A realm publishing its output must say so loudly: a published statement adds apparent authority to a self-report, and that is the one way this product can mislead someone.
  • **No audit.** Every figure here is derived from rows the caller supplied. Deriving them faithfully is the guarantee; that they describe anything real is not.
  • **Two statements and a census**, not a statement set. No statement of changes in equity, no notes, no comparatives.

p/journal: /p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/journal

Functions

SectionOf

func SectionOf(k journal.Kind) (Section, error)
Ask AI Claude ChatGPT

SectionOf maps an account kind to the section it presents in. An invalid kind is ErrInvalidKind; there is no default bucket.

This is the only place in the package that knows the partition, and it is exported so a consumer grouping rows for presentation uses the same mapping the totals were built from rather than a second copy of it.

Param

Command

gnokey query vm/qeval -remote "https://rpc.onyx.testnets.gno.land" -data "gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/statements.SectionOf()"

Result

Derive

func Derive(rows []journal.Account) (Statement, error)
Ask AI Claude ChatGPT

Derive classifies rows and returns the statement figures.

rows must be in strictly ascending Code order (ErrRowsNotOrdered) and no longer than MaxRows. Every Kind must be one of journal's five (ErrInvalidKind) and neither column may be negative (ErrNegativeTotals, which is what makes the checked adds here sufficient). Every accumulation is checked (ErrOverflow).

It is a pure function of rows: the same rows always give the same Statement, and nothing about the caller, the chain or the time enters it. On any error the returned Statement is the zero value, so a caller that ignores the error reads zeros rather than a half-summed chart.

Param

Command

gnokey query vm/qeval -remote "https://rpc.onyx.testnets.gno.land" -data "gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/statements.Derive()"

Result

MustDerive

func MustDerive(rows []journal.Account) Statement
Ask AI Claude ChatGPT

MustDerive is Derive and panics instead of returning an error. It is for a realm's mutating path, where an error return does not revert the transaction and only a panic does.

Param

Command

gnokey query vm/qeval -remote "https://rpc.onyx.testnets.gno.land" -data "gno.land/p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/statements.MustDerive()"

Result