ajhahn.de
← FlashOS
Markdown 310 lines
<div align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="assets/flashos_logo_dark.png">
    <img src="assets/flashos_logo_light.png" alt="FlashOS" width="280">
  </picture>

<h1>Versioning Policy</h1>

<p><i>The contract for how FlashOS is versioned, released, supported, and retired.</i></p>

<p>
    <a href="README.md"><b>README</b></a> ·
    <a href="DOCUMENTATION.md"><b>Documentation</b></a> ·
    <a href="SETUP.md"><b>Setup</b></a> ·
    <a href="PORT.md"><b>Port</b></a> ·
    <b>Versioning</b> ·
    <a href="CHANGELOG.md"><b>Changelog</b></a> ·
    <a href="LICENSE.md"><b>License</b></a>
  </p>
</div>

---

This document is the authoritative policy for how FlashOS is
versioned, released, supported, and retired. It is the contract every
release of FlashOS honours; a breach of any clause stated with **MUST**
is a bug, not a feature.

FlashOS is, at the time of writing, **pre-stability**. The most
important thing this document does is mark that line clearly and
describe what changes — and what does not — when the project crosses
it.

Companion documents:

- [`DOCUMENTATION.md`](DOCUMENTATION.md) — the architectural overview,
  including the modules whose behaviour is named below.
- [`PORT.md`](PORT.md) — the lineage record of the Zig-to-Flash port.
- [`CHANGELOG.md`](CHANGELOG.md) — the per-release human-readable log.

The keywords **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, and
**MAY** in this document are to be interpreted as described in
[RFC 2119](https://www.rfc-editor.org/rfc/rfc2119).

## 1. Scope

This policy governs every artefact released under the
[`ajhahnde/FlashOS`](https://github.com/ajhahnde/FlashOS) GitHub
repository. It applies to every tag of the form `vMAJOR.MINOR.PATCH`,
including the pre-stability `v0.y.z` line, **with the explicit
caveats** stated in §2.1 below.

## 2. Grammar

FlashOS follows [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html)
over the surface defined in §3. Until v1.0.0, the special pre-1.0
clause of SemVer (§4) applies; see §2.1.

A release version is `vMAJOR.MINOR.PATCH` (the leading `v` is preserved
on every git tag, GitHub Release, and CHANGELOG section header)
optionally followed by a pre-release identifier as defined in §6.

| Component | Trigger |
|---|---|
| **MAJOR** | A breaking change to any item enumerated in §3 *(reserved; no MAJOR bump has been issued yet — the first MAJOR is v1.0.0, the stability-freeze release)*. |
| **MINOR** | Under pre-1.0 (§2.1): any change, including a breaking change. Under post-1.0: an additive change to the public surface — a new boot option, a new syscall, a new test-harness output line. |
| **PATCH** | A bug fix, performance improvement, documentation change, build-system fix, or internal refactor that does not alter the public surface. PATCH is **always** backwards-compatible, including pre-1.0. |

A change that fits more than one bucket MUST take the most disruptive
applicable bucket.

### 2.1 Pre-v1.0.0 (current line)

Under SemVer 2.0.0 §4 a major version of zero is for initial
development and "anything MAY change at any time". FlashOS adopts the
literal reading of that clause for its `v0.y.z` line:

- A **MINOR** bump (`v0.y.z``v0.(y+1).0`) MAY include a breaking
  change to the surface enumerated in §3. Any such breaking change
  MUST be called out in the CHANGELOG entry (under `### Changed`, with the
  migration path) per the project's no-silent-breaking-changes rule.
- A **PATCH** bump (`v0.y.z``v0.y.(z+1)`) MUST NOT include a
  breaking change to the surface enumerated in §3. PATCH is
  backwards-compatible even pre-1.0.
- **No support guarantee** is made for any pre-v1.0.0 release. Only
  the latest pre-v1.0.0 tag receives any further attention; once
  v1.0.0 ships, the entire pre-1.0 line enters the **Archived** tier
  of §8 permanently.

### 2.2 Post-v1.0.0 (future)

From v1.0.0 onward the standard SemVer interpretation applies without
the §2.1 carve-out: a breaking change MUST take a MAJOR bump. Hardware
support tiers (§4) and deprecation procedure (§9) become enforceable.

## 3. Public surface

The **frozen public surface** of FlashOS, once v1.0.0 ships, is the
union of:

- **Boot contract.** The MMIO addresses, the kernel-load address,
  and the conventions documented in [`DOCUMENTATION.md`](DOCUMENTATION.md)
  §Boot path: the calling state from firmware (`ARM_LOCAL`, `_start`
  entry, EL2/EL1 transition expectations) and the serial console
  baud / framing for the platforms in Tier 1.
- **Serial console output format.** The kernel banner, the
  in-kernel `[TEST]` / `[PASS]` / `[FAIL]` test-harness tally lines,
  and the panic-on-fault format documented in [`DOCUMENTATION.md`](DOCUMENTATION.md).
  A regression in these lines breaks the boot-replay tooling and
  third-party harnesses that key off them.
- **Syscall numbers and ABI.** The mapping of syscall numbers to
  syscall entry points and the calling convention for each. Once
  enumerated under v1.0.0 in [`DOCUMENTATION.md`](DOCUMENTATION.md),
  removal or renumbering is a MAJOR change.
- **Build-system entry points.** The top-level `build.zig` targets
  the [`SETUP.md`](SETUP.md) names (`zig build`, `zig build qemu`,
  `zig build pi`, `zig build test`). Adding a target is a MINOR;
  removing or renaming a target is a MAJOR.
- **Hardware support matrix.** The OS×board tiers defined in §4.

The following are **explicitly NOT** part of the public surface and
MAY change in any release:

- The kernel's internal source layout — scheduler internals, page-
  table layout, exception-vector implementation, driver-internal
  function signatures, memory-manager free-list shape.
- The boot-asset bundle layout under `assets/` — the demo GIF format,
  the screenlog encoding, the VHS tape script.
- The CI workflow file shapes under `.github/workflows/`.
- The test-harness internals — only the per-line output format under
  §3 is frozen; the order, count, and identity of individual tests
  MAY change in any release.

## 4. Hardware support tiers

FlashOS commits explicitly to which hardware it intends to run on.
The model follows the Mesa driver tier convention.

| Tier | Promise | Boards |
|---|---|---|
| **Tier 1 — guaranteed** | Every tagged release MUST boot to the kernel banner and pass the in-kernel test harness on this hardware. CI MUST exercise the boot path for every PR. A regression here is a release blocker. | Raspberry Pi 4 Model B (BCM2711, AArch64, 4-core); QEMU `aarch64` `-M virt` (the version pinned in [`SETUP.md`](SETUP.md)). |
| **Tier 2 — best-effort** | Building, booting, and the test harness SHOULD work, but no PR is blocked on a regression here and no PATCH is issued for a Tier-2-only defect. | Other Raspberry Pi models; QEMU `aarch64` boards other than `virt`. |
| **Tier 3 — experimental** | Actively being worked on. May break in any release without notice or CHANGELOG entry. | Anything not in Tier 1 or Tier 2. |

A board MUST NOT be promoted from Tier 2 to Tier 1 in a PATCH; the
promotion is a feature-add and goes in a MINOR. A demotion from Tier 1
to Tier 2 — or removal of the board entirely — is a **breaking
change** and MUST take a MAJOR bump once the project is post-1.0.

## 5. Release cadence

| Bump | Target cadence | Hard rule |
|---|---|---|
| **PATCH** | As-ready. | Never blocked on a feature. A confirmed defect on Tier-1 hardware (§4) SHOULD reach a tagged PATCH within **14 days**. |
| **MINOR** | As-ready pre-1.0; soft target of one per month post-1.0. | Each MINOR MUST boot cleanly on every Tier-1 board (§4) under the CI matrix. |
| **MAJOR** | As-needed (post-1.0 only). A MAJOR MUST be announced under `## [Unreleased]` in [`CHANGELOG.md`](CHANGELOG.md) and on the GitHub Releases page **at least 60 days** before its tag. The announcement enumerates every breaking change. | An RC train (§6) MUST precede the GA tag of any post-1.0 MAJOR. |

The §1.0.0 stability-freeze release is the **single exception** to the
60-day announcement window: v1.0.0 may be cut from the last
pre-v1.0.0 release without a fresh 60-day signal, because every
pre-v1.0.0 release is itself a signal that v1.0.0 is approaching.

## 6. Pre-releases

A pre-release tag carries the suffix `-rc.N` (release candidate; `N`
is a strictly increasing non-negative integer starting at `0`).
`-alpha` and `-beta` pre-release identifiers are **not** used.

- The first `-rc.N` of the project MUST be cut against `v1.0.0` once
  the surface defined in §3 is judged ready to freeze.
- Post-1.0, an RC MUST be used for every MAJOR. It SHOULD be used for
  any MINOR that materially changes default behaviour or boot output.
- An RC MUST be published to GitHub Releases marked as **pre-release**.
- The RC train ends when the corresponding GA tag is cut from the same
  commit as the last RC, with no behaviour change between the two.

## 7. Branching and tagging

- The default branch is `main`. Every release tag is reachable from
  `main` at the moment of tagging.
- Pre-v1.0.0: only `main` exists. Post-v1.0.0, a MAJOR line that is
  still under any support tier (§8) MUST have a `stable-X.Y` branch
  where its PATCH fixes are prepared. The branch is force-push-
  protected.
- A release tag MUST match the regex `^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$`.
- A release tag MUST be annotated (`git tag -a`). GPG-signed tags are
  the **target**; the signing key fingerprint will be published in the
  release that introduces them.
- A release tag MUST NOT be deleted, force-moved, or re-pointed. A
  defective release is handled by an immediate follow-up PATCH (the
  same procedure §10 of [`eeco`'s VERSIONING.md`](https://github.com/ajhahnde/eeco/blob/main/VERSIONING.md)
  formalises for that project; FlashOS will adopt the equivalent yank
  procedure with the v1.0.0 freeze).

## 8. Support windows

Under the §2.1 pre-1.0 clause, **no support tier exists yet**: only
the latest pre-v1.0.0 tag is the supported release. There is no
backporting, no security maintenance window, no LTS.

The support model that takes effect at v1.0.0 is:

| Tier | Receives | Applies to | Ends |
|---|---|---|---|
| **Active** | Every bug fix, every applicable feature, every security fix. | The **current MAJOR**. | When the next MAJOR's GA ships. |
| **Maintenance** | **Security fixes** and **critical bug fixes** (boot regression on Tier-1 hardware, syscall-ABI regression, panic-format regression that breaks the test harness). No feature backports. | The **previous MAJOR**. | **6 months after the next MAJOR's GA tag.** |
| **Archived** | Nothing. | Every MAJOR older than Maintenance, and the entire pre-v1.0.0 line. | Permanent. |

The trailing-maintenance window of 6 months is deliberately shorter
than eeco's 12 months because FlashOS is a research kernel: the
expected user is running source-built tags against bare metal or QEMU
and can rebuild from any commit if needed. The window is intended to
buy migration time, not multi-year stability — an **LTS** tier will
be designated only if and when the user surface justifies it; a future
amendment to this document MAY introduce one with an explicit start
tag and end date.

## 9. Deprecation policy

Under §2.1 pre-1.0, no deprecation procedure applies — a breaking
change in a pre-1.0 MINOR is documented in the CHANGELOG entry (under
`### Changed`) and that is the entire policy.

The deprecation procedure that takes effect at v1.0.0:

### 9.1 Announce

- A `### Deprecated` section is added to the next release's CHANGELOG
  entry, naming each deprecated item, the replacement (if any), and
  the earliest version in which the item MAY be removed.
- The deprecated item, where it has a runtime presence (a syscall, a
  boot option, a `[TEST]`-line tag), SHOULD emit a one-line notice on
  the serial console at first use per boot beginning with
  `flashos: DEPRECATED: ` and naming the replacement.
- [`DOCUMENTATION.md`](DOCUMENTATION.md) MUST mark the item with a
  `*(deprecated since vX.Y.0; removed in vM.0.0 or later)*` annotation.

### 9.2 Wait

The minimum window between the deprecation MINOR and the removal
release MUST be the longer of:

- **2 MINOR releases**, and
- **6 months** of wall-clock time.

### 9.3 Remove

- Removal MUST happen in a MAJOR. A PATCH or MINOR MUST NOT remove a
  deprecated frozen-surface item.
- The release that removes the item MUST list it in the `### Removed`
  CHANGELOG section for the release.

## 10. Security release policy

Until v1.0.0, FlashOS publishes no separate `SECURITY.md` — security-
relevant defects on Tier-1 hardware are treated as ordinary bugs and
fixed in the next PATCH. A public GitHub issue is the reporting
channel.

From v1.0.0:

- A `SECURITY.md` MUST exist at the repository root, modelled on the
  GitHub Private Vulnerability Reporting flow.
- The default embargo window between report and tagged fix is
  **90 days**, in line with Project Zero industry practice. Hardware-
  specific issues that require a Tier-1 board firmware coordination
  MAY extend to **120 days** by negotiation on the advisory thread.
- A security PATCH MUST be issued to every MAJOR line currently in
  **Active** or **Maintenance** tier (§8) that carries the defect.
- The CHANGELOG entry for a security PATCH MUST link the advisory
  (GitHub Security Advisory; a CVE identifier when one is assigned).

## 11. Roadmap signalling

A breaking change MUST NOT be a surprise.

- Pre-v1.0.0: each pre-1.0 release that contains a breaking change
  MUST call it out under `### Changed` in the CHANGELOG entry,
  describing the migration path inline in that entry.
- Post-v1.0.0: every breaking change planned for the next MAJOR MUST
  be listed under `## [Unreleased]` in [`CHANGELOG.md`](CHANGELOG.md)
  **before** the first RC of that MAJOR. The list is updated whenever
  a candidate breaking change is added or removed; the diff itself is
  the public signal.

## 12. Governance

FlashOS is currently maintained by a single operator. A release MUST
be cut by:

1. A commit on `main` (or on a `stable-X.Y` branch for a post-1.0
   Maintenance PATCH).
2. Verifying that the in-kernel test harness passes for every Tier-1
   board (§4) — CI MUST be green and a real Pi 4B boot SHOULD be
   captured in `screenlog.0` when the change touches the boot path,
   the early-init sequence, or any console-output convention.
3. Adding the release section to [`CHANGELOG.md`](CHANGELOG.md),
   including any breaking-change migration notes.
4. Tagging the commit `vX.Y.Z[-rc.N]` and pushing the tag.

This policy MAY be amended; an amendment MUST itself follow the
versioning of this repository — a substantive change to the contract
is announced under `## [Unreleased]` and lands together with the next
release. A clarifying edit (typo, link rot, formatting) MAY land at
any time.

---

[← Prev: Port](PORT.md) · [Next: Changelog →](CHANGELOG.md)