Story: Entity classification and drift baseline: ores.iam
Table of Contents
This page documents a story in Sprint 25. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
1. Goal
Bring ores.iam to the same proven state as the ores.refdata pilot: every codegen-eligible entity (discovered once, under projects/ores.iam/modeling – the iam and iam-cpp catalogue entries share the same modeling_dir and no longer have a live legacy-JSON split, so this is one survey, not two) bound to a profile or recorded as a genuine no-match, zero-diff regeneration verified, and any real gap the check surfaces fixed rather than skipped. Once trusted, iam and iam-cpp are added to the CI regeneration-drift check.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent sprint | Sprint 25 |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-09-05 |
3. Acceptance
- Every ores.iam entity is bound to a matching Variability Profile, or recorded as a genuine no-match with a documented reason. Done 2026-09-05.
- Every rebound entity is regenerated and diffed against its pre-rebind checked-in output; zero diff is the pass condition, and any non-zero diff is fixed, not worked around. Done 2026-09-05 (retangle leaves the tracked tree byte-identical; check_component_drift.py).
- Full local build clean, validate_schemas.sh green, full ctest suite green after regeneration. Done 2026-09-05 (build clean at 100% with ores.qt.exe linked, linux-clang-debug-make; ctest 71/71 green on the recreated DB;
compass db statusreports schema drift current, the successor of validate_schemas.sh). - check_component_drift.py –components is extended to include iam and iam-cpp, and the refdata-codegen-drift CI job is updated so future PRs touching ores.iam fail on any regeneration drift. Done 2026-09-05 (b85c6ac327; the pr.yml-era CI job named in the acceptance was deleted, so the drift gate is the compass-pr-raise local check list, extended to iam,iam-cpp per the compute unit's pattern).
- The superseded ad hoc task 'Apply safe drift to iam-cpp' is marked ABANDONED, pointing here. Done 2026-09-05 (verified at the branch point).
- The known starting-point wrinkle already recorded for iam-cpp (service_find_prefix on tenant_type and tenant_status) is resolved as part of reaching zero drift. Done 2026-09-05 (already declared at the branch point; both orgs regenerated byte-identically through the unit).
- The known, previously-flagged tenant_type has_tenant_id model/table drift (see capture 2F793500-FBD1-4E4F-8B6E-15D03337FBD2) is investigated and resolved, not left as stale drift. Done 2026-09-05 (closed pre-branch by the ir-curve-followups task; this unit's zero-diff regen independently confirms the model set and the committed schema agree).
4. Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Bind ores.iam entities to profiles; verify zero-diff regen | DONE | 2026-09-05 | 2026-09-05 | Implement profile binding for ores.iam's org-mode entity set (iam and iam-cpp catalogue entries share the same modeling_dir), rebind every matching entity, regenerate, and confirm byte-identical output, following the ores.refdata pilot method exactly. |
| Grant iam_service select on refdata for the account_party soft FK | DONE | 2026-09-05 | 2026-09-05 | The regenerated ores_iam_account_parties_insert_fn runs under the plain invoker idiom, so its soft-FK validation subselect against ores_refdata_parties_tbl executes as the iam service user. The service registry granted iam_service select on ores_assets_ and ores_dq_ only, so the first live tenant provisioning on a fresh DB failed with 'permission denied for table ores_refdata_parties_tbl'. Add ores_refdata_ to iam's Select prefixes in service_registry.org and regenerate iam_service_db_grants_create.sql. |
5. Decisions
- Every SQL rule the pre-rebind iam tables carried was restored
through codegen, never dropped: the standing directive (extend
codegen or use paste blocks unless a drop is signed off) applies,
and the #1961 audit found that PR set an adds-only precedent this
unit followed. New template features: the
** Delete setsorg table (soft-delete SET extension) and the column:unique:flag (active-record partial index). The tenant table checks, the status = 'terminated' delete-set member, the hostname unique index, the type/status insert validations, and the account_party soft FKs all have org homes in the committed tree. - Tenant type/status validation moved from inline trigger blocks to the generated validate fns of the lookup SQL. The 23503 rejection rule is unchanged; the message text (allowed-values listing) and bootstrap pass-through differ from the committed blocks and were accepted as an idiom improvement.
- The junction insert function lost its legacy security-definer attribute in regeneration. This is the current template idiom, not a drop: all nine committed refdata junction outputs already ship the plain form; the iam junction simply predated that template era.
- The drift gate now covers iam and iam-cpp. The refdata-codegen-drift CI job named in this story's acceptance was deleted with pr.yml (ea283ef0b9); its successor is the compass-pr-raise local check list, which the compute unit extended to compute-cpp and this unit extended to iam,iam-cpp after the six-component convergence check passed.
- Template-era modernization on regenerated iam output (clock_timestamp, security-definer function-attribute form, delete- rule parens) is the sign-off class the refdata anchors already carry, verified byte-identical against the current template.
- Moving the acceptance runs onto a recreated test DB (
compass db recreate) surfaced three defects the superseded DB had masked, each fixed at source rather than worked around. The eventing-test template now branches on the system-scoped table flag and stamps a system write context (the insert trigger forcestenant_id = systemand RLS WITH CHECK runs after it), and the eventing-test org carries the parent_seed include emission and the declare/write ancestor phasing so the retangle cannot revert them (aaab07e8c1). - Synthetic
:unique:plain-string columns (the tenant hostname) take the process-counter suffix, because a faker-derived value is a process constant and collides on the unique index from the second write in one process (a9ecc71021). - The hand-authored
tenant_lookupskeep their plain, unfiltered reads: RLS still applies, so a session resolves what thetenants_read_policyadmits – the system tenant (every row) and a tenant's own record by id. Bootstrap callers run under the system-scoped base context, never under a peer tenant's; the lookup test asserts exactly that resolution and peer isolation (15e4abbc25).