Skip to content

Fiscal institutions

canwu-fiscal, the fiscal simulation extension, models fiscal institutions as procedure: versioned rules, their adoption region by region, assessments, remissions, authorized collections and transfers, audits, receipts proven by evidence, accounting cycles that close and archive, and reports to observers. Grain, silver, and other balances stay in your resource or logistics domain; the fiscal extension records what was owed, what was authorized, and what evidence proved. Its state is partitioned into records, so a boundary reads and writes only the records its packets touch, and a world of tens of thousands of scopes runs on the same contracts as the three-scope Ming starts. Read this page when your game needs tax and treasury rules that change by period and region; the Ming content in canwu-ming-fiscal and the runnable canwu-ming-fiscal-reference integration are the worked example.

Crate What it owns Published
canwu-fiscal The period-neutral model: the pack schema and compiler (compile_fiscal_content), the catalog and the partitioned state records, FiscalPlugin, authority and appointment checks, receipt validation, accounting cycles, the fiscal archive, and holder reports Published on crates.io
canwu-ming-fiscal Ming content: the embedded data/pack.json (1368–1683), three start fixtures, and compile_ming_fiscal Published on crates.io
canwu-ming-fiscal-reference A runnable host: scenario builder, execution adapter plugin, semantic validator, trace writer and viewer, a sample cycle with its close and archive helpers, and the ming_fiscal_starter example Repository only
Crate dependencies: canwu-fiscal and the Ming pack build on canwu-api, and the reference integration combines them with the reference world. View diagram source.
View diagram source
flowchart TB
  Host["Your host application<br/>scenario, adapter, commands"]
  Ref["canwu-ming-fiscal-reference<br/>runnable Ming host"]
  Ming["canwu-ming-fiscal<br/>Ming data pack"]
  World["canwu-reference-world<br/>example world"]
  Fiscal["canwu-fiscal<br/>period-neutral model"]
  Resource["canwu-resource<br/>archive lookup index"]
  Api["canwu-api<br/>public API"]
  Host -.->|"can start from"| Ref
  Host --> Fiscal
  Ref --> Ming
  Ref --> World
  Ref --> Fiscal
  Ming --> Fiscal
  Ming --> Api
  Fiscal --> Api
  Fiscal --> Resource
  Resource --> Api
  World --> Api

Arrows point from a crate to what it depends on. Among Canwu crates, canwu-fiscal depends on canwu-api and, for the lookup-index functions of its archive only, on canwu-resource; no resource type appears in the fiscal API, and the engine core has no fiscal code. canwu-ming-fiscal holds data, a fixture loader, and a compile helper, with no runtime behavior. The reference integration borrows a government, an army, and people from canwu-reference-world to act as institutions and officials.

What is period-neutral and what the pack supplies

Section titled “What is period-neutral and what the pack supplies”
Layer Supplies Example
canwu-fiscal (period-neutral) Pack schema, validation, coverage resolution, closed vocabularies, fiscal records, actions, authority and appointment checks, receipt validation, accounting cycles, the archive, reports compile_fiscal_content, FiscalPlugin
Content pack (period-specific) Periods, regions, institutions, rules with legal windows, reform transitions, coverage declarations, and provenance with forbidden inferences canwu-ming-fiscal data/pack.json
Host (run-specific) Year and mode, bindings, appointment policies, starting adoption stages, institution entities, the execution adapter, the archive store, and the commands canwu-ming-fiscal-reference

The vocabularies are closed Rust enums in canwu-fiscal: 11 FiscalMechanism values (such as LandTax, SaltMonopoly, and MerchantCredit), 7 FiscalPaymentForm values (Grain, Silver, Labor, SaltCertificate, Coin, Goods, Credit), 10 FiscalAssessmentBasis values, and 4 FiscalCommutationPolicy values. A pack lists the mechanisms it uses in its manifest and maps its institutions onto these values.

compile_fiscal_content(&pack, selection) validates the whole pack and returns a CompiledFiscalCatalog. It requires canonical unique IDs, resolved references, windows inside the pack’s historical scope, a SemVer pack_version, the license Apache-2.0, provenance for every institution, rule, and transition, acyclic transition prerequisites, and a status for every coverage cell. In FiscalContentSelection, empty region and mechanism sets mean all of them. The catalog keeps every period, so one run can move through the years; selected_period_ids names the periods that cover the selection year, and content_hash hashes the whole pack.

Type What it represents
FiscalContentPack An authored pack: manifest, periods, regions, institutions, rules, transitions, coverage declarations, provenance
CompiledFiscalCatalog The immutable run catalog, stored as the create-only record canwu.fiscal:catalog
FiscalRuleDefinition One rule: mechanism, legal window, jurisdictions, assessment basis, payment forms, commutation policy, provenance, confidence
FiscalTransitionDefinition A reform: source and target rules, observed and eligibility windows, jurisdictions, rules it supersedes or suspends, prerequisites
FiscalState The logical and authoring model of the whole fiscal state: the root, the archive head, and the offices, scope ledgers, jurisdictions, observers, and report queue by key. into_records partitions it into the records a run holds; from_records assembles it
FiscalRoot The canwu.fiscal:root record: the historical context and its revision, approved evidence kinds, the earliest due time of the report queue, whether any queued entry is parked, and the parked rotation’s cursor
FiscalScopeLedger, FiscalCycleBook One scope binding’s record: its adoptions, one accounting cycle book per hot cycle (assessments, remissions, requests, receipts, audit findings), its revision, recent outcomes, and cycle watermark
FiscalOffice One institution’s record: authority and audit bindings, appointment policy and auditor proposals, per-cycle bookkeeping, the mechanisms of its scopes, and the observers that see it, each with its first row, granularity, and whether its cadence is an interval
FiscalJurisdiction One catalog region’s record: scope and adoption counts and the transition candidates
FiscalObserver One observer binding’s record: its row layout, cycle slots, and the digest of every published report part
FiscalReportSchedule The canwu.fiscal:report-schedule record: each report-queue page’s earliest due time and the pages that hold parked entries
FiscalHistoricalContext The current historical year and FiscalHistoricalMode
FiscalAuthorityBinding Who may act for one institution
FiscalAuditBinding, FiscalAppointmentPolicy, FiscalAuditProposal One outside auditor who may record audit findings on one institution; who appoints and removes it; a pending nomination or removal petition
FiscalActionIssuer, FiscalRebinding Who issued a settled action, under which binding and role; the action that last rebound or re-pointed a binding
FiscalScopeBinding One institution’s responsibility for one jurisdiction, subject scope, and mechanism
FiscalObserverBinding Who receives reports (a person, or a government with no actor), about which institutions, at what confidence and granularity, on what cadence, and which institution may re-point or remove it
FiscalReportGranularity, FiscalReportCadence What one row of a report is (Scope, the default, or Institution); when the report is due (OnChange, the default, or Interval { every, offset }, spread with staggered)
FiscalAdoptionState The stage of one rule in one scope, with a generation that counts changes
FiscalActionBatch, FiscalActionEntry, FiscalAction One command of up to 4,096 procedure steps under one binding; one step with its ID and expected revision; the step itself
FiscalActionBatchSet One command of up to 64 batches under one issuer, so several offices’ batches settle in one round
FiscalActionTarget The one record an action names the revision of: a scope ledger, an office, a jurisdiction, or an observer
FiscalExecutionRequest An authorization to collect, remit, disburse, reserve, or return a quantity
FiscalExecutionEvidence, FiscalExecutionEvidencePart The typed result an adapter writes after the real operation, naming the scope and request it settles; or, as aggregated evidence, one part per scope, each with its request and quantity
FiscalExecutionReceiptPacket, FiscalExecutionReceipt A receipt request citing exact evidence versions, and the settled receipt
FiscalArchiveKeyV1, FiscalArchiveStore The key of an archived book, institution totals, or maintenance receipt; the host-owned store the archive lives in
FiscalReport, FiscalProjection, FiscalReportFact One observer’s report as a reader gets it, with each total as a range and each fact labelled by cycle, row, and place
FiscalReportRecord One published knowledge record: a report’s summary, or one part of 16 rows (scope rows, or institution rows) of one cycle

FiscalAdoptionStage runs Promulgated, Communicated, Accepted, Implemented, Audited, Entrenched, Suspended, and Repealed. Only Implemented, Audited, and Entrenched are operational (is_operational), and an assessment can open only under an operational adoption. A rule can be promulgated for a province and still not be operational there.

A fiscal coverage cell (FiscalCoverageCell) is one period, region, and mechanism combination. The compiler builds every combination and resolves each one from the pack’s FiscalCoverageDeclaration entries: the matching declaration with the highest priority wins. A cell with no match fails compilation, and so does a tie at the top priority, so file order never picks a historical reading.

FiscalCoverageStatus Meaning Declaration rule
Supported Cited definitions support direct simulation Needs provenance and a rule or transition for the cell’s mechanism in that region
ArchetypeFallback A comparative archetype stands in, with stated limits Needs provenance and a rule or transition for the mechanism, possibly from another region
ExplicitUnknown The pack says it has no behavior for this cell Carries no definitions
NotApplicable The mechanism does not apply here Carries no definitions

The Ming pack has 8 periods, 8 regions, and 11 mechanisms, so 704 cells: 160 supported, 101 archetype fallback, and 443 explicit unknown. Of the unknowns, 425 come from the priority-0 default and 18 from zheng_other_mechanisms, a priority-60 declaration covering nine mechanisms in two regions of the Zheng period. Each FiscalProvenance entry names a citation, URL, claim scope, confidence, and at least one forbidden inference, such as “Do not infer actual receipts directly from statutory quotas.”

Coverage, provenance, confidence, and commutation policy are catalog metadata for your host, tools, and reviewers. The plugin’s admission checks read rules, legal windows, jurisdictions, mechanisms, payment forms, and adoption stages.

A run keeps its fiscal state as records in the canwu.fiscal namespace. No fiscal record references another, except the root’s reference to the create-only catalog, so writing one record makes the engine re-validate no other:

Kind Identity Holds Written when
catalog primary the compiled catalog never after creation
root primary the historical context and its revision, approved evidence kinds, the earliest due time of the report queue, whether a queued entry is parked, the parked rotation’s cursor a context change, report bookkeeping
archive primary the archive head (FiscalArchiveHeadV1): what every applied commit archived, the maintenance receipts, the unacknowledged retention handles an archive commit or acknowledgement
office fiscal_office_key(&institution) authority and audit bindings, appointment policy and proposals, revision and outcome ring, per hot cycle the hot-book count, partition keys, and archived totals, the cycle watermark, the mechanisms of its scopes, the observers that see it with each one’s first row, granularity, and cadence kind a binding, proposal, or appointment action; the first book or partition key of a cycle in one of its scopes; an archive commit
ledger scope binding ID the scope binding with its office key and rank, revision and outcome ring, adoptions, one FiscalCycleBook per hot accounting cycle, the cycle watermark an action, receipt, close, or archive commit on the scope
jurisdiction catalog region ID revision and outcome ring, scope counts per mechanism, adoption counts per rule, transition candidates an adoption change or transition in the region, a context change that moves its candidates
observer observer binding ID the binding, revision and outcome ring, row layout, cycle slots, and the digest of every published part a publication to the observer, a re-pointing, a removal
directory dir. and 3 hex digits the office of every binding, policy, and proposal ID whose digest names the bucket a binding, policy, or proposal is created, moved, or removed
index index., the owner’s digest, and a page number the scopes of one office in rank order, or of one region, 1,024 to a page never after creation
report-queue queue. and 3 hex digits the report work owed to every observer whose binding ID’s digest names the page, each entry with its due time a book changes that an observer sees; a publication; an interval report queued again at its next due time
report-schedule primary each report-queue page’s earliest due time, and the pages that hold parked entries a page’s earliest due time or parked count changes

Build the state with FiscalState::new and the add_* helpers (add_scope, add_adoption, add_assessment, add_authority_binding, add_audit_binding, add_appointment_policy, add_audit_proposal, add_observer), then call FiscalState::into_records(&catalog): it brings every derived field up to date (ranks, counts, candidates, office cycle bookkeeping, observer layouts, the report schedule’s page due times and the root’s earliest due time), validates the state, and partitions it, directory buckets, index pages, queue pages, and the schedule included. A derived field you supply is recomputed, never trusted. Activation runs audit_fiscal_records on every new scenario and restored snapshot, so a record set that is not exactly the partition of a valid state is refused when the run is created. load_fiscal_state assembles a run’s committed state for a host, at a cost proportional to the fiscal records; fiscal_root_reference, fiscal_office_reference, fiscal_ledger_reference, fiscal_jurisdiction_reference, fiscal_observer_reference, fiscal_archive_reference, and fiscal_report_schedule_reference name single records.

Every record has a byte budget, held at settlement less FISCAL_RECORD_RING_RESERVE_BYTES (4 KiB), which keeps room for the record’s outcome ring: a ledger MAX_FISCAL_LEDGER_RECORD_BYTES (256 KiB, its payload measured exactly), an office or a jurisdiction MAX_FISCAL_RECORD_BYTES (1 MiB); the others are bounded by their counts. An action whose result would not fit is rejected as its own outcome with FISCAL_RECORD_BUDGET_EXHAUSTED, and its rejection fits in the reserve; a receipt or historical-context change that would not fit is refused with state_budget_exhausted. A ledger with one hot annual book takes about 1 to 2.5 KiB, so a ledger reaches its budget only with years of books left unarchived: close and archive them. An office is held to its bytes plus the room its hot cycles keep for what archive commits will merge into them, so an archive commit never puts an office past its budget, and a settled run’s records always restore.

Every host helper takes either run handle, Canwu or a sealed CompactedCanwu, through canwu_api::CanwuRun: fiscal_action_target, fiscal_target_revision, fiscal_recent_outcome, enqueue_execution_receipts, load_fiscal_state, audit_fiscal_records, fiscal_reports_of_holder, enqueue_fiscal_archive, and finalize_fiscal_archive_retention. They read only current records and the current-version index, so a run that sealed its evidence reads and settles as its unsealed fork does.

Fiscal flow from an operational rule through assessment, authorization, external evidence, and receipt into the scope's book, the archive, and holder reports. View diagram source.
View diagram source
flowchart TB
  Adopt["Rule operational in a scope<br/>FiscalAdoptionState"] --> Assess["OpenAssessment<br/>opens the cycle's book"]
  Assess --> Remit["GrantRemission<br/>lowers what is owed"]
  Assess --> Auth["AuthorizeExecution<br/>FiscalExecutionRequest"]
  Auth --> Adapter["Host adapter moves goods<br/>in its own domain"]
  Adapter --> Evidence["Evidence record<br/>FiscalExecutionEvidence payload"]
  Evidence --> Packet["FiscalExecutionReceiptPacket<br/>cites exact versions"]
  Packet --> Receipt["FiscalExecutionReceipt<br/>quantity and disposition from evidence"]
  Remit --> Book["Scope ledger<br/>FiscalCycleBook totals"]
  Receipt --> Book
  Book --> Report["Phase 13<br/>holder report as knowledge"]
  Book --> Close["CloseAccountingCycle"]
  Close --> Archive["Fiscal archive<br/>host store"]

A rule adopted in a scope is the liability; an assessment fixes how much is owed for one accounting cycle and opens that cycle’s book in the scope’s ledger. The engine runs the flow like this:

  1. Install. The scenario carries the compiled catalog (CompiledFiscalCatalog::into_record) and the records of the starting state (FiscalState::into_records). Register FiscalPlugin::new(evidence_kinds), adding .with_authority_basis_kinds(kinds) when bindings use acting actors or auditors, .with_report_cadence(cadence), the wake cadence (the SystemCadence on which wake-fiscal-reports-on-cadence-v1 runs, distinct from a binding’s report cadence) when your boundaries can pass without any event, and .with_report_budget(...) or .with_report_retention(...) to change the report share or the retention of report records (see how a report is published). These knobs are part of the plugin’s recorded identity: choose them before the first boundary, since a restore or replay with another setting is refused. Activation audits every fiscal record, so a run with an invalid or incomplete fiscal record set is refused when it is created or restored, before any boundary runs. Activation also rejects a binding whose authority basis is of a kind the plugin does not read, and a state whose first report derivation would not fit.

  2. Submit. Read the revision of the action’s target with fiscal_target_revision (or fiscal_action_target to find the target of a binding and action), build a FiscalActionBatch of one or more entries under one binding (FiscalActionBatch::single for one), wrap it with fiscal_action_command to get a domain command for apply_fiscal_action_v1, and queue it with Canwu::enqueue_command; the legacy direct command path fails with MixedCommandIngress. Each entry carries its action ID, its target’s expected_revision, and the action. An institution that assesses many scopes in one accounting step sends them in one batch. A person who acts for several offices at one instant sends their batches as one FiscalActionBatchSet with fiscal_action_set_command (apply_fiscal_action_set_v1), so they are admitted at one boundary and all settle at the next (see batch sets).

  3. Admit. At the boundary that admits the command, the handler reads the directory bucket, the office, and each entry’s target record and refuses the whole batch, naming the index and reason of the first inadmissible entry (entry 3: ...), for:

    • more than MAX_FISCAL_BATCH_ENTRIES (4,096) entries, a batch over 4 MiB, an entry over 32 KiB, a non-canonical action ID, binding ID, or ID of a new entry, free text longer than 2,048 bytes, a unit or referenced ID longer than 160 bytes, or one action ID named twice for one target (InvalidPayload);
    • an action ID with an outcome in its target’s ring (IdempotencyConflict), a revision above the target’s (ValueOutOfRange, FISCAL_REVISION_UNKNOWN), or one at or below the target’s outcome floor (ValueOutOfRange, FISCAL_REVISION_EXPIRED), which is how a re-send of an evicted outcome is refused;
    • an issuer who holds no role under the binding, an action that role does not admit, a scope the binding’s institution does not own, including an unknown ApplyTransition target scope, an authority basis that is no longer the current version of its record, or an appointment action the institution’s policy does not allow (InvalidAuthority);
    • an assessment, action scope, audit target, or commutation quote that does not exist, a person that a rebind or nomination names but the run does not hold, or a new authority basis of a kind the plugin does not read (EntityNotFound). A quote must be the current exact version of its record, or a version from the initial scenario, and of a kind the plugin reads. A superseded version that the initial scenario did not provide counts as missing, so a run sealed with seal_evidence admits the same quotes as its exact replay.

    The engine records each refusal as a rejected attempt in Canwu::command_attempts, the boundary commits, and no action ID is used up. Admission does not compare the revision with the state the entry will settle on; settlement does. The handler then schedules one internal fiscal_action_v1 item of canonical ingress (class Decision) that carries the batch and the role the issuer held. A host cannot enqueue that packet itself: the type is internal, and a packet settles only when its ingress record names, as its cause, the command the packet carries.

  4. Settle (phase 7). At the next boundary, settle-fiscal-ingress-v1 runs in DomainDeltaProposal. It settles archive commits and retention acknowledgements first, then every other admitted packet in admission order. It groups the batch entries by target, decodes each target once, and for each entry decides whether it is stale (see targets, revisions, and actions in one boundary), re-checks the issuer’s role and authority basis against the office, applies the action to a copy of the records the previous entry left, and validates every record it changed. It records an Applied or Rejected outcome in the target’s outcome ring, advances the target’s revision, and emits one canwu.fiscal.action_settled.v1 event per entry. The next entry starts from the last good records, and the boundary commits whatever happened to any entry.

  5. Receipts and context. The same system settles fiscal_execution_receipts_v1 (packets of up to 4,096 receipts sent with enqueue_execution_receipts, class Acknowledgement, event canwu.fiscal.execution_receipt_recorded.v1) and fiscal_historical_context_v1 (built with fiscal_historical_context_ingress and queued with enqueue_plugin_ingress, event canwu.fiscal.historical_context_changed.v1). Each receipt settles or is refused on its own, and a refused receipt or context change changes nothing: its only record is one canwu.fiscal.ingress_rejected.v1 event whose summary names the packet and ends with a stable reason (see receipts). Nothing a host can send fails the boundary.

  6. Derived fields. Settlement writes each record it touches with its derived fields current: a ledger’s books carry their totals, an office its cycle bookkeeping, a jurisdiction its counts and transition candidates. There are no separate derived systems and no stored aggregates; a report row is read from its scope’s book.

  7. Report (phase 13). materialize-fiscal-reports-v1 runs in PerspectiveAndReportMaterialization. For each observer whose report is due and whose queued work fits the boundary’s remaining publication budget, it publishes the summary and the parts whose rows changed; see knowledge and visibility.

Both systems are event-driven, so they run in every boundary that admits an event or any ingress, and each first checks cheaply whether it has work: settlement returns when the boundary admitted no fiscal ingress, and the report system reads the root and returns when no report is due yet and nothing is parked. A boundary that has nothing to do with fiscal procedure therefore reads the root only, whatever the world holds. If your boundaries can pass without any event, register FiscalPlugin::with_report_cadence(cadence): on every boundary of that category with no event, the small system wake-fiscal-reports-on-cadence-v1 reads the root and, when a report is due, schedules the internal drain packet due at once, so the report system runs in the next boundary at the same instant. SystemCadence::EventDriven is refused there, and that wake cadence is recorded in the plugin descriptor; the report system itself stays event-driven, and the wake cadence is not a binding’s report cadence, which says when one report is due.

In the Ming starter, the assessment command is admitted at boundary 1 and settles at boundary 2, the authorization takes boundaries 3 and 4, the adapter writes its evidence at boundary 5, and the receipt settles at boundary 6.

FiscalAction Target Effect Main checks
ChangeAdoption ledger Creates an adoption or changes its stage; the generation increases on each change The rule’s mechanism matches the scope and the rule covers its jurisdiction; a new adoption needs the year inside the rule’s legal window and cannot start a transition target at an operational stage; at most 64 adoptions per ledger
ApplyTransition jurisdiction Sets the target rules to Implemented in one jurisdiction and suspends the rules the transition supersedes there, in one action; every ledger whose adoptions it changes advances its revision Each target rule is bound once; target scopes share one jurisdiction; the transition is a current candidate there; the binding owns every target scope
OpenAssessment ledger Records a quantity, unit, payment form, accounting cycle, and optional commutation quote, opening the cycle’s book in the scope if it has none The year is in the rule’s legal window; the adoption is operational; the rule allows the payment form; one assessment per scope, cycle, unit, and payment form; the cycle is above both of the scope’s watermarks; at most 64 hot books per ledger and 64 hot cycles per office; at most 4 partition keys per institution, mechanism, and cycle
GrantRemission ledger Lowers what is owed, in an open book Total remission stays within the assessed quantity; at most 256 per book
AuthorizeExecution ledger Creates a FiscalExecutionRequest of kind Collect, Remit, Disburse, Reserve, or Return, in an open book The unit matches the assessment; source and target differ; the institution is one of them; Collect requests stay within the assessed quantity minus remissions; at most 256 per book
RecordAudit ledger Records a finding with a FiscalAuditSeverity and evidence on an open or closed book; the finding names who entered it, under which binding, and who appointed and nominated the auditor The target is an assessment, request, or receipt of the scope; issued under an authority binding of the institution that owns the scope, or under an audit binding on it; at most 256 per book
CloseAccountingCycle ledger Closes one book of one scope, so that it takes only audit findings and can be archived The book exists and is open; issued under an authority binding of the scope’s institution
RebindAuthority office Replaces an authority binding’s authorized actor, acting actor, and authority basis together See rebinding authority
RebindAudit office Installs, replaces, or removes an audit binding, as the audited institution’s own direct decision Only where the institution’s appointment policy makes it its own appointer
NominateAuditor, PetitionAuditorRemoval, DecideAuditAppointment office Propose a candidate, ask for an auditor’s removal, and decide on a proposal or directly See audit bindings
RebindObserver, RemoveObserver observer Re-point an observer binding to another actor or holder, or remove it Issued under an authority binding of the binding’s controlled_by institution, by its principal or by the institution as a body; a binding with no controlling institution cannot change

GrantRemission, AuthorizeExecution, and RecordAudit name their scope in scope_binding_id, because object IDs are unique among a scope’s hot objects, not across the state. Every book object records the action that created it in source_action_id.

A FiscalExecutionReceiptPacket holds a receipt ID, the scope it settles, a request ID, and 1 to 32 exact evidence versions. For each version, the plugin checks that its kind is in the root’s approved evidence kinds, that the exact version is the current version of its record or a version from the initial scenario, and that its payload decodes as FiscalExecutionEvidence whose scope, request, unit, payment form, execution kind, resource, source, and target match the request. All cited records share one disposition, their total stays within the requested quantity, and each was established no earlier than the request. The receipt’s quantity and FiscalReceiptDisposition come from that evidence. Fulfilled and Partial count toward the totals; Rejected and Excused carry zero. An exact version settles at most one receipt in each scope it names, and one (evidence kind, external_operation_id) pair at most one among the scope’s hot books. Resending the same receipt with the same content changes nothing.

Aggregated execution evidence. One operation that serves several scopes, such as an office’s collection day across its scopes, can be one evidence record. It leaves scope_binding_id and request_id empty and lists parts, up to MAX_FISCAL_EVIDENCE_PARTS (4,096) FiscalExecutionEvidenceParts, at most one per scope, each naming the request it settles and its quantity; the parts’ quantities sum to the record’s quantity, and the record’s other fields (such as unit, payment form, execution kind, resource, source, target, and disposition) apply to every part. Send one receipt per part, each naming its own scope and request and citing the same exact version; one packet can carry them all. Each receipt settles the part naming its scope, at the part’s quantity, by the rules above. A receipt is refused as request_unknown when its part names a scope or request with no hot request; as claim_mismatch when the record has no part for the receipt’s scope, or the part names another request; and as quantity_exceeded when the part asks more than its request still authorizes. A record with a top-level scope or request beside its parts, two parts for one scope, too many parts, or parts that do not sum to its quantity settles no receipt (claim_mismatch). Each part’s receipt is refused or settles on its own.

Receipts come in packets of up to MAX_FISCAL_RECEIPTS_PER_PACKET (4,096) through enqueue_execution_receipts, settled in order, each against its scope’s ledger. A receipt that settlement cannot accept is refused with canwu.fiscal.ingress_rejected.v1 and the receipts after it settle:

Reason When
malformed_payload the packet does not decode
request_unknown the scope holds no hot request with that ID (it never had one, or its book was archived)
cycle_closed the request’s book is closed
evidence_count_invalid, evidence_kind_unapproved, evidence_not_current no evidence or more than 32 versions; a kind the root does not approve; a cited version that is not its record’s current version, for example because the record changed after the packet was queued
claim_mismatch, quantity_exceeded a claim differs from the scope, the request, or the other claims, or predates the request, or aggregated evidence has no part for the scope or breaks its rules; the receipts would fulfil more than the request authorizes
operation_reused, evidence_reused, receipt_id_conflict already settled by a receipt of the scope’s hot books; a hot receipt has the ID with other content
state_budget_exhausted, boundary_limit the ledger would exceed its byte budget; the boundary already wrote 65,536 ledgers (send it again)
context_outside_pack, invalid_packet a context year outside the pack; anything else that leaves the state invalid

A refused receipt consumes nothing, so a corrected one can settle later; if a cited record changed, cite its new version. Cite create-only evidence kinds so that a pending receipt stays current. Use each request ID once per scope for the life of a run: a request ID used again in a later book, at the same simulated time as the evidence of an archived request of that ID, could take that evidence again.

Each ledger, office, jurisdiction, and observer record has its own revision. An outcome (applied or rejected) and a receipt on a record advance that record’s revision by one; a transition advances the revision of every ledger whose adoptions it changes. Archive maintenance, report bookkeeping, and a historical-context change advance no action target, so none of them makes a pending decision stale.

An entry applies only when its expected_revision is its target’s revision at the start of the boundary that settles it. An action is therefore stale only when its own target changed since its issuer looked: activity on another scope or institution leaves it current, and an institution that assesses its scopes in one batch has every entry settle together whatever happened elsewhere. Within a boundary, entries settle in admission order, each validated against the records the previous ones left. A later entry may build on what an earlier one created (an assessment may rely on an adoption the entry before it made operational), but it is rejected as stale if it would overwrite an adoption, binding, policy, proposal, or observer an earlier action of the boundary changed, a transition’s included. Actions that only create do not conflict: two remissions on one assessment both apply when their sum validates. A receipt that settles in the same boundary does not make an entry stale.

Action IDs are per target. Each target keeps the FISCAL_RECENT_OUTCOMES (8) most recent outcomes in a ring and an outcome floor, the revision of the newest outcome the ring evicted. Admission refuses an ID in the ring and a revision at or below the floor, and settlement skips, without an outcome or an event, a copy of an action whose outcome its target’s ring holds or the boundary has already settled; so an action applies at most once, across and within boundaries. Every outcome is recorded for good in its canwu.fiscal.action_settled.v1 event, which FiscalSettledAction::from_events reads back, and fiscal_recent_outcome answers for the outcomes still hot. Reissue a stale or rejected action under a new action ID against the revision you read; never predict a revision.

No action fails a boundary for the others. Each limit rejects the action that would pass it as its own outcome, with a stable reason, and the boundary commits:

Limit Value Reason
MAX_FISCAL_ACTIONS_PER_BOUNDARY 65,536 applied actions FISCAL_BOUNDARY_ACTION_LIMIT
MAX_FISCAL_LEDGER_WRITES_PER_BOUNDARY 65,536 ledgers, actions and receipts together FISCAL_BOUNDARY_ACTION_LIMIT (a receipt: boundary_limit)
MAX_FISCAL_ACTIONS_PER_RECORD_PER_BOUNDARY 64 applied actions on one target FISCAL_RECORD_ACTION_LIMIT
MAX_FISCAL_PARTITION_KEYS 4 partition keys per institution, mechanism, and cycle FISCAL_PARTITION_KEYS_EXHAUSTED
MAX_FISCAL_HOT_BOOKS_PER_LEDGER, MAX_FISCAL_HOT_CYCLES_PER_OFFICE 64 books per ledger, 64 cycles per institution FISCAL_HOT_BOOKS_EXHAUSTED
Record byte budgets see records and byte budgets FISCAL_RECORD_BUDGET_EXHAUSTED

A stale or unauthorized action is rejected without using a limit. None of these is a lifetime cap: closing and archiving books frees them.

A FiscalActionBatchSet carries 1 to MAX_FISCAL_BATCH_SET_BATCHES (64) batches, at most MAX_FISCAL_BATCH_SET_JSON_BYTES (16 MiB) and 65,536 entries in all, each batch within the batch limits. Admission admits each batch as apply_fiscal_action_v1 admits one, under the set’s one issuer, and queues one fiscal_action_v1 packet per batch, in order; an action ID named twice for one target across the batches, or anything one batch’s admission refuses, refuses the whole set, and the message begins with batch N:. The next boundary settles the batches exactly as it settles several batch commands admitted together: each entry against its target’s revision at the start of that boundary, within the same per-boundary limits. Batches that change different records therefore leave the same books and outcomes as the same batches sent one round after another, but in two boundaries in all instead of two per batch. The issuer must hold a role under every batch’s binding; the issuer of a decision in one’s own name does, as authority describes.

Each scope’s ledger holds one FiscalCycleBook per hot accounting cycle, and each institution’s office counts its hot books per cycle. Accounting cycle IDs belong to your host and are separate from historical periods; they compare in byte order, so name them so that they sort ("1644", "1644-03").

  • OpenAssessment opens a cycle’s book. CloseAccountingCycle closes one book of one scope; a closed book takes audit findings and nothing else (FISCAL_CYCLE_CLOSED for an assessment, remission, or authorization, and cycle_closed for a receipt). Books may be closed and archived in any order.
  • An archive commit takes closed books out of their ledgers into the fiscal archive. It raises each scope’s watermark to the greatest cycle it archived and, in the commit that archives an institution’s last hot book of a cycle, archives that institution’s totals of the cycle once and raises the office watermark. No book is opened at or below either watermark (FISCAL_CYCLE_ARCHIVED), so an accounting partition (scope, cycle, unit, payment form) is assessed at most once for the life of a run without reading the archive. A hot book below the office watermark is unaffected.
  • The host archives, with the protocol of the resource and production archives: prepare_fiscal_archive(&run, book_limit, &store) selects closed books in (scope, cycle) order, up to MAX_FISCAL_ARCHIVE_COMMIT_RECORDS (4,096) records in blobs of 64, and builds the blobs, membership, temporal, and lookup-index pages, and the directory of a PreparedFiscalArchiveBatchV1; enqueue_fiscal_archive(&mut run, &prepared, &store) prepares the batch again, requires equality, stores and verifies it in your FiscalArchiveStore, persists the retention handle, and queues the commit (fiscal_archive_commit_v1); finalize_fiscal_archive_retention queues the acknowledgement once the commit has settled. Prepare and enqueue in one gap between boundaries. The helpers take any run handle (CanwuRun) and read only the records a commit needs: the root, the archive head, enough of each ledger to see whether it holds a closed book, and the ledgers and offices of the books the commit takes; finalizing reads the head alone. Preparation refuses (FiscalArchiveError::Backpressure) while the head holds MAX_FISCAL_ARCHIVE_PENDING_HANDLES (64) unacknowledged handles, before it reads any ledger.
  • The sealed cut comes from the run. A book citing an evidence version established after the run’s last seal is refused at preparation (FiscalArchiveError::UnsealedCitations) until a seal covers it, because archiving a book ends the ledger’s payload-required declaration of the quotes and receipt evidence it cites. The helpers read that cut through sealed_evidence_cursor() (on Canwu, CompactedCanwu, and any CanwuRun): the end of the run’s last seal, and None until a run seals after it is created or restored. A run that has not sealed (every Canwu, a CompactedCanwu that has never sealed, a run restored with its whole journal or from a continuation checkpoint, until its next seal) refuses nothing: a continuation restore holds no sealed segment, so its base is not a seal. A sealing host therefore seals at each save, before it writes a continuation checkpoint, if every archived citation is to lie in a sealed segment; a host that saves only by continuation checkpoint and never seals sees no such refusal in any session.
  • A commit settles before every other fiscal packet of its boundary and is checked against the records it binds alone: the archive head, the revision of each selected book, and the affected cycle entries of their offices. An action, receipt, or commit on other books leaves it current. A commit prepared from older books settles as a stale no-op with a receipt and a handle the host acknowledges; a copy of a commit whose handle the head already holds records nothing; each is recorded in its canwu.fiscal.archive_maintenance.v1 event. An acknowledgement retires its handle once. Neither advances any revision. A stale commit past the head’s room (64 unacknowledged stale handles), and one that does not match, is refused with the refusal event and changes nothing; such a commit has no retention handle in the state, so finalize_fiscal_archive_retention returns an error for it and the host abandons that store copy itself.
  • No boundary reads the archive store. Admission, settlement, idempotency, and partition uniqueness use the hot records only, so a run settles exactly the same whether or not its store can be read, and restore and exact replay need no store. Only the host’s archive operations read a store: archived_fiscal_record looks up an archived book, an institution’s totals of a cycle, or a maintenance receipt by FiscalArchiveKeyV1 through the cumulative archive lookup index, and audit_fiscal_archive checks the whole archive against the head. () is a store that holds nothing.

Each closed book’s per-cycle totals are archived with it, and an institution’s totals of a cycle exactly once. The Ming fiscal case shows close_ming_fiscal_sample_cycle and archive_ming_fiscal_books, and its archive_century test runs a century with an archive cadence while the fiscal records stay a few kilobytes.

The fiscal historical context holds year and mode. RecordedBaseline and ResearchReplay test a transition’s observed_window; Counterfactual tests its eligibility_window. A transition becomes a FiscalTransitionCandidate of a jurisdiction when the year fits, the jurisdiction has scopes for the target mechanisms, one of the transition’s source rules (if it names any) is adopted there and not repealed, the targets are not all operational yet, and prerequisite transitions have operational targets there. Settlement keeps each jurisdiction record’s candidates current, and a context change rewrites only the jurisdictions whose candidates move. A candidate applies only through an authorized ApplyTransition. A context change outside the pack’s scope, or one the state does not accept, is refused with the event and changes nothing; an accepted one advances the root’s context_revision and makes no action stale.

FiscalAuthorityBinding names an institution (an EntityRef), a standing authorized_actor, and optionally an acting_actor with an authority_basis. Admission accepts two issuer shapes:

Issuer Admitted when
Issuer::Actor(actor), no decision controller actor is the binding’s authorized or acting actor, or a person the governing appointment policy lists
Issuer::Human or Issuer::Ai, equal to the validated decision_controller_id The command subject in CommandAuthority is the binding’s institution, and the decision origin is DecisionOrigin::Actor naming a bound actor, or DecisionOrigin::Institution for that institution with a bound responsible actor

A batch set also admits a decision in one’s own name: a validated decision whose origin is DecisionOrigin::Actor { actor } and whose command subject is EntityRef::Person(actor). Admission treats such a decision as that person issuing directly under each batch’s binding, so a person who is the authorized or acting actor of several offices can cover all of them in one set. Under an authority binding, the decision holds the principal or acting role the person holds; under an audit binding or appointment policy, it acts as the person in their role as auditor or listed person. It never holds the institution role. The batch command does not admit it. Register such a controller (DecisionAuthority::Actor with that person as command subject) only if it may use all of that person’s fiscal roles: any ticket that offers it a set command lets it act in every office the person holds.

The binding’s institution must also own the action’s scope; for ApplyTransition it must own every target scope, and for an observer action it must be the binding’s controlled_by institution. An acting actor needs an exact authority basis version and must differ from the authorized actor. The basis is a record of an external kind the plugin reads: a kind declared with with_authority_basis_kinds, or an evidence kind passed to FiscalPlugin::new. The acting actor is admitted while that version is still the current version of its record. Once the record advances or retires, the acting actor fails with FISCAL_ACTING_BASIS_NOT_CURRENT (InvalidAuthority) and the authorized actor is still admitted.

Every admitted batch records the role its issuer held (FiscalIssuerRole: Principal, Acting, Institution, Auditor, or ListedActor). Settlement checks that role again against the office for every entry, after any earlier entry of the boundary that changed that office. An entry of an actor who has since been replaced is rejected with FISCAL_ISSUER_NOT_BOUND, and one of an acting actor whose basis is no longer current with FISCAL_ACTING_BASIS_NOT_CURRENT. Currentness is read from an index of current record versions that sealing evidence does not change, so a sealed run decides exactly as its replay does.

Scope bindings come from the starting scenario, and no fiscal action edits them. Authority, audit, and observer bindings also start there and change during a run only through the actions below.

When a grant is renewed or an office changes hands, FiscalAction::RebindAuthority replaces a binding’s authorized actor, acting actor, and authority basis in one commit:

FiscalAction::RebindAuthority {
authority_binding_id,
authorized_actor,
acting_actor,
authority_basis,
}
  • Who may issue it. The request is issued under the binding it replaces, by one of two issuers. The first is the binding’s authorized actor, directly or as a decision origin. The second is the institution deciding as a body: a decision controller whose command subject and decision origin are the binding’s institution, with no responsible actor. An acting actor cannot rebind, and neither can any other person.
  • The institution role is the power to appoint. A controller of that shape can name any actors, or none, and on a binding with no authorized actor it then acts as principal itself. Register such a controller only for the body that appoints the binding’s actors.
  • Persons and basis. Every person the action names must exist; a missing one rejects the command as EntityNotFound. acting_actor and authority_basis are set together. The basis must be the current version of its record when the command is admitted and again in the state the settling boundary began with; otherwise the action is rejected with FISCAL_AUTHORITY_BASIS_NOT_CURRENT.
  • The hand-over is one commit. Entries admitted earlier settle in admission order around the rebind: those before it under the previous actors, those after it rejected. The new actors are admitted from the first admission after the commit. No committed state admits both the old and the new actors, and none admits neither.
  • Evidence. The binding records the rebind in rebound_by (FiscalRebinding): the action ID, the time, and the issuer’s binding, role, and person.

A FiscalAuditBinding lets an auditor from outside an institution record findings on it. It lives in the audited institution’s office beside the authority bindings and names the audited institution, the auditor, and the auditor’s own authority_basis. A request names an audit binding in the same authority_binding_id field; binding and policy IDs are one namespace.

Under an audit binding:

  • only RecordAudit is admitted, and only for a target whose scope the audited institution owns;
  • the issuer must be the auditor, directly or as the deciding or responsible actor of a validated decision on the audited institution;
  • the basis must be the current version of its record at admission and in the state the settling boundary began with (FISCAL_AUTHORITY_BASIS_NOT_CURRENT otherwise).

An auditor gains no other fiscal authority, because no check of who may act for the institution ever looks at audit bindings. Every settled finding names who entered it in FiscalAuditFinding::entered_by (the binding, the role, the person, and the basis) and keeps, in appointed_by and nomination, who appointed and nominated the auditor as the binding held them.

Who appoints and removes an institution’s auditors is its appointment policy, a FiscalAppointmentPolicy declared with the state through FiscalState::add_appointment_policy, at most one per audited institution:

  • The appointer is the institution whose decision appoints and removes. It decides with FiscalAction::DecideAuditAppointment { audit_binding_id, decision } under one of its own authority bindings, as that binding’s principal or as a body; an acting actor never decides. The decision is AcceptNomination (appoint the candidate of a pending nomination, under the basis he was nominated with, which must still be current), Appoint (directly, if appoints_without_nomination), AcceptPetition (remove the auditor the petition names, who must still hold the binding), Remove (directly, if removes_without_petition), or Dismiss (a pending nomination or petition).
  • Nominators and petitioners are institutions, acting under one of their authority bindings, or persons the policy lists by name, acting under the policy’s own ID (FiscalIssuerRole::ListedActor). A nominator proposes a candidate and an authority basis with NominateAuditor { nomination_id, audit_binding_id, institution, candidate, authority_basis }; the binding need not exist yet. A petitioner asks for the removal of a binding’s current auditor on evidence grounds with PetitionAuditorRemoval { petition_id, audit_binding_id, grounds }.
  • Tenure. Replacing a seated auditor by another is a removal as well as an appointment, so it needs removes_without_petition (FISCAL_PETITION_REQUIRED otherwise); where the policy protects him, the appointer accepts a petition against him first and then fills the vacancy. Appointing into a vacancy, or the seated auditor again on a renewed basis, removes nobody and needs only the appointment rule (FISCAL_NOMINATION_REQUIRED without a nomination where one is required).
  • Proposals. Each nomination and petition is a FiscalAuditProposal in the audited institution’s office, recorded with its party and issuer, and pending until it is resolved once: accepted or dismissed by the appointer, or superseded. A party’s new proposal of the same kind on the same binding replaces its pending one; an appointment supersedes every other nomination pending on the binding, and the petitions only when it replaces the auditor they name; a removal supersedes every other petition and leaves nominations pending for the vacancy. Each party has room for MAX_FISCAL_PENDING_PROPOSALS_PER_PARTY (4) pending proposals under a policy, so no party can take another’s (ValueOutOfRange past it), and each policy keeps its latest MAX_FISCAL_RESOLVED_PROPOSALS_PER_POLICY (64) resolved proposals.
  • Refusals. Every refusal is recorded: at admission as InvalidAuthority (FISCAL_ISSUER_NOT_LISTED, FISCAL_ISSUER_NOT_APPOINTER, FISCAL_NOMINATION_REQUIRED, FISCAL_PETITION_REQUIRED, FISCAL_APPOINTMENT_POLICY_MISSING), InvalidPayload (FISCAL_PROPOSAL_NOT_PENDING), EntityNotFound, or ValueOutOfRange; at settlement, when the issuer’s role is gone or the cited proposal was resolved by an earlier entry of the boundary, as a Rejected outcome.

FiscalAction::RebindAudit { audit_binding_id, auditor, authority_basis } installs a binding, replaces its auditor and basis, or, with both None, removes it, as the audited institution’s own direct decision. It is admitted only where the policy makes the audited institution its own appointer and lets it act without a nomination (to install), a petition (to remove), or both (to replace); it then has the effects of the matching decision. Anywhere else the audited institution cannot change its auditors (FISCAL_ISSUER_NOT_APPOINTER), and an institution with no policy has only the audit bindings installed with the state (FISCAL_APPOINTMENT_POLICY_MISSING).

For institutions that decide through seats, votes, and procedure stages, see Society, culture, and law.

The fiscal records are authoritative state. Your host can read them with trusted reads such as typed_domain_record(&fiscal_ledger_reference(scope)) or assemble them with load_fiscal_state. Players and agents should read the fiscal report, which is holder-relative knowledge.

A FiscalObserverBinding names who holds its report in knowledge_holder: the person of its actor, or, with no actor, a government, so a court or a ministry can hold a report no one person does. It lists the institutions the observer sees (at most 4,096, with at most 16,384 rows among them), a confidence_per_mille up to 1,000, optionally the institution that controlled_by lets re-point or remove it, and the binding’s granularity and cadence, both with defaults, so a scenario that names neither behaves as it did in 0.16.0. Set them before FiscalState::add_observer; a rebinding changes neither.

  • FiscalReportGranularity::Scope (the default): the report has one row for each scope of the institutions it sees, in the order of the binding’s institutions and each institution’s scopes in rank order. A row lists the facts of that scope’s book of a cycle, one FiscalReportFact per unit and payment form, where assessed, collected, and outstanding are each a FiscalAmountEstimate range.
  • FiscalReportGranularity::Institution: one row for each institution it sees and each mechanism of the institution’s scopes, whose facts are the institution’s hot books of the cycle of that mechanism summed per unit and payment form (each amount saturating at u64::MAX, so a sum never fails a boundary), rendered at the binding’s confidence. A court over 21 institutions of one mechanism each reads 21 rows, two parts a cycle, however many scopes they have. Summing reads each book once per boundary that publishes such a part. A part of institution rows cannot cite every ledger version it summed within the evidence a knowledge record may carry, so it cites the current version of each office its rows belong to and records in books_summed how many books it summed: weaker provenance than a scope part’s.
confidence_per_mille Bucket width for a value whose magnitude is M
900 to 1,000 M / 100
750 to 899 M / 10
500 to 749 M / 2
below 500 M

M is the largest power of ten at or below the value, and every width is at least 2, so each total reads as a range. At 850, an assessed 100 reads as 100–109 and a collected 70 as 70–71.

Read reports with fiscal_reports. It returns one FiscalReport for each observer binding whose report the viewer’s holder holds, keyed by binding ID; as a trusted host, fiscal_reports_of_holder(&canwu, &holder) reads any holder’s reports, a government’s included:

let viewer = canwu.viewer_for_actor(actor)?;
for (binding_id, report) in fiscal_reports(&viewer)? {
for (fact_id, fact) in &report.projection.facts {
// fact.assessed.minimum ..= fact.assessed.maximum, and so on.
let may_be_older = report.is_stale(fact_id);
}
}

report.projection is a FiscalProjection: the actor (None for a government’s report), as_of, the confidence, and the facts labelled cycle:row:fact. For a complete report it equals what compute_projection(&state, binding_id, as_of) derives from the fiscal records the report was published from. assemble_fiscal_reports does the same from record payloads you already hold.

A report is stored as several knowledge records of schema fiscal_report_knowledge_schema_id() (kind canwu-fiscal / fiscal_report, version 6): one summary record, which names the binding’s granularity and cadence, and, for each hot cycle the report shows, parts of FISCAL_REPORT_ROWS_PER_PART (16) rows (FiscalReportRecord). A part’s payload lists its rows’ institutions once in a table and encodes each row and fact as an array, a third of the earlier size; FiscalReportPart decodes it, and FiscalReportRow on its own keeps its object form. A single record is one summary or one part, so read whole reports through fiscal_reports.

  • Lines live on the observer’s record. Every report record is about the binding’s own observer record, and its report line is named by roles on that record: the summary on line 0, and part p of the cycle in slot s on line 1 + s * 1,024 + p. Rebinding or removing one binding leaves every other binding’s lines where they were.
  • Each record supersedes the one before it on its line. The report system finds that record in the committed knowledge ledger with SimulationView::knowledge_heads, so a run that sealed its evidence supersedes exactly what its replay does. A part of scope rows cites, as evidence, the ledger versions its rows were read from.
  • When a report is due is the binding’s cadence. With OnChange, the default, it is due in the boundary that changes something it shows. With Interval { every, offset }, it is due at offset + k * every minutes after SimTime::EPOCH (k >= 0) and is published by the first boundary at or after each due time that runs the report system, with what changed since its last publication; it is never published on change, so between due times it shows the records as of its as_of boundary. At a due time at which nothing changed, its summary alone is republished once the report has been published at least once, so as_of advances and silence never means “no report”. FiscalReportCadence::staggered(every, index, stride) spreads offsets: thirty-day intervals with a stride of 30 put observer i on day i % 30. every is a fixed duration, so a host that keeps a calendar uses OnChange or an interval close to its calendar month.
  • Only what changed is published. A change of a book queues, on the report-queue page of each observer that sees its institution, the part of the book’s row, read from the office’s list of its observers without opening the observer records. The report system publishes, with the summary, only the queued parts whose digest changed; the observer record keeps a digest of every published part, at the binding’s confidence, so nothing below an observer’s precision reaches it. An OnChange observer’s work is due at the time of the change, and a boundary that changes nothing it can see publishes nothing to it, so its as_of is the time its report last changed. An Interval observer always has one queue entry, due at its next due time. Settlement adds work to that entry without moving it. Once the report system has published what the entry owed, it queues the entry again at the following due time, whether or not anything was published. No future-dated packet is scheduled. A report with no hot cycle is not published.
  • The schedule. The report schedule record keeps each queue page’s earliest due time and the pages with parked entries, and the root keeps the earliest due time of all (FiscalRoot::earliest_due). A boundary before that time, with nothing parked, reads only the root; one at or after it decodes only the pages whose earliest due time has come. audit_fiscal_records checks the chain from the pages to the root and that each active Interval binding has its one entry at one of its due times.
  • Cycles come and go. A report shows at most MAX_FISCAL_REPORT_CYCLE_SLOTS (64) cycles; one past them is counted in the summary’s omitted_cycles and takes the first slot that frees. When the last book an observer sees of a cycle is archived, the cycle leaves the report: its parts are published empty on their lines, the summary no longer lists it, and its slot is free.
  • Re-pointing and removal. When a binding is re-pointed, the new holder gets the whole report at the next publication, and the old holder’s report is withdrawn: its summary is superseded by one marked withdrawn, and the reading functions leave it out. For an Interval binding both happen at its next due time, so the new holder waits up to every for its first report and the old holder keeps its report until then. A removed binding’s report is withdrawn the same way, at once, and the record stays so that its identity is never reused. A withdrawn holder keeps the records it was given as history.
  • What stays in the ledger. The fiscal_report schema is registered with the retention the host chooses in FiscalPlugin::with_report_retention: RetireWhenSuperseded by default, so a holder keeps one record per line and a closed cycle’s figures leave its ledger once the empty parts supersede them; Keep keeps every superseded part readable with FullHistory. A host that reads a closed cycle’s figures from old report records keeps Keep or its own archive of the reports it received.

The report system publishes within its report share of the engine’s publication budget, and within whatever earlier publishers of the boundary left. The share (FiscalReportBudget) counts bodies, entries, and payload bytes. By default it is half of KnowledgeLimitsV1::CURRENT: 16,384 bodies, 16,384 entries, and 32 MiB, enough to publish one changed monthly cycle of the fiscal-world-profile world (see limits and budgets) in one boundary. FiscalPlugin::with_report_budget raises or lowers it between FiscalReportBudget::MINIMUM (two bodies, two entries, 128 KiB) and the engine’s limits. A custom share is carried in the report system’s name, so it is part of the plugin’s identity. Each holder’s records are one group of the directive, and the groups are packed into directives up to the engine’s per-directive bounds, so a boundary that publishes to thousands of holders makes a few directives and a few KnowledgePublished events; parts are cut so that room for the summary always remains. What does not fit stays queued, and the boundary schedules an internal fiscal_report_drain_v1 packet due at once, so the next boundary, at the same instant, publishes it; advance_canonical and step_canonical settle that boundary before they move on, and settle_boundary refuses a later time until a boundary at that instant has admitted the packet. Nothing in the fiscal records changes for that but the report bookkeeping, so no revision advances. Until the queue drains, the summary names the pending parts, FiscalReport::is_complete is false, and is_stale(fact_id) tells a fact of a pending part, which may be older than as_of or missing, from a current one. A run that holds direct command history cannot add canonical ingress, so there no drain is scheduled and the owed parts wait for the next boundary that runs the fiscal systems.

Deferral shows an observer a little that its binding does not: which parts are pending depends on the reports queued before it.

The engine publishes no knowledge to a dead person. While an observer’s holder is a dead person, its queued work is parked, is not due, and nothing is published to it. Each run of the report system checks the holders of the next FISCAL_PARKED_CHECKS_PER_BOUNDARY (16) parked entries after the root’s cursor, in order of queue page and binding ID, wrapping round, and publishes what a revived holder is owed, so a revived holder is published to within ceil(parked / 16) runs at a fixed cost per run; with 16 or fewer parked entries every run checks them all. Re-pointing or removing a parked binding unparks it, and parked entries alone wake nothing. A government holder is always reachable. A state that names a holder who does not exist, or a holder that is not its actor’s person or, with no actor, a government, is refused when the run is created.

A scenario’s report queue is part of its records: add_observer queues the binding’s whole report at its first due time (for an Interval binding, the first aligned time at or after the state’s historical_context.updated_at, so set that to the run’s start first), which the first boundary that runs the report system at or after it publishes once a book it sees is hot.

The fiscal extension draws no random numbers and declares no random streams. Report ranges come from integer bucketing, and outcomes such as partial collection arrive as evidence from your adapter.

Fiscal state lives in the records of records and byte budgets. The catalog record is create-only. Each ledger marks the exact evidence versions, created during the run, that its hot books’ receipts and commutation quotes cite as payload-required, so the engine keeps those payloads loadable while the book is hot; archiving the book ends the declaration, which is why prepare_fiscal_archive refuses unsealed citations on a sealing run. Observer records reference their holder’s person or government, so the engine refuses a state that names a holder who does not exist. The record versions that a rebind, an audit binding, a nomination, or a finding’s entered_by names are not kept this way: no decision reads them again, and after seal_evidence a superseded one may no longer be provable. load_fiscal_state and audit_fiscal_records validate the catalog, every record, and the cross-record invariants.

Every boundary decision reads hot fiscal records, the catalog, the boundary’s own admitted ingress, the current-version index, replay-stable record versions, person availability, and knowledge_heads, never retained evidence or the archive store, so a sealed run, an unsealed fork, a restore from sealed segments, and an exact replay settle alike. The plugin schedules only zero-delay packets (the report drain), which canonical stepping admits in the same call, so it never holds back seal_evidence for long; a report’s due time lives in its queue entry, never in a future-dated packet. Report records are cleared at publication under the default retention, in the live run and its replay alike, never at a seal. Snapshots and exact replay need the same plugin identity: name canwu-fiscal, version 0.6.0-experimental, and its semantic hash, which covers the wake cadence (with_report_cadence), the report share, and the retention you chose. Replay consumes the recorded commands and ingress, so it never reruns a player or AI choice. The reference integration’s restore_ming_fiscal_reference and replay_ming_fiscal_reference register the same three plugins and then run validate_ming_fiscal_reference, which takes either run handle and re-matches every receipt against its evidence using only state a seal cannot change.

  • A content pack: your own FiscalContentPack (serde JSON works) or the Ming pack, plus the FiscalContentSelection.
  • The starting FiscalState: year and mode, evidence kinds, authority, audit, scope, and observer bindings, appointment policies, and the starting adoption stages, turned into records with into_records.
  • Institution entities and actors in the scenario, such as a government, an army, or organizations.
  • An execution adapter that performs the real transfer in your resource, market, production, or logistics domain, writes a typed evidence record that names the scope and request, and calls enqueue_execution_receipts.
  • Authority basis records and their kinds, if you use acting actors or auditors, and a decision controller for the body that appoints a binding’s actors, if an institution should be able to rebind.
  • The decisions: which actions to submit and when, in which batches, quantities, units, accounting cycle IDs, when to close cycles, and when to change the historical context.
  • A FiscalArchiveStore and an archive cadence, if the run is long enough for closed books to matter, and the sealed cut when the run seals evidence.
  • A semantic validator for restore, if you want the checks validate_ming_fiscal_reference performs, and the UI that shows reports.
Constant Value Caps
MAX_FISCAL_SCOPE_BINDINGS 1,048,576 Scope bindings, one ledger each
MAX_FISCAL_AUTHORITY_BINDINGS_PER_OFFICE, MAX_FISCAL_AUDIT_BINDINGS_PER_OFFICE 256 Bindings of one institution, each kind on its own
MAX_FISCAL_OBSERVERS 65,536 Observer bindings; each sees at most 4,096 institutions and 16,384 scope rows, and an institution is seen by at most 4,096
Per book 4 assessments (one per partition key), 256 remissions, 256 execution requests, 1,024 receipts, 256 audit findings Objects of one scope in one cycle
MAX_FISCAL_ADOPTIONS_PER_LEDGER 64 Rules adopted in one scope
MAX_FISCAL_HOT_BOOKS_PER_LEDGER, MAX_FISCAL_HOT_CYCLES_PER_OFFICE 64 Hot books of one scope; hot cycles of one institution
MAX_FISCAL_PARTITION_KEYS 4 Partition keys per institution, mechanism, and cycle
MAX_FISCAL_BATCH_ENTRIES, MAX_FISCAL_BATCH_JSON_BYTES 4,096, 4 MiB Entries and bytes of one action batch
MAX_FISCAL_BATCH_SET_BATCHES, MAX_FISCAL_BATCH_SET_JSON_BYTES 64, 16 MiB Batches and bytes of one batch set, which carries at most 65,536 entries
MAX_FISCAL_ACTIONS_PER_BOUNDARY, MAX_FISCAL_LEDGER_WRITES_PER_BOUNDARY 65,536 Applied actions and written ledgers in one boundary
MAX_FISCAL_ACTIONS_PER_RECORD_PER_BOUNDARY 64 Applied actions on one target in one boundary
FISCAL_RECENT_OUTCOMES 8 Outcomes a target keeps hot
MAX_FISCAL_RECEIPTS_PER_PACKET, MAX_FISCAL_EVIDENCE_PARTS 4,096 Receipts in one packet; parts of one aggregated evidence record
MAX_FISCAL_EVIDENCE_KINDS, MAX_FISCAL_EVIDENCE_PER_RECORD 32 Approved evidence kinds; evidence versions per receipt or audit
MAX_FISCAL_ACTION_JSON_BYTES, MAX_FISCAL_ACTION_TEXT_BYTES, MAX_FISCAL_IDENTIFIER_BYTES 32 KiB, 2,048 bytes, 160 bytes One entry; an audit finding, remission reason, or execution purpose; a unit or referenced ID, an assessment’s unit and accounting cycle, and a domain-record institution’s namespace, name, and ID together
MAX_FISCAL_APPOINTMENT_PARTIES, MAX_FISCAL_PENDING_PROPOSALS_PER_PARTY, MAX_FISCAL_RESOLVED_PROPOSALS_PER_POLICY 32, 4, 64 Nominators or petitioners of a policy; a party’s pending proposals; a policy’s kept resolved proposals
MAX_FISCAL_LEDGER_RECORD_BYTES, MAX_FISCAL_RECORD_BYTES, FISCAL_RECORD_RING_RESERVE_BYTES 256 KiB, 1 MiB, 4 KiB A ledger; an office or jurisdiction; the reserve each keeps for its outcome ring
FISCAL_REPORT_ROWS_PER_PART, MAX_FISCAL_REPORT_CYCLE_SLOTS 16, 64 Rows in one part; cycles one report shows
Report share (FiscalReportBudget, with_report_budget) 16,384 bodies, 16,384 entries, 32 MiB by default What the report system publishes in one boundary, within the engine’s remaining publication budget
FISCAL_PARKED_CHECKS_PER_BOUNDARY 16 Parked entries re-checked per run of the report system
MAX_FISCAL_ARCHIVE_COMMIT_RECORDS, MAX_FISCAL_ARCHIVE_RECORDS_PER_BLOB, MAX_FISCAL_ARCHIVE_PENDING_HANDLES 4,096, 64, 64 Records and blob size of one archive commit; unacknowledged retention handles

Catalog caps (periods, regions, definitions, coverage cells, references per definition, pack size) are listed in model.rs.

None of the hot caps is a lifetime cap: closing and archiving books frees them, and a run makes as many of each object as it archives. A boundary’s cost follows the records its packets touch: in the recorded fiscal-world-profile run (measured on an AMD Ryzen 7 7800X3D desktop; your numbers will differ) of 50,000 scopes, 4,200 institutions, and 4,000 observers on monthly intervals staggered over 30 days, with courts at Institution granularity, a boundary with nothing due settles in 0.63 ms, a day on which 134 observers are due in 43 ms, and a burst of 50,000 assessments in one boundary in about 4.6 s with no report drain, since nothing is due at that instant; the day on which every one of the 4,000 observers is due, each owing one cycle, publishes 9,603 report records (15.7 MB of payload) in one boundary of 2.5 s, where 0.16.0 needed 62 drain boundaries. With the default retention, held knowledge stays flat over simulated years (14,138 records from the second month to the 24th) instead of growing with every publication. The fiscal observers at scale proposal gives the measurements and the world-scale fiscal proposal the records and caps.

终端窗口
cargo run -p canwu-ming-fiscal-reference --example ming_fiscal_starter -- hongwu-1391
cargo run -p canwu-ming-fiscal-reference --example ming_fiscal_starter -- wanli-1581
cargo run -p canwu-ming-fiscal-reference --example ming_fiscal_starter -- hongguang-1644
cargo run -p canwu-ming-fiscal-reference --example ming_fiscal_starter -- hongwu-1391 --days 365 --cadence monthly

Each run prints its checkpoint hash and writes a trace under artifacts/traces/ming-fiscal-reference/<fixture>/. The last command continues for 365 simulation days after the sample cycle, one monthly boundary per 30 days. The Ming fiscal case walks through the sample cycle, the three starts, the trace, and the options. To see the contracts on this page hold, run the tests:

终端窗口
cargo test -p canwu-ming-fiscal-reference --test reference
cargo test -p canwu-ming-fiscal --test pack
cargo test -p canwu-fiscal

The reference tests cover stale rejection, the Single Whip transition, holder reports, forged ingress, receipt reuse, and snapshot and replay; archive_century runs a century of cycles with an archive cadence, and seal_stable_validation and compact_host_helpers drive the integration on a sealed run; pack covers coverage and compilation. In canwu-fiscal, fiscal_partitioned_state audits random runs after every boundary, fiscal_record_revisions and fiscal_action_batches cover per-record staleness and batches, fiscal_action_idempotency the outcome ring, fiscal_cycle_archive and fiscal_archive_lifetime cycles and the archive, fiscal_receipt_refusals the refusal events, fiscal_audit_appointment and gap_g57_fiscal_audit_binding appointments and audit bindings, gap_g48_fiscal_rebind_authority authority rebinding, gap_g13_fiscal_acting_actor acting actors, gap_g41_fiscal_idle_early_exit idle boundaries, fiscal_report_lines, fiscal_report_parts, fiscal_observer_bindings, and fiscal_reports_after_seal the report records, fiscal_report_cadence interval reports, the schedule, and the parked rotation, and fiscal_report_institutions institution rows.