# ADR-007 — Mandala cycles and first-class cell occupations

## Status

Accepted for Alpha.49.2 hardening of the Pix economy.

## Context

A physical cell can be occupied more than once over the lifetime of a Mandala
because the destruction/reset lifecycle clears the live `cells` state and allows
the Mandala to be filled again.

The first Pix economy implementation used `cell_id` as the reference for a paid
cell debit. That is unsafe because `cell_id` identifies a reusable physical cell,
not a unique economic event. A reused cell could therefore collide with an older
debit and incorrectly satisfy the new acquisition without a new charge.

The project needs a durable, server-authoritative economic event that can later
support refunds, receipts, moderation/history and analytics without depending on
client transport details.

## Decision

Introduce two first-class persistence concepts:

- `mandala_cycles` — one active cycle per Mandala; when a Mandala is reset after
  destruction, the previous cycle is archived and a new active cycle is created.
- `cell_occupations` — an immutable business event representing one cell
  acquisition inside one Mandala cycle.

A cell occupation records at minimum:

- Mandala;
- cycle;
- reusable cell;
- user;
- Pix price captured at acquisition time;
- acquisition time and channel.

A cycle may contain at most one occupation for a given cell:

`UNIQUE(cycle_id, cell_id)`.

New paid cell debits in `pix_ledger` reference the occupation event id rather than
the reusable `cell_id`. Occupation creation, the Pix debit and the live cell update
are performed in the same database transaction. If the debit fails, the occupation
and live cell update are rolled back together.

## Migration decision

Migration `008_mandala_cycles_and_occupations.sql` creates a legacy archived cycle
`0` and an active cycle `1` for existing Mandalas. Existing occupied cells are
represented by one current occupation in the active cycle, using the Mandala's
current `cell_price_pix` as the captured price.

The migration deliberately does **not** reconstruct historical occupation events
from old Pix ledger rows. The pre-Alpha.49.2 schema did not store enough information
to establish a trustworthy occupation history, and those rows originated during the
test-era implementation. Existing `pix_ledger` rows therefore remain untouched,
including their original `reference_type` and `reference_id`. They are retained as
legacy accounting data.

From Alpha.49.2 onward, every new paid cell acquisition gets a new occupation event
and a new debit referencing that occupation.

## Consequences

### Positive

- Reusing a cell in a new cycle is a naturally new economic event.
- New paid acquisitions cannot reuse an earlier debit merely because they use the
  same physical cell.
- The Pix price is fixed in the occupation event and does not change retroactively
  when a Mandala's current price changes.
- Database-level uniqueness protects one occupation per cell within a cycle.
- The model remains independent of polling/WebSocket/SSE delivery.
- Legacy test-era ledger data is preserved without inventing historical events.

### Trade-off

Historical occupation reconstruction is intentionally incomplete for pre-Alpha.49.2
data. The old ledger remains available for accounting continuity, but it is not
presented as a fully reconstructed occupation history.

## Future evolution

The occupation id is the stable business-event boundary for later features such as
refunds, moderation/history views, receipts, analytics and other accounting
operations.
