# ADR-0006: Versioning and Release Strategy

**Status**: Superseded **Date**: 2026-01-10 **Authors**: Development Team
**Reviewers**: DevOps Team, Architecture Team **Supersedes**: N/A **Superseded
by**: ADR-0073 (the changesets implementation plan below was never executed;
`nx release` is the mechanism actually wired into `release.yml` and owns
versioning/publishing)

## Context and Problem Statement

The Oshun monorepo requires a unified versioning and release strategy to manage
package versions, generate changelogs, and publish packages across all domains.
Currently:

**Lilith (Current State)**:

- No automated versioning or release process
- Manual version bumps in package.json
- No changelog generation
- Version: 0.1.0 (static)

**Yemaya (Current State)**:

- Uses Changesets for versioning (`@changesets/cli`)
- Configured with GitHub changelog generation
- Scripts: `version-packages`, `release`
- Access: restricted (private packages)
- Automated internal dependency updates

We need to standardize on a versioning/release approach that:

1. Works well with the Nx monorepo structure
2. Supports independent and synchronized versioning
3. Generates meaningful changelogs
4. Integrates with CI/CD for automated releases
5. Handles both public npm packages and private deployable services

The main options are:

- **Changesets**: Community-driven, battle-tested approach (already used by
  Yemaya)
- **Nx Release**: Nx-native release management (newer, integrated with Nx)

## Decision Drivers

- **Nx Integration**: Seamless integration with Nx workspace
- **Changelog Quality**: Meaningful, well-formatted changelogs
- **Independent Versioning**: Ability to version packages independently
- **Fixed Versioning**: Option to lock certain packages to same version
- **Automation**: CI/CD integration for automated releases
- **Developer Experience**: Simple workflow for contributors
- **Existing Investment**: Yemaya's Changesets configuration
- **Ecosystem Support**: npm/GitHub integration, community adoption
- **Flexibility**: Support for various release strategies

## Considered Options

### Option 1: Changesets (Recommended)

**Description**: Use Changesets for version management and changelog generation.
Changesets is a popular approach used by Babel, Atlassian, and many other
monorepos.

**Workflow**:

```
Developer creates PR
       │
       ▼
Run `pnpm changeset` to create changeset file
       │
       ▼
PR merged with changeset
       │
       ▼
CI runs `changeset version` (bumps versions, updates changelogs)
       │
       ▼
Version PR created/updated
       │
       ▼
Version PR merged
       │
       ▼
CI runs `changeset publish` (publishes to npm)
```

**Pros**:

- ✅ **Already In Use**: Yemaya has working Changesets configuration
- ✅ **Battle-Tested**: Used by major projects (Babel, Atlassian, Pnpm itself)
- ✅ **Flexible**: Supports independent, fixed, and linked versioning
- ✅ **Rich Ecosystem**: Multiple changelog formatters, bot integrations
- ✅ **Explicit Intent**: Developers explicitly declare change significance
- ✅ **Human-Readable Changelogs**: Generates quality CHANGELOG.md
- ✅ **Works with pnpm**: First-class pnpm workspace support
- ✅ **GitHub Integration**: Changeset bot, PR changelogs

**Cons**:

- ❌ **Learning Curve**: Developers need to learn `pnpm changeset` workflow
- ❌ **Extra Step**: Requires changeset creation in each PR
- ❌ **Not Nx-Native**: Separate tool from Nx ecosystem
- ❌ **Two-PR Process**: Version bump is a separate PR

**Cost**: Low - minimal setup, leverage existing Yemaya config **Risk**: Low -
proven at scale **Effort**: 1-2 days to configure for full monorepo

### Option 2: Nx Release

**Description**: Use Nx's built-in release management (`nx release`). Nx Release
is newer but designed specifically for Nx workspaces.

**Workflow**:

```
Developer creates PR with conventional commit
       │
       ▼
PR merged
       │
       ▼
CI runs `nx release` (analyzes commits, bumps versions)
       │
       ▼
Git tags created, changelogs updated
       │
       ▼
Packages published to npm
```

**Pros**:

- ✅ **Nx-Native**: Integrated with Nx, uses project graph
- ✅ **Conventional Commits**: Automatic version bumps from commit messages
- ✅ **Single Command**: `nx release` handles everything
- ✅ **Project Awareness**: Understands Nx project dependencies
- ✅ **Git Integration**: Automatic tagging and changelog

**Cons**:

- ❌ **Newer Tool**: Less battle-tested than Changesets
- ❌ **Conventional Commit Enforcement**: Requires strict commit conventions
- ❌ **Less Flexible**: Fewer options for changelog customization
- ❌ **Would Discard**: Yemaya's existing Changesets setup
- ❌ **Learning New Tool**: Team needs to learn Nx release specifics

**Cost**: Medium - need to migrate from Changesets **Risk**: Medium - less
proven than Changesets **Effort**: 3-4 days for setup and migration

### Option 3: Manual/Script-Based

**Description**: Custom scripts for version management without a dedicated tool.

**Pros**:

- ✅ **Full Control**: Complete flexibility
- ✅ **No Dependencies**: No external tools

**Cons**:

- ❌ **Reinventing Wheel**: Solved problem, no need for custom solution
- ❌ **Maintenance Burden**: Custom code to maintain
- ❌ **Error Prone**: Manual processes are error-prone
- ❌ **No Ecosystem**: No bot integrations, changelog generation

**Cost**: High - significant custom development **Risk**: High - maintenance
burden, errors **Effort**: 2+ weeks for complete solution

## Decision Outcome

**Chosen option**: Option 1 - Changesets

**Justification**:

Changesets is the optimal choice for the Oshun monorepo because:

1. **Existing Investment**: Yemaya already has a working Changesets
   configuration. This provides a proven foundation that can be extended to the
   full monorepo.

2. **Maturity**: Changesets is battle-tested by major projects including Babel,
   Atlassian, pnpm itself, and hundreds of open-source monorepos. Nx Release,
   while promising, is newer and less proven.

3. **Explicit Intent**: The changeset workflow requires developers to explicitly
   declare the significance of their changes (major/minor/patch). This produces
   higher-quality changelogs than automated commit message parsing.

4. **Flexibility**: Changesets supports multiple versioning strategies:
   - Independent: Each package versioned independently
   - Fixed: Groups of packages locked to same version
   - Linked: Packages always bump together but can have different versions

5. **pnpm Integration**: Changesets has first-class support for pnpm workspaces,
   which aligns with ADR-0002.

6. **Ecosystem**: Rich ecosystem of tools (changeset bot, changelog formatters,
   GitHub Action) that would take significant effort to replicate with Nx
   Release.

**Nx Compatibility Note**: Changesets works well alongside Nx. Nx handles task
orchestration (build, test, lint), while Changesets handles versioning and
publishing. This separation of concerns is clean and well-established.

**Implementation Plan**:

1. **Phase 1: Root Configuration** (Day 1)
   - Create `.changeset/config.json` at oshun root
   - Configure changelog format (GitHub-linked)
   - Define fixed/linked package groups
   - Add changeset scripts to root package.json

2. **Phase 2: Package Groups** (Day 1)
   - Define fixed groups for tightly-coupled packages
   - Configure independent versioning for standalone packages
   - Set up internal dependency update rules

3. **Phase 3: CI/CD Integration** (Day 2)
   - Configure GitHub Actions for version PR creation
   - Set up automated npm publishing
   - Configure changeset bot for PR status

4. **Phase 4: Documentation** (Day 2)
   - Create contributor guide for changesets
   - Document release process
   - Add PR template with changeset reminder

**Success Metrics**:

- All package releases tracked via changesets
- Changelogs generated for all releases
- Zero manual version bumps
- Release process takes < 5 minutes from merge to publish
- Contributors successfully create changesets in 95% of PRs

**Review Schedule**: 60 days post-implementation

## Implementation Details

### Technical Specifications

**Root Changeset Configuration**:

```json
// .changeset/config.json
{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": ["@changesets/changelog-github", { "repo": "oshun/oshun" }],
  "commit": false,
  "fixed": [
    // Packages that always share the same version
    ["@oshun/types", "@oshun/errors", "@oshun/config"],
    ["@oshun/proto", "@oshun/openapi"]
  ],
  "linked": [
    // Packages that bump together but can have different versions
    ["@oshun/auth", "@oshun/auth-client"],
    ["@oshun/events", "@oshun/events-client"]
  ],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": [
    // Private packages that don't get published
    "@oshun/tools-*",
    "@lilith/service-*",
    "@yemaya/app-*"
  ],
  "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
    "onlyUpdatePeerDependentsWhenOutOfRange": true
  }
}
```

**Root Package.json Scripts**:

```json
{
  "scripts": {
    "changeset": "changeset",
    "changeset:add": "changeset add",
    "changeset:status": "changeset status",
    "version": "changeset version && pnpm install --lockfile-only",
    "release": "pnpm build && changeset publish",
    "release:dry": "changeset publish --dry-run"
  }
}
```

**Package Groups Explanation**:

```
Fixed Groups (same version number):
┌────────────────────────────────────────┐
│  @oshun/types     v1.0.0               │
│  @oshun/errors    v1.0.0  ──► Always   │
│  @oshun/config    v1.0.0      same     │
└────────────────────────────────────────┘

Linked Groups (bump together, different versions):
┌────────────────────────────────────────┐
│  @oshun/auth          v2.3.0           │
│  @oshun/auth-client   v1.5.0  ──► Bump │
│                            together    │
└────────────────────────────────────────┘

Independent (versioned separately):
┌──────────────────┐  ┌──────────────────┐
│  @oshun/isis     │  │  @oshun/sophia   │
│  v3.2.1          │  │  v1.0.5          │
└──────────────────┘  └──────────────────┘
```

**GitHub Action for Version PR**:

```yaml
# .github/workflows/release.yml
name: Release

on:
  push:
    branches:
      - main

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v3
        with:
          version: 10

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install Dependencies
        run: pnpm install

      - name: Create Release Pull Request or Publish
        id: changesets
        uses: changesets/action@v1
        with:
          version: pnpm run version
          publish: pnpm run release
          title: 'chore: release packages'
          commit: 'chore: release packages'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```

**Changeset Bot Configuration**:

```yaml
# .github/changeset-bot.yml
# Automatically comments on PRs missing changesets
sinceMajor: true
```

**PR Template Addition**:

```markdown
<!-- .github/pull_request_template.md -->

## Description

<!-- Describe your changes -->

## Checklist

- [ ] I have added a changeset (`pnpm changeset`) if this PR includes
      user-facing changes
- [ ] Tests pass locally
- [ ] Documentation updated if needed

## Changeset

<!--
If this PR affects published packages, run:
  pnpm changeset

Then select:
- Which packages are affected
- Semver bump type (major/minor/patch)
- Summary of changes for changelog
-->
```

### Versioning Strategy by Package Type

| Package Type          | Strategy    | Example                                                              |
| --------------------- | ----------- | -------------------------------------------------------------------- |
| **Shared Foundation** | Fixed       | @oshun/types, @oshun/errors, @oshun/config - always same version     |
| **Contracts**         | Fixed       | @oshun/proto, @oshun/openapi - breaking changes affect all consumers |
| **Domain Libraries**  | Independent | @oshun/isis-_, @oshun/sophia-_ - version based on their own changes  |
| **Client SDKs**       | Linked      | @oshun/auth + @oshun/auth-client - bump together                     |
| **Internal Tools**    | Ignored     | @oshun/tools-\* - not published                                      |
| **Services**          | Ignored     | @lilith/service-_, @yemaya/app-_ - deployed, not published           |

### Semver Guidelines

```
MAJOR version: Breaking changes to public API
  - Removing exported functions/types
  - Changing function signatures
  - Removing fields from interfaces
  - Changing behavior in incompatible ways

MINOR version: New features, backward-compatible
  - Adding new exports
  - Adding optional fields
  - Adding new functionality
  - Deprecating (not removing) features

PATCH version: Bug fixes, backward-compatible
  - Bug fixes
  - Performance improvements
  - Documentation updates
  - Internal refactoring
```

### Changelog Format

```markdown
# @oshun/types

## 1.2.0

### Minor Changes

- feat: add AssetMetadata type for generation outputs (#123)

  Added new AssetMetadata interface that includes provenance, licensing, and
  lineage information for generated assets.

- feat: add Result<T, E> utility type (#125)

### Patch Changes

- fix: correct ProjectId branded type (#124)
- Updated dependencies
  - @oshun/errors@1.1.0
```

### Migration Strategy

**From Yemaya**:

1. Copy `.changeset/config.json` to oshun root
2. Update repo reference
3. Define package groups for new structure
4. Test with dry-run publish

**For Lilith Packages**:

1. Add to Changesets scope (remove from ignore if needed)
2. Set initial versions
3. Create initial changeset if needed

## Consequences

### Positive Consequences

- ✅ **Consistent Releases**: All packages follow same release process
- ✅ **Quality Changelogs**: Human-written, meaningful changelogs
- ✅ **Automation**: CI/CD handles version bumps and publishing
- ✅ **Flexibility**: Different strategies for different package types
- ✅ **Traceability**: Each release linked to PRs and commits
- ✅ **Proven Process**: Battle-tested workflow

### Negative Consequences

- ❌ **Extra Step**: Developers must create changesets
- ❌ **Learning Curve**: Team needs to understand changeset workflow
- ❌ **Two PRs**: Version bump is separate PR
- ❌ **Tool Dependency**: Relies on external tool

### Risks and Mitigation

| Risk                           | Probability | Impact | Mitigation Strategy                                 |
| ------------------------------ | ----------- | ------ | --------------------------------------------------- |
| Forgotten changesets           | Medium      | Low    | Changeset bot comments on PRs, PR template reminder |
| Wrong semver selection         | Medium      | Medium | PR review, documented guidelines                    |
| CI publish failures            | Low         | Medium | Dry-run before publish, manual fallback             |
| Package group misconfiguration | Low         | High   | Test in staging, careful initial setup              |

## Compliance and Security

### Security Implications

- **npm Tokens**: Stored as GitHub secrets, not in code
- **Publish Access**: Only CI can publish, not individual developers
- **Audit Trail**: All releases tracked in GitHub, npm, and changelogs
- **2FA**: npm publish protected by token, not password

### Compliance Requirements

- **Version History**: Complete changelog for each package
- **Release Tracking**: Git tags for each release
- **Reproducibility**: Lockfile ensures consistent builds

## Monitoring and Observability

### Metrics to Track

- **Release Frequency**: Releases per week/month
- **Changeset Compliance**: % of PRs with changesets
- **Publish Success Rate**: % of successful publishes
- **Time to Publish**: Time from merge to npm availability

### Alerting Strategy

- **Critical**: Publish failure, npm token expiration
- **Warning**: PR missing changeset for affected packages
- **Info**: New release published, version PR created

## Related Decisions

### Upstream Dependencies

- **ADR-0002**: pnpm (Changesets uses pnpm workspace protocol)
- **ADR-0001**: Git Consolidation (single repo for changesets)

### Downstream Impacts

- **CI/CD**: GitHub Actions for release automation
- **Contributors**: Must learn changeset workflow
- **Consumers**: Semantic versions for dependency management

## References

### External Resources

- [Changesets Documentation](https://github.com/changesets/changesets)
- [Changesets GitHub Action](https://github.com/changesets/action)
- [Semantic Versioning](https://semver.org/)
- [Changesets Bot](https://github.com/apps/changeset-bot)

### Internal Resources

- Yemaya changesets config — `yemaya/.changeset/config.json` (pre-consolidation
  source repo)
- [ADR-0002: Package Manager](./ADR-0002-package-manager-pnpm.md)

---

## Revision History

| Version | Date       | Author           | Changes         |
| ------- | ---------- | ---------------- | --------------- |
| 1.0     | 2026-01-10 | Development Team | Initial version |
