Skip to main content

When to Use

When implementing state transitions in the CLI (publish, deprecate, verify), resolving CRDT merge conflicts on the status field, or validating that a unit’s lifecycle state is reachable.

The 6 States

StateVersionMeaning
draft0.x.xWork in progress, not importable by stable units
review0.x.xValidation passed, PR opened
stable1.0.0+Published, Blake3 verified, visible in MERIDIAN
deprecatedanyRetired with —reason and —successor
tamperedanySystem-detected Blake3 mismatch
tombstonedanyTerminal. Remains addressable but not importable

Valid Transitions

draft → review         (stratt validate PASS + PR opened)
review → draft         (reviewer requests changes)
review → stable        (reviewer approves + stratt publish)
stable → stable        (new version published)
stable → deprecated    (stratt deprecate --reason --successor)
deprecated → tombstoned (tombstone record written to R2)
stable → tampered      (Blake3 mismatch detected — system only)
review → tampered      (Blake3 mismatch detected — system only)
tampered → stable      (re-publish by authorised author)
tombstoned → [nothing] (terminal state)

CRDT Merge Ordering (AC-02 Corrected)

When two replicas disagree on a unit’s status, the more restrictive state wins:
[tombstoned, deprecated, tampered, stable, review, draft]
     0           1          2        3       4      5
Lower index = more restrictive = wins the merge. Examples:
  • merge(stable, draft)stable (index 3 < 5)
  • merge(tampered, stable)tampered (index 2 < 3)
  • merge(tombstoned, anything)tombstoned (index 0 wins always)
Important: The original TAD spec was missing tampered from this ordering. AC-02 corrected this. Without the correction, a tampered unit could be silently overridden by a stable merge.

Usage

import { resolveLifecycleMerge, isValidTransition, crdtPriority } from "@stratt/schema";

resolveLifecycleMerge("stable", "tampered"); // → "tampered"
isValidTransition("draft", "review");        // → true
isValidTransition("stable", "draft");        // → false
crdtPriority("tombstoned");                  // → 0 (most restrictive)