Task: Route has_parent_id to the entity root and rebind the entities the defect masked

Table of Contents

This page documents a task in the Fix the has_parent_id feature namespace so profile bindings take effect story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

Route has_parent_id to the entity root, where every reader looks for it, so a bound profile's assignment reaches the generator. Then retire the explicit workaround lines the defect forced, and repair the entities the defect masked.

2. Status

Field Value
State DONE
Parent story Fix the has_parent_id feature namespace so profile bindings take effect
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-09-17

3. Acceptance

  • _FEATURE_NAMESPACE maps has_parent_id to the empty namespace, that is, the entity root.
  • The four hierarchy models (business_unit, counterparty, party, folder) carry no explicit has_parent_id line and still generate the hierarchy block.
  • The eleven flat entities bind uuid-identified-lookup, carry no explicit has_pagination, and generate no hierarchy block.
  • Regeneration over the nine known-drift-free components produces no diff.

4. Plan

  1. Locate every reader of the feature, in core.py and in the template library, and record which namespace each one reads. Confirm that nothing reads sql.has_parent_id.
  2. Change the one line in _FEATURE_NAMESPACE that routes the feature.
  3. Drop the four explicit :has_parent_id: true lines the profile now supplies.
  4. Survey every model that binds self-referencing-hierarchy and check each one against the profile's stated contract, the two column properties.
  5. Pick the profile for the entities that fail that contract. Compare the candidates on feature assignments and on the physical-space table.
  6. Rebind those entities and drop their now-redundant :has_pagination:.
  7. Prove the whole change is output-neutral by regenerating the nine known-drift-free components and diffing.
  8. Correct the documents the defect had misled. The feature page, the feature index, the variability model, and the two codegen meta-model pages had all filed the feature under ores.sql.schema.

5. Notes

The reader inventory. Every reader resolves to the entity root. In the template library, eighteen files read the key, most as bare {{#has_parent_id}} inside a {{#domain_entity}} section, and the SQL facet's create template as {{#domain_entity.has_parent_id}}. In core.py, the hierarchy candidate test and the C++ uuid-include gate read domain_entity['has_parent_id']. doc_generate.py groups the feature with has_tenant_id and has_workspace_id at the root in its hierarchical-composite shape preset. Nothing anywhere reads sql.has_parent_id.

What the feature gates. The SQL facet emits a recursive-CTE hierarchy_fn returning flat (id, parent_id, name) rows. The C++ side gates repository::get_hierarchy, service::get_hierarchy, and the protocol and NATS-handler entries that reach them.

The two column properties. :parent_id_column: and :hierarchy_name_field: are read only by the two SQL-facet templates, yet every model authors them in the root * Flags drawer. Two readers and one authoring site disagree on the namespace. Moving them into * SQL would tidy that up, but the reader paths must change in the same edit. Not done here; the story records it as out of scope.

Why a guard would have helped. The defect's shape is silence. A profile feature whose value no reader consults produces no error, and removing the workaround line produced deleted generated code with no model-level signal. A loader check that fails when has_parent_id is true and either column property is missing would convert that silence into a hard error at regeneration time. It would not have caught the namespace fault itself, but it would have caught the eleven masked entities the moment the namespace was fixed. Filed as a capture.

The physical-space tiebreaker. uuid-identified-lookup and self-referencing-hierarchy both carry a * Physical space table enabling ores.cpp.eventing-integration-test. uuid-surrogate-lookup carries no such table at all, so rebinding the eleven to it would have dropped that facet and deleted eleven generated integration tests. This is what decided between two profiles whose feature assignments are otherwise interchangeable here.

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
#2090 [codegen] Route has_parent_id to the entity root so profile bindings take effect

8. Review

# Comment summary File Decision Notes
1 Story claimed none of the eleven rebound entities has a natural key; ten declare :natural_key: true. story.org Accepted Fixed in the Decisions entry. The earlier check searched for the phrase Natural key and missed the property.
2 Story frontmatter said the one entity whose profile does not describe it; the count is eleven. story.org Accepted Fixed in #+description.
3 The predecessor story's sprint row still described the has_parent_id namespace as broken in the present tense. sprint.org Accepted Reworded in the same commit.

9. Result

The feature routes to the entity root. _FEATURE_NAMESPACE now maps has_parent_id to the empty namespace, where has_tenant_id and has_workspace_id already lived, so a bound profile's assignment reaches every reader.

One line of code changed; the rest is models and documents. The four hierarchy models dropped their explicit :has_parent_id: true lines and still generate the hierarchy block. The eleven flat entities that had bound self-referencing-hierarchy without the profile's two column properties moved to uuid-identified-lookup and dropped their redundant :has_pagination:. The documents the defect had misled were corrected: the feature page, the feature index, the variability model, and the two codegen meta-model pages, whose UVL diagrams were recompiled and re-rendered.

Check Result
Codegen drift, nine registry components No drift: regenerated output matches the checked-in tree
Site build 33 pages published, 0 failures
Compass suite 164 passed, 1 skipped
UVL diagram recompile byte-identical to each committed SVG

Acceptance:

  • _FEATURE_NAMESPACE maps has_parent_id to the entity root: met, by the one-line change in org_loader.py.
  • The four hierarchy models carry no explicit line and still generate the hierarchy block: met, and proven by the drift gate, which regenerates all nine components and finds no difference.
  • The eleven flat entities bind uuid-identified-lookup, carry no explicit :has_pagination:, and generate no hierarchy block: met.
  • Regeneration over the nine known-drift-free components produces no diff: met.

The loader guard that would reject the feature without both column properties is not built here. It is filed as a capture, as the story's out of scope records.

Emacs 29.3 (Org mode 9.6.15)