Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.

ClassMeaningRequired handling
Compatible additionExisting clients keep working without recompilation or behavior change.Add tests or generated-code drift evidence. Update docs when semantics matter.
Compatible tighteningExisting 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 deprecationOld 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 changeExisting 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-onlyNot 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.