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.

cashflow source realm

Package cashflow publishes a direct-method statement of cash flows over a book this realm does not own, cannot write,...

Overview

Package cashflow publishes a direct-method statement of cash flows over a book this realm does not own, cannot write, and did not supply.

What it is, in one sentence

An owner of a book in r/books declares which of their account codes hold cash and what every other code's movement is for; this realm then reads the entries in a window straight out of that ledger, hands them to p/cashflow, and freezes the resulting statement at a sequence number.

A PUBLISHED STATEMENT IS A CLAIM ABOUT A CLAIM — and here, about TWO

r/statements already says this of itself and it is true here with one extra layer. A book is a set of claims by its owner; nothing ties an account reading `Cash 5000` to 5000 real ugnot anywhere. A cash-flow statement derived from such a book inherits that completely, and then adds a SECOND caller declaration on top: which codes are cash at all.

p/cashflow states the consequence exactly and it is repeated here rather than linked, because it is the single most important sentence about this realm: *"A realm that declares a receivable as cash produces a plausible, wrong statement. The declaration is the trust boundary."*

So what this realm guarantees is narrow:

  • the ENTRIES are read from r/books, not supplied by the publisher;
  • the CLASSIFICATION is the publisher's own declared policy, frozen with the statement so a reader sees what it was;
  • the ARITHMETIC is p/cashflow's, which nobody here can parameterise.

That the chart describes anything real, and that the codes called cash hold cash, are not claimed here and are not checkable from here.

Derived, not supplied — and the one figure that is supplied

Every figure comes from r/books through its own read surface, except one. p/cashflow cannot derive an OPENING cash position from a window-filtered entry slice — a window carries period movement, not a cumulative position — so `opening` is an argument to Publish and is echoed into the report unchanged. [Closing] is `Opening + NetChange` and is therefore only as good as a number the publisher typed.

This realm does not leave it at that. See OpeningReconciled: when the window extends past every entry the book holds, the sum of the declared cash accounts' balances is the cumulative cash position, and that is comparable to [Closing]. Where the comparison is available, Publish REFUSES to publish a statement that fails it. Where it is not available, the report says so and the figure stands as a declaration.

The window is REFUSED when it is too wide, never chunked

p/cashflow is explicit that it does no paging and no merging, because merging reports across pages would make the unresolved set an artifact of the paging. Its entry cap is 4096, exactly books.MaxEntriesPerBook, so the primitive can always accept a whole book and the binding constraint is not its cap — it is the cross-realm call budget, two reads per entry.

So this realm declares MaxWindowEntries and refuses a window holding more, telling the caller to narrow it. A chunk-and-merge would be cheaper to use and would violate the primitive's own stated rule.

Window selection rests on a premise OWNED BY ANOTHER REALM

Entries are located by binary search over entry ID, which is correct only because `At` is non-decreasing in ID. That is not a property of p/journal, which refuses only a negative `at` and one at or before the close cutoff. It is a property of r/books, which dates every entry with `runtime.ChainHeight()` at all three of its posting call sites and exposes no `at`-taking entrypoint. r/books declares the obligation in its own package doc.

The failure mode if that premise ever breaks is the dangerous kind: a statement over FEWER entries than the window holds, which still balances and still reconciles. So the premise is checked rather than assumed — [scan] verifies `At` is non-decreasing across every entry it reads (free, since each `At` is already in hand) and probes the two entries immediately outside the located range to prove the range is maximal. A violation panics instead of publishing.

RESIDUAL, stated with its boundary: that makes a violation at or adjacent to the window edges loud. A violation deep outside the scanned range is invisible without a full scan, which is the cost this design exists to avoid. OpeningReconciled closes it for the one window shape where the cumulative cross-check applies, and nowhere else.

Entry IDs are relied upon to be dense, and the argument is structural

The binary search indexes entries 1..books.EntryCount. That is sound because p/journal allocates `id := nextID; nextID++` and writes the entry immediately, in one function with no error return between the two, into a tree that has no delete; a post that fails panics and reverts the whole transaction. So there are no gaps and no reuse. It is stated here because it is a premise, not an observation: [EntryInfo] panics on an absent ID, so a gap would abort the scan loudly rather than skew a figure.

A reversal lands in the period it was MADE

r/books dates a reversing entry at the current height, not at the reversed entry's date, and p/cashflow deliberately does not special-case reversals: a reversing entry that touches cash moved cash. So reversing a prior-period entry shows as movement in the CURRENT period and the corrected period's published statement does not change. That is right for a cash-flow statement and surprising to a reader expecting otherwise, which is why it is here.

NO CUSTODY, and no re-derivation seal

There is no coinio import, no payable path, no fee, no withdrawal, no admin. Publish and DeclarePolicy refuse a transaction carrying coins.

There is deliberately NO `Verify` accessor re-deriving a stored report and comparing. For a window that closed before the publication height such a check is a CONSTANT TRUE by construction: entries are dated at the chain height and the journal is append-only, so no entry can later fall into a closed window, and the chart cannot lose an account. Shipping it would be the fifth instance of the vacuous-true class this project keeps finding in its own work. What ships instead is Rescan, whose non-vacuity is exact and narrow: it re-locates the window NOW and so tests the selection premise above, not the ledger's contents.

No cross-owner aggregate beyond a count

r/books scopes every read to one owner, and a cash-flow statement mixing owners would assert a claim no single owner can make. Total is a count and there is no way to enumerate publishers.

Limits, stated plainly

  • `opening` is caller-supplied, and verified only where OpeningReconciled says it was.
  • The policy is caller-declared and is the trust boundary. A wrong cash declaration yields a plausible, wrong statement and no on-chain check here can detect it.
  • The cost bound is reasoned against a live precedent (r/statements performs roughly 130 cross-realm reads per report), not measured in gas.
  • Memos and account codes and names are an owner's free text in r/books and are unsanitized there. Every one of them goes through [cell] before it reaches Render.
  • The chart reconstruction here is a second copy of r/statements' unexported `chartOf`. Promoting it would modify a live realm.

r/books: /r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/books r/statements: /r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/statements p/cashflow: /p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/cashflow p/journal: /p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/journal p/periods: /p/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/periods

Constants 7

const BooksPath

1const BooksPath = books.RealmPath
source

BooksPath is the ledger realm every entry here is read from.

Taken BY VALUE from that realm's own exported constant rather than typed out again, so this is the compile-time pin itself and not a second copy that could drift. A reader checking which ledger a statement describes is reading the import.

const MaxWindowEntries

1const MaxWindowEntries = 256
source

MaxWindowEntries bounds how many entries one Publish may read.

This is the §7.4 refusal bound and the number has a derivation rather than a feel. Reading one entry costs TWO cross-realm reads — books.EntryInfo for the header and books.EntryLegs for the postings — because r/books returns them separately. Add the chart reconstruction, which is one books.Accounts, one books.Codes at the chart cap and one books.AccountInfo per account, and the live precedent r/statements pays about 130 reads per report. Add the search: 2*ceil(log2(N+1)) + 4 header reads to locate and prove the range.

At 256 the whole publish is about 666 plain reads, roughly five times a report r/statements performs on this chain today. At r/books' own entry cap of 4096 it would be about 8,350, which is the figure the discovery gate for r/receivables used to defer this product.

It is a REFUSAL and not a truncation: a window holding more entries than this panics and names the count, and the caller narrows the window. Publishing a statement over a silently-truncated entry set is the one failure this product is least able to detect, because a short statement still balances.

const PolicyIsReplaceable

1const PolicyIsReplaceable = true
source

PolicyIsReplaceable records a decision a reader will look for.

DeclarePolicy overwrites an owner's previous declaration and keeps no history of it. That is safe only because every Publish FREEZES a copy of the policy it used into the record: a published statement is readable with the classification that produced it forever, via PolicyOf, and changing the live policy cannot restate a published figure.

The alternative — versioned policies with reports pointing at a version — is the same information with an extra indirection and one more place for the two to disagree.

const PublicationsAreUncapped

1const PublicationsAreUncapped = true
source

PublicationsAreUncapped mirrors r/statements' decision for the same three reasons, which hold here unchanged: keys are per owner so an owner can only fill their own history; no accessor and no Render path walks a publisher's whole history; and there is no engine cap above this realm to mirror.

const RealmPath

1const RealmPath = "/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/cashflow"
source

RealmPath is this realm's own path, used to build Render links.

const RenderCensusLimit

1const RenderCensusLimit = 25
source

RenderCensusLimit caps how many unresolved or net-zero rows one Render call emits. A window may hold MaxWindowEntries entries and in a book with no policy rules every one of them is unresolved.

Functions 30

func Complete

Action
1func Complete(owner address, seq int64) bool
source

Complete reports whether every in-window entry that moved cash was attributed to a category.

A complete statement is not a correct one. Completeness is a property of the POLICY's coverage, and a policy that classifies every account wrongly is complete. p/cashflow says this of its own accessor and it is worth repeating at the realm boundary, where the word will be quoted.

func Count

Action
1func Count(owner address) int
source

Count is how many statements an owner has published.

func DeclarePolicy

crossing Action
1func DeclarePolicy(cur realm, cash, rules string)
source

DeclarePolicy records the caller's own classification policy for their own book, replacing any previous one.

`cash` is a comma-separated list of account codes that hold cash, strictly ascending — for example `1010,1020`. It must be non-empty and every code must be an asset in the caller's chart.

`rules` is a comma-separated list of `code:category` pairs, strictly ascending by code, where category is `operating`, `investing` or `financing` — for example `4000:operating,1500:investing,3000:financing`. A code absent from `rules` is NOT defaulted to anything: an entry touching it is reported unresolved, by name, because a default bucket turns a missing declaration into a figure nobody questions. `rules` may be empty.

The owner is `cur.Previous().Address()` and there is NO owner parameter. r/books derives a book's owner the same way and no mutating function there takes one either, so the only party who can declare a policy for a book is the only party who can write to it. An owner parameter would move the trust boundary to whoever called this.

The declaration is validated against the caller's LIVE chart by deriving over an empty entry set: cf.Derive validates the window, the chart and the policy before it reads an entry, so a nil entry slice exercises exactly the declaration's validity and nothing else. A policy that is valid now stays valid, because r/books has no way to remove an account from a chart.

func EntryRange

Action
1func EntryRange(owner address, seq int64) (lo, hi uint64, ok bool)
source

EntryRange is the inclusive r/books entry-ID range this statement was derived from. `ok` is false when the window held no entries.

It is stored because it is the evidence for the statement's scope: a reader can take the two IDs to r/books and read the entries themselves. A statement is the only artifact here, and this is what makes it checkable against its source.

func Has

Action
1func Has(owner address, seq int64) bool
source

Has reports whether a statement exists.

func HasPolicy

Action
1func HasPolicy(owner address) bool
source

HasPolicy reports whether an owner has declared a policy.

func Height

Action
1func Height() int64
source

Height is the current block height, so a reader can tell how old a statement is without a second query.

func Latest

Action
1func Latest(owner address) (int64, bool)
source

Latest is the newest sequence number for an owner, and false if they have published none.

func Ledger

Action
1func Ledger() string
source

Ledger is the realm every entry here is read from.

func LineOf

Action
1func LineOf(owner address, seq int64, category string) (inflows, outflows, net int64, entries int)
source

LineOf is one category's gross flows. `category` is `operating`, `investing` or `financing`; anything else panics.

Inflows and outflows are GROSS and both non-negative. A category with 1,000 in and 1,000 out is not the same business as one with nothing happening, and a net of zero is all a netted figure could say about either.

func LiveCash

Action
1func LiveCash(owner address) int64
source

LiveCash is the declared cash accounts' summed balance right now.

This is the book's cumulative net cash movement since its first posting, and it is a LIVE figure — it moves with every posting. It is not a published statement and must not be quoted as one.

func NetZeroAt

Action
1func NetZeroAt(owner address, seq int64, i int) uint64
source

NetZeroAt is one net-zero entry's ID, by index.

func NetZeroCount

Action
1func NetZeroCount(owner address, seq int64) int
source

NetZeroCount is how many in-window entries touched cash and moved none on net.

func OpeningReconciled

Action
1func OpeningReconciled(owner address, seq int64) bool
source

OpeningReconciled reports whether this realm was able to check the publisher's declared opening position against the ledger — and, because a failed check REFUSES to publish, it being true means the check passed.

When it applies

Only when the window extended past every entry the book held at publication. Then the window's net change covers all movement from `from` onward, the declared cash accounts' summed balance covers all movement ever, and the difference between them is exactly the movement before `from` — which is what a correct opening is. An empty book qualifies too: with no postings every balance is zero, so the check requires an opening of zero.

It does NOT apply to a window that closed before later entries were posted. There the balances carry post-window movement the statement rightly excludes, and comparing them would be comparing two different periods.

What it proves, and the second thing it proves

First, that the declared opening is consistent with the ledger. Second — and this is why it is worth its cost — that THE ENTRY SCAN WAS COMPLETE. A scan that silently missed entries produces a short net change, and a short net change fails this comparison. That is the one mechanical control this realm has against the silent-under-reporting failure mode the package doc names, and it covers exactly the window shape where it is available.

What it does not prove

Nothing about whether the codes called cash hold cash. Both sides of the comparison are the same owner's self-report, read through the same realm. It is an internal consistency check, not a custody attestation.

func PolicyCash

Action
1func PolicyCash(owner address) string
source

PolicyCash is the owner's CURRENT declared cash codes, comma-separated.

func PolicyDeclaredAt

Action
1func PolicyDeclaredAt(owner address) int64
source

PolicyDeclaredAt is the height the owner's current policy was declared at.

func PolicyOf

Action
1func PolicyOf(owner address, seq int64) (cash, rules string)
source

PolicyOf is the classification policy that produced a published statement, re-encoded in DeclarePolicy's own input format.

It is the statement's policy, frozen with it, NOT the owner's current one. PolicyIsReplaceable explains why both exist: a reader of a published figure needs the declaration that produced it, and an owner needs to be able to correct a declaration without restating history.

func PolicyRules

Action
1func PolicyRules(owner address) string
source

PolicyRules is the owner's CURRENT declared rules, comma-separated `code:category` pairs.

func Publish

crossing Action
1func Publish(cur realm, from, until, opening int64) int64
source

Publish freezes a statement of cash flows over [from, until) and returns its sequence number, which counts from 1 per publisher.

The window is half-open: `from` is included and `until` is not. The unit is whatever r/books dates with, which is block height.

`opening` is the caller's declared opening cash position. It cannot be derived from a windowed entry set and is echoed into the report unchanged; see OpeningReconciled for the one window shape where this realm can and does check it.

The owner is `cur.Previous().Address()`. There is NO owner parameter and no way to publish over someone else's book, for the reason given at DeclarePolicy.

It PANICS, rather than returning an error, on: no book, no declared policy, an invalid window, a window holding more than MaxWindowEntries entries, a violation of the entry-dating premise at either window edge, a disagreement between the chart's two reads or an entry's two reads, any cf.Derive error, and a failed cumulative cross-check. An error return would not revert a Gno transaction; only a panic does.

func PublishedAt

Action
1func PublishedAt(owner address, seq int64) int64
source

PublishedAt is the block height a statement was frozen at.

func ReconciledCash

Action
1func ReconciledCash(owner address, seq int64) (int64, bool)
source

ReconciledCash is the declared cash accounts' summed balance at publication, and false if OpeningReconciled does not apply to this statement. The figure is meaningless when ok is false and is returned as zero.

func Reconciles

Action
1func Reconciles(owner address, seq int64) bool
source

Reconciles reports whether the attributed lines plus the unattributed residual equal the net change.

On a statement published here it is ALWAYS TRUE, because cf.Derive produces it that way and nothing between there and storage touches the figures. It is exposed anyway, and the reason is narrow: it is the one check a reader can run against a stored report without re-reading the ledger, and an exposed constant-true that is DOCUMENTED as one is better than a reader assuming the invariant holds without ever being told where it comes from. It must not be quoted as evidence that a statement is right.

func Render

1func Render(path string) string
source

Render serves the index at "", a publisher's page at "<address>", and one statement at "<address>/<seq>".

Every caller-supplied string reaching this page — an account code, an entry memo — is an owner's free text in r/books and arrives unsanitized, because that realm does not sanitize what it stores. Free text reaching a page unescaped is the one injection-shaped surface a realm with no custody still has, and the bytes coming from a THIRD realm's state does not make them safer. Everything goes through [cell].

func Rescan

Action
1func Rescan(owner address, seq int64) (entries int, netChange int64, agrees bool)
source

Rescan re-locates a published statement's window in the ledger NOW and reports whether the entry count and the net change still agree with what was frozen.

Why this exists and the re-derivation accessor does not

The package doc says there is no `Verify` here, because re-deriving a statement over a window that has closed is a CONSTANT TRUE: entries are dated at the chain height and the journal is append-only, so nothing can later fall into a closed window.

This is the part of that comparison which is NOT constant. Window selection is a binary search resting on a premise owned by r/books — that entry dates are non-decreasing in entry ID — and nothing freezes that premise. A future change there could break it silently. Re-locating the range and comparing is therefore a real test of the selection, and it is the only check here whose answer can change for a reason that matters.

What it costs and what it does not cover

It is a plain read, so the caller pays. It re-reads the window's entries, which is up to 2*MaxWindowEntries cross-realm reads plus the search.

It compares the entry COUNT and the NET CHANGE, not every line. The net change is the figure that moves if the entry set changed, and it is derived from the postings rather than from the policy, so a disagreement points at the ledger or the selection rather than at a reclassification. A false return means do not trust the statement and does not say which of the two it is.

func Scope

Action
1func Scope(owner address, seq int64) (entries, cashEntries, netZero, unresolved int)
source

Scope is the statement's own coverage line, and it is the thing to read before quoting any figure above.

  • `entries` is how many entries fell in the window, including the ones that moved no cash. Zero is a quiet period, not an error.
  • `cashEntries` is how many touched a declared cash account at all.
  • `netZero` is how many touched cash and moved none on net — a transfer between two cash accounts. Classification is not attempted for them: there is nothing to attribute.
  • `unresolved` is how many could not be classified. A statement with unresolved entries is still arithmetically whole — the residual is in `unattributed` — but its SPLIT is incomplete.

func Total

Action
1func Total() int
source

Total is how many statements every publisher has published together. There is deliberately no way to enumerate the publishers; see the package doc.

func Totals

Action
1func Totals(owner address, seq int64) (opening, netChange, unattributed, closing int64)
source

Totals is the four cumulative figures. `closing` is `opening + netChange`, and `opening` was supplied by the publisher — see OpeningReconciled for whether this realm was able to check it.

`unattributed` is the net movement of the entries in the unresolved census and is part of `netChange`, not additional to it.

func UnresolvedAt

Action
1func UnresolvedAt(owner address, seq int64, i int) (id uint64, reason string, net int64, categories, codes string)
source

UnresolvedAt is one unresolved entry, by index into the census.

  • `reason` is `conflict` (the non-cash legs classify to more than one category), `undeclared` (a non-cash leg's account has no policy rule) or `unbalanced`.
  • `net` is the entry's net cash movement, which is real movement the statement could not attribute.
  • `categories` is the conflicting categories, comma-separated, for a conflict.
  • `codes` is the undeclared account codes, comma-separated, for an undeclared entry. Declaring them may resolve the entry, which is why `undeclared` takes precedence over `conflict` when both apply.

func UnresolvedCount

Action
1func UnresolvedCount(owner address, seq int64) int
source

UnresolvedCount is how many entries could not be classified.

func Window

Action
1func Window(owner address, seq int64) (from, until int64)
source

Window is the period a statement covers, half-open: `from` is in, `until` is out.

Dependencies

Source Files 2