Draft Isolation Rule (FM-07)
grace intermediate 5 min read
ELI5
Stable things should not depend on unstable things. A finished cookbook can’t cite a recipe still being scribbled. Draft isolation enforces that wall: only drafts import drafts, only stable imports stable, with a thin bridge for review.
Technical Deep Dive
Source: packages/schema/src/lifecycle.ts:129-173, packages/schema/src/validate.ts:76-90, packages/graph/src/protect.ts.
Status Compatibility Matrix
importer_status allowed to import imported_status:
| Importer ↓ \ Imported → | draft | review | approved | published | active | deprecated |
|---|---|---|---|---|---|---|
| draft | yes | no | no | no | no | no |
| review | yes | yes | no | no | no | no |
| approved | no | no | yes | yes | yes | no |
| published | no | no | yes | yes | yes | no |
| active | no | no | yes | yes | yes | no |
| deprecated | no | no | yes | yes | yes | no |
| archived | no | no | no | no | no | no |
| tombstoned | n/a (no imports allowed at all) | |||||
| tampered | n/a (cannot be imported by anything) |
Decision Flow
flowchart TD A[importer + imported pair] --> B{importer status} B -->|draft| C{imported = draft?} B -->|review| D{imported in draft, review?} B -->|approved/published/active| E{imported in approved+?} B -->|deprecated| F{imported in approved+?} B -->|archived| G[no new imports allowed] B -->|tombstoned| H[no imports] B -->|tampered| I[cannot import or be imported] C -->|yes| J[OK] C -->|no| K[FM-07 warning] D -->|yes| J D -->|no| K E -->|yes| J E -->|no| K F -->|yes| J F -->|no| K G --> K style K fill:#fef3c7Validate vs Graph
validate.ts:76-90does a coarse 0.x.x vs 1.x.x semver check — published+ (1.x.x+) cannot import draft (0.x.x).lifecycle.ts:129-173(canImport) does the full status-pair check at the graph level, where statuses are known.
Why Warning, Not Blocking
A unit promoted from draft to approved without simultaneously promoting its draft dependencies is a real refactor in progress. FM-07 surfaces the drift without halting the build, letting authors batch promotions.
Tampered & Tombstoned
- A
tamperedunit cannot be imported by anything — the digest mismatch breaks SPEC-02 trust. - A
tombstonedunit is irreversibly deleted; no further imports of any status are possible.
Key Terms
- Approved+ → The set
{approved, published, active}; mutually importable. - Deprecated importing → Allowed to import approved+ (so deprecated units can keep working) but cannot regress to importing drafts.
- 0.x.x convention → Semver major-zero range conventionally used for
draftunits; stable starts at1.0.0.
Q&A
Q: Can a review unit import a draft unit?
A: Yes. Review is the bridge state — it must be able to pull in drafts to evolve, but cannot expose them upward to approved consumers.
Q: Can a deprecated unit import a published unit?
A: Yes. Deprecation freezes the unit’s outgoing surface to stable dependencies — it doesn’t sever existing approved+ links.
Q: What happens if I add a new import to an archived unit?
A: FM-07 fires. Archived units cannot accept new imports of any status; they are frozen by definition.
Examples
A dev/task/intake-parse@0.4.0 (draft) is imported by dev/chain/sol-1-boot@1.0.0 (published). validate.ts coarse check fires immediately (1.x.x importing 0.x.x). lifecycle.canImport(published, draft) returns false. FM-07 warning lands in stratt ci output. Fix: bump intake-parse to 1.0.0 (gate-required review→approved) before promoting the chain.
neighbors on the map
- Cross-Namespace Resolution: stratt:// & choco:// adding a choco:// import to a STRATT unit
- Nine Failure Modes (FM-01..FM-09) interpreting a `stratt ci` failure
- FNP CRDT Conflict-Free Merge Semantics understanding CRDT properties and guarantees