RevRec brainstorm · Supporting · Rules / policies

11 — Rules reference (the policy catalog)

Status: draft Purpose: One place for the rules that drive recognition, allocation, modifications, credits, close, and journals. Use this to make product decisions and to configure a tenant. Principle: Rules are named config + policy, resolved deterministically — not logic buried in joins or spreadsheet branches.

Read with: 01-domain-asc606.md (why) · 03-event-catalog.md (policy ids) · 04-engine-scenarios.md (numbers) · 10-use-cases-and-flows.md (where rules fire)

Naming/precedence here are design proposals. Lock any rule that affects a booked number via an ADR.


0. Rule resolution order (precedence)

When multiple levels set a rule, the most specific wins:

line override  >  contract/PO  >  product/SKU  >  org default  >  system default

Every effective rule value is stamped on the entity it affects, so audit (F5) can show which rule applied and from which level.


1. Recognition method rules (Step 5)

recog.method — when/how control transfers.

Method Use when How revenue is spread Key inputs
ratable (default) SaaS access over a term (series of distinct services) Even over service window (daily or monthly calendar) service_start, service_end, allocated amount
point_in_time One-time delivery (setup fee at go-live, hardware) 100% on delivery/transfer date delivery date/event
proportional Professional services / delivery-based % complete or units delivered delivery feed (record_delivery)
milestone Fixed-fee stages On milestone acceptance milestone events
usage (later) Metered / variable As usage occurs, constrained usage events + constraint policy

Calendar sub-rule: daily (precise proration) vs monthly (simpler). Pick per tenant; affects amendment/cancel proration. Lock in ADR.


2. Transaction price rules (Step 3)

Rule Meaning MVP
Fixed consideration Known contracted amount yes
Variable consideration Usage/discounts/rebates estimated later
Constraint Only include variable amount not likely to significantly reverse later (with usage)
Significant financing Adjust for time value if payment timing is long out
Non-cash consideration Fair value of non-cash out

TP source order (Chargebee): subscription/item price → contract amount → read first invoice amount as an input (never as contract creator). See 03 §3.1 open question.


3. Allocation rules (Step 4)

Rule Use when Method
Single PO 100% One promise (most SaaS) All TP to the PO
Relative SSP Multiple distinct POs Allocate by standalone selling price ratio
Residual One PO has no observable SSP Others at SSP, remainder to that PO
Discount allocation Bundle discount Proportional to SSP unless discount clearly belongs to specific PO

SSP source (config): observable list price → adjusted market → residual. SSP library is tenant config; multi-PO is a deferred feature (08 §8).


4. Modification rules (contract changes)

Decision tree for amend_contract (ASC 606-10-25-10..13):

Is added scope a distinct good/service AT its SSP?
  YES → separate contract (new PO, no touch to existing)
  NO  → is remaining scope distinct from what's transferred?
          YES → PROSPECTIVE  (reallocate remaining TP over remaining POs; no restatement)
          NO  → CUMULATIVE CATCH-UP (adjust revenue-to-date immediately)
Policy ID Trigger Effect MVP
mod.upgrade mid-term increase prospective: reflow remaining schedule yes (prospective)
mod.downgrade mid-term decrease prospective yes (prospective)
mod.separate_contract distinct add-on at SSP new PO, existing untouched later
mod.cumulative not-distinct change catch-up adjustment to date later

MVP does prospective only; cumulative + separate-contract are ADR-gated additions.


5. Credit note / return rules

record_credit resolves a CB reason_codenamed policy (config map, not join logic).

Policy ID Substance Effect on revenue Effect on deferred/AR
cn.refund_unrecog (default) Price reduction on unrecognized portion unchanged deferred ↓ / remaining schedule ↓
cn.reverse_recog Return / cancellation of delivered value reverse recognized portion revenue ↓, adjust balances
cn.ar_only Billing-only credit (re-bill, admin) unchanged AR credit only; recognition untouched

Overflow rule (CN > unrecognized): define whether excess reverses recognized revenue or becomes AR credit — ADR (08 §4.5). Steal ideas from Hotglue apply_accounting_treatment; do not steal its control flow.


6. Cancellation / termination rules

terminate with policy term.cancel:

Option Remaining deferred becomes Use when
recognize_remaining Revenue now (obligation released) Non-refundable, obligation satisfied/waived
refund AR/refund liability Refundable prepayment
write_off Reversed (no revenue) Contract void / never earned

Proration to effective date follows the recognition calendar (§1). Default is ADR-gated — do not hardcode.


7. Contract-existence rules (Step 1 gate)

A contract is recognized only when ASC 606-10-25-1 criteria hold, notably collectibility probable.

Rule Effect
Collectibility probable Normal recognition
payment_required_for_revenue_recognition Defer recognition until cash/collectibility established (delayed revenue)
Not probable Hold / cash-basis deposit method until threshold met

This is the clean home for today’s payment_required_for_revenue_recognition flag and "Delayed Revenue" — a Step-1 policy, not a pipeline hack.


8. Period & close rules

Rule Statement
Recognize idempotency recognize(period) repeatable while period unlocked; same result
Lock Locked period is immutable; balances frozen
Reopen Allowed only pre-lock, or via controlled restatement with audit note
Late fact (locked period) Route to next open period as catch-up/adjustment; no silent rewrite
Cutoff Period membership by service/recognition date, not arrival time
Restatement Explicit, logged, and disclosed — never in-place

State machine: OPEN → READY → RECOGNIZED → POSTED → LOCKED (see 10 §5).


9. Currency & rounding rules

Rule Statement
Functional currency Each contract recognized in its currency; report in tenant functional currency
FX rate source Period/spot per policy; store rate used on each entry (audit)
Zero-decimal currencies JPY, KRW, VND, CLP, XAF, XOF, KRW — no minor units
Penny reconciliation Schedule lines must sum exactly to allocated TP; put rounding remainder on last (or first) period deterministically
Multi-decimal Support configurable precision where source needs it

Invariant: ∑ recognized + deferred_remaining = allocated TP (after amendments/credits per policy), to the cent.


10. Journal / account mapping rules

post_journals(period) maps subledger movements to GL accounts (config per tenant).

Movement Dr Cr
Bill prepaid (paid) Cash / Clearing Deferred revenue
Bill on credit AR Deferred revenue
Payment Cash AR
Recognize Deferred revenue Revenue
Recognize-before-bill Unbilled AR / Contract asset Revenue
Credit (refund_unrecog) Deferred revenue AR / Credit
Credit (reverse_recog) Revenue AR / Refund liability

Only summarized batches post to GL; line-level detail stays in the subledger (that’s the "subledger" promise in 00).


11. Config surface (what an admin sets per tenant)

Config Example
Recognition calendar daily | monthly
Default method by product plan→ratable, setup→point_in_time
SSP library product → SSP amount/source
CN reason → policy map subscription_changecn.refund_unrecog, product_unsatisfactorycn.reverse_recog
Modification defaults upgrade/downgrade → prospective
Cancellation policy term.cancel = recognize_remaining | refund | write_off
Collectibility rule payment_required_for_revenue_recognition on/off
Currency + FX source functional currency, rate table
GL account map subledger movement → account codes

Rule of thumb: if a behavior changes a booked number, it must be (a) a named rule here, (b) settable as config, and (c) covered by a golden scenario in 04.


12. Rules → scenarios coverage

Rule area Golden scenario
Ratable recognize S01 / S02
Billing vs recognition S02
Modification prospective S03
CN refund_unrecog S04
Cancellation S05 (todo)
Multi-PO SSP S06 (later)
Usage constraint S07 (later)
Proportional delivery S08 (later)

Any new rule needs a scenario before it ships.