Browse the docs

DocsReference

A filed declaration is frozen and superseded, not edited

Status: accepted

Context

Everything else in the schema is derived on demand. A filed declaration has left the building: the administration holds a set of figures, and the ledger will differ the moment anything is posted into the period.

Decision

The freeze

The figures are kept, not recomputed. A copy that exists because the original went elsewhere is the record of what was claimed, not a duplicate.

Box by box, in rows (tax_filing_boxes), keyed on box and kind, because some forms print a base and a tax on one line. A JSON snapshot would make the filed figures the only numbers nobody can query.

A nil return is a return. What is checked is that the figures were computed (prepared_at), not that there are any.

Frozen by a trigger, not by convention.

A frozen box is at the unit of its form. tax_filing_boxes.amount is an unscaled numeric; tax_report_templates.rounding_unit (a power of ten) is read by filing_rounding() only, applied by prepare_filing(), supersede_filing() and filing_drift(). vat_return() keeps answering exact figures. Each box is rounded from its own exact figure.

Settlement

The accounts are roles of the pack (tax_payable, tax_receivable), refused by name when missing. They must be distinct from the accounts the taxes post to, or settling would net a period against itself; where a national chart keeps a claim on the State among assets and a debt among liabilities, the pack adds two reconcilable sub-accounts named after what they hold.

It settles the ledger, not the boxes. The lines cleared are those the return read; the debt is what they sum to. filing_drift() says how far the boxes and the ledger differ; no account absorbs the difference.

It settles the tax of its own form (amended 19 October 2026, 20261019161437). A tax line is cleared when the box it names is on the filing's form, or when it names none, its tax writes a box of that form through another posting — the form prints the base and computes the tax — and it is not on the account a tax due on collection waits on. A tax booked on a liability no box of the form carries — self-assessed on a service bought from abroad, withheld, levied by a province beside the federal return — stays where it was posted, for the return that declares it or an entry somebody writes. Before, every tax line of the period was cleared, and the debt of the return could exceed its boxes.

A filing knows when it is due. prepare_filing() writes tax_filings.due_date from filing_deadline(), and the debt the settlement posts matures on it. No rule in the pack, no date.

A credit has two outcomes and no default. Carried forward or claimed back is the company's choice, which settle_filing() requires and records.

The administration is a third party, whose contact account must be the one the pack names; this is checked when the entry is written.

No rounding of the debt unless a pack declares a rule.

After filing

An entry in a declared period is ordinary, and it is signalled. filings_touched_since() lists declarations whose period moved after they went, entry by entry — an entry is "about" a declaration when a line names a box, the same test the tax lock uses.

The lock is its own function and comes last. Locking at filing would lock the declaration's own settlement out of its period; the order is file, hear back, settle, then lock_filed_period(), which refuses while tax accounts remain to clear.

A corrective never overwrites. The filing that went becomes superseded and the new one points at it; it settles only the difference (filing_tax_movements() nets earlier settlements). What a country does with a correction — replacement, adjustment, threshold — is pack data not yet modelled.

Consequences

  • The database can always say which figures were sent, and how far the ledger has moved since.
  • Late entries are allowed and visible; corrections supersede, never overwrite.

See also

Rendered from docs/decisions/0037-a-filed-declaration-is-frozen.md, in the repository, when the site was built. Read or change it on GitHub