# ABI Evolution Policy

This policy governs externally visible capOS ABIs:

- Cap'n Proto schema in `schema/capos.capnp`.
- Generated schema bindings checked by `make generated-code-check`.
- Ring and bootstrap ABI constants and layouts in `capos-config/src/ring.rs`,
  `capos-config/src/capset.rs`, and `capos-abi/src/lib.rs`.
- Debug/log formats only when a document explicitly declares them stable.

The current project is still a research tree, not a released platform with a
public compatibility promise. Even so, schema and ring changes must follow this
policy before external clients, host tools, or out-of-tree runtimes depend on
them.

## Design Grounding

This policy is grounded in current capOS docs and the checked-in prior-art
notes that apply to schema and transport evolution:

- `docs/architecture/capability-ring.md` for the implemented process-wide ring,
  fixed 64-byte `CapSqe`, fixed 32-byte `CapCqe`, opcode boundary, and current
  completion semantics.
- `docs/proposals/ring-v2-smp-proposal.md` for the undecided future
  per-thread-ring version-negotiation shape.
- `docs/proposals/error-handling-proposal.md` for the transport/application
  error split and unsupported-operation behavior.
- `docs/trusted-build-inputs.md` for generated-code drift checks and pinned
  Cap'n Proto tooling.
- `docs/design-risks-register.md` for the prior open ABI compatibility and
  Ring v2 compatibility questions.
- `docs/research/capnp-error-handling.md` for Cap'n Proto exception and schema
  error-model precedent. Other files in `docs/research/` were listed during
  review; no OS scheduling, filesystem, networking, or hardware prior-art file
  directly changes this schema/ring ABI policy.

## Compatibility Classes

Every ABI change must name one class in its task, review, or commit message.

| Class | Meaning | Required handling |
| --- | --- | --- |
| Compatible addition | Existing clients keep working without recompilation or behavior change. | Add tests or generated-code drift evidence. Update docs when semantics matter. |
| Compatible tightening | Existing malformed or previously unspecified inputs fail earlier or more specifically. | Document the rejected shape and expected error. Add hostile coverage when reachable from userspace. |
| Soft deprecation | Old shape still works, but new callers should stop using it. | Mark the field/method/opcode as deprecated in docs and keep a replacement path live through the deprecation window. |
| Breaking change | Existing valid clients can fail, observe different semantics, or require regenerated code. | Requires a proposal or backlog plan, migration notes, compatibility proof or explicit break decision, and `REVIEW_FINDINGS.md`/risk updates when relevant. |
| Internal-only | Not visible outside one crate or generated artifact and not serialized, mapped, or invoked across a boundary. | Normal code review; do not label serialized or mapped data as internal-only. |

## Cap'n Proto Schema Rules

Schema interface IDs, method ordinals, struct field ordinals, enum discriminants,
union tags, and named constants are stable once checked in.

Allowed compatible changes:

- Add a new field with a new ordinal and a default value that old readers can
  safely ignore.
- Add a new method with a new ordinal when old clients do not need it.
- Add a new result union arm only when old clients already treat unknown or
  unsupported domain outcomes as a controlled failure.
- Add a new interface or struct with a fresh ID/name.
- Add documentation that narrows previously undocumented behavior without
  changing wire compatibility.

Disallowed without a breaking-change plan:

- Reuse a removed field, method, enum, or union ordinal.
- Change the meaning, type, units, authority, or lifetime of an existing field.
- Rename a schema item when generated code or logs expose the old name as a
  public integration surface.
- Make an optional/defaulted field mandatory for existing callers without a
  versioned fallback.
- Replace a schema result union with a transport error or vice versa without an
  error-layer migration note.

Removed schema space stays reserved. If a field or method is retired, leave a
comment at the old ordinal explaining why it is reserved and where the
replacement lives.

## Ring ABI Rules

The ring ABI is a fixed-layout shared-memory contract. `CapSqe`, `CapCqe`,
ring header fields, opcodes, flags, transfer descriptor layout, CQE result
codes, and fixed virtual addresses are kernel/userspace ABI.

Rules for the current process-wide ring:

- Do not change the size, alignment, byte order, or meaning of an existing ring
  struct field without a breaking-change plan.
- Preserve objective layout checks for current ABI structs. At minimum,
  `capos-config/src/ring.rs` must keep compile-time checks for `CapSqe`,
  `CapCqe`, `CapTransferDescriptor`, endpoint caller-session metadata, endpoint
  message headers, and ring capture records. Any new negotiated ring layout must
  add equivalent checked constants for SQE size, CQE size, transfer descriptor
  size, ring header offsets, SQE/CQE array offsets, and feature/version fields.
- Do not change `SQE_ARRAY_OFFSET`, `CQE_ARRAY_OFFSET`, `SQ_ENTRIES`,
  `CQ_ENTRIES`, `RING_VADDR`, or fixed SQE/CQE sizes by arithmetic side effect.
  A change to any of those values is a layout change and must name its
  compatibility class.
- Reserved SQE fields must be rejected unless the opcode explicitly defines
  them. New meanings for reserved fields require hostile tests that old kernels
  fail closed.
- New opcodes must start as reserved or unsupported. A reserved opcode should
  return `CAP_ERR_UNSUPPORTED_OPCODE`; malformed non-reserved opcodes should
  return `CAP_ERR_INVALID_REQUEST`.
- New flags must specify whether old kernels reject them, ignore them, or treat
  them as malformed. Silent ignore is allowed only for flags that cannot carry
  authority or resource effects.
- New negative CQE result codes must be appended as new constants. Existing
  negative result codes cannot be renumbered or repurposed.
- Capability transfer descriptors must continue to reject unknown reserved bits
  until a documented transfer mode consumes them.

Ring v2 or per-thread-ring work must declare whether it is:

- a negotiated compatible extension to the current ring page;
- a new ring layout selected by boot/runtime version negotiation; or
- an intentional ABI break.

That decision belongs in the Ring v2 proposal/backlog before implementation.

## Version Negotiation

When an ABI cannot be evolved by compatible addition, introduce an explicit
version gate instead of inferring compatibility from struct size or accidental
behavior.

Acceptable gates include:

- manifest or boot-package `schemaVersion` fields;
- a future runtime boot-info field that names ring layout and feature bits;
- interface methods that return a structured unsupported-version result;
- manifest/tooling checks that reject unsupported data versions before boot.

Unsupported versions must fail closed with a stable, documented error. A client
must not need to parse debug text to distinguish "unsupported version" from
"malformed input".

## Deprecation Window

Before external consumers exist, a deprecation may be removed after the
replacement path, docs, and smokes land in `main`.

After external consumers are declared for an ABI, deprecated schema or ring
surfaces must remain for at least one full selected milestone after the
replacement is documented and tested. Removing them earlier is a breaking
change and must be called out as such.

Deprecation notes must name:

- the old field, method, opcode, flag, or constant;
- the replacement;
- the last proof target that still exercises the old shape;
- the planned removal condition.

## Review Gates

Schema or ring ABI changes must include the relevant checks:

- `make generated-code-check` for `schema/capos.capnp` changes.
- `cargo test-config` for manifest/schema validation changes.
- `cargo test-ring-loom` for ring queue protocol changes.
- Compile-time layout assertions and host tests for ring struct size, alignment,
  offsets, entry counts, and fixed virtual addresses when a ring layout changes.
- `cargo test-lib` for CapTable/capability transfer semantics.
- A focused QEMU smoke when a userspace-visible behavior changes.
- `make docs` for policy or manual changes.

Reviewers should reject ABI changes that lack a compatibility class, migration
notes for breaking behavior, or an unsupported-version/error story for new
version gates.

## Current Open ABI Decisions

- Ring v2 backward compatibility remains undecided. Until it is decided, do
  not claim per-thread rings are compatible with the current process-wide ring.
- Production release reproducibility remains separate from ABI compatibility.
  Final ISO, manifest, and embedded ELF checksums are tracked in
  `docs/trusted-build-inputs.md` and `REVIEW_FINDINGS.md`.
