07 — ASC 606 worked examples: demand vs need
Status: draft design
Purpose: Make ASC 606 concrete with numbers, then separate what the standard demands from what our product must build, and from what today’s code does.
Visual companion: open the canvas asc606-design.canvas.tsx beside chat, or ../visuals/asc606-design.html.
1. The only pipeline ASC 606 requires
1 Identify contract
2 Identify performance obligations (POs)
3 Determine transaction price (TP)
4 Allocate TP to POs (relative SSP)
5 Recognize when/as control transfers
Everything else in software (joins, snapshots, Camunda, xlsx) is implementation.
2. Worked example A — plain SaaS (most merchants)
Facts (Chargebee-shaped)
| Fact | Value |
|---|---|
| Customer | Acme |
| Subscription | sub_1, plan Pro, created 2026-01-01 |
| Term | 12 months, annual prepaid |
| Invoice | INV-1 on 2026-01-01 for $1,200 |
| Recognition rule | Ratable monthly over term |
What ASC 606 demands
| Step | Outcome |
|---|---|
| 1 Contract | Enforceable sub with Acme |
| 2 PO | One: “Pro access” over 12 months (series / over-time) |
| 3 TP | $1,200 (fixed) |
| 4 Allocate | 100% to that PO |
| 5 Recognize | $100 / month |
Balances (recognize-as-you-go after prepaid bill)
| Month | Bill / cash | Revenue | Deferred liability | AR |
|---|---|---|---|---|
| Jan (invoice + recog) | +1200 cash (or AR→cash) | 100 | 1100 | 0 if paid |
| Feb | — | 100 | 1000 | 0 |
| … | 100 | ↓100 | ||
| Dec | — | 100 | 0 | 0 |
Billing timing ≠ recognition timing is the whole deferred story. ASC 606 does not ask you to invent the PO from the invoice via date joins — the subscription + term already define the promise.
What we actually need to build
open_contract(sub_1)→ one PO, term, TP 1200record_billing(INV-1)→ AR / deferred setuprecognize(month)→ 100 revenue, −100 deferred
No merge_asof. No OrderDetails manufacturing. No full history reload.
What current code typically does instead
- Pull invoices + subs + snapshot history
match_invoices_with_contracts/process_base_invoices— join invoice lines to contract terms by date- Emit OrderDetails (synthetic sales-order lines) + BillingSchedule
- Camunda loads sheets → Redis SO processing → warehouse schedules
Same accounting outcome for this simple case; far more machinery.
3. Worked example B — mid-term upgrade (essential complexity)
Facts
- Same sub, Pro $100/mo ratable
- On 2026-07-01, upgrade to Enterprise, remaining 6 months at $200/mo (prospective)
What ASC 606 demands (prospective modification)
- Remaining PO / allocation updated from July onward
- No restatement of Jan–Jun revenue (under prospective)
- Jul–Dec recognize $200/mo
What we need
amend_contract(upgrade, effective=2026-07-01, policy=prospective)
Then recognize uses the new remaining schedule.
What current code often does
Re-derive order lines from invoice/proration history + snapshots; infer future items; CN/proration treatments — so the sheet looks right for the old engine. The policy (prospective vs cumulative) is buried in pandas paths, not a named operation.
4. Worked example C — credit note (policy, not joins)
Facts
- After 3 months recognized ($300), customer gets CN for $150 “service dissatisfaction” on unrecognized period
What ASC 606 might require (depends on substance)
| Policy | Effect |
|---|---|
| Reduce remaining TP / deferred | Cut unrecognized liability; maybe adjust future recog |
| Partial return / break | Reverse some recognized revenue |
| Billing-only credit | AR/credit memo; recognition unchanged |
ASC 606 demands a coherent policy + audit. It does not demand reason-code → merge_asof spaghetti as architecture.
What we need
record_credit(CN-1, policy=cn.refund_unrecog) (or chosen default) with explicit journal effects.
What current code does
apply_accounting_treatment by CN reason code inside the contract rebuild — correct intent, wrong shape for a clean product.
5. Demand vs need vs today’s code (summary)
| Topic | ASC 606 demands | We need to build | Today (Hotglue→RevRec) |
|---|---|---|---|
| Contract / POs | Explicit promises + periods | open / amend from sub/terms/catalog |
Reconstruct via invoice↔term asof + snapshots |
| TP + allocate | Amount + SSP when multi-PO | Allocation on open/amend | Embedded in OrderDetails amounts |
| Recognize | When/as control transfers | Period recognize + method |
Post-ingest SO / schedule processing |
| Billing | Consideration / AR timing | record_billing / pay / credit |
BillingSchedule sheet (+ AC_* for Premium) |
| Modifications | Prospective / cumulative / … | Named policies | Buried in contract engine branches |
| Audit / close | Traceable subledger + journals | Ops DB + close workflow | Warehouse + MSTR + posting jobs |
| Files / Camunda / org lock | — | Not required | Central path |
6. Spec pointer
Normative MVP behavior: 08-mvp-spec.md.
Chargebee field mapping: 03-event-catalog.md.
Golden tests: 04-engine-scenarios.md.
Current path detail: reference/current-behavior.md.