Port allocation/distribution engine #32

Closed
opened 2026-06-14 23:39:31 +02:00 by myrmidex · 1 comment
Owner

Rebuild the phased income-distribution engine as a tested service.

  • Phased fill order: needs→base, wants→base, needs→buffer, wants→buffer, overflow.
  • Division mode within each phase: even split (default) or priority order.
  • Effective-capacity / buffer logic (allocation_value * (1 + buffer_multiplier)); single source of truth for capacity.
  • Stateless preview endpoint (/api/.../projections/preview) returning the computed distribution.
  • Pure service layer; API thin over it.

Exit: engine reproduces today's behaviour; covered by unit + functional tests.

Rebuild the phased income-distribution engine as a tested service. - Phased fill order: needs→base, wants→base, needs→buffer, wants→buffer, overflow. - Division mode within each phase: even split (default) or priority order. - Effective-capacity / buffer logic (allocation_value * (1 + buffer_multiplier)); single source of truth for capacity. - Stateless preview endpoint (`/api/.../projections/preview`) returning the computed distribution. - Pure service layer; API thin over it. Exit: engine reproduces today's behaviour; covered by unit + functional tests.
myrmidex added this to the v0.3.0 milestone 2026-06-14 23:39:31 +02:00
myrmidex added the
enhancement
label 2026-06-14 23:39:31 +02:00
myrmidex self-assigned this 2026-06-14 23:39:31 +02:00
Author
Owner

Done. Phased allocation engine + stateless preview endpoint shipped. 170 tests green, PHPStan clean, Pint clean, 100% line coverage on all new classes. Pre-commit (code-reviewer) + finish-phase (pr-reviewer full-diff) reviews both passed.

Delivered:

  • App\Service\Allocation engine cluster: AllocateIncome (single-use Action), BucketRoomCalculator, EvenSplitter, Result.
  • POST /api/scenarios/{scenario}/projections/preview — stateless preview via an API Platform Processor (PreviewProcessor) + separate input/output DTOs (ProjectionPreviewInput / ProjectionPreviewOutput). First DTO #[ApiResource] + first State class in the project.
  • BucketRepository::findByScenarioOrderedByPriority.

Conscious divergence from the "reproduces today's behaviour" exit criterion: #32 deliberately became a redesign, not a faithful port of the v0.2.0 PipelineAllocationService. Differences from the old engine are intentional, not regressions:

  • Model C distribution (type-phased macro-order + priority tiers within + percentage participates in its type's base phase) replaces the old type-grouped model.
  • Floor (not round) all caps — a cap is a ceiling; never overfill.
  • getCurrentBalance collapses to startingAmount — no Draw/Inflow/Outflow ledger entities in #32 (stateless preview only; the persisted apply path is a later ticket).
  • Fixed a money-vanishing bug discovered during the build: no buckets + positive income now reports the full income as unallocated (was 0).

Deferred / follow-up:

  • remaining_capacity is intentionally always null (real per-bucket capacity math is a later ticket — anemic Bucket has no getEffectiveCapacity).
  • Per-user ownership / object-level authorization is a pre-existing gap, now tracked as #50 (any ROLE_USER can currently preview any scenario by UUID).
  • DistributionMode enum + column are now obsolete (even-split is intrinsic within tiers) — cleanup deferred to its own ticket.
Done. Phased allocation engine + stateless preview endpoint shipped. 170 tests green, PHPStan clean, Pint clean, 100% line coverage on all new classes. Pre-commit (code-reviewer) + finish-phase (pr-reviewer full-diff) reviews both passed. **Delivered:** - `App\Service\Allocation` engine cluster: `AllocateIncome` (single-use Action), `BucketRoomCalculator`, `EvenSplitter`, `Result`. - `POST /api/scenarios/{scenario}/projections/preview` — stateless preview via an API Platform **Processor** (`PreviewProcessor`) + separate input/output DTOs (`ProjectionPreviewInput` / `ProjectionPreviewOutput`). First DTO `#[ApiResource]` + first State class in the project. - `BucketRepository::findByScenarioOrderedByPriority`. **Conscious divergence from the "reproduces today's behaviour" exit criterion:** #32 deliberately became a redesign, not a faithful port of the v0.2.0 `PipelineAllocationService`. Differences from the old engine are intentional, not regressions: - **Model C distribution** (type-phased macro-order + priority tiers within + percentage participates in its type's base phase) replaces the old type-grouped model. - **Floor (not round) all caps** — a cap is a ceiling; never overfill. - **`getCurrentBalance` collapses to `startingAmount`** — no Draw/Inflow/Outflow ledger entities in #32 (stateless preview only; the persisted `apply` path is a later ticket). - Fixed a money-vanishing bug discovered during the build: no buckets + positive income now reports the full income as `unallocated` (was `0`). **Deferred / follow-up:** - `remaining_capacity` is intentionally always `null` (real per-bucket capacity math is a later ticket — anemic Bucket has no `getEffectiveCapacity`). - Per-user ownership / object-level authorization is a pre-existing gap, now tracked as **#50** (any ROLE_USER can currently preview any scenario by UUID). - `DistributionMode` enum + column are now obsolete (even-split is intrinsic within tiers) — cleanup deferred to its own ticket.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lvl0/buckets#32
No description provided.