Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Changelog

OpenBooks follows [Semantic Versioning](https://semver.org/) while its public
API and deployment format stabilize. Alpha releases may contain breaking
changes; each release documents required operator action.

## [Unreleased]

- Replace the migration history with one verified release baseline,
  `baselines/alpha35.sql`. Fresh installations apply the baseline and the
  forward migrations above it, which are numbered again from `0001`. The
  retired migration identities and their digests remain recorded in
  `schema/migrations/baseline.json`.
- Upgrade to drizzle-orm 1.0.0-rc.5. Query parameters are no longer included
  in database error messages.

Existing installations must first complete v0.1.0-alpha.34.3, then verify and
adopt the baseline with `scripts/adopt-migration-baseline.mts --check` and
`--apply` during a maintenance window with a verified backup, following the
[baseline cutover procedure](docs/operations/migration-baseline-cutover.md).
Adoption refuses an incomplete previous-release ledger or any catalog
difference and changes no tenant data. Older releases upgrade to
v0.1.0-alpha.34.3 first.

## [0.1.0-alpha.31] - 2026-10-13

- Add multi-book accounting, account mappings and translation, intercompany
  settlement, period-end journals, account merges and segment dependencies.
- Add prepaid amortization, compound assets, construction in progress,
  maintenance, insurance, recognition, renewal and rebate workflows.
- Add governed journal instructions, statistical measurements, typed FX
  adjustments, accounting preferences and GL audit numbering. Preserve posted
  history and published migration identities during upgrades.
- Add RBC STD152 payment and payroll artifacts with live authority checks,
  retained numbering and governed replacement. Improve payroll cheque design
  and preserve issued payee identity.
- Add processor receipt funding, saved settlement account review and native
  posting-effects recovery for payments. Require complete evidence before
  period-reopen decisions and independent reconciliation sign-off reviews.
- Keep till sales, reservations and drop cutoffs within the selected legal
  entity, including when several entities share a cash account.
- Correct Canadian separate-payment CPP exemptions and separate periodic and
  bonus tax bases. Retain the committed regular-income reference used for
  standalone bonus calculations without altering historical payroll.
- Preserve field-ticket revisions and exact crew hours. Review, correct and
  selectively submit pending time, including resubmission after withdrawal,
  without changing prior approvals or unselected entries. Use declared time
  classifications for billing adjustments and refuse missing pricing.
- Consolidate payroll navigation, lists and review actions; improve shared
  drawers, audit context, Setup help and localized financial reports.

Migrations 0568 through 0705 and 0707 apply forward through the native migration runner.
Run the release's read-only upgrade check and retain a verified backup before
applying them. Resolve exact schema or published-body drift refusals instead of
editing migration files or existing ledger identities. Enable new capabilities
through Company Settings and configure their native accounts and policies
before use. This release does not reprice or reconcile historical payroll,
issue incomplete separation records, or transmit payments automatically.

## [0.1.0-alpha.30] - 2026-10-05

- Add commerce channels: sales channels and channel orders, a Shopify
  connector with inventory sync, item families with price schedules,
  promotions and restocking, stored value, tenders, shipping, and order
  economics.
- Add payment-service automation: PSP payout pull and reconciliation,
  autopay with setup tokens, payment-run approval flows and reservation
  guards, revenue recovery, and Stripe billing history import.
- Extend revenue and billing: quote-to-cash, usage schedules, revenue
  contract scope, contract costs, payer hierarchies, SaaS entitlements and a
  customer portal.
- Add cross-border tax with evidence, marketplace tax commits, registration
  filing-period starts, and FX rate age policies.
- Extend payroll and workforce: benefit program identity and selected-hours
  components, entitlement bank drawdown, compensation packages and source
  cycles with approved compensation paid through native payroll under
  currency-aware caps, prior-provider period payments within annual payroll
  carry-in (native drawer, API and Data Import), optional governed rosters and
  device attendance, training delivery, business calendars, and component
  protection classes.
- Rebuild Analytics dashboards on shared scoped aggregates, add demand
  forecasting, configurable aging bucket policies and explicit department
  billable expectations.
- Expand global search: menu pages and workspace tabs, reports, settings,
  help articles, operational records (opportunities, activities,
  subscriptions, fixed assets, equipment, timesheets, custom records, files,
  dashboards, locations, warehouses), contact people, phone numbers,
  migrated-system ids, line descriptions, barcodes, and recently opened
  results re-checked against current permissions.
- Fence the subscription drawer and its customer picker to the reader's
  subsidiaries.
- Fix opening CRM opportunities, cash agent settlement statistics,
  compensation cycle access order, and report subsidiary policies for channel,
  contract cost and billing import entities.
- Upgrade an install that has not adopted the alpha.29 release baseline by
  replaying exactly the migrations and tenant-policy environment the baseline
  was verified with, adopting it, then applying later migrations forward.

Migrations 0482 through 0567 apply forward on the alpha.29 release baseline.
Migration 0567 builds search indexes with `CREATE INDEX CONCURRENTLY` outside
a transaction. Run the release's read-only upgrade check before deploying and
resolve any preflight refusal it names. No new operator configuration is
required.

## [0.1.0-alpha.29] - 2026-10-02

- Install new databases from one verified release baseline. Preserve historical
  SQL and migration identities for controlled upgrades of existing databases.
  Existing installations must complete historical migrations, verify schema
  equivalence and adopt the release baseline before deployment. See the
  [baseline cutover procedure](docs/operations/migration-baseline-cutover.md).
- Consolidate native Benefits contributions and employer vacation policies.
- Refine Talent recruiting, performance reviews and Conversations workspaces.
- Use native line action menus with structural editing and distribution controls.

## [0.1.0-alpha.28.3] - 2026-10-01

- Verify production PDF generation through the application's pinned Puppeteer
  driver, close the browser explicitly and check PDF structure with qpdf.
- Run native renderer verification before copying the application bundle so
  browser failures surface early in image builds.
- Include the Benefits wording, table-footer and patched native browser
  changes prepared in alpha.28.1 and alpha.28.2.

No additional migrations or operator configuration are required.

## [0.1.0-alpha.28.2] - 2026-10-01

- Pin the production PDF browser to the patched official native release on
  both AMD64 and ARM64. Verify archive integrity, browser version and actual
  PDF output during image builds, independently of distribution package lag.
- Include the English Enrollment wording and Benefits table-footer corrections
  prepared in alpha.28.1.

No additional migrations or operator configuration are required.

## [0.1.0-alpha.28.1] - 2026-10-01

- Use Enrollment consistently throughout English Benefits buttons, headings,
  empty states, enrollment-window drawers and report labels.
- Render Benefits record counts in native table footer rows to preserve valid
  markup during server rendering and hydration.

No additional migrations or operator configuration are required.

## [0.1.0-alpha.28] - 2026-10-01

- Consolidate Benefits into native Programs, Enrollments, Rewards, Incentives
  and Payouts workspaces. Manage insured plans inside Benefits and enrollment
  windows from the enrollment header, with one operational list per workspace.
- Make approvals optional per program. No approvals required is the default;
  employers may instead configure conditional, delegated and multi-level native
  Flows decisions. Pin the setting and decision evidence on each reward.
- Process cash rewards and noncash provider benefits through native payroll.
  Noncash valuation follows the earning component's statutory treatment without
  increasing cash pay, and posts to its configured prepaid or clearing account.
  Record provider fulfillment separately after payroll processing.
- Preserve precise approval thresholds, serialize concurrent decisions across
  policies, and refuse incomplete decisions, zero-value obligations and stale
  payroll calculations with actionable remedies.
- Edit recruiting availability, offer clauses and retention scope through
  native structured setup controls while preserving their stored evidence.
- Preserve verified currencies during account imports, report unavailable
  source denominations, scope HR scheduler work to each tenant and correct
  Sales reversal journal dates.

Apply migrations 0473 through 0475 using the native migration runner before
starting the updated application and worker. Existing programs receive the
audited No approvals required setting. Unprocessed pending rewards return to
draft for resubmission; posted payroll and fulfilled rewards remain unchanged.
Configure a noncash earning component and its posting account before issuing
provider benefits. Active program rules change through closure and creation
of a replacement program with a new code.

## [0.1.0-alpha.27.1] - 2026-10-01

- Correct the alpha27 worker's deferred startup: live authorization and
  shared validation schemas no longer initialize HTTP framework adapters
  in the standalone transfer worker.
- Verify deferred transfer dependencies in the final production image and
  load them before the worker starts publishing readiness.
- Require sustained worker readiness when verifying deployment completion;
  a live web process or a previous worker heartbeat cannot satisfy that gate.
- Preserve independent web and worker image pins during recovery, then
  repin both atomically after migration verification. Refuse if deployment
  configuration changed during verification.

This correction adds no migration. It preserves the immutable alpha27 tag
and all staged transfer data. Update both web and worker to alpha27.1 before
running background imports and exports.

## [0.1.0-alpha.27] - 2026-10-01

### Durable import and export

- Add organization-scoped background transfers with bounded upload parts,
  record batches, live progress, resumable checkpoints, cancellation and retry.
- Bind approval to the immutable source, mapping, field definitions and
  legal-entity scope. Preserve native permissions, posting rules, precise
  amounts and atomic batch audit evidence; detect identities shared across
  worker batches before approval.
- Stream CSV, JSON and XLSX exports from a consistent database snapshot,
  support spreadsheet sheet rollover and resumable completed downloads,
  and preserve financial decimals without spreadsheet rounding.
- Keep import, export and history within the native Company Setup workspace,
  restore transfers after navigation, and correct Back navigation. Sample
  company provisioning remains a separate Company Setup action.

### Company and employee workspaces

- Standardize operational lists, local navigation, filters and drawers on
  shared registered components, including payroll, inventory, banking,
  property management, construction and administration.
- Add governed Benefits programs, eligibility and enrollment workflows,
  incentive settlements and payroll-linked awards with financial evidence
  and controlled reversals.
- Add employee-backed Sales planning, quotas, customer territory maps and
  performance charts. Reorganize Recruiting and Performance workspaces,
  succession plans and native review forms.
- Rework the HR organization directory and employee update policy; improve
  audit query indexes, asynchronous drawers, dashboard scrolling and module
  cockpit presentation.

### Upgrade requirements

- Update Next.js and DOMPurify to patched releases.
- Apply additive migrations 0467 through 0472 with the release's native
  migration runner before starting the updated application and worker.
- Run the updated worker for background import/export progress. Previously
  committed batches remain committed after cancellation or a later refusal;
  correct financial history through native reversals or adjusting entries.
- Plan database capacity for source files, staged rows, evidence and export
  artifacts, and temporary disk for spreadsheet decoding. No automatic
  transfer-evidence retention deletion is enabled.

## [0.1.0-alpha.26] - 2026-09-30

### Accounting and operational controls

- Add governed provision recognition and reassessment, including supported
  construction-contract loss forecasts and independent approval.
- Add native prepaid-rights breakage assessments, sales-agency accounting,
  partial assembly disassembly and controlled reversals, and consolidated
  net-investment FX attribution with correction lineage.
- Select registered Canadian goods taxes through native invoices and bind
  filing identity to the applicable registration. Add Canadian cumulative
  withholding with verified opening history and bonus pension deductions.
- Preserve atomic document corrections, exact overhead allocation, business
  clock ownership, and durable evidence for uncertain email deliveries and
  failed background work.

### Workspaces and demonstration companies

- Provide 11 verified industry demonstration masters, isolated demo copies,
  explicit capability coverage, idempotent native scenarios, and guarded
  provisioning that refuses an unverified source.
- Consolidate operational lists, journal drawers, setup child collections,
  shared table rendering, and role-sensitive dashboard defaults. Essentials
  workspaces prioritize everyday bookkeeping and setup actions.
- Compose Inbox search and filters in the standard list header. Navigation,
  Inbox tabs, and Home share unfiltered personal approvals and task totals,
  including signatures and unread notices. Failed task sources remain named.
- Complete the shipped locale catalogs for the new accounting controls.

### Verification and upgrades

- Require per-file test-registration receipts derived from actual registered
  test counts, including failed, skipped and pending tests. Empty or unloadable
  selected files fail verification.
- Scope conformance setup to its tenant and distinguish caught-error
  serialization from safe validation messages. Update dependency protections
  for glob expansion, URI parsing and IP-address validation.
- Align accounting, architecture and mutation documentation with measured
  evidence and declared capability limits. Passing conformance cases prove
  their stated scope; they do not certify every accounting standard.

This release includes forward schema migrations. Back up the database and
retain the matching data key before upgrading. Run the read-only migration
preflight and resolve its named refusals. The reference release rehearses
representative populated upgrades before publishing scanned, attested images;
production deployment backs up first, applies migrations, then updates both
web and worker services. An application rollback must remain compatible with
the migrated schema; do not reverse schema changes by deleting tenant data.

## [0.1.0-alpha.25.3] - 2026-09-29

The corrected alpha.25 release preserves existing organization role
configuration during bootstrap, including custom roles whose keys overlap
the built-in catalogue. Explicit role seeding still refuses collisions and
names the supported replacement-and-reassignment procedure. Order reads
preserve eight-decimal unit prices without relaxing monetary amount precision.
Non-posting orders retain a null open balance as not applicable, never as an
invented zero monetary amount.

Production image builds isolate Webpack compilation with a bounded JavaScript
heap, collect page data with one worker, and generate one page at a time to
reduce peak memory use on standard build runners.

Routine updates run static checks; comprehensive test matrices remain
available on demand. Release verification exercises real database-backed
financial controls and representative upgrades, followed by scanned,
attested images and backup-first, migrate-first deployment. Upgrade refusals
retain the underlying command error in their reports.

The deployment applies pending forward migrations automatically. Run the
read-only migration preflight and resolve any named refusals before upgrading
an installation outside the reference deployment. The maintenance corrections
above add no new migration and do not change published migration fingerprints.

### Backups

- **Operator action: none for new backups; old backups remain readable.**
  Organization backup archives are now encrypted: one JSON envelope line
  (format version 3, key id `v1`, nonce, content key wrapped by
  `OPENBOOKS_DATA_KEY`), AES-256-GCM ciphertext of the gzip stream, and the
  authentication tag as the trailer. A new backup object is opaque without
  the source data key and is not readable by `zcat`. Restore reads encrypted
  v3 natively and still reads unencrypted v1/v2 archives under the existing
  explicit `--allow-legacy-*` flags; the restore CLI prints a
  `backup-legacy-unencrypted` notice naming any file without an envelope. A
  backup refuses before writing anything when `OPENBOOKS_DATA_KEY` is unset
  or still the `.env.example` placeholder — set it from the secret manager;
  restore requires the same key. Keep the key with the same care as the
  archive.

### Bank feeds

- **Operator action: SFTP import schedules created before the expected-account
  binding need a one-time bind.** The scheduled-import identity check binds
  each schedule to the one external bank account it accepts, and schedules
  predating that check have no binding — every identified OFX, BAI2, MT940,
  or CAMT.053 statement in their watch folders refuses, so an active feed
  stops importing after the upgrade with only a per-file error to show for
  it. Affected tenants: any organization with an active SFTP import schedule
  in an identifying format (including `auto`) whose expected account was
  never set. CSV schedules are unaffected (CSV carries no account identifier
  and imports on folder isolation). What the operator must do: open the named
  notice (Notifications/inbox, linking the exact schedule) or Company
  Settings → Bank Feeds, where each affected schedule reads "Paused: expected
  account not set", and bind the expected bank account in the schedule
  settings — identified statements import on the next run. The binding is
  never guessed: nothing imports unverified, before or after this change.

### Engine

- **The engine namespace is bounded.** The 204 files that lived side by side at
  `engine/src` root now live in module directories (`engine/src/ledger/`,
  `engine/src/payroll/`, `engine/src/tax/`, …), each declared in
  `engine/src/modules.json` with the modules it may import.
  `npm run check:engine-boundaries` refuses a file at root, an undeclared
  cross-module import, a declared edge nothing uses, engine code importing the
  web app, and any growth of the pinned dependency cycles. Pure relocation: no
  file's behaviour changes. Every deep import path
  (`@openbooks/engine/src/<file>.ts`) changed; `scripts/engine-modules/moves.json`
  records every move.

### Permissions

- **Operator action: existing organizations must grant the new fund permissions
  explicitly.** Existing organizations retain their built-in role permissions
  byte-for-byte and receive no automatic `funds.read`/`funds.manage` grant, so
  the new nonprofit funds surfaces stay hidden until access is granted. An
  administrator must explicitly grant the needed permissions in
  Admin → Users & Roles before users can open the nonprofit module home,
  funds, releases, or setup. New organizations receive the current defaults.

### Sealed secrets

- **Operator action: no key change is required, but read this before rotating
  keys.** Stored secrets (connections, bank feeds, provider credentials,
  payroll identifiers, MFA factors, email credentials) now seal as
  `enc:v2:<keyId>:<nonce>:<ct>:<tag>`, bound to their tenant and purpose, so
  a blob copied into another row refuses instead of decrypting. The existing
  `OPENBOOKS_DATA_KEY` keeps working as key id `k1`. To rotate, list every
  live key as `OPENBOOKS_DATA_KEYS=k1=<old>,k2=<new>` with
  `OPENBOOKS_DATA_KEY_ACTIVE=k2`, run `npx tsx scripts/rotate-data-key.ts`
  (dry run, read-only) and then with `--apply`, and remove the retired id
  once every blob reports current. `node --import tsx scripts/bootstrap.ts
  --check` refuses a missing, placeholder, or wrong-length data key and names
  the fix (`openssl rand -hex 32`). Pre-`v2` blobs still open until rotated;
  email credentials sealed before the move keep reading through the same
  window.

## [0.1.0-alpha.17] - 2026-09-19

Three forward migrations (0180-0182). The swarm release script migrates before
it swaps, so no manual step is required.

**Operator action, multi-country payroll only.** An organization running BOTH
the United Kingdom and Ireland packs shared ONE `PAYE` component between them
(see below). Ireland now seeds its own `IEPAYE`, which starts unmapped, and a
pay run refuses by name until someone maps the Irish PAYE slot in Payroll setup
→ Accounts & posting. The refusal is loud and names the remedy; the remedy is
to map the slot and recalculate. An organization running only one of the two
packs is unaffected.

### Payroll

- **No Dutch employee could be paid at all.** The pipeline hands packs money in
  the canonical 4-decimal ledger form — even `"0.0000"` for an empty base —
  and the Netherlands and Singapore packs each hand-rolled a parser accepting
  one or two decimals, so every NL calculation died on its own money-parse
  refusal. The money contract is now written on the shared statutory compute
  context and both packs converge on it. The four per-employee Dutch inputs
  (age class, AWf low, AOf high, and the employer's own Whk beschikking
  percentage) also had no entry surface anywhere, so no NL employee could be
  configured even once the parse defect was gone; they are pack-declared
  certificates on the profile, and the German and French row-backed forms light
  up on the same surface.
- **France over-withheld from every employee, twice over.** The prélèvement à
  la source was applied to gross rather than to the net imposable — the assiette
  is gross less deductible social contributions plus the non-deductible 2,4
  points of CSG (CGI art. 204 A–M; BOFiP BOI-IR-PAS-20-10-10) — which
  over-withheld roughly 30,58 € a month on a 3 400 € salary. And allocations
  familiales were charged at the flat 5,25 % with no taux réduit: 3,45 % applies
  at or below 3,5 SMIC (CSS art. L241-6-1, D241-3-1).
- **Ireland had no PAYE component of its own.** `pay_components` is unique on
  (org, code) and on (org, system_key, kind), so installing Ireland after the
  United Kingdom hit `on conflict do nothing` and Irish runs pushed onto the
  British component — each country's account mapping erasing the other's.
  Ireland seeds `IEPAYE`/`ie_paye`; withheld payroll tax is wired through a
  new `payrollDeductions` chart ROLE rather than any hardcoded account number.
- **A statutory rate could save successfully and resolve to nothing.** A rate
  written with a scope key the slot does not declare stored cleanly, returned
  `{ok}`, and then resolved to `null` forever — so the engine priced the levy
  as unconfigured, refusing or accruing zero, with a rate visibly on file. The
  write now refuses a scope point the declaration does not admit, and an update
  matching zero rows throws instead of reporting success.
- **Remittance bills posted to the wrong legal entity, in the wrong currency.**
  The bill stamped the root subsidiary unconditionally and took that root's base
  currency, while the accruals it clears were credited on whichever entity ran
  the payroll — so the liability never cleared per entity. Remittance groups
  now carry per-entity slices: the consolidated totals remain the worksheet
  reading, the slices are the write path, and a group spanning two entities
  raises one bill per entity. A filing account registered to a different entity
  than the accruals refuses, naming both.
- **A partially-refused pay run committed and posted silently.** Calculation
  refusals are persisted per employee, and a commit is gated on them unless the
  refusals are explicitly acknowledged against the run's digest.
- **Canadian employees were unpayable in any period containing a statutory
  holiday**, and the attestations that answer the eligibility question are now
  persisted rather than re-demanded on every recalculation.
- **Two currencies were added together and labelled with one symbol.** A mixed
  currency sum is now refused or translated, never added as raw units.
- Live-but-unconfigured employer levies refuse BY NAME rather than accruing
  0.00 in silence, and Québec-only rate slots no longer demand a Revenu Québec
  account from an Ontario-only employer.
- **Pay runs could be scoped to the wrong subsidiary.** The wizard asks, drafts
  are discardable, and re-scoping re-resolves rather than inheriting.
- **Trace factors rendered as raw codes.** One flat 49-entry label map, keyed by
  bare short codes and shared by every country, covered 543 codes the packs
  actually trace; the rest fell through to the raw key beside a UI that already
  prints it, so an unlabelled factor rendered the code TWICE — a Maryland admin
  auditing a run read `MD_PA_LOCAL_EXEMPT   MD_PA_LOCAL_EXEMPT`. The flat
  namespace was itself the defect: `CA_TAX` is California while `CA` is
  Canada's country code, and `DE_WITHHELD` is Delaware while `DE` is Germany's.
  Labels are now a pack-declared channel resolved through the registry, with a
  guard that derives the traced set rather than restating it.
- **Saving a payroll profile on a freshly created employee returned "employee
  or pay schedule is not available."** Creating a person leaves the party
  inactive until the record is saved, and one message covered four distinct
  causes — no such party, inactive party, inactive employee role, and no such
  schedule — so the refusal was undiagnosable from the outside. Each cause now
  names itself, and the draft case says what to do.
- Employee identifiers are pack-declared rather than a hardcoded nine-digit
  SIN/SSN shape, which had made ten countries' employees unsaveable.
- Per-item payroll expense routing: an earning line posts to the service item's
  own expense account where one is set, so direct labour can reach cost of
  sales, and item accounts join the staleness digest so an account edited after
  calculation refuses the commit rather than posting a stale mapping.
- German Konfession help text no longer tells administrators church tax is not
  withheld, and the payroll setup write path accepts every country its own
  picker offers.

### Changed

- One account surface across the relationship lifecycle. Leads, prospects and
  customers are three stages of one record, but they had three list pages and
  two record flyouts — and `/entities/customers` inner-joined `customer_roles`,
  a row written only on promotion, so a real prospect could never appear there
  and its "potential customer" status could only ever mean a DEMOTED customer.
  `/crm/leads` and `/crm/prospects` are removed; the customer list now outer-
  joins both the customer role and the relationship profile and segments on
  lifecycle stage, carrying the retired lists' sub-status, owner, territory,
  qualification and last-activity columns. The CRM account drawer is gone: its
  fields are a Relationship tab of the party flyout, so a company has exactly
  one record. A customer with no profile can start one from that tab. With the
  CRM switch off — or without `crm.accounts.read` — the list collapses to the
  AR customer roll exactly as before.
- The Customers workspace gets the payroll-style route-tab strip: Overview,
  Accounts, Opportunities, Activities, Forecasts and Receivables, permission-
  and feature-filtered in one place rather than per page.
- The party flyout has ONE tab rail. The shared shell's Details / Attachments /
  Audit trail strip no longer sits above a second, record-specific strip:
  Overview, Pulse, Relationship, Invoicing, Pricing, Transactions, Activities,
  Contacts, Addresses, Attachments and Audit trail are peers.
- "Customer 360" is now **Pulse**, and it lives only on the customer record.
  The standalone `/crm/customer-360` page — which picked an arbitrary customer
  — is deleted. The panel was also entirely hardcoded English and formatted
  money as `en-US` USD regardless of locale or org currency; it now runs
  through the catalogs and the money formatter like every other surface.

### Added

- An Add button on the customer flyout's Activities tab, matching Add contact
  and Add address. It mints the activity already linked to the account and
  hands off to the activity editor with a return path, so closing lands back
  on the customer.

### Fixed

- Saved list views no longer sort by a direction chosen for a column they are
  not sorting by. Orgs are seeded with a snapshot of the system default view,
  so a snapshot naming a column that has since left the registry fell back to
  a different column while keeping the stored direction — which listed
  customers Z→A. Column and direction now move together, and the party-family
  record types declare `name ascending` explicitly.

### Fixed

- Insight charts over a time bin render chronologically. A card that stores no
  explicit sort fell through to the compiler's default, which ranks by the
  first measure descending — so "Revenue by month" drew twelve months in
  descending revenue order, a line that always slopes down. A binned temporal
  dimension now orders by that dimension ascending; an unbinned dimension
  still ranks by its measure.
- Chart category labels name the period rather than the instant it begins on
  (Sep 2026, Q3 2026), and survive the JSON round trip. The formatter tested
  `instanceof Date`, but every card fetches over HTTP and parses with
  `res.json()`, which delivers a string — so axes printed a raw
  `2026-09-01T00:00:00.000Z`.

### Payroll and tax

- Thailand's 7% VAT band renewed for 2026-10-01..2027-09-30 (Revenue
  Department release 18/2569, rate unchanged).
- Canada and the United States become country packs like the other eight,
  rather than object literals inside the registry. Behaviour-preserving: the
  canonical dump of both packs is byte-identical across 10,241 lines.

## [0.1.0-alpha.16] - 2026-09-18

Nine forward migrations (0171-0179). The swarm release script migrates
before it swaps, so no manual step is required; operators running Compose
get the same ordering from the bootstrap one-shot.

### Payroll

- Ten installable countries: CA, US, GB, DE, FR, IE, AU, IT, NL, ES, each
  with agency-published goldens, hand-worked cases independent of the
  engine, and band-boundary sweeps. DE reproduces both official BMF
  Pruftabellen; AU reproduces the legislative instrument's own tables.
- A generic `credit` pay-component kind threaded through net math, GL,
  the deduction-protection pool, remittance netting and parallel-run
  attribution, with no country branches (0179).
- Employer-aggregate levies with their own opening balances (0174, 0177).

### Tax

- 41 country packs. Every source URL is now required to sit on an
  authority host or a named, reasoned exception.

### Product

- Notifications inbox replaces the header bell, as a first-class page.
- CRM phase 1 and 2: pipeline kanban, cost margins, and a customer-360
  cockpit (0178).
- Dashboard gains money and operational widgets, each permission-gated so
  a tile a caller cannot see never runs its query.
- Approvals worklist pages server-side with honest select-all.
- Expense lines carry an explicit settlement: out-of-pocket reimburses the
  employee, company-paid settles with the card issuer, personal is a
  receivable (0171).

### Correctness

- Posting effects claim exactly one due row per drain call; the previous
  `UPDATE..FROM` re-evaluated `SKIP LOCKED LIMIT 1` per outer row and could
  mark every due effect running while reporting one.
- Signing and encryption secrets are read live rather than from a snapshot
  taken at module evaluation, which could be taken before the value was set.
- Tenant isolation is enforced across the integration suite under FORCE
  row-level security as the constrained runtime role, not the bootstrap
  superuser.
- Lint warnings and explicit `any` are both zero, and both ceilings are
  pinned at zero rather than tracking the real count upward.

## [0.1.0-alpha.15] - 2026-09-17

Defect fixes on top of alpha.14. No new migration.

### Payroll, parties, and close

- Backdated wage rates persist, capped before their successor.
- Parallel-run net is attributed against stated gross; pay-run funding
  reads ledger balances including reversals.
- Party PATCH accepts stored customer/vendor/employee kinds.
- Close reporting-package slugs resolve to names and links.

### Gates, documents, and send

- Disabled features and refused permissions explain themselves instead
  of silent 404s and bounces; Scripts and REST API docs name the
  Features-switch prerequisite.
- Unset subsidiary stays unset; save and convert refusals pin as
  record alerts. Incomplete email config is a typed refusal; failed
  sends stay visible in the composer.
- Inventory Post refusals pin on the record; line-less budget submits
  refuse with a typed message.

### Inventory, fulfilment, assets, and approvals

- Standalone invoices refuse to post when stock-relief issue effects
  fail, so revenue cannot land without its matching COGS.
- Fulfilment is a sales-order conversion target; an approved order is
  no longer a dead end.
- Orders approved before line warehouse pickers existed name the
  warehouseless line and offer assignment instead of a generic
  conversion failure.
- Depreciation runs that post nothing name the next due line.
  Equipment activation names the missing charge item.
- Directly submitted budgets reach the approvals inbox.

### Banking, retainage, and CAM

- A first bank reconciliation counts the proven statement opening toward
  cleared, so it can reach zero and be signed off.
- Retainage Receivable has a Company Settings home; pay-application
  invoices are no longer blocked by an invisible control-account
  requirement.
- CAM finalize refusals pin on the pool card instead of vanishing with
  a toast.

### Inventory chain, billing provenance, and hygiene

- Order and invoice drawers have line-level warehouse pickers with
  save APIs, so stock relief can follow the line that will post COGS.
- Draft line replacement keeps billed-time/cost provenance, so a
  billing-request invoice can be saved.
- Project merge previews key by group and direction; refusals pin on
  the duplicates screen.
- Hygiene flags persistently credit-normal unreconciled bank accounts.
- Asset-category setup labels the default depreciation formula in
  every locale.

### Reports, analytics, purchasing, and tax

- Vendor drills and compliance open-payables read the shared open-items
  reader, never reversed entries. Purchasing recovers through the
  lenient scope and groups the hero off that same set.
- Registers keep capped-out parties with exact closings. The trial
  balance keeps zero-balance accounts that had activity. Statements
  print gross account balances so lines foot to section totals.
- The OpEx-to-revenue ratio shares one P&L operating-expense reader.
- Waiver forms are required while enforcement applies. Positive NOL
  and provision inputs measure as DTA, never DTL.
- PSP settlement drafts are postable, with typed import refusals.
- Dashboard money and AR tiles label the as-of cut-off.
- Empty field-ticket drafts can be discarded instead of orphaned.

### Aging, budgets, and bank setup

- Aging derives opens from stored base amounts and folds documentless
  control balances into a per-party residual, so the subledger ties to
  its control account.
- Budget variance is direction-aware: a revenue shortfall reads Under.
  Self-approval is refused with a typed reason.
- Bank-feed targets use the unified reconcilable-bank reader. Setup
  drawer edits write the keys the controls read, so a bank profile can
  be deactivated.
- True-cost explains an empty Assign picker when no burden categories
  exist.

### Pay runs, journals, and locale catalogs

- Pay-run posting failures persist per instruction and render in the
  activity feed.
- Closed-period Post refusals pin on the record. Journals warn when
  control legs post with no party.
- Journal counts read one scope across the setup guide, header, and
  list.
- Send-for-signature refusals pin as a dialog alert.
- All six non-English locales now carry the full product. The
  remaining keys are reviewed cognates, not gaps. Each namespace is
  pinned with placeholder-parity so English cannot be pasted back.
- All seven aging and statement precision suites now seed and read
  under the scratch org. That was test drift, not money: they had been
  asserting against zero rows because an imported web reader denied
  unscoped queries. Assertions are unchanged.
- Fifteen drifted integration suites now seed and read under the
  scratch org — MFA and reset, documents, orders, payroll, report
  drill and currency basis, account register, currency chain, partner
  statements, and draft columns. That was the same resolver drift, not
  product arithmetic. Assertions are unchanged.
- Lien-waiver project-required refusals pin on the record.
- The setup rail stacks below phone width. Readiness points at the
  chart of accounts. A blank tax-code percent falls through with a
  spoken refusal. Rate-card lapse uses the shared invoicing label.
  The book-policy custom-formula picker is labelled. Setup column,
  field, and filter keys must resolve to English labels; four orphaned
  keys are now labelled in every locale, and a dead allocations mode
  column is gone.
- Project list cells and filters resolve custom type names.

## [0.1.0-alpha.14] - 2026-09-17

Defect fixes on top of alpha.13. Requires migration 0170.

### Locale remediation

- Admin and analytics catalogs are fully translated in fr, es, de, ja,
  zh, and pt-BR, each namespace pinned so English cannot be pasted back.
- Payroll catalogs land in all six non-English locales (848 keys each).

### CRM, banking, drawers, and PDF

- Lead stage changes persist; new prospects start at the right stage.
- Forecast snapshots file at the displayed scope, including the whole
  organization (0170 relaxes the target CHECK).
- Banking overview uses one reconcilable-account reader even when
  consolidated rates are underived.
- Dirty document drawers keep a header Save and confirm before close.
- PDF template duplication no longer collides on default names; a taken
  name is a typed 409.
- Currency-mismatched postings refuse with a typed message, never raw
  SQL. Unapplied credits net against party open balance. AR customer
  search gives an honest empty state. Close review tasks offer start,
  evidence, and complete. Customer status facets count without group-by
  when CRM is off. Catalog placeholder-parity pins no longer match a
  literal backslash-brace.

## [0.1.0-alpha.13] - 2026-09-17

Defect fixes on top of alpha.12. No new migration.

### i18n, shell, and allocations

- `ar.collections` and `agents` catalogs backfill de, ja, zh, and pt-BR.
- The platform workspace switcher lives in the account menu.
- Allocation-rule wizard destination menus stay above the modal and
  match on any dimension, with codes in the option labels.
- Pre-flow vendor bank accounts can be submitted into the current
  approval flow; party payloads publish the canonical OCC token so
  Edit-then-Save no longer 409s.
- French and Spanish property type/status labels agree with the
  masculine building noun.

## [0.1.0-alpha.12] - 2026-09-16

Fixes across setup, banking, assistant, payroll, CRM, reports,
dashboard, documents, allocations, construction/AR, rates, assets,
payroll, i18n, drawers/search/mobile, expenses, compliance, invites,
agents/AI, and a11y UX on top of alpha.11. Requires migration 0169.

### Setup and shell

- Typed validation and duplicate conflicts with user-language messages;
  required fields persist errors and reset busy on transport failure;
  blank `keepDefault` fields are legal; time-classification option labels
  resolve under `options`.
- Shell empty-state no longer repeats the boundary copy in the body.

### Banking, approvals, CRM

- Account KPI reads posted+reversed lines; the 7-day work-queue badge
  counts only posted documents.
- Approvals render an empty state instead of a blank surface.
- Lead/prospect first save sends the party revision token; the lead
  owner picker uses the translated unassigned label.

### Payroll, assistant, allocations

- Stub register buckets and the overview setup checklist come from pack
  declarations; FICA carry-in splits into W-2 boxes 4 and 6.
- Assistant runs persist on the server across navigation and stick to
  the bottom with jump-to-latest.
- Period-sweep preview runs inline on the rule Test tab; empty
  dimension options guide the user and bad values speak user language.
- Deleted assistant threads stay deleted across chat switches; local
  blue/green rebuilds can override `NEXT_DIST_DIR`.
- Posted pay-run journal entries are visible on the journal; FX test
  warns when no currencies exist; an already-running agent scan explains
  the 409.
- Schedule editor mutations surface the server error; a blocked account
  save stays on a form-level alert; standalone checks require payee and
  funding bank.
- AR/AP dashboard tiles use the shared open-item reader; remittance
  pickers list org-wide vendors; lease add-charge is satisfiable;
  ownership create refuses a full-method write with a typed error.
- Data-io re-imports exported party kinds; PDF responses keep a strict
  CSP; pack-driven stubs re-resolve the open stub against live rows.
- Approvals center tabs read the same union worklist as the dashboard
  tile; API-key fingerprints stay stable across revoke; users accept
  last_sign_in sort; agent finding hrefs resolve through the nav
  registry; period lists show locked modules and book; journal Origin=All
  includes migration entries; document drawer post fails closed.

### Construction, AR, rates, and consolidation (batches 23–29)

- Rates-blocked banner on aging, registers, GL, journal, and workspaces;
  aging export uses the same as-of rule as the screen; consolidation
  refusals carry typed reason codes.
- AR never renders a sync source handle as the document number; CRM
  lead/prospect first save completes the draft; owner picker resolves
  the nested unassigned label.
- Allocations uncovered kinds answer empty instead of 404; new-rule
  setup is a guided wizard.

### Assets, payroll, i18n, drawers, search, expenses

- Depreciation extends a stale schedule before posting and surfaces run
  problems instead of failing silent; payroll posts one labeled burden
  debit per employer component and lists org-wide vendors.
- Inventory locations, BOM tabs, run funding, and the property workspace
  translate in every locale.
- Document title row wraps so the status pill never clips; AR-pulse
  hero amounts wrap on narrow screens; mobile search sits in the topbar;
  exact numbers bypass the search candidate cap and journal entries are
  indexed.
- Expense reports are editable via recall and correct; the vendor
  drawer Compliance tab assigns the class; funding-bank override
  persists on save.
- Approvals center binds assignee ids as a PostgreSQL array literal so a
  single user-assigned gate no longer 500s the page.

### Invites, close, agents, AI, and a11y (batches 30–35)

- Users can be invited with a set-password link and a pending state;
  the period drawer shows pending reopen requests.
- Agent tiles and status filters no longer depend on the current query;
  the shortcut legend documents a/d; team roles and banner dates
  translate; evidence kinds are labeled in en/fr/es.
- AI Test connection verifies the typed key; load-models errors stay
  structured. Saved list views and bank-feed disconnects confirm first;
  discard-draft on an app always confirms.
- Open-aging built-ins count application-aware open lines; statement
  tables stay readable on a phone; cash cockpit, bank feeds, project
  billing, setup sidebar, and report filter presets translate.
- Drawer banners wrap at 390px instead of squeezing.

### Invites, remittance, banking, and tax (batches 36–39)

- Pending invites expose a one-time set-password link and resend;
  reset-request failures no longer claim the link is on its way; a blank
  company display name pins an inline required error.
- Remittance vendor listbox reads parties+vendor_roles; card-liability
  is offered when no card instruments exist; reconcile never swallows
  an unreadable error; KPI titles wrap and trend ticks stay thin.
- Failed flow runs can be retried; mark-as-filed refusals are typed in
  the filing drawer; delete-payment confirm resolves through the drawer
  scope.

### Invites, i18n, and cockpit (batches 40–41)

- CSRF treats localhost / 127.0.0.1 / [::1] as one origin so invite
  activation works across loopback addresses.
- Feature-toggle 409s map to localized copy; recent-entry status and
  line counts translate; opportunity status cells and filters use the
  drawer catalog; mobile tabs prefer short AR/AP labels.
- Stat tiles wrap instead of truncating; a retried flow parks the
  subject in pending_approval so the engine-enforced release can land.

### Budgets, reports, drawers, and search (batches 42–44)

- Draft budgets can be submitted, approved, and rejected with
  revision-guarded provenance so Pending approval / Approved are reachable.
- Report-schedule DELETE accepts a bodiless request; add-journal refusals
  stay as a dialog alert; the related-party overlay receives Compliance
  tab inputs.
- Exact journal-entry numbers resolve outside list origin/link scope;
  recurring cadence options translate in fr/es; setup wizard, go-live
  guide, api-keys, and the property buildings table copy backfill.

## [0.1.0-alpha.11] - 2026-09-16

UI and session-gate fixes on top of the self-deploy release. The
per-process database pool size is now configurable.

### UI

- Open receivables read the as-of book; the AR overdue subtitle takes a
  bare percent; recent journal widgets link through the posted-entry route.
- Approvals show loading/pending/empty states; document lines derive amount
  from quantity × unit price; project create activates the placeholder on
  a completing save.
- Customization form edits PATCH the member route, remount per session,
  confirm before deleting the org-default form, and expose visibility
  toggle pressed state.
- Banking fails closed at the root route error boundary; Business Central
  invoice numbers land as `documentNumber`; US state/local income-tax
  statutory slots are labeled.

### Platform

- The session gate fails closed per request with a request id.
- The per-process connection pool size is configurable.

## [0.1.0-alpha.10] - 2026-09-16

Integrity fixes on top of the allocations release, and production now
deploys itself from a version tag.

### Production release

- Pushing a `v*` tag publishes the attested image, then
  `deploy-production.yml` runs on the LAN runner: it executes
  `deploy/swarm-release.sh` over a dedicated forced-options ssh key
  (migrate first, then swap both service pins) and stays red until
  `/api/v1/health` reports the tag. Manual edge publishes never deploy.

### Integrity

- Period allocation runs refuse to post after the rule is deactivated or
  its published version is retired.
- Report-backed allocation drivers resolve features through the canonical
  feature path.
- A bank return supersedes a pending manual payment void and keeps its own
  evidence.
- Sync identity writes qualify the stored row on party-role conflicts, and
  evidence refresh matches lines by the stored `sourceLineRef`.
- Statement-format arithmetic goes through the engine money helpers;
  boolean custom-field list values extract as real booleans; workspace
  package edges that were imported undeclared are now declared.
- Posted journal lines cannot be re-homed onto another entry (0165).
- Optimistic-concurrency tokens advance a `revision_seq` counter on every
  update, independent of the editable `updated_at` display timestamp (0167).
- Retainage draws and releases settle in whole currency minor units and
  refuse a release that would invert draw/reversal posting order.
- Overhead published rates and preview share one exact decimal contract.

### Operator action

- Two additive forward migrations: `0165_jl_guard_original_parent_immutability`
  (replaces `jl_guard()`; no data rewrite) and
  `0167_document_revision_counter` (`revision_seq` column and bump trigger
  on revisioned tables; existing rows backfill 0). No other data changes.

## [0.1.0-alpha.9] - 2026-09-16

Setup polish for the allocations release, from testing alpha.8 in production.

### Allocations setup workspace

- Rules, Drivers, and Runs tabs now use the same composition as every other
  setup list: description plus one primary New/Preview action, the shared
  search toolbar with the show-inactive pill, and a table with a single
  "Nothing here yet." row when empty. The New rule and New driver actions are
  visible on an empty tenant.
- Drawers carry their primary action in the header like the shared setup
  drawer. The driver drawer gets its own Description field, per-source
  configuration (account scope, unit, measure, report), and the manual
  values grid inside the drawer after the driver is saved; loading states
  use the house skeleton.
- Rule drawer dimension filters render a proper none-state when a dimension
  has no values; all copy resolves from the catalog.

### Features page

- Sub-features nest under their parent (indented, secondary type, no icon)
  and stay hidden until the parent is on, with a quiet "N options once
  enabled" hint; category counts cover visible rows only. Applies to
  Projects, Flows, and Allocations children.

### Operator action

- No migrations. No data changes.

## [0.1.0-alpha.8] - 2026-09-16

Allocations release. One allocation kernel replaces three requests that used
to be separate products elsewhere (allocation schedules, distribution keys at
transaction entry, and a posting-time GL plug-in): a versioned, effective-dated
rule model bound at three moments, a driver registry, one exact apportionment
engine, and a lineage table that traces every allocated cent to its source
line, rule version, and driver value.

### Allocation kernel

- Rules are versioned and effective-dated; a published version is frozen and
  hashed, and every run and lineage row carries that hash. Applicability is
  per GL account (or account group) and per department, location, class,
  project, subsidiary, party, item, or custom segment, including untagged
  pools. Bases are fixed percentages, stepped tiers, or a driver; targets are
  explicit or dynamic (every active dimension value with weight). Impacts are
  reclass, net-zero pair (never changes an account total), or report-only.
- Drivers resolve from statistical journals (`journal_lines.quantity`), GL
  activity or balance, seven native measures (headcount, labor hours, billed
  hours, labor cost, revenue, direct cost, rentable area), effective-dated
  manual tables, or any saved report definition, run under the actor's own
  permissions; unavailable measures fail loudly instead of returning zeros.
- Entry mode: a bill, expense, or journal line that matches an automatic
  rule explodes on save into a stamped group of real lines (amounts exact,
  quantities proportional, tax recomputed per child); suggest rules offer a
  chip; a split dialog, group headers, un-split, and lock live in the line
  grid; imports and the records API accept `distributionKey`.
- Post mode: contributions land on the transaction's own journal entry,
  stamped with their contributor (`journal_lines.contributor_kind/ref`),
  balanced per contributor and per subsidiary, mirrored on void, written to
  secondary posting books as their own entries, and grouped in the GL impact
  drawer. A `custom_gl_lines` user-script trigger contributes lines the same
  way, with the kernel lines frozen.
- Period mode: preview, post, reverse, and re-run per rule, period, and book
  with one posted run per occurrence, an explain payload (sources, driver
  vector, shares, residual), re-run idempotency by fingerprint, scheduled
  occurrences through the durable outbox, a close automation action
  (`run_allocation`), and approval flows that hold a run pending until the
  flow approves.
- The overhead net-zero-pair writer is now a system-owned kernel rule derived
  from the overhead settings and rate card, proven byte-identical to the
  previous journal lines, with per-time-entry lineage.
- Setup → Allocations workspace (Rules, Drivers, Runs tabs with a
  four-tab rule drawer, driver values grid, run detail with lineage drill),
  Allocation summary and Allocation lineage reports, an in-app help article,
  six locale catalogs, seven read-only assistant/MCP tools, and an
  internal-controls evidence set (seven cases) published beside the trust
  corpus.

### Assistant, agents, and setup

- Chat threads appear in the sidebar instantly, page long histories, get short
  generated titles, and forward finding handoffs; page headers wrap actions
  under the title on phones.
- Agents overview, library, policy pages, activity, inbox, proposals, and
  briefings are rebuilt on the shared setup and table components.
- Analytics sentences are localizable; source-evidenced bank sign-offs count
  as reconciled for close readiness; JPY/KWD are pinned end to end.

### Operator action

- Five additive migrations (0160–0164) run automatically before the new code
  serves. No posted history is reinterpreted; the dormant planning-era
  allocation tables are replaced only if empty (they are, on every install).
- Re-run `engine/src/seed-roles.ts` after upgrading: built-in roles gain the
  `allocations.read/manage/run/approve` grants (roles are snapshots).
- The `allocations` feature defaults off. Enable it, and the entry and
  posting sub-features, under Company Settings → Features.
- Posting a document under a rule whose driver is a saved report requires the
  posting actor to hold `reports.read` (fail-closed by design).

## [0.1.0-alpha.7] - 2026-09-16

Assistant and agents release. A live benchmark of the in-app assistant on a
real ledger (three models, graded against tool output) showed nearly every
lost point was a tool-surface gap; this release closed those gaps, made
the model's context proportional to the question, generalised the
background-agent runtime, and gave agent work a home in the product.
Everything the assistant and MCP clients can do reuses the same services,
permission gates, subsidiary scoping, and feature switches as the screens.

### Assistant and MCP

- One capability catalog for chat and `/mcp`: read tools across ledger,
  reporting, banking, payroll, tax, projects (portfolio ranking), inventory,
  orders, fixed assets, equipment, subcontracts and WIP, CRM, subscriptions,
  property, time, expenses, close and periods, FX, budgets, files, data-io,
  sync, environments, PDF templates, reporting deliveries, and admin reads
  (secrets never leave the server). Governed commands with a review card and
  idempotency key: settings, feature switches, setup records, journal post,
  bank reconciliation actions, FX revaluation, budget cells, file upload.
- Tools of disabled modules are hidden from the model, MCP, and the close
  agents; the system prompt states the org's module switchboard; every tool
  declares its feature key, and parity tests pin feature, permission,
  subsidiary scoping, and chat/MCP visibility.
- Context proportional to the question: a 24-tool core is always on,
  `find_tools` activates a module's tools mid-turn, a pre-router pre-activates
  modules from the message, tool results are compacted for the model (full
  results still stream and persist), older turns become summaries, a rolling
  conversation summary with resolved entities persists per conversation
  (migration 0152), pronouns resolve from pinned entities, and step budgets
  adapt. A typical turn now sends roughly 6k–13k tokens of tool definitions
  instead of 45k.
- Turns can no longer end silently: the last permitted step must answer, and
  a turn that produced no prose gets a visible fallback. Engine domain errors
  reach the model as actionable messages instead of `tool_failed`.
- Strict provider compatibility: every tool schema is linted for RE2-safe
  patterns, described properties, and bounded sizes (an unescaped bracket
  had made one provider reject the whole catalog); a contract harness runs
  every read tool against a scratch org under a size budget.
- App packages declare their own assistant/MCP tools (`tools[]` in the
  manifest with validated JSON-schema inputs and install-time contract
  checks); they run through the app runtime with governance evidence and use
  the same confirmation path as built-in mutations.
- `describe_capabilities` answers "what can you do" from the live catalog.

### Agents

- The continuous-close runtime is a registry of agent packs: accounting,
  finance, collections, payables, reconciliation, data hygiene, forensics,
  tax readiness, payroll compliance, project margin, and cash alerts
  (migrations 0151 and 0155 widen the agent-key constraints). Packs read and
  propose; nothing runs a write without a confirmed review card.
- Agents are a first-party Setup category: overview with enable switches and
  run-now, a library, per-pack policy pages with detector controls and
  notification routing (migration 0154), and an activity log. `/admin/ai`
  is provider configuration only.
- Agent Workbench at `/agents`: a ranked inbox with keyboard and bulk triage,
  a proposals lane rendering the same review cards as chat, a cached morning
  briefing with email send, ask-about-this handoff into chat, assignment with
  due dates and notes (migration 0153), and a dashboard tile.

### Connectors, banking, assets, currencies

- Connectors mirror cleared markers and party merges/holds and carry source
  reconciliation evidence on every mirror run; a source-evidenced sign-off
  engine can close reconciliations from that evidence (migration 0158).
- Fixed assets and lessee schedules continue from opening balances
  (migration 0156); the fixed-asset register import carries openings in.
- The currency registry is the full active ISO 4217 list, backfilled for
  existing tenants (migration 0157), with localized picker labels.
- Analytics sentences, sentinel forensics, ratio definitions, and health
  findings are localizable; sentinel duplicate groups and per-currency stats
  corrected; close readiness ignores non-posting order kinds.

### Operator action

- Eight additive migrations (0151–0158) run automatically before the new
  code serves. No data is reinterpreted.
- Agent packs beyond accounting and finance are off until enabled under
  Setup → Agents; the `continuousClose` feature still gates the runtime.
- The MCP endpoint requires the `apiAccess` and `mcpAccess` features and an
  API key; provider model lists are cached for ten minutes.

## [0.1.0-alpha.6] - 2026-09-15

Defect-remediation release: ~300 atomic fixes from a third audit
(persona attacks, real-data replay, mutation survivors, standards
conformance, boundary sweeps), each with a red-then-green regression test
and an independent review. Highlights below; every commit carries its own
defect / root cause / fix / verification record.

### Integrations

- Chargebee settlement imports now receipt what was actually collected.
  `amount_paid` is the booked receipt, `amount_adjusted` posts as its own
  adjustment line against the customer (carrying the provider's reason when
  the export surfaces one) instead of being silently dropped, and the import
  refuses to post when the provider total does not foot to amount paid plus
  adjustments plus applied credits — naming the invoice rather than booking
  an unreconciled receipt. Adjustments are tracked apart from refunds in
  batch totals and post as their own clearing line. Schema gains
  `psp_settlement_batches.adjustment_amount` and the `adjustment` settlement
  line kind (migration 0144, additive).

### Scheduler topology

- Scheduled work now runs in the worker process only (`npm run worker`, the
  `worker` Compose service / worker Deployment). The web process no longer
  starts the scheduler unless `OPENBOOKS_RUN_SCHEDULER=1` is set explicitly
  (single-process installs), and never under `next dev`
  (`OPENBOOKS_RUN_SCHEDULER=force` is the only development override). Each
  process logs one `[scheduler]` line at boot stating which mode it is in.
  Concurrent worker replicas still run each tick once via the existing
  Postgres claim lock. No job semantics changed.

### Analytics

- Analytics: True Cost dashboard restored as a hub dashboard; the report
  remains at /reports/true-cost.

### Operator action

- Scheduler topology: multi-process deployments take no action — keep the
  worker service running (it already runs in `compose.yaml` and the HA
  reference). Single-process installs that run web without a worker: set
  `OPENBOOKS_RUN_SCHEDULER=1` on web.

### Ledger and close

- Posted journal entries can no longer be flipped back to draft through the
  kernel guard (migration 0146, `je_guard` v3: posted exits only to
  reversed). Tax amounts without calculation evidence fail closed instead of
  silently dropping at posting. Account-parent cycles no longer hang every
  statement. Direct inventory postings stamp the GL location dimension.
- Close readiness scopes the posting-period check to the run period, goes red
  on unrecognized deferred revenue, and re-publishing after a reopen versions
  the binder (original retained, restatement note required). Consolidation,
  elimination, lease, asset and FX-revaluation writes into closed periods
  refuse with named errors instead of raw storage failures. Depreciation
  catches up skipped months and allocates 4-4-5 calendars; secondary books
  revalue; asset disposal refuses while a begun stub period is unposted.
- New admin remediation paths: bulk assign-posting-period from the readiness
  blocker, and duplicate-project detection with an audited merge.

### Cash, receivables and payables

- Open items net unapplied credit memos (cash forecast, cash position,
  vitals and assistant tools now tie to aging to the cent); as-of agings and
  forecasts reconstruct settlement timing instead of reading live balances;
  day-90 items age into the 90+ bucket; quiet parties keep their balance on
  statements. Consolidated open items, bank balances, cockpit tiles and the
  analytics hubs translate every functional currency to the presentation
  currency at the correct spot and fail closed on missing rates.
- Ad-hoc vendor payments honour subcontractor compliance blocks. Early-payment
  discounts round to the bill currency's minor units. Refund-first PSP
  webhooks park as pending clawbacks and settle exactly once (migration
  0149). Void versus application races no longer deadlock.

### Tax, payroll and standards

- GST34 packs installed by the pre-split seed are healed to the collected /
  paid / taxable bases (migration 0147; a real tenant filed net tax at double
  the true amount). Codeless source tax is refused upstream with the source
  reference. The payroll remittance summary survives a run with an unknown
  filing account and statutory payable remappings return a typed warning.
- Conformance matrix republished at 75 passing cases and 15 declared gaps
  (partial disposal, intercompany asset transfer, lease early termination,
  4-4-5 depreciation, partial disassembly, loss of control, …).

### Integrity, contracts and concurrency

- Reference ownership is fenced on every write path (records API, documents
  and lines, journals, expenses, items, parties, assets, timesheets, rate
  cards, property, custom records, scripts, Flows actions and imports):
  foreign-org ids are refused with tenant-opaque 404s instead of storage
  errors. Dozens of routes refuse magnitudes wider than their numeric columns
  and dates that are not real calendar days with typed 4xx responses.
- Revision tokens on prebill lines, AP-capture reviews, custom records and
  opportunities; compare-and-swap on percent-complete overrides; sorted
  advisory locks for inventory reversals; repeatable-read sandbox clones with
  per-sandbox refresh serialization; sandboxes holding posted documents can
  be created, refreshed and deleted (migration 0148). Audit rows now carry
  actor and before/after for the v1 writer, imports, Flows mutations,
  pay-run commits and mirror-posted documents.
- The approvals worklist and the pending-approvals count unify Flows gates,
  document-status approvals and pay runs. KPI definitions are single-sourced
  (DSO across all six surfaces). Paginated lists carry a unique tiebreaker and
  malformed filters fail closed to empty. Budget vs actual and the dashboard
  cash tile bind to the resolved period.

### Imports and integrations

- Every registered data resource round-trips export → import into a fresh
  org and re-imports idempotently (matrix test committed). Settlement links
  state their currency on all six connectors and the reconciler converts or
  refuses. Source subsidiary functional-currency changes are held for review.
  The QuickBooks Desktop Web Connector SOAP route is reachable through the
  edge and password guessing is bounded.

### Dashboard

- Saving Quick Actions on a never-customized dashboard no longer wipes the
  widget grid; malformed or empty stored layouts fall back to the default and
  self-heal on the next view. The greeting follows the viewer's clock.
- Performance: the indirect cash flow's outer scans are bounded by the window
  (138 s → ~10 s on a multi-million-line tenant); capped detail exports
  disclose the cap in every format.

### Operator action

- Migrations 0146–0149 apply automatically on deploy (forward-only,
  idempotent). 0147 rewrites installed CA_GST34 pack rows for lines 101 /
  103 / 106 on every org that installed the pre-split seed; re-run affected
  returns after upgrading.

## [0.1.0-alpha.5] - 2026-09-15

A hardening release. A multi-agent audit read the engine, API, and application
layers end to end and shipped about 350 atomic defect fixes, each with a
regression test that failed before the fix and passes after it. No feature
work is included. Operator action: none beyond the normal migration step; the
three payroll migrations below are additive.

### Financial integrity

- Posting: source corrections can no longer over-apply live settlements;
  negative-total credit memos and vendor credits are refused at the posting
  boundary; FX spot lookups break direct/inverse ties deterministically; line
  accounts and parties are checked against the tenant and subsidiary before
  any write; the vendor-payment "total is the cash amount" contract is pinned.
- Payments and receipts: allocation totals use exact money everywhere the UI
  or engine summed them; provider over-collection stays on account instead of
  being dropped; early-payment discounts are vendor-only; settlement evidence
  is scoped to the run's bank account; CPA-005, NACHA and SEPA writers refuse
  blank, oversized or checksum-invalid account and creditor identifiers.
- Banking: Plaid pending authorizations are no longer imported as statement
  truth; GoCardless and CAMT.053 lines are keyed by provider-unique ids;
  inactive reconciliation rules cannot be applied; SFTP statements are parsed
  from exact bytes.
- Payroll: signed stub lines net the deduction-protection base; WCB and
  employer QPIP caps consume committed stubs only; staleness watches pay
  schedules, statutory rates and union fringes; US state withholding engines
  receive YTD supplemental wages and current federal tax; RL-1 slips carry
  opening YTD; Quebec-only remittances use the Revenu Quebec calendar; SINs
  are Luhn-checked on T4/RL-1 transmission; bank-file generation re-verifies
  approval inside its transaction; opening balances now carry second-order YTD
  history and capped employer levies (migrations 0141 and 0143); retro
  readiness compares against a persisted quantification snapshot (0142).
- Tax: taxable-base return boxes convert at the posted FX rate; MACRS pool
  runs refuse short-year factors; nexus rates compare at ledger scale;
  provision reconciliation percents round half away from zero; filing boxes
  keep exact decimals; 1099 thresholds and box rules follow the IRS
  instructions (fishing boat proceeds, OBBBA 2026 threshold, corporate boxes).
- Consolidation and FX: proportionate interests are eliminated; source-to-
  elimination rate pairs are derived; test FX syncs no longer move the
  production schedule cursor.
- Reports and analytics: quarter breakouts follow the organization's fiscal
  start month; cash-basis drill-downs tie to settlement-share recognition;
  utilization and true-cost bases count approved time only; project margins
  scale identically in tables and exports; CSV exports keep exact decimals;
  cockpit tiles are scoped to the primary book and visible subsidiaries and
  translate mixed-currency totals.

### Isolation, authorization, and audit

- Subsidiary scope is enforced on budgets, journals, timesheets, approvals,
  flows, custom records, file-cabinet folders, parties, assistant and MCP
  tools, payroll run populations, and every module cockpit that read past it.
- Feature gates for field tickets, WIP billing, work breakdown and project
  scheduling are enforced in services, not only in navigation.
- Configuration saves (close policy, automation, calendars, reporting
  packages, sandbox schedules), timesheet decisions, and approval gate
  decisions write actor-attributed before/after audit evidence.
- Sealed tax identifiers are omitted from directory payloads; sandbox clones
  scrub masked custom data and users and rebuild derived aggregates.

### API contracts

- Malformed ids answer 404 on every verb instead of surfacing database errors;
  PATCH and DELETE validate what POST validates (dates, booleans, enums,
  referenced ids, custom fields on partial updates); document edits and voids
  carry the exact revision token so stale writes are refused.

### Sync

- Open-item verification compares expense reports alongside invoices, bills
  and credits, so a clean ledger no longer fails the financial gate;
  QuickBooks report dates are normalized
  at the adapter boundary; realized-FX groups get their own entry numbers;
  master-data upserts type their JSON parameters; tax-rate mirrors touch only
  the open current window.

### Test infrastructure

- Test fixtures refuse databases that do not carry the ephemeral marker, so a
  stray test run cannot write to a real database.

### Payroll

- Remittance bills for Revenu Québec destinations are now due on Revenu
  Québec's own timetable. The Canada pack declares the RQ schedule
  (quarterly, monthly, or twice-monthly by average monthly remittance, per
  Guide TP-1015.G and form TPZ-1015.R): Québec income tax, QPP, and QPIP bills
  carry RQ due dates and rules instead of inheriting the filing account's CRA
  remitter type, which previously stamped CRA accelerated-threshold dates on
  RQ bills. Set the frequency from your Revenu Québec notice under Setup →
  Payroll (new employers remit monthly, the default); Setup readiness warns
  while it is unconfirmed and when last year's average points at another band.

## [0.1.0-alpha.4] - 2026-08-20

### Time and timesheets

- Timesheet weeks have a lifecycle. Approved time stays read-only, but a week
  can be reopened while nothing downstream has consumed its hours; the reasons
  it cannot be (invoiced, paid, costed) are named rather than implied. Weeks
  carry their own record, with rejection reasons and amendment links.
- Whether hours require approval before they can be billed or paid is now
  organization policy rather than an assumption, and approval routing runs
  through flows, so approver, order, and quorum are configuration.

### Payments

- Fixed: the NACHA and SEPA direct-debit writers accepted a half-configured
  originator. They checked only that each required field was non-empty, while
  the credit rails additionally reject unfinished `FILL-ME` placeholders and an
  ODFI routing number that is not exactly nine digits. Because the writer
  slices that number to eight characters, an over-long value produced a
  well-formed file addressed to the wrong originating institution. Both debit
  rails now parse their originator to the same standard as the credit rails.

### Integrations

- NetSuite accounts can map their own job billing types instead of inheriting a
  single tenant-wide convention.

### Internal

- Raw SQL now carries its row type as a type argument (`db.execute<Row>(…)`)
  instead of asserting the shape back afterwards. 2,381 laundering casts across
  504 files were removed, along with a dozen ad-hoc "anything with `.execute`"
  parameter types that discarded the row type at the boundary; they share one
  `SqlExecutor` seam. Type-level only — no runtime behaviour changed.

### Operator action

- None. The schema gains `timesheet_weeks` plus two nullable columns on time
  entries; existing weeks derive their state on first use.

## [0.1.0-alpha.3] - 2026-08-04

The first public community preview of OpenBooks.

### Accounting and operations

- PostgreSQL-enforced double-entry ledger, exact decimal money arithmetic,
  periods and close controls, audit evidence, receivables, payables, payments,
  banking, reconciliation, budgets, tax workpapers, and income-tax provisions
- Multi-currency, multi-book, multi-subsidiary, intercompany, consolidation,
  eliminations, non-controlling interest, and goodwill configuration
- Inventory costing and reconciliation, fixed assets and tax pools, project
  accounting, time and job costing, construction progress billing, retainage,
  change orders, and project revenue recognition
- Configurable transaction approvals and workflows, reports and analytics,
  saved searches, exports, custom fields and records, scripts, apps, API keys,
  backups, sandboxes, and optional AI assistance

### First-run experience

- Adaptive company setup that uses industry, size, entity structure, currency,
  operational complexity, and control requirements to shape the workspace
- Three progressive operating profiles—Essentials, Growing, and Advanced—with
  authoritative feature gates that remain fully adjustable in Company Settings
- Go-live readiness guidance from company identity and fiscal calendar through
  opening balances, controls, and first month-end close
- RLS-isolated industry sample-company imports for evaluation and training
- Maintained country tax packs for Canada, the United States, Australia, New
  Zealand, the United Kingdom, Germany, France, Spain, Italy, the Netherlands,
  Ireland, Singapore, India, South Africa, the UAE, and Japan

### Data, integrations, and platform

- Generic migration and mirror framework with adapter-scoped source identities
  for NetSuite, QuickBooks, Xero, ERPNext, Odoo, and Microsoft Dynamics
- Governed tenant-scoped query console with schema browsing, contextual table
  actions, and access only through reviewed reporting views
- Platform controls for apps, scripts, API documentation and keys, MCP, query
  tools, workflows, sandboxes, and AI features
- English, French, Spanish, German, Brazilian Portuguese, Chinese, and Japanese
  locale catalogs

### Deployment, security, and integrity

- One-command Docker Compose installation using separate database-owner and
  constrained runtime roles, generated secrets, health checks, MinIO, Redis,
  web, worker, and migration-first startup
- Multi-platform GHCR image built once, scanned at the exact digest, retagged
  without rebuilding, and published with provenance attestation
- One audited canonical PostgreSQL baseline for clean installations, plus
  release tests for row-level security, source identity, setup provisioning,
  accounting invariants, and documented claims
- Production startup rejection of database roles that can bypass tenant RLS;
  tenant context is enforced across APIs, integrations, scripts, query tools,
  and background jobs
- Product-neutrality, history-hygiene, secret, dependency, container, and
  workflow checks in the release and security pipelines

### Known limitations

- This is alpha software and has not completed an independent accounting audit,
  security audit, or broad production validation. Start with test or parallel
  books and reconcile all opening balances, tax treatment, permissions,
  reports, backups, and jurisdiction-specific requirements.
- Country packs provide maintained configuration, workpapers, and exports; they
  are not universal electronic-filing certification or professional tax advice.
- The included Compose deployment is a single-host installation. A separate HA
  application-tier reference is provided, but operators remain responsible for
  production-grade database, cache, object-storage, ingress, monitoring,
  backup, and recovery infrastructure.

### Operator action

- Fresh installations bootstrap directly from the canonical baseline.
- Keep the generated `.env.compose` file secure and back it up; it contains the
  first administrator login and deployment secrets.
- Before using OpenBooks as a system of record, complete a restore rehearsal and
  the validation steps in the upgrade and backup runbooks.

[0.1.0-alpha.4]: https://github.com/braedonsaunders/openbooks/releases/tag/v0.1.0-alpha.4
[0.1.0-alpha.3]: https://github.com/braedonsaunders/openbooks/releases/tag/v0.1.0-alpha.3