Problem
The infrahub-managing-schemas skill's guidance on branch-agnostic attributes and schema migrations has gaps that a real customer migration exposed (moving a rule_id NumberPool off a generic to per-node pools + cleaning up orphaned values — a multi-day investigation). An SA following the skill as written would hit the same failures:
rules/attribute-branch-agnostic.md encourages marking identity fields branch: agnostic ("keep the identity field global") and never warns that this is actively harmful for a NumberPool attribute.
rules/migration-state-absent.md doesn't cover relocating a NumberPool from a generic to child nodes, the merge behavior of schema load, or how to retire a Schema-managed pool.
Proposed solution
A. attribute-branch-agnostic.md — add a "Never use branch: agnostic on a NumberPool" section:
A branch-agnostic value is stored on the -global- branch and is not tombstoned when its node is deleted (the delete is recorded at branch level; the -global- value stays active). Over create/delete churn — e.g. repeated data re-imports — this leaves orphaned "active" pool values that uniqueness validation keeps scanning, so proposed changes fail referencing nodes that no longer exist ("node not found" / count 0). Pool-allocated values are per-object identifiers → keep NumberPools branch-aware (the default). Ref: opsmill/infrahub#9762.
B. migration-state-absent.md — add three subsections:
- Relocating a NumberPool attribute (generic → child nodes): must be two-pass —
state: absent on generic + children, load; then re-add it on each child, load. A one-pass move is read as inherited→owned and creates no new pools (the old shared pool is reused).
schema load MERGES — clear node-level fields explicitly: removing human_friendly_id / display_label / uniqueness_constraints / order_by from the YAML does not unset them server-side. If they reference a removed attribute the load fails ("Requested unique constraint not found" / "display_label … is invalid"). Set them to [] / "" to actually clear.
- Retiring a Schema-managed NumberPool: the "in use" gate is schema-based, not object-based — blocked while any branch's schema still defines the attribute (
get_branches_with_schema_number_pool). Deleting objects does nothing; strip the attribute from each branch's schema (or delete the branch) and it auto-deletes. Never DETACH DELETE the pool node (corrupts branch versioning).
C. (optional) infrahub-analyzing-data — investigation reference: reproduce/validate a customer issue by restoring their Neo4j backup into an isolated local stack. A .backup artifact needs the neo4j enterprise image to restore; point the Infrahub server at the restored volume.
Alternatives considered
- Leaving it as tribal knowledge / buried in a Slack thread — but encoding exactly this kind of hard-won pattern is the point of the skills.
- A standalone
attribute-numberpool.md rule — viable, but folding into the existing branch-agnostic + migration rules keeps it where people already look.
Use case
A real customer migration: move a rule_id NumberPool from a generic to per-node branch-aware pools, and clean up thousands of orphaned agnostic values that were breaking proposed-change validation. Each gap above caused a concrete failure: dangling-reference load errors (merge behavior), no new pools created (one-pass move), pool undeletable (schema-gated in-use).
Additional context
Problem
The
infrahub-managing-schemasskill's guidance on branch-agnostic attributes and schema migrations has gaps that a real customer migration exposed (moving arule_idNumberPool off a generic to per-node pools + cleaning up orphaned values — a multi-day investigation). An SA following the skill as written would hit the same failures:rules/attribute-branch-agnostic.mdencourages marking identity fieldsbranch: agnostic("keep the identity field global") and never warns that this is actively harmful for a NumberPool attribute.rules/migration-state-absent.mddoesn't cover relocating a NumberPool from a generic to child nodes, the merge behavior ofschema load, or how to retire a Schema-managed pool.Proposed solution
A.
attribute-branch-agnostic.md— add a "Never usebranch: agnosticon a NumberPool" section:B.
migration-state-absent.md— add three subsections:state: absenton generic + children, load; then re-add it on each child, load. A one-pass move is read as inherited→owned and creates no new pools (the old shared pool is reused).schema loadMERGES — clear node-level fields explicitly: removinghuman_friendly_id/display_label/uniqueness_constraints/order_byfrom the YAML does not unset them server-side. If they reference a removed attribute the load fails ("Requested unique constraint not found" / "display_label … is invalid"). Set them to[]/""to actually clear.get_branches_with_schema_number_pool). Deleting objects does nothing; strip the attribute from each branch's schema (or delete the branch) and it auto-deletes. NeverDETACH DELETEthe pool node (corrupts branch versioning).C. (optional)
infrahub-analyzing-data— investigation reference: reproduce/validate a customer issue by restoring their Neo4j backup into an isolated local stack. A.backupartifact needs the neo4j enterprise image to restore; point the Infrahub server at the restored volume.Alternatives considered
attribute-numberpool.mdrule — viable, but folding into the existing branch-agnostic + migration rules keeps it where people already look.Use case
A real customer migration: move a
rule_idNumberPool from a generic to per-node branch-aware pools, and clean up thousands of orphaned agnostic values that were breaking proposed-change validation. Each gap above caused a concrete failure: dangling-reference load errors (merge behavior), no new pools created (one-pass move), pool undeletable (schema-gated in-use).Additional context