FEAT-OBL-002: Schedule Next Bill Cycle
| Reference Number | Version | Effective Date | Supersedes | Authority Level |
|---|---|---|---|---|
| FEAT-OBL-002 | 2.2 | 2026-10-14 | 2.1 | Normative |
Important
v2.2 (2026-10-14), documentation modernization. Fixed a Dependencies citation that named a nonexistent file, FEAT-OBLI-001_ASSESS_OBLIGATION.md; the real file is FEAT-OBL-001_ASSESS_OBLIGATION.md. No content change.
I. Purpose
This FEAT records the next lawful bill cycle for a recurring obligation lineage through the Obligations succession command schedule_next_bill_cycle (DOM-OBL-001 §V.7).
There is no separate genesis command. The domain derives the cycle number from authoritative Obligations state: 1 where the lineage has no cycle, otherwise current + 1. The caller requests succession for a lineage and never supplies or asserts a cycle number.
The bill cycle is identity-blind temporal reminder state. It does not determine business meaning, amount, class, seat, or contract authority. It only records that a continuing internal reference must be reconsidered at a lawful boundary.
This FEAT is used for recurring rent and recurring insurance premium progression when the lawful upstream authority permits another cycle.
II. Authority
Obligations owns:
bill_cycles- recurring progression legality for obligation sources
Class Configuration owns:
- rent policy terms
- insurance policy terms
- effective version lineage
Store and Entitlements owns:
- insurance entitlement / coverage lifecycle inputs
Ledger owns:
- monetary truth
This FEAT SHALL NOT decide business meaning from labels or mutate upstream contractual truth.
III. Required Context
Required canonical context:
class_idinternal_refseat_idwhen the source is seat-scopedactor_seat_idcycle_boundary_atandnext_assessment_atfor the requested cyclepolicy_uuidin force for the requested cycleidempotency_key— the command identity (DOM-OBL-001 §V.7), scoped toclass_id- the canonically resolved reference time (execution context; not part of the command’s terms)
The request carries no cycle number. The lawful caller SHALL provide the upstream authority reference and version snapshot needed to validate the requested cycle.
IV. Orchestration Logic
1. Verification
- Look up the command identity. If it was already executed with the same terms, return that execution’s cycle (exact replay); if with different terms, fail closed (replay mismatch). Replay is decided before eligibility.
- Verify succession eligibility from authoritative Obligations state (DOM-OBL-001 §V.7): the lineage is empty, or its latest cycle is non-terminal and its assessment point has arrived at the reference time, evaluated through the Canonical Temporal Evaluation helper (INV-ARC-015 §VII). The assessment point is
next_assessment_at − preview, wherepreviewis the bill preview interval of the immutable policy referenced by that cycle’s ownpolicy_uuid, obtained through the Policies read (DOM-POL-001A §V.E); a preview of0places it atnext_assessment_at. Succession after a terminal cycle, or before the assessment point, is unlawful. - Verify
next_assessment_atis strictly later thancycle_boundary_at(DOM-OBL-001 §VII.2). - Derive the cycle number once from the state read in step 2.
- Verify the recurring source still lawfully exists, and resolve the lawful version snapshot that governs the cycle.
2. Mutation
- Create the
bill_cyclesrow and record the command identity (obligation_command_reservation: identity, request fingerprint, produced cycle) in the same transaction. - If a different command created the derived cycle first, fail with a succession conflict. Do not replay it and do not re-derive a later cycle (DOM-OBL-001 §V.7 case 3).
- Emit any resulting lawful obligation assessment through the canonical obligations FEAT surface.
3. Terminal case
If the authoritative source has terminated, no successor cycle is created. Termination itself is a separate command (terminate_bill_cycle) and is not routed through succession.
V. Invariants
bill_cyclesSHALL NOT store monetary amount.bill_cyclesSHALL NOT store business meaning for the source.bill_cyclesSHALL NOT store class/seat identity when that identity belongs upstream.- A terminated recurring relationship produces no successor cycle.
- Succession is idempotent on command identity, never on the shape of the row it would write. Two distinct commands deriving the same cycle are two commands: exactly one creates it and the other receives a succession conflict.
- The cycle number is derived (
1for an empty lineage, otherwisecurrent + 1) and is never caller-supplied. - Succession is lawful only for an empty lineage or a non-terminal latest cycle whose assessment point has arrived. A caller’s own scheduling predicate does not substitute for this check. A later policy submission cannot move an existing cycle’s assessment point.
- The latest cycle is not the current cycle: under advance assessment it is routinely an upcoming cycle whose period has not begun. Callers that need the current cycle use the period-containment query (DOM-OBL-001 §V.7).
VI. Dependencies
docs/DOMAIN/DOM-OBL-001_OBLIGATIONS_DOMAIN.mddocs/DOMAIN/DOM-CLASS-001_CLASS_CONFIGURATION_DOMAIN.mddocs/DOMAIN/DOM-STORE-001_STORE_AND_ENTITLEMENTS_DOMAIN.mddocs/FEATURE-EXECUTION/FEAT-OBL-001_ASSESS_OBLIGATION.mdschedule_next_bill_cycle(Obligations bill-cycle succession command; DOM-OBL-001 §V.7, §VII.2)
Last updated: 2026-10-14