Skip to content

Versioning and Lifecycle Specification

Version: 1.0.0
Status: Draft
Part of: ProvenanceCode Open Standard

Abstract

This document defines how ProvenanceCode artifacts progress through lifecycle states, how versions are managed, and how decisions evolve or become superseded over time.

Table of Contents

  1. Overview
  2. Lifecycle States
  3. State Transitions
  4. Versioning Rules
  5. Supersession
  6. Expiration
  7. Artifact-Specific Lifecycles
  8. Best Practices
  9. Examples

Overview

ProvenanceCode artifacts (decisions, specs, risks, mistakes) follow defined lifecycles that track their progression from initial draft to final state. This ensures:

  • Clarity - Everyone knows the current status
  • Auditability - State changes are tracked
  • Immutability - Accepted artifacts are never edited, only superseded
  • Traceability - History is preserved through supersession chains

Lifecycle States

Decision States

State Description Can Edit? Terminal?
draft Initial creation, work in progress ✅ Yes ❌ No
proposed Ready for review, awaiting approval ⚠️ Minor edits ❌ No
accepted Approved and active ❌ No ❌ No
rejected Not approved, will not implement ❌ No ✅ Yes
superseded Replaced by newer decision ❌ No ✅ Yes

Specification States

State Description Can Edit? Terminal?
draft Initial requirements, under discussion ✅ Yes ❌ No
review Ready for stakeholder review ⚠️ Minor edits ❌ No
approved Accepted, ready for implementation ❌ No ❌ No
implemented Completed and deployed ❌ No ✅ Yes
rejected Not moving forward ❌ No ✅ Yes
superseded Replaced by newer spec ❌ No ✅ Yes

Risk Acceptance States

State Description Can Edit? Terminal?
active Risk is currently accepted ⚠️ Update mitigations ❌ No
expired Acceptance period ended ❌ No ⚠️ Review needed
mitigated Risk has been eliminated ❌ No ✅ Yes
rejected Risk not accepted ❌ No ✅ Yes

Mistake Record States

State Description Can Edit? Terminal?
open Identified, not yet fixed ⚠️ Add details ❌ No
mitigated Prevention rules in place ⚠️ Add learnings ❌ No
closed Fully resolved, guardrails active ❌ No ✅ Yes

State Transitions

Decision Lifecycle Flow

   draft
     ↓
  proposed
   ↙   ↘
accepted  rejected
   ↓         (terminal)
superseded
 (terminal)

Valid Transitions

From To Condition
draft proposed Ready for review
draft rejected Decided not to proceed
proposed accepted Approval granted
proposed rejected Approval denied
proposed draft Needs more work
accepted superseded New decision replaces this

Invalid Transitions

Cannot transition: - From accepted back to draft or proposed (must supersede instead) - From rejected to any other state (terminal) - From superseded to any other state (terminal)

Versioning Rules

Version Numbers

Each artifact has a version field (integer starting at 1):

{
  "id": "DEC-SDM-FRD-0000042",
  "version": 1
}

When to Increment Version

Increment the version number when making substantive changes to: - Outcome or decision - Risk level - Acceptance criteria (specs) - Mitigations (risks)

Do NOT increment for: - Typo fixes - Formatting changes - Adding links or tags - Updating timestamps

Version History

Store version history in timestamps.updated_at:

{
  "version": 3,
  "timestamps": {
    "created_at": "2026-02-01T10:00:00Z",
    "accepted_at": "2026-02-02T14:30:00Z",
    "updated_at": "2026-02-10T09:15:00Z"
  }
}

For detailed history, optionally create:

provenance/decisions/DEC-SDM-FRD-0000042/
├── decision.json           (current version)
├── decision.v1.json        (previous version)
├── decision.v2.json        (previous version)
└── CHANGELOG.md            (version history)

Supersession

Purpose

When an accepted decision needs substantial changes, supersede it instead of editing:

  1. Create a new decision with new ID
  2. Mark old decision as superseded
  3. Link old ↔ new with lifecycle.supersedes and lifecycle.superseded_by

Supersession Fields

Old Decision (DEC-000010):

{
  "id": "DEC-SDM-FRD-0000010",
  "version": 1,
  "lifecycle": {
    "state": "superseded",
    "superseded_by": "DEC-SDM-FRD-0000042"
  }
}

New Decision (DEC-000042):

{
  "id": "DEC-SDM-FRD-0000042",
  "version": 1,
  "lifecycle": {
    "state": "accepted",
    "supersedes": "DEC-SDM-FRD-0000010"
  }
}

Supersession Chains

Decisions can form chains:

DEC-SDM-FRD-0000010 (superseded)
    ↓
DEC-SDM-FRD-0000042 (superseded)
    ↓
DEC-SDM-FRD-0000081 (accepted) — current

DEC-SDM-FRD-0000081:

{
  "lifecycle": {
    "state": "accepted",
    "supersedes": "DEC-SDM-FRD-0000042"
  },
  "supersession_chain": ["DEC-SDM-FRD-0000010", "DEC-SDM-FRD-0000042"]
}

When to Supersede vs. Update

Scenario Action
Typo in rationale ✏️ Edit and increment version
Add missing link ✏️ Edit without version increment
Change outcome 🔄 Supersede with new decision
Change risk level 🔄 Supersede with new decision
Reverse decision 🔄 Supersede with new decision

Rule of thumb: If it changes what was decided or why, supersede. If it's just clarification, update.

Expiration

Purpose

Some decisions and risk acceptances have time limits: - Temporary workarounds - Trial periods - Time-boxed experiments - Compliance waivers

Expiration Field

{
  "timestamps": {
    "created_at": "2026-02-01T00:00:00Z",
    "accepted_at": "2026-02-01T00:00:00Z",
    "expires_at": "2026-08-01T00:00:00Z"
  }
}

Handling Expiration

When expires_at is in the past:

  1. Validator behavior:
  2. Light preset: warn
  3. Standard preset: warn
  4. Regulated preset: block

  5. Team action:

  6. Review the decision/risk
  7. Either:
    • Extend expiration (update expires_at)
    • Make permanent (remove expires_at)
    • Supersede with new decision
    • Mark as expired (for risks)

Expiration Notifications

Optional: Create automation to notify teams of upcoming expirations:

# Example: Find decisions expiring in next 30 days
jq -r 'select(.timestamps.expires_at and 
  (.timestamps.expires_at | fromdateiso8601) < (now + 30*24*60*60)) | 
  .id' provenance/decisions/*/decision.json

Artifact-Specific Lifecycles

Decision Lifecycle Details

Draft State: - Use for exploring options - AI assistants create drafts automatically - Can be freely edited - Not enforced by validation

Proposed State: - Submitted for review - Minor edits allowed (typos, clarifications) - Substantive changes → back to draft - Reviewers provide feedback

Accepted State: - Approval granted - No longer editable - Active and enforced - Can only be superseded

Best Practices: - Keep decisions in draft until implementation starts - Move to proposed when PR is ready - Accept only after human approval - Supersede if decision changes after acceptance

Specification Lifecycle Details

Draft State: - Requirements gathering - Stakeholder input - Can change freely

Review State: - Ready for approval - Stakeholders confirm requirements - Minor adjustments allowed

Approved State: - Ready for implementation - No changes without new spec - Linked to implementing decision

Implemented State: - Code deployed to production - Terminal state - Serves as historical record

Best Practices: - Create spec before starting work - Move to review when complete - Approve before significant implementation - Mark implemented when deployed

Risk Acceptance Lifecycle Details

Active State: - Risk is currently accepted - Mitigations are in place - Monitor regularly - Update mitigations as needed

Expired State: - Acceptance period ended - Requires review - Either renew or mitigate

Mitigated State: - Risk eliminated - Successful outcome - Document lessons learned

Best Practices: - Set expiration dates for all non-permanent risks - Review active risks monthly - Document mitigation strategies - Link to implementing decisions

Mistake Record Lifecycle Details

Open State: - Incident documented - Root cause identified - Prevention rule drafted

Mitigated State: - Guardrails in place - Enforcement active - Monitoring impact

Closed State: - Fully resolved - No recurrence - Lessons captured

Best Practices: - Create mistake records for all significant incidents - Define clear prevention rules - Link to enforcement policy - Review quarterly for effectiveness

Best Practices

1. Start in Draft

Always create new artifacts in draft state:

{
  "lifecycle": {
    "state": "draft"
  },
  "timestamps": {
    "created_at": "2026-02-12T10:00:00Z"
  }
}

2. Update Timestamps

Set timestamps when changing states:

{
  "lifecycle": {
    "state": "accepted"
  },
  "timestamps": {
    "created_at": "2026-02-12T10:00:00Z",
    "accepted_at": "2026-02-14T15:30:00Z"
  }
}

3. Record Actors

Track who made state transitions:

{
  "lifecycle": {
    "state": "accepted"
  },
  "actors": {
    "author": "user:alice",
    "approver": "user:bob"
  }
}

4. Use Supersession Chains

When superseding, maintain full chain:

{
  "lifecycle": {
    "supersedes": "DEC-SDM-FRD-0000042"
  },
  "supersession_chain": ["DEC-SDM-FRD-0000010", "DEC-SDM-FRD-0000042"],
  "rationale": "Updated authentication approach based on new security requirements. Previous decisions (DEC-SDM-FRD-0000010, DEC-SDM-FRD-0000042) are superseded."
}

5. Document State Changes

In decision.md, document major state changes:

## Version History

### Version 2 (2026-02-14)
- **State Change:** draft → accepted
- **Reason:** Team approved GraphQL migration approach
- **Approver:** @bob

### Version 1 (2026-02-12)
- **Created:** Initial draft
- **Author:** @alice

6. Handle Expiration Proactively

For expiring decisions:

{
  "timestamps": {
    "expires_at": "2026-06-01T00:00:00Z"
  },
  "expiration_note": "Temporary workaround for payment provider migration. Review before June 1, 2026."
}

Examples

Example 1: Decision Evolution

Initial Draft:

{
  "id": "DEC-SDM-FRD-0000042",
  "version": 1,
  "lifecycle": {
    "state": "draft"
  },
  "timestamps": {
    "created_at": "2026-02-10T10:00:00Z"
  }
}

After Review:

{
  "id": "DEC-SDM-FRD-0000042",
  "version": 2,
  "lifecycle": {
    "state": "proposed"
  },
  "timestamps": {
    "created_at": "2026-02-10T10:00:00Z",
    "updated_at": "2026-02-12T14:30:00Z"
  }
}

After Acceptance:

{
  "id": "DEC-SDM-FRD-0000042",
  "version": 2,
  "lifecycle": {
    "state": "accepted"
  },
  "timestamps": {
    "created_at": "2026-02-10T10:00:00Z",
    "accepted_at": "2026-02-13T09:15:00Z",
    "updated_at": "2026-02-12T14:30:00Z"
  },
  "actors": {
    "author": "user:alice",
    "approver": "user:bob"
  }
}

Example 2: Supersession

Old Decision Marked as Superseded:

{
  "id": "DEC-SDM-FRD-0000010",
  "title": "Use JWT for authentication",
  "version": 1,
  "lifecycle": {
    "state": "superseded",
    "superseded_by": "DEC-SDM-FRD-0000042"
  },
  "timestamps": {
    "created_at": "2025-06-01T10:00:00Z",
    "accepted_at": "2025-06-05T14:00:00Z",
    "superseded_at": "2026-02-13T09:15:00Z"
  }
}

New Decision:

{
  "id": "DEC-SDM-FRD-0000042",
  "title": "Migrate from JWT to OAuth2 with session tokens",
  "version": 1,
  "lifecycle": {
    "state": "accepted",
    "supersedes": "DEC-SDM-FRD-0000010"
  },
  "timestamps": {
    "created_at": "2026-02-10T10:00:00Z",
    "accepted_at": "2026-02-13T09:15:00Z"
  },
  "rationale": "OAuth2 provides better security and refresh token support. Supersedes DEC-SDM-FRD-0000010 which used simpler JWT approach."
}

Example 3: Risk Expiration

Active Risk with Expiration:

{
  "ra_id": "RA-000015",
  "status": "active",
  "timestamps": {
    "created_at": "2026-02-01T00:00:00Z",
    "expires_at": "2026-05-01T00:00:00Z"
  },
  "risk_statement": "Temporary use of deprecated API until migration complete",
  "acceptance": {
    "accepted_by": "team-lead",
    "accepted_at": "2026-02-01T00:00:00Z",
    "expires_at": "2026-05-01T00:00:00Z",
    "reason": "Migration in progress, target completion April 2026"
  }
}

After Expiration (needs review):

{
  "ra_id": "RA-000015",
  "status": "expired",
  "timestamps": {
    "created_at": "2026-02-01T00:00:00Z",
    "expires_at": "2026-05-01T00:00:00Z",
    "expired_at": "2026-05-01T00:00:00Z"
  },
  "review_note": "Migration delayed, need to extend acceptance or expedite migration"
}

Example 4: Mistake Record Lifecycle

Open Mistake:

{
  "mr_id": "MR-000003",
  "status": "open",
  "timestamps": {
    "created_at": "2026-02-12T10:00:00Z"
  },
  "root_cause": {
    "summary": "Missing input validation allowed SQL injection"
  },
  "prevent_rule": {
    "rule_id": "PRV-MR-000003-validate-all-inputs",
    "statement": "All user inputs must be validated and sanitized before database queries"
  }
}

After Fix:

{
  "mr_id": "MR-000003",
  "status": "mitigated",
  "timestamps": {
    "created_at": "2026-02-12T10:00:00Z",
    "mitigated_at": "2026-02-14T15:00:00Z"
  },
  "fix": {
    "pr": "https://github.com/org/repo/pull/456",
    "commit": "abc123",
    "summary": "Added input validation library and updated all query builders"
  },
  "enforcement": [
    {
      "kind": "linter",
      "ref": "eslint-plugin-security",
      "must_exist": true
    }
  ]
}

Fully Resolved:

{
  "mr_id": "MR-000003",
  "status": "closed",
  "timestamps": {
    "created_at": "2026-02-12T10:00:00Z",
    "mitigated_at": "2026-02-14T15:00:00Z",
    "closed_at": "2026-03-01T10:00:00Z"
  },
  "closure_note": "Validation in place for 2 weeks, no recurrence, enforcement automated"
}

Validation Requirements

Validators SHOULD check:

  1. Valid States:
  2. lifecycle.state is one of the defined states for the artifact type

  3. Timestamp Consistency:

  4. created_ataccepted_atupdated_at
  5. expires_at (if present) > accepted_at

  6. Supersession Integrity:

  7. If supersedes is present, referenced artifact exists
  8. If superseded_by is present, that artifact references this one

  9. Terminal States:

  10. Artifacts in terminal states cannot transition further
  11. Terminal artifacts should not be edited

  12. Expiration Warnings:

  13. Warn or block if expires_at is past and state is still active/accepted

Next: Implementation Guides - How to use ProvenanceCode
See Also: Decision Evidence Objects (DEO) - Decision format details