Problem
TREE_DEPTH is a hardcoded 20 in both circuits/shielded_pool/src/main.nr and contracts/pool/src/lib.rs (MAX_LEAVES = 1u32 << TREE_DEPTH), independently defined in each. There is no documented or tested path for growing capacity once a pool approaches 2^20 leaves — doing so today would mean deploying an entirely new circuit + contract with no continuity for existing notes.
Why it matters
A fixed-capacity tree is a hard ceiling on protocol adoption: once full, deposits stop working with no migration story, and users' existing shielded notes would need a bespoke, one-off migration if that day ever comes without advance planning.
Scope
contracts/pool/src/lib.rs: near-capacity guard/warning (e.g. an event or explicit error once the tree crosses a high-water mark) so operators get advance notice before MAX_LEAVES is hit.
- New
circuits/shielded_pool_v2/ (or a depth-parameterized circuit) proving membership against either an old (depth 20) or new (deeper) root, so a note minted under the old tree stays provably spendable after a capacity migration.
contracts/pool/src/lib.rs: a migration entrypoint that starts a new tree while retaining lookups against historical roots for outstanding notes (is_known_root already tracks historical roots and is the existing pattern to extend).
frontend/src/lib/indexer.ts, sync.ts: handle reconstructing a Merkle path against whichever tree/depth a given note's commitment actually lives in.
- Contract + circuit tests: a note minted pre-migration can still be withdrawn post-migration.
docs/THREAT_MODEL.md/DESIGN.md: document the capacity ceiling and the migration story explicitly (today neither mentions it).
Acceptance criteria
- There's a tested, documented procedure for increasing pool capacity that doesn't strand notes minted before the migration.
- Operators get an on-chain signal well before
MAX_LEAVES is reached, not just a hard failure at the boundary.
Problem
TREE_DEPTHis a hardcoded20in bothcircuits/shielded_pool/src/main.nrandcontracts/pool/src/lib.rs(MAX_LEAVES = 1u32 << TREE_DEPTH), independently defined in each. There is no documented or tested path for growing capacity once a pool approaches2^20leaves — doing so today would mean deploying an entirely new circuit + contract with no continuity for existing notes.Why it matters
A fixed-capacity tree is a hard ceiling on protocol adoption: once full, deposits stop working with no migration story, and users' existing shielded notes would need a bespoke, one-off migration if that day ever comes without advance planning.
Scope
contracts/pool/src/lib.rs: near-capacity guard/warning (e.g. an event or explicit error once the tree crosses a high-water mark) so operators get advance notice beforeMAX_LEAVESis hit.circuits/shielded_pool_v2/(or a depth-parameterized circuit) proving membership against either an old (depth 20) or new (deeper) root, so a note minted under the old tree stays provably spendable after a capacity migration.contracts/pool/src/lib.rs: a migration entrypoint that starts a new tree while retaining lookups against historical roots for outstanding notes (is_known_rootalready tracks historical roots and is the existing pattern to extend).frontend/src/lib/indexer.ts,sync.ts: handle reconstructing a Merkle path against whichever tree/depth a given note's commitment actually lives in.docs/THREAT_MODEL.md/DESIGN.md: document the capacity ceiling and the migration story explicitly (today neither mentions it).Acceptance criteria
MAX_LEAVESis reached, not just a hard failure at the boundary.