PowerFill Phase 6 — Sub-Phase Breakdown
Author: PSSaaS Systems Architect Date: 2026-04-17 Status: Draft — pending Collaborator review and PO approval before sub-phase 6b planning begins. Companion docs:
- Architect-internal Phase 6a plan:
.cursor/plans/powerfill-phase-6a.plan.md(gitignored, like Phase 4 / 5 plans) - Open questions to PO:
powerfill-phase-6-open-questions.md - Original kickoff:
powerfill-architect-phase6-kickoff.md
Why a sub-phase breakdown
The Phase 6 kickoff (line 49-62) explicitly says:
Phase 6 is the biggest phase of the module (3-4 weeks per spec estimate). Substantially more substantive than Phases 1-5 combined. … This is NOT a single-PR phase; the planning output should explicitly propose sub-phases (6a / 6b / 6c …) so each sub-phase is independently reviewable and shippable.
Phase 6 ports two of the largest legacy procedures in the codebase (psp_powerfill_conset ≈ 5,887 lines of T-SQL string-concat at NVO 50-5886, plus psp_powerfillUE ≈ 6,556 lines split across two PB functions at NVO 13246-19801). A monolithic plan would defer review until the work is unreviewable; a single PR would block on every detail. The sub-phase breakdown is the Reviewable Chunks practice (process-discipline §6) applied at phase scale.
Each sub-phase is:
- Independently reviewable — produces an artifact a Collaborator can verify against the NVO and the PS_DemoData live arm in one pass
- Independently shippable — bumps the canonical
/api/powerfill/statussentinel (statusfield) so deploy-verification arms (a) sentinel and (c) live probe are both satisfied per sub-phase - Dependency-ordered — each sub-phase's preconditions are satisfied by the prior sub-phase's outputs, so a halt at any boundary leaves the system in a coherent state
The 7 cross-sub-phase open questions in powerfill-phase-6-open-questions.md are PO-input gates before sub-phase 6b planning begins. Sub-phase 6a can proceed in parallel with the open-questions discussion because 6a's scope (candidate-builder + carry-cost integration + BX cash-grid pre-step) is upstream of every open question except #6 (calculator integration pattern), and #6 is internal to 6a's design.
At-a-glance summary
| Sub-phase | Scope (one line) | Shippable artifact | Staging sentinel | Estimated effort |
|---|---|---|---|---|
| 6a | Run-orchestration scaffold + BX pre-steps + candidate-builder + carry-cost integration | POST /api/powerfill/run returns run_id (synchronous for now); pfill_loan2trade_candy_level_01 populated; BX cash-grid + settle-and-price procs deployed and invoked; preview at POST /api/powerfill/candidates/preview | phase-6a-candidate-builder-ready | 5-7 days |
| 6b | Multi-pass allocation engine (exact_fit / best_fit / fill_remaining / orphan_handling) | pfill_powerfill_guide populated by psp_powerfill_conset port; pfill_kickout_guide_01 populated; allocation passes run synchronously | phase-6b-multi-pass-ready | 7-10 days |
| 6c | Pool-action derivation (BR-3 state machine: Remaining / Leaving / Joining / Switching / Swapped In) + tolerance enforcement (BR-4) | pfill_pool_guide populated; psp_powerfill_pool_guide port complete (live NVO 8770-11185 range) | phase-6c-pool-actions-ready | 5-7 days |
| 6d | UE pass: psp_powerfillUE port + 3 pfill_syn_* synthetic-trades tables added to schema + populated by UE | pfill_syn_trade_base, pfill_syn_powerfill_guide_all_rank, pfill_syn_powerfill_guide populated; pfill_powerfill_log auto-create included; A28 closed | phase-6d-ue-syn-trades-ready | 7-10 days |
| 6e | Async run orchestration + pfill_run_history audit + BR-8 single-active-run guard + BR-9 failure cleanup + PoC sign-off | POST /api/powerfill/run is asynchronous; pfill_run_history row per run; GET /runs, GET /runs/{id}, POST /runs/{id}/cancel; PS_DemoData PoC: a full run produces sensible pool_action distribution | phase-6e-async-runs-ready | 5-7 days |
Total estimated effort: 29-41 days = 4-6 work-weeks. Within the spec's "3-4 weeks" estimate at the optimistic end, slightly over at the realistic end. The estimate is ranges, not points; Phase 4 ran ~1.5x the initial estimate due to F3 escalation, and Phase 6 has 7 known open questions.
Sub-phase 6a — Run-orchestration scaffold + candidate-builder + BX pre-steps
Scope (in)
POST /api/powerfill/run— accepts the full Run Options body (spec §Run Options, lines 226-238); returnsrun_idand a synchronous result; the async version moves to 6e. 6a's run is "synchronous best-effort" — it executes inline and returns200 OK+ body when finished, OR500if it fails. This lets 6a be testable end-to-end without taking on the BackgroundService design dependency (Open Q1).- BX cash-grid pre-step — port
psp_pfill_bx_cash_gridsfrom NVO line 12834-13137 to a new SQL file006_CreatePowerFillRunProcedures.sql. This is the first proc invoked fromw_powerfill.srw::ue_perform_powerfillline 111 withbx_price_floorasls_proc_parms[1]. Skippable whenbx_price_flooris unset per A12. - BX settle-and-price pre-step — port
psp_pfill_bx_settle_and_pricefrom NVO line 11345-11710 to the same006script. Second proc invoked at w_powerfill.srw line 131. Always invoked (not gated). - Candidate-builder — populate
pfill_loan2trade_candy_level_01from the eligible-loans × open-trades cartesian, applying:- Sec-rule filter (BR-1) via
pfill_constraint_sec_rule_rel↔pscat_securitization_rules - Loan-stage filter (A15)
- Lockdown filter (BR-2) via
pfill_lockdown_guide - Price-floor filter (BR-6) when
bx_price_flooris set interest_earning_days = DATEDIFF(D, COALESCE(close_date, lock_expiration_date), settlement_date)per NVO line 1232-1233 / 1442marketlookup viapfill_cash_market_mappricefrom BX settle-and-price output
- Sec-rule filter (BR-1) via
- Carry-cost integration — invoke
PowerFillCarryCostCalculator(Phase 5) over the materialized candidate batch; UPDATEpfill_loan2trade_candy_level_01with the calculatedcarry_costandprx_plus_carry. Calculator integration pattern (Open Q6) resolved here. - Diagnostic preview endpoint —
POST /api/powerfill/candidates/previewreturns the candidate set without writing topfill_loan2trade_candy_level_01(analogous to Phase 5'sPOST /carry-cost/preview). Diagnostic-only; lets PO/Collaborator inspect what the candidate-builder produces before allocation runs over it. - Run orchestration scaffold (synchronous) —
PowerFillRunServicemodeled onPowerFillPreprocessService(Phase 3 pattern); no BackgroundService yet; failure leavespfill_loan2trade_candy_level_01in whatever state the failed pass produced (cleanup is Phase 6e BR-9). /api/powerfill/statussentinel bump tophase-6a-candidate-builder-ready.
Scope (out)
- Multi-pass allocation (6b)
- Pool-action derivation (6c)
- UE pass / synthetic trades (6d)
- Async runs /
pfill_run_history/ single-active-run guard / failure-state cleanup (6e) - Output query APIs (Phase 7)
- React UI (Phase 8)
- The 4 read APIs over
pfill_loan2trade_candy_level_01(/runs/{id}/candidates, etc.) — those are Phase 7
Shippable artifact
After 6a:
POST /api/powerfill/runagainst PS_DemoData with{}body (defaults) returns200 OK+ arun_idand a count of candidates produced, OR returns500if a step fails. The candidate count is sensible (non-zero, < cartesian explosion).pfill_loan2trade_candy_level_01in PS_DemoData has rows after the call, with all carry-cost columns populated where curve match succeeded.POST /api/powerfill/candidates/previewreturns the same candidate shape without writing.- Both BX procs are deployed to PS_DemoData via
006; verifiable viaOBJECT_ID('dbo.psp_pfill_bx_cash_grids') IS NOT NULL. /api/powerfill/statusreturnsphase-6a-candidate-builder-ready.
Sentinel
phase-6a-candidate-builder-ready on /api/powerfill/status.
Why this sub-phase first
The candidate-builder is the least dependent part of Phase 6: every later sub-phase consumes pfill_loan2trade_candy_level_01. Building it first means 6b/6c/6d/6e can each test their work against a stable upstream. Also, 6a is what proves the run-orchestration plumbing works end-to-end — if 6a can't get a request from POST /run through DI, tenant resolution, and the existing preflight stack, that's a blocker for everything downstream and we want to find it as early as possible.
The BX pre-steps are bundled into 6a (rather than split into 6a-pre) because they have no consumers other than the candidate-builder; splitting them would create a deploy state where the BX procs exist but nothing calls them.
Sub-phase 6b — Multi-pass allocation engine
Scope (in)
- Port
psp_powerfill_consetbody (NVO line 50-5886) into the new006script (or a new007_*.sqlif 006 grows too large; Architect's call when 6b plans). Specifically the multi-pass allocation core: the iterative blocks scattered through NVO line 7500-12500 per kickoff §"NVO PRIMARY-SOURCE CITATION INDEX". - Trace and document the actual pass boundaries — A1 says "four passes" but that's an interpretation. The 6b plan must read the NVO and identify each pass empirically (separate INSERT/UPDATE blocks against
pfill_loan2trade_candy_level_01), document them as A1.1 / A1.2 / A1.3 / A1.4 in a 6b-specific addendum to the assumptions log, and resolve A1 to "verified" or "needs PO escalation." This is itself a Primary-Source Verification Gate output. - Constraint priority iteration — walk
pfill_constraintsinconstraint_priorityASC order; for each constraint, run the multi-pass allocation against the candidate slice that matches that constraint's(investor_id, investor_instrument_name). - Populate
pfill_powerfill_guide— one row per allocated loan (PK isloan_idper the 001 schema; matches A8's "allocation output" interpretation). 6b stops here; pool-action derivation goes to 6c. - Populate
pfill_kickout_guide_01— loans that fall through every pass. - Populate
pfill_trade_basewith per-trade fulfillment counters (pre_session_assigned,post_session_assigned,pre_session_space,post_session_space, etc.) — the 35-column wide table from001line 304-345. - Carry over to candidate-builder integration — 6b consumes the carry-cost columns 6a wrote to
pfill_loan2trade_candy_level_01; ranking usesprx_plus_carry(orpricein PriceOnly mode). /api/powerfill/statussentinel bump tophase-6b-multi-pass-ready.
Scope (out)
- Pool-action derivation (6c —
pfill_pool_guidepopulation) pfill_cblock_guideandpfill_trade_cblock_base(A9 still has Low confidence on what "cblock" means; 6b plan must include a Primary-Source Verification probe of where these are populated and consumed; if the answer is "inpsp_powerfill_consetitself" then 6b owns them, if "inpsp_powerfillUE" then 6d does, if "neither — they're computed elsewhere" then we have an A9 escalation)- UE pass / synthetic trades (6d)
- Async / audit / failure cleanup (6e)
Shippable artifact
After 6b: POST /api/powerfill/run against PS_DemoData populates pfill_powerfill_guide with allocated loans + pfill_kickout_guide_01 with rejects + pfill_trade_base with fulfillment counts. The output count is sensible (most candidates resolve to either allocated or kicked-out; trade-base counters sum correctly). No pfill_pool_guide yet.
Sentinel
phase-6b-multi-pass-ready.
Why this sub-phase second
The multi-pass allocation is the largest single piece of Phase 6 work and consumes 6a's output. It must come before 6c (pool actions need allocation results) and before 6d (UE rebuilds pfill_powerfill_guide from 6b's output). The decision on whether to port psp_powerfill_conset as a single ~5.8K-line stored procedure or to break it into smaller named procs is a 6b-plan decision — kickoff §"EXPLICIT SCOPE" leaves it open ("hybrid C# orchestration + T-SQL execution per ADR-021"); 6b plan must Alternatives-First it.
Sub-phase 6c — Pool-action derivation + tolerance enforcement
Scope (in)
- Port the live
psp_powerfill_pool_guidebody at NVO line 8770-11185 (≈2,415 lines; the commented-out older version at 7194-8769 is dead code — verified during Phase 6 kickoff verification gate, finding F-VERIFY-5). Output ispfill_pool_guide(PK(pa_key, trade_id, loan_id, pool_action)per001). - BR-3 pool-action state machine — derive
Remaining/Leaving/Joining/Switching/ internalSwapped Inper A3 by comparing each loan's prior pool assignment (frompscat_trades_pools_relation) to its post-allocation assignment (frompfill_powerfill_guide). - BR-4 trade tolerance enforcement — verify each allocated trade's total assigned amount falls within
tolerance_amountband; flag exceptions inpfill_pool_guide.assignfield. psp_pfill_insert4_pool_guide(NVO line 11712-12483) — investigate during 6c planning whether this 771-line proc is invoked frompsp_powerfill_pool_guide(likely; it has the_insert4_naming convention suggesting it's a sub-step) or invoked separately. F-VERIFY-4 finding from kickoff verification gate; the kickoff doc omitted this proc entirely. 6c plan owns its disposition.- Populate
pfill_cblock_guide/pfill_trade_cblock_baseif the 6b plan's A9 disposition put them here. Otherwise 6c plan documents why they're elsewhere. /api/powerfill/statussentinel bump tophase-6c-pool-actions-ready.
Scope (out)
- UE pass (6d): UE re-runs the pool-guide step internally; 6c's output is the pre-UE state. After 6d,
pfill_pool_guidewill be the UE-modified version. - Async / audit / failure cleanup (6e)
- Output query APIs (Phase 7)
Shippable artifact
After 6c: POST /api/powerfill/run populates pfill_pool_guide with one row per (allocated loan, pool_action) and the BR-3 state machine produces a sensible distribution. PS_DemoData should show a mix of Remaining (most), Joining (some), Switching (a few), Leaving (paired with Switching). No Swapped In yet visible to API consumers — that's an internal state surfaced by the Switching Thumbnail report (Phase 7).
Sentinel
phase-6c-pool-actions-ready.
Why this sub-phase third
Pool-action derivation depends on allocation results being in pfill_powerfill_guide. UE (6d) runs after this and modifies the output, so 6c is the "pre-UE" snapshot — useful for 6d's parity validation (does UE preserve, augment, or override 6c's pool actions?).
Sub-phase 6d — UE pass + synthetic trades subsystem
Scope (in)
- Add 3
pfill_syn_*tables to schema —pfill_syn_trade_base(11 cols),pfill_syn_powerfill_guide_all_rank(40 cols),pfill_syn_powerfill_guide(40 cols). DDL recoverable from PS_DemoDatainformation_schema.columnsper syn-trades deep dive §"The three tables". Add to a new007_CreatePowerFillSynTradesSchema.sql(separate from006to keep diff reviewable). Add EF entities + register inPowerFillModule. A28 closed by this sub-phase. - Add
pfill_powerfill_logtable to007_*.sql. Per F-VERIFY-2 (kickoff verification gate), the legacypsp_powerfillUEauto-creates this table on first invocation (NVO line 13265-13275). PSSaaS deploys it explicitly via007to make the dependency visible at DDL deploy time rather than implicit at run time. Closes the syn-trades deep dive Open Question 1. - Port
psp_powerfillUEbody — the two-part syntax viaof_get_psp_powerfillue_syntax_a(NVO line 13246-16463) +of_get_psp_powerfillue_syntax_b(NVO line 16465-19801). Total ≈ 6,556 lines of T-SQL string-concat. PowerBuilder concatenates_a + _b; PSSaaS deploys the concatenated SQL as oneCREATE PROCEDUREin007. - UE invocation order —
psp_powerfillUEruns immediately afterpsp_powerfill_consetperw_powerfill.srwline 170-172 (verified in Phase 6 kickoff verification gate). UE receives the same parameter array. Both procs are mandatory; UE is not optional per syn-trades deep dive TL;DR. - UE teardown — UE deletes
pfill_powerfill_guide,pfill_syn_powerfill_guide_all_rank,pfill_cash_market_map,pfill_syn_powerfill_guide(NVO 13441-13451 verified) before rebuilding. Implication: the post-psp_powerfill_consetstate ofpfill_powerfill_guideis discarded and rebuilt by UE. 6c's "pre-UE pool actions" output is therefore intermediate — 6d documents that the user-facingpfill_pool_guideis the post-UE state. - UE synthetic-trades populate — TRUNCATE
pfill_syn_trade_base, rebuild frompscat_instruments×rmcat_todays_prices(NVO line 19019-19082). Then populatepfill_syn_powerfill_guide_all_rank(NVO 19083-19250 + 19450-19790 second pass for unallocated loans) with four parallel rank columns per syn-trades deep dive Phase D. Then populatepfill_syn_powerfill_guidewith the recommended synthesis per loan (Phase E). - UE Pool Guide downstream consumption — UE re-runs
psp_powerfill_pool_guide(or the equivalent inline logic) sopfill_pool_guidereflects synthesis-substituted trade IDs (trade_id_origin = 'pfill_syn_powerfill_guide'per syn-trades deep dive Phase G). 6d may need to re-port pool-guide logic from 6c if UE's version differs structurally. /api/powerfill/statussentinel bump tophase-6d-ue-syn-trades-ready.
Scope (out)
- The 5 open questions to Tom/Greg in the syn-trades deep dive remain logged. 6d plan should re-survey them and propose answers from PS_DemoData empirical observation where possible.
- Whether to port UE as a verbatim T-SQL proc (per ADR-021) or to lift the synthesis logic into C# — the syn-trades deep dive flags this as a Phase 6 decision. 6d plan owns the Alternatives-First decision; recommend defaulting to verbatim T-SQL per ADR-021's hybrid rule, but explicitly consider C# lift for the synthesis CTE pipeline if ADR-021 doesn't cleanly extend.
- Async / audit / failure cleanup (6e)
Shippable artifact
After 6d: a full POST /api/powerfill/run produces a populated pfill_powerfill_guide (UE-rebuilt), pfill_pool_guide (UE-modified), pfill_syn_trade_base, pfill_syn_powerfill_guide_all_rank, pfill_syn_powerfill_guide. Synthetic trades visible in pfill_pool_guide rows where trade_id_origin = 'pfill_syn_powerfill_guide' (column added by UE per syn-trades deep dive Phase G; 6d schema work must include it on pfill_pool_guide).
Sentinel
phase-6d-ue-syn-trades-ready.
Why this sub-phase fourth
UE depends on conset (6b) having produced a candidate set and pool-guide (6c) being live. UE then teardowns and rebuilds pfill_powerfill_guide and pfill_pool_guide, so it's the last data-modifying sub-phase before 6e adds run-management around it.
The syn-trades work is bundled into 6d (rather than split as 6d.1 schema + 6d.2 logic) because the UE proc populates the syn tables; deploying schema without populate logic produces empty tables that look broken to anyone querying them.
Sub-phase 6e — Async runs + audit + concurrency + PoC
Scope (in)
- Convert
POST /api/powerfill/runto async — runs return202 Accepted+run_idimmediately; execution happens in a background worker. Background-job pattern is Open Question #1; 6e plan resolves it. pfill_run_historytable — PSSaaS-only audit table per spec §Audit Trail line 251-253. Schema TBD pending Open Question #3 resolution (replay-capable vs summary-only). Phase 6e plan owns this table's schema and the 008 SQL script. Documented in spec under "Phase 6e PSSaaS-only tables" (mirroring spec §"Phase 4 PSSaaS-only tables").GET /runs— paginated list of recent runs for tenant.GET /runs/{run_id}— full status response per spec line 449-474.POST /runs/{run_id}/cancel— graceful cancellation (cancel token wired through to the background worker).- BR-8 single-active-run-per-tenant — return
409 Conflictif a run isPending/PreProcessing/Allocating/PostProcessingfor the same tenant. Mechanism is Open Question #2; 6e plan resolves it. - BR-9 failure-state cleanup — when a run fails mid-pass, the output tables must be left in a "consistent state" per spec line 246. 6e plan defines what that means: option (i) preserve prior run's output verbatim (rollback); option (ii) clear the output tables with error markers; option (iii) leave the partial output and mark the run as
Failedwith no cleanup. Open Question #7 is essentially this; 6e plan resolves it. - PS_DemoData PoC sign-off — execute one full async run against PS_DemoData; assert
pfill_powerfill_guidepopulated, pool-action distribution sensible, no NULLpool_actionvalues; document the PoC outputs in a 6e completion-report Markdown for PO review. This is the kickoff §"CONSTRAINTS" success criterion. /api/powerfill/statussentinel bump tophase-6e-async-runs-ready.
Scope (out)
- Output query APIs (Phase 7) — the run is auditable; the rich query surface comes later
- React UI (Phase 8)
- Phase 9 parallel-validation against Desktop App
- Connector Plugin spec/code (separate workstream)
Shippable artifact
After 6e: POST /api/powerfill/run returns 202 Accepted + run_id, run completes in background, GET /runs/{run_id} returns Complete + summary, pfill_run_history has the row, BR-8 enforced (a second concurrent POST /run returns 409), failed runs leave the system in a documented state. PS_DemoData PoC completed and the result documented for PO sign-off.
Sentinel
phase-6e-async-runs-ready — the canonical Phase 6 completion sentinel. After 6e, the /api/powerfill/status endpoint reflects "Phase 6 complete" until Phase 7 ships.
Why this sub-phase fifth (last)
Async execution and audit are cross-cutting concerns that only make sense once the synchronous run produces correct output. Trying to parallelize "build async first, then add allocation" inverts the dependency — you end up with a job framework wrapping nothing. Keeping 6e last also means the BackgroundService design (Open Q1) can be informed by what 6a-6d actually do (estimated CPU/memory shape, transaction boundaries, cancellation points).
Cross-cutting concerns
Schema artifact growth
| Sub-phase | New SQL artifacts | Why |
|---|---|---|
| 6a | 006_CreatePowerFillRunProcedures.sql (BX procs) | First Phase 6 SQL deploy; PRINT-in-guards per A32 |
| 6b | (extends 006 OR 007_CreatePowerFillConsetProcedure.sql if 006 grows too large; Architect's call when 6b plans) | conset is huge (~5,887 NVO lines); may justify own file for diff reviewability |
| 6c | (extends 006/007 OR 008_CreatePowerFillPoolGuideProcedure.sql) | pool_guide is ~2,415 NVO lines; may justify own file |
| 6d | 00x_CreatePowerFillSynTradesSchema.sql (3 syn tables + pfill_powerfill_log) + 00x_CreatePowerFillUeProcedure.sql (UE proc) | Schema additions are first PowerFill schema growth since Phase 1; tracking separately matches the per-sub-phase reviewability principle |
| 6e | 00x_CreatePowerFillRunHistoryTable.sql | Last PSSaaS-only addition before Phase 7 |
The exact numbering and file-split decisions are deferred to each sub-phase's plan. This breakdown commits only to at least one new SQL artifact per sub-phase, each with PRINT-in-guards (A32 / Deploy Verification Gate arm c).
Status sentinel discipline
Every sub-phase must bump /api/powerfill/status status field to its sentinel before the sub-phase commit ships. Verification (Deploy Verification Gate arm a) is a one-line curl:
curl -s http://pssaas.powerseller.local/api/powerfill/status | jq .status
# expected after each sub-phase: phase-6a-…-ready / phase-6b-…-ready / etc.
After staging deploy:
curl -s https://pssaas.staging.powerseller.com/api/powerfill/status | jq .status
If the sentinel doesn't reflect the new sub-phase, do not interpret subsequent run outputs (per Deploy Verification Gate canonical text).
Required Delegation Categories per sub-phase
The kickoff requires aggressive delegation of boilerplate. Per architect-context.md and process-discipline §9:
| Cluster | Default delegation | Sub-phases affected |
|---|---|---|
| T-SQL transcription from NVO (with Truth-Rot trap avoidance) | Fast subagent, per Phase 3 protocol that worked | 6a (BX procs), 6b (conset), 6c (pool_guide), 6d (UE) |
| Working-table CREATE TABLE + EF entity + registration | Fast subagent when ≥3 tables | 6d (3 syn tables + pfill_powerfill_log) |
| Boilerplate Minimal API endpoint + DTO + tests | Fast subagent when ≥5 endpoints | 6a (preview + run), 6e (run management endpoints) |
| Boilerplate parameterized unit tests | Fast subagent when ≥5 tests | All sub-phases |
Each sub-phase's plan commits to specific delegation clusters with specific subagent prompts following the Template 2 / Phase 3 SQL-transcription pattern. Deliberate Non-Delegation justifications must accompany any work that matches a category but is self-implemented, per the canonical process-discipline format.
Open questions touch order
| Open Q | Sub-phase that needs the answer | Notes |
|---|---|---|
| 1. Background-job pattern | 6e | Can defer until 6e begins; not blocking 6a-6d |
| 2. Single-active-run mechanism | 6e | Same |
3. pfill_run_history shape | 6e | Same |
| 4. A1 multi-pass semantics | 6b | 6b cannot start without resolution — either Architect verifies from NVO, or PO escalates to Tom/Greg |
| 5. Synthetic-trades scope split | 6d (currently set in 6d per this breakdown) | If PO prefers 6a does the schema and 6d does the logic, breakdown changes here |
| 6. Calculator integration pattern | 6a | Resolved in 6a plan — recommendation: per-constraint-iteration batches (small scope, fresh calculator scope, cleaner failure isolation) |
| 7. Failure-state semantics | 6e | Connects to BR-9 |
So sub-phase 6a can begin after PO answers Open Q6 (or accepts the Architect's recommended default in the 6a plan). Sub-phases 6b through 6e cannot start until at least #4 (for 6b) and #1/#2/#3/#5/#7 (for 6e) are resolved. Recommendation: PO answers all 7 before 6b kickoff is written, even though 6a doesn't need them.
Failure-mode and rollback per sub-phase
Each sub-phase's commit batch should be independently revertable: if 6c's pool-action logic is wrong, reverting 6c should leave 6b's allocation output intact (just not pool-actioned). Specifically:
- 6a → revert removes
POST /run,POST /candidates/preview,006. System back to Phase 5 state. - 6b → revert removes the conset proc + the 6b status sentinel; 6a's candidate-builder still works in isolation via the preview endpoint.
- 6c → revert removes
psp_powerfill_pool_guideinvocation; 6b's allocation output survives. - 6d → revert removes UE invocation + syn tables (kept in DB for forensics; no DROP TABLE) + the UE-modified pool-guide; 6c's pre-UE pool actions become the user-facing output again.
- 6e → revert restores synchronous run;
pfill_run_historyrows preserved (no DROP TABLE).
This rollback discipline is the Fail-Fast Permission practice (process-discipline §7) made concrete at sub-phase scope.
Risks captured at the breakdown level
- R-BREAKDOWN-1 — Estimate fragility. Each sub-phase estimate is a range; the lower bound assumes no Truth Rot escalations beyond the 5 already found in the verification gate. The upper bound assumes 1-2 escalations per sub-phase. Phase 4's 1.5x slip suggests the upper bound is the realistic case for Phase 6.
- R-BREAKDOWN-2 — Open Q4 (multi-pass semantics) is on the critical path of 6b. If PO can't get Tom/Greg input quickly, 6b plan must commit to Architect's empirical NVO trace as the answer, with explicit Phase 9 critique flag. The empirical trace is estimated at ~1-2 days of NVO reading; that's already absorbed in 6b's 7-10 day range.
- R-BREAKDOWN-3 — UE-rebuilds-pool-guide invalidates 6c work. The UE pass deletes and rebuilds
pfill_powerfill_guideand modifiespfill_pool_guideper syn-trades deep dive (verified at NVO 13441-13451). 6c's "pre-UE pool actions" output is intermediate. If 6d discovers the UE pool-guide differs structurally from 6c's, 6c may need partial rework. Mitigation: 6c's plan must explicitly call out "the 6c output is overwritten by UE; 6c's parity test compares against the pre-UE legacy state." - R-BREAKDOWN-4 — Sub-phase 6e's PoC depends on PS_DemoData stability. Per A35, PS_DemoData carry-cost rates are uniform 0.27 placeholders; per the Phase 4 preflight probe, PS_DemoData has only
PRICES_STALEwarning (prices from 2023-04-26). The 6e PoC will produce technically valid output but the economic meaningfulness is limited. Phase 9 parallel-validation against a Desktop App customer's real DB is the ultimate parity test; 6e is the "shape correctness" PoC. - R-BREAKDOWN-5 — The kickoff-doc itself had Truth Rot. Five findings from the Primary-Source Verification Gate before any code was written: kickoff-listed
psp_powerfill_consetparameters wrong (7 vs actual 6);psp_pfill_insert4_pool_guide(771 NVO lines) entirely omitted;psp_powerfill_pool_guideline range stale (kickoff says 7192-11186; live version is 8770-11185); syn-trades deep dive Open Q1 wrong aboutpfill_powerfill_log(it's auto-created in UE, not orphaned); BX cash-grids takesbx_price_flooras its own parameter, not as a conset parameter. Mitigation: every sub-phase plan must run Primary-Source Verification before drafting; assume more lurks. Kickoff text is not primary source.
Approval gate
This breakdown is itself a deliverable that needs Collaborator review and PO approval before sub-phase 6a planning artifact is treated as committed direction. The 6a plan can be drafted in parallel with breakdown review (since 6a is upstream of every breakdown decision except whether 6e has 5 sub-phases or 4) — but the 6a plan should not be merged until the breakdown is approved.
Approval signal: PO comments "approved" or "approved with edits" on this doc; Architect updates the doc and marks Status: Approved.
Next deliverable from this Architect session: the full sub-phase 6a plan at .cursor/plans/powerfill-phase-6a.plan.md, drafted per the Phase 4/5 12-section template, plus the open-questions document at powerfill-phase-6-open-questions.md.