Task: Migrate remaining junctions to generated C++ (roll out beyond tenor_convention_resolution)
Table of Contents
This page documents a task in the Codegen: mustache-to-address rename + junction codegen rollout story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Regenerate every remaining has_tenant_id: true junction's domain/
generator/repository via the junction codegen path this story added
(validated so far only against tenor_convention_resolution),
retiring their hand-authored equivalents. Fixes a real, independently-
discovered class of bug along the way: hand-authored junction
repositories that forget the tenant_id filter on their "list all" query
return duplicate rows to the client (both the requesting tenant's own
rows and any other tenant's, since Postgres RLS on these tables is
deliberately permissive – tenant_id = current_tenant() OR tenant_id =
system_tenant() – to support a "global registry + tenant override"
pattern; the app-level query is the only thing narrowing that back
down, and hand-written code has already gotten this wrong four times
independently).
Status
| Field | Value |
|---|---|
| State | BACKLOG |
| Parent story | Codegen: mustache-to-address rename + junction codegen rollout |
| Now | Not yet started. |
| Waiting on | Nothing. |
| Next | Begin implementation. |
| Last touched | 2026-07-18 |
Acceptance
- Every
has_tenant_id: truejunction with an existing C++ repository is audited for the missing-tenant-filter bug (see Notes) and, ideally, regenerated via the working junction codegen path rather than hand-patched – proving out the codegen path across more than one junction is this task's real point, not just fixing the bug. currency_currency_group(junction, refdata) – currently SQL-only, no C++ repository exists – gets a generated one if/when it's wired into a real caller; otherwise leave as-is and note why.- No regression to any existing junction or domain_entity's generated output.
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.)
Notes
- 2026-07-18: Discovered while debugging duplicate rows in the Badge
Mappings tab (Add a
badge_mapping browser UI task, badge colour scheme story).
badge_mapping_repository::read_all()had notenant_idfilter at all, relying solely on RLS – which for this table (and every other "system-owned global registry, tenant-overridable" table) permitstenant_id = current_tenant() OR tenant_id = system_tenant(), so any tenant with its own published copy of a row (e.g. via a publish-from-dq bundle) sees it twice. - Root cause, found after an initial wrong hypothesis: first assumed
this was a codegen tooling gap (no template support for junctions'
C++ layer at all). That was wrong –
ores.cpp.repository.org(and its sibling domain/generator facets) has a real\{\{#junction\}\}Mustache branch, shared withdomain_entity, already correctly tenant-scoping every query it generates. The actual root cause:resolve_output_path'scomponent_core_dircomputation (projects/ores.codegen/src/codegen/core.py, ~line 596) falls back to a flat, pre-split path (ores.\{component\}) unless the model sets:subcomponent: apiunder a** Flagsheading in* C++–badge_mapping_junction.orgnever set it, socompass codegen entity generate badge_mappingsilently targeted a staleprojects/ores.dq/include/ores.dq/...path instead of the realprojects/ores.dq/core/include/ores.dq.core/...one (which is also whycompass codegen entity show badge_mappingreported the C++ files as❌ MISSING– comparing against the wrong location, not flagging a real gap). Fixed: added the missing:subcomponent: apiflag tobadge_mapping_junction.org, regenerated for real (superseding an earlier direct hand-patch of the generated.cpp, reverted), and updatedbadge_service.cpp(the one caller) to the richer generated interface (read_latest()returningdomain::badge_mapping, mapped down to the lightweightmessaging::badge_mappingthe NATS response still uses). Full, verified inventory of all 12
has_tenant_id: truejunctions (not 11 – miscounted on first pass). Verified two ways: does the model set:subcomponent: api, and doescompass codegen entity generate <name> --dry-run's output path actually match where the real repository file lives on disk (the authoritative test – a junction can only be genuinely regenerated, not just hand-written to look similar, if these match):Junction Component Codegen wired (path matches) Notes badge_mapping dq yes (fixed today) was hand-authored, missing tenant filter; now generated currency_pair_convention_calendar refdata yes party_currency refdata yes party_country refdata yes tenor_convention_resolution refdata yes this story's original validation target dataset_bundle_member dq no – wrong path hand-authored; read_latest() has NO tenant_id filter – same bug class, unfixed account_party iam no – wrong path hand-authored; read_latest() has NO tenant_id filter – same bug class, unfixed party_counterparty refdata no – wrong path hand-authored; read_latest() has NO tenant_id filter – same bug class, unfixed app_version_platform compute no – wrong path hand-authored; DOES correctly filter tenant_id (raw SQL), so not currently broken, just not codegen'd currency_calendar refdata no – wrong path hand-authored; DOES correctly filter tenant_id, not currently broken, just not codegen'd currency_country refdata no – wrong path hand-authored; DOES correctly filter tenant_id, not currently broken, just not codegen'd currency_currency_group refdata n/a no C++ repository exists at all yet, SQL-only, not wired into any caller So: 5 of 12 are genuinely codegen'd today (this story's tasks wired more than just the one validation target, contrary to the story's own
Resultsection which only mentionstenor_convention_resolution). 6 are still hand-authored with thecomponent_core_dirpath bug blocking regeneration; of those, 3 (dataset_bundle_member,account_party,party_counterparty) have the same missing- tenant-filter bug asbadge_mappingdid, unfixed. The other 3 hand-authored ones happen to filter correctly already. This task's fix for each of the 6 is the same one-line:subcomponent: apimodel additionbadge_mappingjust got – not a deeper tooling problem.
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 |
|---|---|---|
PRs
| PR | Title |
|---|---|
Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|