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: true junction 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 no tenant_id filter at all, relying solely on RLS – which for this table (and every other "system-owned global registry, tenant-overridable" table) permits tenant_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 with domain_entity, already correctly tenant-scoping every query it generates. The actual root cause: resolve_output_path's component_core_dir computation (projects/ores.codegen/src/codegen/core.py, ~line 596) falls back to a flat, pre-split path (ores.\{component\}) unless the model sets :subcomponent: api under a ** Flags heading in * C++badge_mapping_junction.org never set it, so compass codegen entity generate badge_mapping silently targeted a stale projects/ores.dq/include/ores.dq/... path instead of the real projects/ores.dq/core/include/ores.dq.core/... one (which is also why compass codegen entity show badge_mapping reported the C++ files as ❌ MISSING – comparing against the wrong location, not flagging a real gap). Fixed: added the missing :subcomponent: api flag to badge_mapping_junction.org, regenerated for real (superseding an earlier direct hand-patch of the generated .cpp, reverted), and updated badge_service.cpp (the one caller) to the richer generated interface (read_latest() returning domain::badge_mapping, mapped down to the lightweight messaging::badge_mapping the NATS response still uses).
  • Full, verified inventory of all 12 has_tenant_id: true junctions (not 11 – miscounted on first pass). Verified two ways: does the model set :subcomponent: api, and does compass 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 Result section which only mentions tenor_convention_resolution). 6 are still hand-authored with the component_core_dir path bug blocking regeneration; of those, 3 (dataset_bundle_member, account_party, party_counterparty) have the same missing- tenant-filter bug as badge_mapping did, 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: api model addition badge_mapping just 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
       

Result

Emacs 29.3 (Org mode 9.6.15)