From a968cefbc24c8d5259076fce604161a3b8bb64b6 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 12 May 2026 08:13:11 -0400 Subject: [PATCH] docs(templates): record derive-on-compose decisions (naming, migration, tree UX) --- .../2026-05-12-derive-on-compose-design.md | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/plans/2026-05-12-derive-on-compose-design.md b/docs/plans/2026-05-12-derive-on-compose-design.md index 04e2383..4a21ed8 100644 --- a/docs/plans/2026-05-12-derive-on-compose-design.md +++ b/docs/plans/2026-05-12-derive-on-compose-design.md @@ -243,30 +243,30 @@ Each phase is independently shippable and reviewable. `ParentTemplateId`, but the UX hasn't been designed. - Cross-tenant template libraries. -## Open questions +## Decisions -- **Derived-template names**: `Pump.TempSensor` vs `Pump_TempSensor` vs - `${parentName}::${instanceName}`? Visible only on the edit page since the - tree hides derived templates, but appears in audit logs and error messages. - Default: dot-separated mirrors the canonical path format already used in - flattening (`TempSensor.Temperature`). Pick this unless the dot is - problematic for any existing pipeline. +- **Naming**: dot-separated (`Pump.TempSensor`). Matches the canonical-path + format used in flattening. Visible in audit logs / error messages. +- **Delete base with derivatives**: block the delete and list the derivatives. + User must remove or repoint them first. +- **Migration of existing data**: EF Core migration on next startup + auto-derives every existing composition. After deploy all compositions are + derived; no mixed-mode code paths. +- **Tree UX**: derived templates hidden by default. "Show derived templates" + toggle on the tree page reveals them indented under their base. Always + reachable from the parent's Compositions tab. -- **Re-composing the same base in two slots on the same parent**: e.g., Pump - composes Sensor twice as `IntakeSensor` and `OutletSensor`. Two derived - templates: `Pump.IntakeSensor` and `Pump.OutletSensor`. Both inherit from - `Sensor`. Confirmed OK. +## Confirmed semantics -- **Composition order / dependency**: if the user composes A inside B and - later edits A's base — does B's derived template auto-pick up the changes? - Answer per inheritance: yes for `IsInherited = true` fields, no for - overrides. Aveva-consistent. +- **Re-composing the same base on the same parent in two slots** (e.g. Pump + composes Sensor twice as `IntakeSensor` and `OutletSensor`) produces two + derived templates: `Pump.IntakeSensor` and `Pump.OutletSensor`, both + inheriting from `Sensor`. -- **Cascade-delete confirmation**: deleting a base template that has - derivatives — block with a clear error listing the derivatives, force user - to delete them first? Aveva blocks. Likely we should too. +- **Inheritance updates flow downward**: if a base attribute changes value + later and the derivative has `IsInherited = true` for that attribute, the + derived value updates. Once overridden (`IsInherited = false`), changes to + the base no longer affect that field. -- **Validation**: if base adds an attribute, derived inherits it on next load. - But what about derived overriding a field that base subsequently locks via - `LockedInDerived`? Force-revert the override on next deploy? Surface as a - validation error? Probably the latter. +- **Subsequent `LockedInDerived` after overrides exist**: surface as a + validation error at deploy time; do not force-revert silently.