PowerFill Module — Phase 6 Architect Kickoff
This is the prompt Kevin pastes into a new Cursor session to bootstrap the Systems Architect on PowerFill Phase 6 (Core Allocation Engine + post-allocation UE pass).
Important context for this kickoff:
- Phase 6 is the biggest phase of the module (3-4 weeks per spec estimate). Substantially more substantive than Phases 1-5 combined.
- Phase 6 ports the legacy
psp_powerfill_conset(~6K lines of T-SQL) ANDpsp_powerfillUE(~3K lines of T-SQL), the two largest procedures in the legacy codebase. - Phase 6 is the FIRST phase that consumes the carry-cost calculator from Phase 5 — calculator becomes part of the candidate-builder pipeline.
- Phase 6 is the FIRST phase to touch the
pfill_syn_*synthetic-trades subsystem documented indocs-site/docs/legacy/powerfill-syn-trades-deep-dive.md. - Use Opus 4.7 High Thinking. Do NOT use Cursor Auto. Phase 4's Auto-mode first attempt produced a known-broken commit; the verification regression that followed is documented in process-discipline canonical.
Usage
- Open a new Cursor session in the PSSaaS repo.
- Set the model to Opus 4.7 High Thinking (or your project's strongest reasoning model with extended-thinking enabled).
- Copy everything inside the fenced block below.
- Paste as the first message in the new session.
- The Architect will self-onboard and respond with an acknowledgement.
The Prompt
You are the PSSaaS Systems Architect agent. This is a new session.
Start with your session-start checklist:
1. Read `CLAUDE.md` (project identity, invariants, role-identification procedure)
2. Read `AGENTS.md` (agent memory: principles, lessons, preferences,
especially the "push is an ask" convention and the F-PSD findings summary)
3. Read `docs-site/docs/agents/architect-context.md` (your role definition,
including v4 Required Delegation Categories)
4. Read `docs-site/docs/agents/process-discipline.md` (canonical v4.1)
5. Read `docs-site/docs/agents/handoff-prompts.md` (templates for delegating
to Developer subagents and for escalating decisions to PO)
6. Read `docs-site/docs/handoffs/pssaas-session-handoff.md` (current state)
7. Read `docs-site/docs/agents/powerfill-architect-phase6-kickoff.md`
(this kickoff doc — full task description below)
After you have read those, acknowledge your role and proceed with the
Phase 6 task as described below.
== YOUR TASK — PowerFill Phase 6 ==
**Scope: Core Allocation Engine (psp_powerfill_conset + psp_powerfillUE
ports, candidate-builder, multi-pass allocation, run orchestration).**
This is the biggest phase of the module. Phases 1-5 produced the
foundation: schema, preflight, pre-processing, configuration CRUD, and
the carry-cost calculator. Phase 6 produces the part of PowerFill that
actually allocates loans to trades — the legacy "the engine."
Per the spec at `docs-site/docs/specs/powerfill-engine.md` line 571:
"Phase 6: Core allocation engine (biggest phase) — 3-4 weeks." 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.
== KEY CONTEXT FROM PRIOR PHASES ==
**Phase 1-4 shipped:** 17 pfill_* tables (entities + EF mapping + 001
schema script); 9 preflight checks (POST /api/powerfill/preflight); 3
pre-processing procedures (POST /api/powerfill/preprocess); CRUD APIs
for constraints / sec-rules / carry-cost / lockdown (Phase 4 surface);
preflight settings table (script 004); rowversion column on constraints
(script 005). 4 Phase-4 PSSaaS-only additions documented in spec
§"Phase 4 PSSaaS-only tables".
**Phase 5 shipped (just before this kickoff):** PowerFillCarryCostCalculator
service in `src/backend/PowerSeller.SaaS.Modules.PowerFill/Services/`,
diagnostic POST /api/powerfill/carry-cost/preview endpoint. Computes
carry_cost and prx_plus_carry per (loan, trade) candidate. NVO-verbatim
algorithm; decimal arithmetic; AwayFromZero rounding for T-SQL parity.
A2-compliant: never returns a filter verdict.
**3 pfill_syn_* synthetic-trades tables exist in PS_DemoData but were
missed by Phase 1's reverse engineering.** A28 in the assumptions log
documents this; the deep dive at
`docs-site/docs/legacy/powerfill-syn-trades-deep-dive.md` traces the
populate / consume / teardown lifecycle. Phase 6 owns these tables in
schema work AND in the psp_powerfillUE port.
**Real customer data live as a tenant:** PS_DemoData on Azure SQL MI is
configured locally (X-Tenant-Id: ps-demodata in docker-compose.override.yml;
not yet in K8s staging secrets). 295 carry-cost rows, 11,674 loans,
8,902 trades, 6,246 pools. Use this for live-DB verification AND for
the manual PoC artifact.
**Tonight's CI/CD refactor:** deploy-staging now decoupled from build
gating; always rolls both deployments to :latest with rollout-restart.
This means a Phase 6 push (or any Phase 6 sub-phase push) reliably rolls
to staging even if the path-filter is funky. Less to worry about there.
== EXPLICIT SCOPE ==
In scope:
* Port psp_powerfill_conset (NVO line 51-5887 — the body is huge)
to a hybrid C# orchestration + T-SQL execution per ADR-021.
* Port psp_powerfillUE (NVO line 13246-19782, two-part syntax functions
of_get_psp_powerfillue_syntax_a and _b) — synthetic-trades subsystem
+ post-allocation re-scoring + run-output table population.
* Add 3 pfill_syn_* tables to schema work (entities + 001 extension OR
a new 006 script — Architect's call). Tables: pfill_syn_powerfill_guide
(40 cols), pfill_syn_powerfill_guide_all_rank (40 cols),
pfill_syn_trade_base (11 cols).
* Candidate-builder pipeline: constraint priority loop + sec-rule filter
+ loan-stage filter + lockdown filter + carry-cost calculator
invocation (Phase 5 service consumption).
* Multi-pass allocation: exact_fit / best_fit / fill_remaining /
orphan_handling per ADR-022 (verbatim port of legacy passes).
* Pool-action derivation (BR-3 state machine: Remaining / Leaving /
Joining / Switching with internal Swapped In).
* Trade tolerance band enforcement (BR-4).
* Run orchestration: POST /api/powerfill/run that returns run_id,
asynchronous job execution per spec §"Run Execution Model" lines
147-155. Use background-job pattern (Architect's design call —
options: hosted service, queue, etc.; Alternatives-First Gate).
* Run history audit: pfill_run_history table per spec §"Audit Trail"
lines 156-161 (this is a PSSaaS addition; mark it so in the spec
section on PSSaaS-only tables).
* Single-active-run-per-tenant guard (BR-8).
* Failed-run state cleanup (BR-9 / spec line 153).
Out of scope (later phases):
* Run output query APIs (Phase 7) — guide / recap / switching /
pool-candidates / existing-pool-disposition / pooling-guide /
cash-trade-slotting / kickouts. Phase 6 populates the underlying
tables; Phase 7 exposes the read APIs.
* React UI (Phase 8).
* Phase 9 parallel-validation against Desktop App.
* Connector Plugin spec/code (separate workstream).
* BX procs psp_pfill_bx_cash_grids and psp_pfill_bx_settle_and_price
— moved to Phase 6 from Phase 3 per finding F2, but Architect must
decide whether they're in this kickoff's scope or a sub-phase
(recommendation: include in Phase 6a as the candidate-builder
prerequisites; bx_price_floor option flows from there).
== KEY REFERENCES ==
* Spec: `docs-site/docs/specs/powerfill-engine.md` — sections
§"Core Allocation Engine" (lines 200-219), §"Post-Allocation (UE Pass)"
(lines 220-227), §"Run Options" (lines 229-241), §"Run Execution Model"
(lines 243-251), §"Audit Trail" (lines 253-260), §"Algorithm — High-Level
Pseudocode" (lines 503-547), §"Business Rules" (BR-1 through BR-10).
* Assumptions log: `docs-site/docs/specs/powerfill-assumptions-log.md` —
every A1-A36 is potentially relevant, but especially A1 (multi-pass
semantics — "needs Tom/Greg confirmation"), A6 (Pre-Process scope:
fixed by Phase 3 F2), A14 (scoring formula carry sign — RESOLVED in
Phase 5 by A34), A23 (phantom trades), A24 (pair-offs), A28
(pfill_syn_* synthetic trades), A36 (carry-cost INT-truncation
rescinded; calculator is decimal).
* ADRs: `docs-site/docs/adr/adr-021-powerfill-port-strategy.md` (hybrid
T-SQL + C#), `adr-022-powerfill-allocation-algorithm.md` (verbatim
iterative passes), `adr-023-powerfill-constraint-model.md` (preserve
legacy tree).
* Phase 5 plan (Architect-internal, gitignored at
`.cursor/plans/powerfill-phase-5.plan.md`) — its "Appendix —
primary-source citation index" was specifically prepared for this
Phase 6 kickoff. Read it.
* syn-trades deep dive:
`docs-site/docs/legacy/powerfill-syn-trades-deep-dive.md` — the
pfill_syn_* lifecycle and the psp_powerfillUE → psp_powerfill_conset
procedure relationship. This is a Phase 6 prerequisite; the deep
dive WAS the prep work.
* Phase 4 plan (Architect-internal, gitignored at
`.cursor/plans/powerfill-phase-4.plan.md`) — structural reference
for plan format (gate findings table, Alternatives-First decisions,
delegation plan, edge cases, Counterfactual Retro).
* Calculator service: `src/backend/PowerSeller.SaaS.Modules.PowerFill/
Services/PowerFillCarryCostCalculator.cs` — what Phase 6 consumes.
* Existing pre-process orchestrator:
`src/backend/PowerSeller.SaaS.Modules.PowerFill/Services/
PowerFillPreprocessService.cs` — pattern to follow for the run
orchestrator.
== NVO PRIMARY-SOURCE CITATION INDEX ==
(Seeded from Phase 5 plan's appendix, expanded for Phase 6 needs.
Architect must verify these still match before relying on them — the
NVO file changes occasionally; Phase 5 found 4 entity-drift issues
that were live in PS_DemoData but not anticipated.)
* psp_powerfill_conset SIGNATURE: n_cst_powerfill.sru:51-58 (parameters
@as_scope, @as_price_value, @as_status_code, @ai_max_eligible_days,
@ai_max_trade_settle_days, @ai_eligible_settle_buffer_days,
@ad_bx_price_floor)
* psp_powerfill_conset BODY: built by of_get_psp_powerfill_conset_syntax
starting at line 50; concatenated SQL string spans roughly lines 60-5887
(yes, ~6000 lines of T-SQL string-concat). This is a multi-stage
pipeline, not a monolithic SELECT.
* Working tables declared inside the body: @pfill_loan2trade_candy_level_01
(line ~200-220), @average_carry_rate (line ~432-440),
@pfill_loan2trade_candy_level_02 (line ~441), #pfill_loans_purchased
(line ~244), #cte_remix_orphan_01 (line ~18900-19018).
* interest_earning_days computation: line 1232-1233, 1442 — formula
DATEDIFF(D, COALESCE(close_date, lock_expiration_date), settlement_date)
* Carry-cost INNER JOIN + AVG: line 1333-1347 (and 14440-14453 in UE)
* carry_cost UPDATE with /365: line 1348-1354 (and 14455-14459 in UE)
* prx_plus_carry CASE WHEN 'po': line 1361-1364 (and 14467-14472 in UE)
— note: NVO line 1364 has parens that Phase 5 C1 finding nearly
misinterpreted as INT truncation; the parens are evaluation-order
only and the dividend is NUMERIC(4,0), so the division promotes to
decimal. See A36 in the assumptions log for the full saga.
* Multi-pass allocation core: scattered throughout 7500-12500 (specific
pass boundaries are Architect's job to identify; A1 says "four
passes" but that's an assumption that needs verification against
the actual NVO). Read carefully; this is the section Phase 9 parity
validation will be most sensitive to.
* psp_powerfillUE SIGNATURE: line 13252 ("CREATE PROCEDURE
[dbo].psp_powerfillue @as_scope VARCHAR(2)" — note params different
from conset)
* psp_powerfillUE BODY: built by of_get_psp_powerfillue_syntax_a (line
13246+) AND of_get_psp_powerfillue_syntax_b (line 16465+) — the legacy
syntax exceeded PowerBuilder's max script length and had to be split
across two functions. UE reconstructs the body via
ls_syntax = of_get_psp_powerfillue_syntax_a();
ls_syntax = of_get_psp_powerfillue_syntax_b(ls_syntax);
* UE teardown of run-output tables: line 13441-13451 — DELETEs from
pfill_powerfill_guide, pfill_syn_powerfill_guide_all_rank,
pfill_cash_market_map, pfill_syn_powerfill_guide. Note: pfill_syn_*
rebuilt every run; not preserved.
* UE synthetic-trades populate: line 19019-19790 — TRUNCATE
pfill_syn_trade_base then rebuild from pscat_instruments x
rmcat_todays_prices.
* UE consumed BY psp_powerfill_pool_guide (line 7192) and
pfillv_pf_forensics_tradeside view (line 11187) via
trade_id_origin = 'pfill_syn_powerfill_guide' join pattern.
* w_powerfill.srw INVOCATION ORDER: ue_perform_powerfill (line 94-192)
invokes psp_powerfill_conset THEN psp_powerfillUE in sequence; both
receive the same parameter array. UE is mandatory, not optional.
* Pool-action state machine: derived primarily in psp_powerfill_pool_guide
(NVO line 7192-11186) — Architect must trace how pool_action values
(Remaining / Leaving / Joining / Switching / Swapped In) are computed
from the working set diff.
== PROCESS DISCIPLINE REQUIREMENTS (v4.1 + Phase 5 lessons) ==
Phase 6 is too large for any one of these to be optional. Treat each as
a hard precondition.
1. **Verification-before-completion is non-negotiable.** Phase 4's first
attempt shipped a known-broken commit because dotnet build/test were
not run before commit. Required pattern in this project:
docker exec pssaas-api dotnet build --nologo
docker exec pssaas-api dotnet test --nologo --no-build --filter "~PowerFill"
Before EVERY commit, including sub-phase commits. If your shell can't
reach the container, surface that fact to the Collaborator BEFORE
committing. Phase 5 added this discipline; Phase 6 inherits it.
2. **Primary-Source Verification Gate** — both arms, more important
than ever for a large port:
- Static: read the actual NVO computation directly. Do NOT trust
the spec as the source of truth — the spec is derived from the
NVO, and Phase 1-5 have all found cases where the derivation lost
fidelity. Phase 5 found that A14 was incomplete; Phase 3 found
that A6 was wrong about which event invokes which procs; Phase 1
found A28 (entire syn-trades subsystem missing). Assume more lurks.
- Live: probe pfill_* and pfill_syn_* tables in PS_DemoData. Phase 5
surfaced that pfill_carry_cost rates are uniform 0.27 placeholders
(A35) — Phase 6 may find similar realities. Sample data, don't
assume.
3. **Sub-phase planning per Reviewable Chunks.** This phase is too big
for one CreatePlan output. Plan should propose 3-5 sub-phases
(e.g., 6a candidate-builder + carry-cost integration, 6b multi-pass
allocation, 6c pool-action derivation, 6d UE / synthetic trades,
6e run orchestration + audit). Each sub-phase gets its own plan
later; this kickoff produces the SUB-PHASE BREAKDOWN plan plus the
full plan for the FIRST sub-phase only.
4. **Required Delegation Categories** — Phase 6 has substantial boilerplate
surface in candidate-builder T-SQL transcription, working-table
creation, output-table writes. The Architect should AGGRESSIVELY
delegate boilerplate; Phase 5's drift on the 27-test cluster was
honestly logged and is the calibration data. Default-delegate
anything matching the categories in `architect-context.md`. Document
Deliberate Non-Delegation justification for non-delegated work.
5. **Deploy Verification Gate (v4.1)** — every Phase 6 sub-phase that
ships needs a sentinel signal: a status string change, a new endpoint,
or a new audit-log entry that proves the new code is live on staging.
The /api/powerfill/status endpoint's `status` field is the canonical
sentinel — bump it per sub-phase (e.g., phase-6a-candidate-builder-ready,
phase-6b-multi-pass-ready, etc.).
6. **Gate Output Action mandatory disposition per finding** — corrected
in place / scope-changed / deferred-with-justification. Phase 4's F3
escalation is the exemplar.
7. **Push is an ask, not a tell** — never `git push`. Commit only.
Architect commits per sub-phase; PO pushes when ready.
== WHAT I WANT FROM YOU ==
This kickoff is unusually big because Phase 6 is unusually big. Your
output here is NOT "the full Phase 6 plan." Your output is:
1. **The sub-phase breakdown:** propose 3-5 sub-phases with (a) the
approximate scope of each, (b) the dependency order, (c) the
shippable artifact each sub-phase produces, and (d) the staging
sentinel each sub-phase introduces.
2. **The full plan for sub-phase 6a (the FIRST sub-phase)** following
the structural template from Phase 4 / Phase 5 plans.
3. **The Phase 6 OPEN QUESTIONS DOCUMENT** — a list of questions that
span multiple sub-phases that PO should answer or escalate before
sub-phase 6b begins. Examples I anticipate: "what background-job
pattern (hosted service, queue, hangfire-equivalent)?", "how to
handle a tenant database connection drop mid-allocation?", "should
pfill_run_history capture the full input loan set for replay
purposes, or just summary stats?". Surface, don't silently resolve.
Process for sub-phases 6b through 6e: each gets its own kickoff doc
when the prior sub-phase ships. Don't pre-plan them in detail. Their
SCOPE goes in the breakdown above; their PLAN waits for their kickoff.
For the sub-phase 6a plan, the structural sections are the same as
Phase 4/5:
* §1 Scope (in / out — for SUB-PHASE 6a only, not all of Phase 6)
* §2 Primary-Source Verification Gate findings + dispositions
* §3 The candidate-builder pipeline (formal algorithm; NVO line
citations; integration with PowerFillCarryCostCalculator)
* §4 New SQL artifacts (006? or extend 001? — Architect's call) + new
entities (pfill_syn_* tables if 6a needs them)
* §5 Edge cases — what happens when no constraints exist, when no
loans pass sec-rule filter, when no trades have capacity, when a
loan matches multiple constraints, etc.
* §6 New service interfaces (e.g., ICandidateBuilder) + DTOs
* §7 Alternatives-First decisions (background-job pattern; T-SQL vs C#
for specific computations; how to inject the calculator)
* §8 Delegation plan (substantial — Phase 6 has more boilerplate than
prior phases combined; aggressive delegation expected)
* §9 Test strategy (unit + integration + PS_DemoData PoC)
* §10 SQL deploy verification convention (PRINT-in-guards per A32)
* §11 Risks captured
* §12 Counterfactual Retro placeholder
Open questions to surface in the sub-phase 6a plan (don't try to
resolve these alone):
1. **Background job pattern** for asynchronous run execution. Options:
.NET hosted service, in-memory queue, BackgroundService + Channel,
Hangfire-equivalent persistent queue, etc. ADR candidate.
2. **Single-active-run-per-tenant enforcement mechanism.** Options:
advisory lock in pfill_run_history, SQL unique constraint on
(tenant_id, status='running'), redis lock, etc.
3. **pfill_run_history shape.** Spec line 158-159 lists base columns
but is silent on whether to capture full input loan set (replayable)
or summary stats only (cheaper).
4. **A1 multi-pass semantics.** Phase 5 plan §10 risk R5 noted A1 is
"needs Tom/Greg confirmation." Phase 6 NEEDS this answered. Either
trace it from the NVO empirically (Architect's primary task) or
escalate to PO if NVO ambiguity remains.
5. **Synthetic trades scope split.** Per the deep dive, syn-trades is
part of psp_powerfillUE. Should sub-phase 6a include syn-trades
table creation (so the schema is whole), defer to 6d, or split
(table CREATE in 6a, populate logic in 6d)?
6. **Calculator integration pattern.** PowerFillCarryCostCalculator
takes a batch of CarryCostInput records. Phase 6 candidate-builder
produces those records mid-pipeline. Should the calculator be called
per-constraint-iteration (small batches, fresh calculator scope) or
once for all candidates (large batch, single round-trip)?
7. **Failure-state semantics.** BR-9 (run output is immutable) vs
BR-10 (run output overwrites prior run) — what happens to an
in-progress run when a new one starts? Spec says BR-8 prevents this
but doesn't say what happens to the partial outputs.
== COLLABORATION PROTOCOL ==
* PO is Kevin. Collaborator is in a different Cursor session.
* Escalate decisions affecting: spec/ADR text, BestEx module, tenant
provisioning, cross-product integration, the carry-cost calculator
contract. Use handoff-prompts.md Template 3 for escalations.
* The sub-phase breakdown is itself a deliverable that needs
Collaborator review and PO approval before sub-phase 6a planning
begins. Surface it explicitly.
* Each sub-phase gets its own commit batch. Don't try to ship 6a-6e
in one commit.
== CONSTRAINTS ==
* `decimal` for all financial values — never `float`/`double`
* Tenant isolation absolute (ADR-005)
* Schema preservation per ADR-006 — pfill_* legacy columns unchanged;
pfill_syn_* tables are NVO-derived (deep dive has the structure);
pfill_run_history is PSSaaS-only and follows Phase 4's PSSaaS-only
table convention (documented in spec).
* Phase 6 success criterion: a PowerFill run invoked via
POST /api/powerfill/run against PS_DemoData with the configured
constraints, carry-cost curves, and lockdown rows produces a
populated pfill_powerfill_guide table whose pool_action distribution
is sensible (mostly Remaining + some Joining/Switching, few or no
unexpected NULLs). Phase 9 will validate against Desktop App; Phase 6
just needs to PRODUCE plausible output.
== WHEN YOU'RE DONE PLANNING THIS KICKOFF ==
Respond with:
(a) Your sub-phase breakdown (3-5 sub-phases, scope each, dependency
order, shippable artifact each).
(b) The full plan for sub-phase 6a (12 sections per template above).
(c) The open questions document (the 7 above plus anything that
surfaces during planning).
(d) Acknowledgement that the 7 open questions are pending PO input
BEFORE sub-phase 6b planning begins.
Use the CreatePlan tool for (b). The sub-phase breakdown (a) and the
open questions (c) can be appendices to the plan, separate sections
in the plan, or separate docs — Architect's call.
Phase 6 is the heart of the module. Take the time it needs.
What Happens After
- Kevin pastes the prompt into a new Cursor session running Opus 4.7 High Thinking.
- Architect acknowledges role, reads onboarding docs (this is heavier than Phase 5; expect more reading time).
- Architect produces the sub-phase breakdown + sub-phase 6a CreatePlan + open questions document.
- Collaborator reviews per Phase 4/5 protocol — verifies Architect's gate findings against actual NVO and PS_DemoData; spot-checks the algorithm citations.
- PO reviews the sub-phase breakdown and answers (or escalates) the 7 open questions.
- Architect dispatches per the sub-phase 6a plan's delegation strategy and self-implements the non-delegated clusters.
- Architect produces sub-phase 6a completion report following Phase 5's format; deploy verification proves staging carries
phase-6a-...-readysentinel. - Sub-phase 6b planning begins — its own kickoff, its own plan, its own commits.
Notes
- Each sub-phase (6a-6e) is essentially its own "phase" by Phase 1-5 standards. Plan accordingly.
- The Phase 5 plan's appendix at
.cursor/plans/powerfill-phase-5.plan.mdwas specifically prepared for this kickoff — Architect should read it as the FIRST primary-source citation reference. - The syn-trades deep dive at
docs-site/docs/legacy/powerfill-syn-trades-deep-dive.mdis mandatory reading; psp_powerfillUE port is impossible without it. - A36 (Phase 5 carry-cost int-truncation rescinded) is the exemplar of how to handle a "looks-like-a-bug-actually-isn't" finding. Phase 6 will likely have several similar moments.
- Phase 6 ships when ALL sub-phases ship. The sub-phase commits accumulate; PO pushes when each sub-phase is verified.