Task: Bind ores.iam entities to profiles; verify zero-diff regen
Table of Contents
This page documents a task in the Entity classification and drift baseline: ores.iam story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
Survey every ores.iam entity (projects/ores.iam/modeling) against the profile catalogue, rebind matches, regenerate, and require zero additional diff against the pre-rebind checked-in output.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Entity classification and drift baseline: ores.iam |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-09-05 |
3. Acceptance
- Every entity discovered under projects/ores.iam/modeling is surveyed against all Variability Profiles.
- Every matching entity is rebound and regenerated with zero additional diff versus its pre-rebind checked-in output.
- No-match entities are recorded with their actual feature values, not silently dropped.
- The tenant_type has_tenant_id model/table drift is resolved as part of this survey, not carried forward as a separate open item.
- The known service_find_prefix gap on tenant_type and tenant_status is resolved as part of reaching zero drift.
4. Plan
4.1. Survey (2026-09-05)
All six codegen-eligible orgs under projects/ores.iam/modeling were surveyed against the profile catalogue; there is no genuine no-match. The iam and iam-cpp catalogue entries share this modeling_dir, so this is one survey.
| Org | Kind | Profile | Change in this unit |
|---|---|---|---|
| ores.iam.tenant | entity | uuid-identified-lookup | SQL rules and :unique: declared (below) |
| ores.iam.account_party_junction | junction | tenant-scoped-junction | soft-FK declarations (below) |
| ores.iam.account_contact_information | entity | self-referencing-hierarchy | profile declared |
| ores.iam.account_type | entity | simple-lookup (+ service_find_prefix) | none; pre-bound, byte-stable |
| ores.iam.tenant_status | entity | simple-lookup (+ service_find_prefix) | none; pre-bound, byte-stable |
| ores.iam.tenant_type | entity | simple-lookup (+ service_find_prefix) | none; pre-bound, byte-stable |
Known starting-point items from the story acceptance:
- service_find_prefix on tenant_type and tenant_status was already declared at the branch point; both orgs regenerated byte-identically through this unit.
- The tenant_type has_tenant_id model/table drift was investigated and closed before this unit branched (see Notes: capture 2F793500…). This unit's zero-diff regeneration independently confirms the model set and the committed schema agree.
4.2. SQL rule restorations
Every committed SQL rule for the regenerated tables was restored through codegen, per the standing directive to extend codegen rather than drop SQL (see Notes, #1961 audit):
| Committed rule (pre-rebind SQL) | Org declaration this unit | Template feature |
|---|---|---|
| four table checks (system-tenant id/code guard, system tenant_id, code <> '', hostname <> '') | tenant.org * SQL ** Checks |
Checks section (pre-existing) |
| delete rule sets status = 'terminated' | tenant.org ** Delete sets |
Delete sets section (new, 29438cdb8e) |
| unique index on hostname (active records) | hostname column :unique: true |
unique-non-key column feature (new, 29438cdb8e) |
| type/status FK validation on insert (23503) | tenant.org * Insert trigger ** Validations |
Validations table wiring generated validate fns (pre-existing) |
| account_party soft-FK validation blocks | account_party_junction.org * Foreign keys |
junction soft-FK section (pre-existing) |
The checks and the junction FK blocks regenerate byte-identically to the committed rule text (verified hunk-for-hunk, zero diff). The hostname index differs only by the idiom comment the template adds. The validate-fn wiring keeps the 23503 rejection rule; message text and bootstrap behaviour differ from the committed inline blocks and are accepted as an idiom improvement (Notes).
The remaining SQL delta is template-era modernization, the sign-off class that refdata anchors already carry: clock_timestamp in place of current_timestamp, security definer as a function attribute on entity insert fns, the junction insert fn dropping its legacy security-definer attribute to the plain idiom all nine committed refdata junction outputs ship, and delete-rule parens. Regeneration also surfaced a latent generator bug the old template never rendered: the tenant name snippet called the nonexistent faker::company::name(), fixed to faker::company::companyName() to match every sibling org (05c1a89a2d).
4.3. Commit sequence
- 29438cdb8e [ores.codegen] template features + parser coverage.
- 8e077020be [iam] modeling org declarations.
- 5395fe890e [iam] regenerated outputs (63 files; SQL rule restorations, era modernization, bound-profile C++/Qt growth).
- 90fc228c60 [agile] task start flips.
- b85c6ac327 [ci] drift gate extended to iam,iam-cpp.
- 05c1a89a2d [iam] tenant generator faker fix.
- bec4d7d61d [ores.iam] restore the tenant provisioning protocol and handler lost in the C3 regen (custom flow, no template output path).
- ffc22e94f6 [agile] record the iam survey and SQL rule restorations.
- ef7a2a8ee2 [iam] restore the cross-tenant tenant_lookups lost in regeneration (hand-authored; RLS-subject plain reads).
- e8094a710d [shell, qt] adapt the tenant history command to the regenerated response member.
- d61e26fd61 [ores.qt] adapt IamPlugin to the regenerated TenantController API.
- 4e3fc08cd6 [ores.codegen] seed transitive FK ancestors in generated eventing tests.
- 4bad7fffe7 [iam] fix the tenant type generator; declare the account seeding snippet in the org.
- 53363539e8 [iam, compute, refdata] regenerate outputs after seed closure and generator fix.
- 5ea58e41b2 [ores.codegen] split ancestor seeding into declare and write phases.
- 94ade14712 [compute, refdata] regenerate eventing tests after the two-phase seeding split.
- 5433e022c5 [ores.codegen] let the parent_seed org block name its own includes.
- 7de2f9b47e [iam] declare the account seeding includes in the contact-information org.
- 6ada58025f [ores.codegen] emit the parent_seed snippet's named includes in the test head.
- a9ecc71021 [ores.codegen] suffix synthetic :unique: plain-string columns with the process counter.
- aaab07e8c1 [ores.codegen] emit the system-scoped write context in generated eventing tests.
- 72687b2bb2 [ores.iam] regenerate the tenant generator and eventing test; sweep tenants.
- 15e4abbc25 [ores.iam] align the tenant lookup test with the tenants_read_policy design.
5. Notes
- #1961 audit: the PR that first regenerated the iam lookup SQL under the then-new lookup templates was audited for dropped rules. The audit found adds-only: the committed tree gained the generated validate fns and their wiring; no committed rule was dropped and no rule text was weakened. #1961 does not set a drop-SQL precedent, so this unit followed its lead: every rule the pre-rebind iam SQL carried has a codegen home in the committed tree today.
- The tenant type/status validation idiom changes shape: committed inline blocks raised 23503 with bespoke messages; the regenerated tables call the generated ores_iam_validate_tenant_type_fn and ores_iam_validate_tenant_status_fn (lookup SQL), which raise 23503 with an allowed-values listing and pass through bootstrap inserts while the lookup has no active system rows. Rule semantics (reject unknown type/status at insert) are unchanged.
- tenant_type has_tenant_id drift (capture
2F793500-FBD1-4E4F-8B6E-15D03337FBD2): closed pre-branch by the
ir-curve-followups task (task_tenant_type_has_tenant_id_drift.org,
DONE), which deleted the three
_lookup_entity.orgduplicates; the simple-lookup entity orgs are the sole authority and regenerate byte-identically. - The superseded ad hoc task 'Apply safe drift to iam-cpp' (task_apply_safe_drift_iam.org) is ABANDONED and already points to this story.
6. 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 |
|---|---|---|
7. PRs
| PR | Title |
|---|---|
| #2014 | [iam,codegen] Bind iam entities to profiles, zero-diff regen |
8. Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | Regenerated tenant.hpp documents the system tenant UUID as all zeros; the system tenant id is the max UUID (ffffffff-ffff-ffff-ffff-ffffffffffff), per tenant_id::system(), ores_utility_system_tenant_id_fn() and the tenant table's own check | ores.iam.tenant.org | Accept | Org prose (overview, id column description) corrected at source and regenerated; tenant.hpp and iam_tenants_create.sql doc comments now state the max UUID (15bd8482d0) |
9. Result
Closed 2026-09-05. Bound the six ores.iam codegen-eligible orgs per the
Plan survey: ores.iam.tenant to uuid-identified-lookup,
ores.iam.account_party_junction to tenant-scoped-junction,
ores.iam.account_contact_information to
self-referencing-hierarchy; account_type, tenant_status and
tenant_type were pre-bound simple-lookup entities and regenerated
byte-identically through the unit. Every committed SQL rule the
pre-rebind iam tables carried has a codegen home: the four tenant table
checks via the Checks section, the status = 'terminated' delete rule
via the new ** Delete sets section, the hostname active-record unique
index via the new column :unique: flag, the type/status insert
validations via the generated lookup validate fns, and the
account_party soft-FK blocks via the junction foreign-keys section.
Template-era modernization on the regenerated tables
(clock_timestamp, the security-definer function-attribute form, the
junction insert fn losing its legacy attribute) is the sign-off class
the refdata anchors already carry; regeneration also surfaced a latent
generator bug the old template never rendered, the tenant name snippet
calling the nonexistent faker::company::name(), fixed to
companyName() to match every sibling org (05c1a89a2d).
Regeneration surfaced two further losses from the earlier C3-era
regeneration, both restored at source: the tenant provisioning
protocol and handler (a custom flow with no template output path,
restored by hand, bec4d7d61d) and the cross-tenant tenant_lookups
(the hand-authored counterpart of tenant_repository; no template
emits the file, and it keeps the pre-rebind unfiltered reads,
ef7a2a8ee2). The shell tenant-history command and the qt IamPlugin
were adapted to the regenerated APIs (e8094a710d, d61e26fd61). The
drift gate now covers iam and iam-cpp (b85c6ac327, per the compute
unit's extension of the compass-pr-raise check list); a full retangle leaves
the tracked tree byte-identical to the committed output.
Moving the acceptance runs onto a recreated test DB (compass db
recreate) surfaced three defects the previous DB had masked, each
fixed at source rather than worked around. Generated eventing tests
now seed transitive FK ancestors in a two-phase declare/write split
and write under the system-scoped context (4e3fc08cd6, 5ea58e41b2,
aaab07e8c1); synthetic :unique: plain-string columns take the
process-counter suffix, ending the tenant-hostname collisions on
unique indexes (a9ecc71021); and the tenant lookup test now asserts
what the committed tenants_read_policy admits – the row's own
tenant context and the system context resolve the system-owned tenant
rows, a peer tenant's context stays isolated – with the constraint
documented in the tenant_lookups header (15e4abbc25).
Acceptance: every entity surveyed and every match rebound (survey
table above); regenerated output byte-identical to the committed tree
for refdata, reporting, marketdata, compute-cpp, iam and iam-cpp
(check_component_drift.py, 2026-09-05); no genuine no-match; the
tenant_type has_tenant_id drift closed pre-branch and independently
confirmed by the zero-diff regen; the service_find_prefix gap on
tenant_type and tenant_status was already declared at the branch
point and stayed byte-stable; full build clean at 100% with
ores.qt.exe linked (linux-clang-debug-make); ctest 71/71 green on the
recreated DB; iam and iam-cpp covered by the drift gate.