Task: Remove explicit model properties the bound profile already fixes

Table of Contents

This page documents a task in the Entity classification and drift baseline: redundant explicit properties story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

Remove the explicit property lines from every profiled entity model where the bound profile already fixes the same value, so the profile is the single source of truth for those features. Keep genuine overrides and the structural properties profiles deliberately omit. Prove each removal output-neutral by regenerating the component.

2. Status

Field Value
State DONE
Parent story Entity classification and drift baseline: redundant explicit properties
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-09-17

3. Acceptance

  • Every entity model bound to a profile is surveyed for explicit properties the profile also assigns, across every component in the drift gate's known-drift-free registry.
  • Every redundant line is removed. Every line whose stated value differs from the profile's is kept and recorded with its reason.
  • Each affected component regenerates byte-identical output after the removal. A component whose output moves is a finding, not a pass.
  • The drift gate still passes for each affected component in KNOWN_DRIFT_FREE.

4. Plan

The survey is mechanical, so it is a script, not a reading. It parses each model's :profile:, loads that profile's * Assignments table through the generator's own _load_profile_assignments, and intersects the assigned feature names with the keys the model states explicitly. Reusing the generator's loader matters: the survey then agrees with the merge the generator actually performs.

Each intersection is one of two things. The stated value equals the profile's, which makes the line redundant. Or the stated value differs, which makes it a deliberate override that the profile's default must not replace. Only the first kind is removed; the second is recorded.

Removal alone proves nothing, because a profile supplies defaults and the generator merges them at a specific point in its pipeline. The proof is regeneration. The model edits are committed first, since the drift check diffs the whole tree and a modified model would show up as drift. With the tree otherwise clean, the check regenerates each affected component and requires the generated output to match byte for byte.

5. Notes

The survey is a script, not a reading. It parses each model's :profile:, loads that profile's * Assignments through the generator's own _load_profile_assignments, and intersects the assigned feature names with the keys the model states. Reusing the generator's loader matters: the survey then agrees with the merge the generator actually performs.

The survey runs over projects/*/modeling/*.org for the components in KNOWN_DRIFT_FREE. It found 47 intersections: 45 candidates to remove and 2 overrides to keep.

Feature Lines Outcome
has_uuid_primary_key 19 removed
has_pagination 8 removed
has_tenant_id 7 removed
has_change_reason_cache 7 removed
has_parent_id 4 restored, not removable
has_workspace_id 1 override, kept

compute.result sets has_change_reason_cache false against the profile's true. reporting.report_definition sets has_workspace_id true against the profile's false. Both are deliberate overrides, so both lines stay.

The four has_parent_id lines did not turn out to be removable. The first regeneration proved it: removing them dropped the hierarchy function, the repository method, the handler and the service for business_unit, counterparty and party in refdata, and for folder in synthetic, over 24 and 8 generated files. The cause is a namespace mismatch. The profile files has_parent_id under sql, because that is what _FEATURE_NAMESPACE says. The templates and core.py read it at the entity root. The explicit line was the only thing putting the value where the readers look. Those four lines are restored.

dq is out of scope. Its models carry the same redundancy, but neither dq nor dq-cpp is in KNOWN_DRIFT_FREE, and regeneration there already materializes 37 untracked files from a template family the committed tree predates. The gate cannot prove a removal in an unregistered component, so the sweep leaves it alone.

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
#2089 [codegen] Remove model properties the bound profile already fixes

8. Review

Comment summary File Decision Notes
       

9. Result

The sweep removed 41 redundant property lines across 19 models in six components. Every removal is proven output-neutral by regeneration: all seven registry catalogue entries report No drift on the committed tree.

Catalogue slug Result
analytics-cpp No drift
compute-cpp No drift
iam No drift
iam-cpp No drift
refdata No drift
reporting No drift
synthetic No drift

Two findings came out of the run.

The four has_parent_id lines are not removable. Regeneration dropped the hierarchy machinery for the three refdata hierarchy entities and for synthetic.folder, because the profile writes the feature into the sql namespace while the generator reads it at the entity root. The lines are restored and the removal waits for a generator fix.

dq is out of scope. Its models carry the same redundancy, but neither dq nor dq-cpp is in KNOWN_DRIFT_FREE, and regeneration there already drifts for an unrelated template reason.

The audit gained the check. Model and profile hygiene joins the manual checklist of the component architecture audit, so a later pass on any component looks for this class of finding.

Acceptance:

  • Survey across the registry: met. The survey covers every profiled model of the six registry components.
  • Redundant lines removed, overrides kept and recorded: met. 41 lines removed. The two overrides and the four restored has_parent_id lines are recorded in * Notes with their reasons.
  • Each affected component regenerates byte-identical: met, for all seven registry entries.
  • The drift gate still passes for each affected component in KNOWN_DRIFT_FREE: met, by the same seven runs.

Emacs 29.3 (Org mode 9.6.15)