Task: Scaffold a Group Treasury book/portfolio for the holding company
Table of Contents
This page documents a task in the Holding company treasury functionality: FX/CRM visibility, Group Treasury book, consolidated reporting story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Acme Corporation Plc (the holding company party) has its own Group
Treasury business unit, portfolio, and books – scoped to genuine
parent-level treasury activity (intercompany loans, FX hedges), not
a trading desk – provisioned the same way each operating office
already gets its book/portfolio tree, via the acme_group DQ bundle.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Holding company treasury functionality: FX/CRM visibility, Group Treasury book, consolidated reporting |
| Now | Group Treasury business unit/portfolio/books scaffolded and verified live via provisioning. |
| Waiting on | Nothing. |
| Next | None – task closed. |
| Last touched | 2026-08-06 |
Acceptance
- Acme Corporation Plc (the holding party) has a
acme_group.treasuryDIVISION-type business unit. [DONE] - The holding party has a single Group Treasury portfolio (GBP, virtual). [DONE]
- The holding party has two Banking-classified books under that portfolio: "Group Intercompany Loans" (GL-TREAS-001) and "Group FX Hedges" (GL-TREAS-002), both cost_center CC-GROUP-TREASURY, rates_centre_code GBLO. [DONE]
- Data is generated via the Acme seeder pipeline (
generate_data.py/generate_sql.py), not hand-edited JSON/SQL, and wired into both the schema-bootstrap populate order and the liveacme_groupDQ bundle so a freshdb recreateand a liveprovision tenant --source acmeboth produce it. [DONE]
Plan
(Implementation strategy. Written when work starts; key decisions
are distilled into the parent story's * Decisions at close, but the
plan itself stays — it is the historical record of what we did.)
Followed the data model already decided in the "Define holding
company treasury data model additions" task: one DIVISION business
unit (acme_group.treasury, "Group Treasury"), one portfolio ("Group
Treasury Portfolio", GBP, virtual), two Banking-classified books
("Group Intercompany Loans" GL-TREAS-001, "Group FX Hedges"
GL-TREAS-002), both cost_center CC-GROUP-TREASURY, rates_centre_code
GBLO.
- Added a
build_group_treasury()function togenerate_data.py(mirroring the existing per-officebuild_office()shape) and wired its output intomain(), extendingall_business_units=/=all_portfolios=/=all_booksrather than hand-editing the generated JSON. Regeneratedbusiness_units.json=/=portfolios.json=/=books.json(+1/+1/+2 entries respectively). - Extended
generate_sql.py: added anacme_groupentry toCOMPANY_CCY(GBP), and extended the acme_group-specific block inmain()=/=generate_dataset_populate()to also register and generate SQL foracme.acme_group.business_units,.portfolios,.books(previously only.accountswas handled for the holding company). Regenerated the three new artefact populate SQL files underprojects/ores.sql/populate/acme/. - Wired the new artefact files into the two hand-maintained
orchestrators that don't get touched by seeder regeneration:
projects/ores.sql/populate/populate.sql(schema-bootstrap\irorder, used bydb recreate): added the three new\irlines ahead of the existingacme_group_accounts_artefact_populate.sqlline, in the same business_units -> portfolios -> books dependency order used for each operating office.projects/ores.sql/populate/acme/acme_bundle_populate.sql(DQ bundle membership, used by the liveprovision tenant --source acmeflow viatenant_handler.hpp's Step 3): added the three new dataset members to theacme_groupbundle at priorities 10/20/30 (business_units/portfolios/books), renumbered the existingaccountsmember to 40 to sit after them (matching the per-office bundle ordering), and fixed the now-inaccurate "no business units/portfolios/books of its own" comment.
- Verified end-to-end:
db recreateapplied the schema/populate scripts cleanly with no errors; queried the DB directly and confirmed all fouracme.acme_group.*datasets are registered and are members of theacme_groupbundle in the right order. Then started the service fleet and ran a realprovision tenant --source acmeviahow_do_i_provision_the_system_with_acme_corporation_holding_group.oresend to end – Step 3 publishedacme_group.portfolios,acme_group.business_units,acme_group.booksalongside the pre-existingacme_group.accounts, with no errors across the full provisioning run (base refdata, LEI import, all three operating offices, cross-entity access). - Live QA in the Qt client's Org Explorer surfaced a real bug the DB
query alone had missed: both books showed up under an
"(Unassigned)" bucket instead of nested under the Group Treasury
portfolio/business unit. Root cause:
ores_refdata_publish_ portfolios_from_dq_fnresolvesowner_unit_idby joining the already-published business_units row for the same party, and the workflow engine dispatches bundle members in an order driven byores_dq_dataset_dependencyedges, not rawdisplay_order–acme_uk=/=acme_us=/=acme_hkalready had explicitportfolios -> business_unitsandbooks -> portfoliosdependency rows inacme_dataset_dependency_populate.sql(with a comment predicting exactly this failure mode), butacme_grouphad none since it previously only ever publishedaccounts. Without them, the publish workflow could (and did, once) run portfolios before business_units, silently leavingowner_unit_idnull. Added the same two dependency rows foracme_group. Re-randb recreateand a liveprovision tenant --source acme: Step 3 now consistently completesbusiness_unitsbeforeportfoliosbeforebooks, and a direct DB query confirmedowner_unit_idis correctly set on both the portfolio and both books, pointing at the Group Treasury business unit. - Re-ran the QA Validation Runner scenario end to end in the Qt client after the fix: all three steps pass, including the previously-failing "Open the portfolio/book tree under Group Treasury" step – both books now correctly nest under Group Treasury in the Org Explorer instead of "(Unassigned)".
- Considered whether a third book is needed for profit remittances specifically (raised during review) – decided no: this system's books represent risk/trading positions (NPV, market risk), and a dividend/profit remittance is a cash-settlement/equity accounting event, not a priced position. The FX exposure of a remittance is already covered by "Group FX Hedges"; any intercompany funding leg is covered by "Group Intercompany Loans". Two books matches how a real group treasury centre's risk book structure normally looks – not adding a third.
Notes
Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario, run
through the QA Validation Runner panel) that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
| Group Treasury book/portfolio visible for the holding company party | PASSED | First run caught the owner_unit_id/dependency bug (step 3 FAIL); re-run after the fix passed all 3 steps. |
PRs
| PR | Title |
|---|---|
| #1888 | [seeder,sql,agile] Scaffold Group Treasury book/portfolio for the holding company |
Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
Result
Acme Corporation Plc (the holding company party) now has a Group
Treasury business unit (acme_group.treasury), a single virtual GBP
portfolio ("Group Treasury Portfolio"), and two Banking-classified
books ("Group Intercompany Loans" GL-TREAS-001, "Group FX Hedges"
GL-TREAS-002), correctly nested under that business unit – both via
db recreate and via a live provision tenant --source acme run,
verified both at the DB level and live in the Qt client's Org
Explorer through a QA Validation Runner scenario. Along the way,
found and fixed a real bug (missing DQ dataset-dependency
registrations for acme_group, letting the publish workflow race
and leave every new row's owner_unit_id null) that the office
bundles had already worked around but acme_group never needed to
until this task added cross-referencing datasets to it.