The rules, written down and executed
Each area of Saybooks is governed by a written spec: the acts it must support, the invariants it must keep, and scenario files that replay real sequences of acts, refusals included, through the actual command registry. A module that claims an area must map every act and pass every scenario; the contract test fails the build otherwise. The specs speak in acts, not commands, so a competing implementation can be certified by the same files.
bridge@0.3 · 6 acts · 4 scenarios · conformantcrm — Relationship Pursuit · Area SpecificationRelationship pursuit: campaigns with a goal, accounts that earned their place, contacts with sources or recorded as gaps, drafts the agent writes and a person sends, events with the page their date came from.
crm@0.5 · 26 acts · 7 scenarios · conformantjobhunt — One Person's Search · Area SpecificationA job search as a system of record: postings, applications, interviews, recruiters, a duplicate guard, and one next action per pursuit.
jobhunt@0.1 · 18 acts · 3 scenarios · conformanto2c — Order to Cash · Area SpecificationQuotes, orders, shipments, invoices, receivables and credit: the order-to-cash cycle of a small business, with a credit gate the agent cannot talk past.
o2c@0.2 · 26 acts · 10 scenarios · conformantp2p — Procure to Pay · Area SpecificationProcure-to-pay, specified ahead of any implementation: purchase orders, receipts against them, supplier invoices matched three ways, payment runs.
p2p@0.1-draft · 21 acts · 0 scenarios · no run yetProspect stagingThe holding area in front of the CRM: bought or scraped rows the agent stages and judges, that only a person promotes.
prospect@0.1 · 6 acts · 3 scenarios · conformantpurchases — What You Buy · Area SpecificationBank and card statements and receipts the agent read: rows with provenance, accepted whole or not at all, reviewed in the person's own words; standing rules that suggest, subscriptions and spend, and bills only a person approves paying.
purchases@0.5 · 30 acts · 9 scenarios · conformantsolo — Freelancer Invoicing · Area SpecificationA freelancer's invoicing: numbered invoices with a link and a PDF, any currency, your tax scheme, payments and what is still open, and reminders for overdue ones that the person sends. Issued means issued.
solo@0.3 · 14 acts · 6 scenarios · conformant
Every invariant, in one place
120 rules across 8 areas. Each is one sentence, enforced at the one place every command passes through, and shown identically to a person and to an agent when it refuses. The area pages hold the acts, the scenarios and the last conformance run.
bridge — The Ledger Bridge · Area Specification
| Id | Invariant |
|---|---|
B-1 | The journal is a derivation, never a posting: an export reads it and changes nothing. |
B-2 | Money is integer minor units; every export balances, per entry and in total. |
B-3 | One currency per hand-over; a period holding more than one is refused until a currency is named. |
B-4 | An export is refused while an account the period uses lacks the mapping the format needs, naming it. |
B-5 | Every hand-over records format, period, counts, control totals, a hash and the actor, and keeps the exact file. |
B-6 | Omitting the period start continues from the last hand-over in that format. |
B-7 | Re-exporting a period already sent is allowed and always visible, naming the earlier hand-over. |
B-8 | The chart is theirs: codes and names come from the accountant, never invented. |
B-9 | Every write is a logged act with an actor; refusals are logged too. |
B-10 | Spending posts against the account it was paid from; a transfer posts nothing, so money already recorded elsewhere is never counted twice. |
B-11 | An unreviewed row posts nothing and is reported as left out, in the preview and on the hand-over. |
B-12 | Preliminary statements are derived on request and never stored, balance by construction from the statements' printed openings, say whether each statement account ties, and name on their face what they leave out. |
crm — Relationship Pursuit · Area Specification
| Id | Invariant |
|---|---|
CRM-1 | Never invent a person: named contacts require a source; facts come only from sources. |
CRM-2 | A gap is a finding: recorded with a note, listed in the worklist, resolved only with provenance. |
CRM-3 | Every account earned its place: why_them and source_url are mandatory. |
CRM-4 | Relationship-graph fields are human-only: refused to agents regardless of role. |
CRM-5 | Activities record when it happened, not when it was typed. |
CRM-6 | Nothing is deleted: exclusion and closure are reasoned statuses. |
CRM-7 | Parking or killing an account requires a reason. |
CRM-8 | Promotion is a bridge act: won → core customer via the owner's API, at most once. |
CRM-9 | Provenance survives updates: correctable, never removable. |
CRM-10 | Interpretation is free; facts are sourced. |
CRM-11 | Every write is a logged command with an actor; refusals are logged; reads are not. |
CRM-12 | Every account pursues a campaign; pursuit state is campaign-relative. |
CRM-13 | No campaign without a goal — the goal is the brief agents read before filling the list. |
CRM-14 | There is no outbound channel: a draft is written and held; only a person sends it. |
CRM-15 | A sent draft is immutable and its exact words are copied onto the activity trail; a discarded draft is never revived. |
CRM-16 | Every draft carries a rationale for its reviewer, and the rationale is never part of what is sent. |
CRM-17 | What a campaign may claim is written by a person; refused words are checked against every draft and edit alike. |
CRM-18 | Parking is a fact about what happened and is orthogonal to status; it needs a reason and is reversible. |
CRM-19 | Account state is derived on read, never stored: an approach already made is never reported as an untouched door. |
CRM-20 | An event carries the source its date came from; a date not on the source is not a date. |
CRM-21 | Events are never deleted or reopened: done takes an outcome, cancelled takes a reason. |
CRM-22 | Attendance is the person's stance and a separate axis from the event's status; it is recorded only on their word. |
jobhunt — One Person's Search · Area Specification
| Id | Invariant |
|---|---|
JH-1 | Record of reality: facts only from the JD or correspondence; unknown beats guessed. |
JH-2 | Every contact has a source. |
JH-3 | Duplicate warnings are surfaced, never auto-resolved — a person decides. |
JH-4 | One application per posting. |
JH-5 | The end client is first-class; a missing one is visible work. |
JH-6 | One open next action per posting; supersede history kept. |
JH-7 | Suggestions, never actions: the area never sends, submits or clicks. |
JH-8 | Skips are reasoned pattern memory. |
JH-9 | Ghosted is a status, not a deletion. |
JH-10 | Applications record the resume version actually sent. |
JH-11 | Comp is annualized with caveats in prose. |
JH-12 | Interview rounds close with outcomes; outcomes are touches. |
JH-13 | Thresholds are reference data, not code. |
JH-14 | Every write is a logged command with an actor; refusals kept; reads unlogged. |
o2c — Order to Cash · Area Specification
| Id | Invariant |
|---|---|
INV-1 | Money is integer minor units, everywhere. |
INV-2 | Both prices survive: list price and charged price on every line. |
INV-3 | Documents don't mutate past draft except through defined acts. |
INV-4 | Bill what was fulfilled, never what was ordered. |
INV-5 | One credit gate, at confirmation; exposure counts open AR plus committed. |
INV-6 | Stock never goes negative; only the stock owner's API changes it. |
INV-7 | Short fulfilment leaves the remainder open; only close_short extinguishes it. |
INV-8 | Recording cash is not applying cash; unapplied cash is a valid state. |
INV-9 | Document numbers are sequential and never reused. |
INV-10 | Void only when untouched; anything applied-against is corrected by credit note. |
INV-11 | The credit note is the only downward correction past draft. |
INV-12 | Restock only what physically returns sellable. |
INV-13 | Cash is not transferable between customers. |
INV-14 | Tax is frozen at issuance. |
INV-15 | Due dates derive from terms at issuance. |
INV-16 | Write-offs are reasoned, visible credit acts. |
INV-17 | Refusals name the numbers. |
INV-18 | One sentence per rule, on every surface. |
INV-19 | Prices freeze when a document is raised from another. |
INV-20 | Closure is derived, not declared. |
INV-21 | Every write is a logged command with an actor; reads are never logged. |
INV-22 | The books produce documents; they never send them. |
INV-23 | Every journal entry balances — debits equal credits, derived from the books, never entered. |
p2p — Procure to Pay · Area Specification
| Id | Invariant |
|---|---|
P2P-1 | Money is integer cents, everywhere. |
P2P-2 | Nothing is paid without an approved bill; nothing approves without a match on the record. |
P2P-3 | The 3-way match names its numbers; tolerance is config, breach is a refusal. |
P2P-4 | Stock enters only through a receipt; receipts are immutable facts. |
P2P-5 | Item cost is derived from receipts, never entered. |
P2P-6 | Vendor bank details are human-only; an agent can record a bill, never redirect money. |
P2P-7 | A disputed bill cannot be paid; dispute and resolution carry reasons. |
P2P-8 | PO prices freeze at issue; variances are shown, never averaged away. |
P2P-9 | Payments are recorded, never executed — no outbound rails. |
P2P-10 | The duplicate-bill guard surfaces warnings; it never auto-resolves them. |
P2P-11 | Over-receipt and over-billing are refusals naming the quantities. |
P2P-12 | Every write is a logged command with an actor; refusals are logged too. |
P2P-13 | Journal entries derive balanced: receipt to GRNI, approval to AP, payment to cash; COGS arrives with cost. |
P2P-14 | Goods received not invoiced is always visible — a real liability, not a residue. |
Prospect staging
| Id | Invariant |
|---|---|
PRO-1 | The same pull never lands twice: a repeated hash is refused, naming the pull that holds it. |
PRO-2 | Every pull records the brief it was made under, and it is mandatory at the door. |
PRO-3 | A verdict carries a reason a person can overrule, or it is refused. |
PRO-4 | An unjudged row is a distinct state from any verdict, and is queryable as such. |
PRO-5 | Only a person promotes. The act is refused to agents whatever their role. |
PRO-6 | A promoted row records what it became; a promoted row is never re-judged or re-promoted. |
PRO-7 | A staged row is counted in no pipeline, coverage or campaign statistic. |
PRO-8 | Rows are never edited: a wrong pull is discarded and staged again from a fresh read. |
PRO-9 | A discard keeps rows that already became accounts, so those accounts keep their provenance. |
PRO-10 | A promoted account is held to the curated list's own gate: why_them and source_url, from the verdict. |
PRO-11 | Every write is a logged act with an actor; refusals are logged; reads are not. |
purchases — What You Buy · Area Specification
| Id | Invariant |
|---|---|
P-1 | Money is integer minor units, signed; every source and transaction carries a currency; sums are per currency and never cross. |
P-2 | Every transaction traces to a source: source id, row index, and the raw line as read. |
P-3 | A statement is accepted whole or not at all: the rows must reconcile to the printed opening and closing balance, and to the printed row count when the statement prints one, or the batch is refused with the gap named. |
P-4 | The same source hash is refused a second time; rows already present are skipped and listed, never silently merged or duplicated. |
P-5 | Nothing is invented: category, vendor and status are empty or unreviewed until an act with a reason sets them. |
P-6 | A subscription is declared, then confirmed by the record: a period with no matching charge is missed, two make it lapsed; a charge is never assumed. |
P-7 | A receipt matches at most one transaction and vice versa; matching is a reasoned act, refused when the total or date does not fit unless overridden with a reason. |
P-8 | Every write is a logged act with an actor; refusals are logged too. |
P-9 | Files never live here: a source or a receipt is its hash, its metadata and what was read. |
P-11 | A standing rule suggests and never books: matching rows stay unreviewed with the suggestion until a reasoned review confirms them; ending a rule removes its suggestions and changes no reviewed row. |
P-12 | A bill is a record, never a payment: only a person approves paying it, a payment is recorded after it happened and by an agent only for an approved bill, a linked statement row must match it, and the same bill is refused twice. |
solo — Freelancer Invoicing · Area Specification
| Id | Invariant |
|---|---|
S-1 | Money is integer cents, everywhere. |
S-2 | An issued invoice is immutable — mistakes are void-and-reissue, on the record. |
S-3 | The seller and bill-to blocks freeze at issuance; issuing without a profile or a client address is refused with the guide sentence. |
S-4 | Numbers are sequential and never reused; a voided number stays burned. |
S-5 | Invoice timing is the freelancer's agreement — the system records, never gatekeeps terms. |
S-6 | No invented facts: amounts, dates and names come from the person or stay empty. |
S-7 | Documents are produced, never sent; the doc link views one document (DRAFT-stamped until issued) and nothing more. |
S-8 | Every write is a logged act with an actor; refusals are logged too. |
S-9 | Journal derivation balances: issue to AR/Revenue, receipt to Cash/Deposits, application to Deposits/AR. |
S-10 | An invoice carries exactly one currency from the company's set, a payment too; cash never crosses currencies; sums are per currency. |
S-11 | Tax follows the company's scheme, frozen at issue: unregistered lines cannot carry tax; registered lines default to the rate and the document prints TAX INVOICE. |
S-12 | Numbers follow the company's format (sequence token, optional year token) and stay sequential and never reused within it. |
S-13 | A reminder is a draft a person sends: only for an overdue invoice with money open, one waiting at a time, its figures the invoice's own, a send recorded only with the day it went, another within seven days only with a reason. |
These pages are generated from the files in specs/ in the repository; scenarios are executed by src/conformance.js on every build. Written and maintained by Peter Varga, who also runs Portland AI Works. github.com/alviso/saybooks, AGPL-3.0.