Refinements become versioned specs refining another spec #12

Closed
opened 2026-10-25 12:12:18 +00:00 by Gilles · 0 comments
Owner

Goal

Replace the Refinement link model by refinement specs: a refinement is a regular, versioned Spec located at a direct child place, with a FK to the spec it refines.

Model

  • Removed: Refinement (parent version, child place, target version or explicit absence).
  • Spec.refines: nullable FK to the refined Spec (null for root-place specs). Must be located at place.parent.
  • SpecVersion.refines_versions: M2M to versions of spec.refines — one refinement version can cover several versions of the refined spec (e.g. parent v2, v3, v4 when the parent changed without the refinement needing to).
    • Monotonic coverage: for a given refinement spec, every parent version covered by version n+1 is strictly newer than every parent version covered by version n (each parent version is covered by at most one version of a given refinement spec).
  • SpecVersion.is_absence: absence is a property of a refinement version, not of the spec. An absent version's content is its mandatory justification. It needs no refinements of its own and is vacuously implemented. A refinement can be "deleted" (new absent version) and later come back (new non-absent version), history kept.
  • Completeness: for the current version of a spec, every direct child place needs at least one refinement version (absent or not) covering it — 1..n refinement specs per child place; no implicit absence.
  • Codes: migrated refinement specs keep their former R-* code as an alias, still resolved by the coverage upload; no new R-* codes are issued.

Reopen cascade

When a spec (or a refinement spec) goes back to draft, every refinement spec covering the reopened version is reopened too, recursively down the tree, each with a pending decision:

  1. Keep the version — the cascade draft is dropped and the previous validated version now also covers the new parent version. Descendants that are still untouched cascade drafts are reverted the same way automatically.
  2. New version — the draft is edited/validated and covers the new parent version.
  3. Remove the refinement — the new version is marked is_absence (with justification).

A project version cannot be validated while any decision is pending.

Data migration

  • Each non-absent Refinement → sets refines on the target spec and adds the parent version to the target version's refines_versions; the refinement's code becomes an alias, its attachments and automatic tests move to the target spec/version.
  • Each explicit absence → new refinement spec at the child place, v1 is_absence=True (validated if the parent version was), content = absence_reason, code alias = the R-* code.
  • Targets refined by several parent specs (if any exist) must be reported before migrating — they cannot fit the single refines FK.

Impact

  • backend: models, migrations, serializers, views (coverage upload code resolution, attachments), admin, tests.
  • frontend: refinement tree view, spec detail/panel, cascade decision UI.
  • thierryade-pytest / thierryade-wdio: refinement codes and fixtures.
  • Thierryade's own specs describing refinements, and the thierryade-specs scripts.
## Goal Replace the `Refinement` link model by refinement **specs**: a refinement is a regular, versioned `Spec` located at a direct child place, with a FK to the spec it refines. ## Model - **Removed:** `Refinement` (parent version, child place, target version or explicit absence). - **`Spec.refines`**: nullable FK to the refined `Spec` (null for root-place specs). Must be located at `place.parent`. - **`SpecVersion.refines_versions`**: M2M to versions of `spec.refines` — one refinement version can cover several versions of the refined spec (e.g. parent v2, v3, v4 when the parent changed without the refinement needing to). - **Monotonic coverage:** for a given refinement spec, every parent version covered by version n+1 is strictly newer than every parent version covered by version n (each parent version is covered by at most one version of a given refinement spec). - **`SpecVersion.is_absence`**: absence is a property of a refinement *version*, not of the spec. An absent version's content is its mandatory justification. It needs no refinements of its own and is vacuously implemented. A refinement can be "deleted" (new absent version) and later come back (new non-absent version), history kept. - **Completeness:** for the current version of a spec, every direct child place needs at least one refinement version (absent or not) covering it — 1..n refinement specs per child place; no implicit absence. - **Codes:** migrated refinement specs keep their former `R-*` code as an alias, still resolved by the coverage upload; no new `R-*` codes are issued. ## Reopen cascade When a spec (or a refinement spec) goes back to draft, every refinement spec covering the reopened version is reopened too, recursively down the tree, each with a **pending decision**: 1. **Keep the version** — the cascade draft is dropped and the previous validated version now also covers the new parent version. Descendants that are still untouched cascade drafts are reverted the same way automatically. 2. **New version** — the draft is edited/validated and covers the new parent version. 3. **Remove the refinement** — the new version is marked `is_absence` (with justification). A project version cannot be validated while any decision is pending. ## Data migration - Each non-absent `Refinement` → sets `refines` on the target spec and adds the parent version to the target version's `refines_versions`; the refinement's code becomes an alias, its attachments and automatic tests move to the target spec/version. - Each explicit absence → new refinement spec at the child place, v1 `is_absence=True` (validated if the parent version was), content = `absence_reason`, code alias = the `R-*` code. - Targets refined by several parent specs (if any exist) must be reported before migrating — they cannot fit the single `refines` FK. ## Impact - backend: models, migrations, serializers, views (coverage upload code resolution, attachments), admin, tests. - frontend: refinement tree view, spec detail/panel, cascade decision UI. - thierryade-pytest / thierryade-wdio: refinement codes and fixtures. - Thierryade's own specs describing refinements, and the `thierryade-specs` scripts.
Gilles self-assigned this 2026-10-25 14:51:43 +00:00
Sign in to join this conversation.
No description provided.