Version-owned implementations
gh_common::harness_catalog! generates harness identity, enumeration, discovery
metadata, and the config implementation registrations. Add a catalog entry and
an adapters/<harness>/ family module containing the interval registrations,
shared writer and inspection code, named atomic operation sets, and an initial
version specification. Close the previous breaking-generation interval when
adding a new version.
Contract ownership
Keep each fact in one layer. Public summaries may be derived from a lower layer, but contributors must not author the same compatibility rule in two registries.
The public harness metadata endpoint retains top-level
capabilities and
component_rules for older consumers. Those fields are derived from the version
specifications: capabilities are the union across generations and component
rules describe the current generation. New consumers should read the matching
generations[] entry.
Family layout
A harness family follows this shape:HarnessImplementation delegates through an immutable VersionSpec. Every
spec selects a complete Operations table, while Feature<T> requires each
optional capability to be either Supported(strategy) or
Unsupported(reason). A version that changes only one capability reuses the
existing operation set and changes that field. A version that changes paths,
rendering, inspection, package placement, gateway wiring, transcript discovery,
installation, launch behavior, or native update controls adds a named operation
set in the family module. Existing specs and operation sets remain unchanged.
Reusing an operation set is an assertion that every operation remains compatible.
If only an optional feature changes, reuse the operation set and change the
feature strategy in the new
VersionSpec.ImplementationPaths, consume immutable, package-grouped
ResolvedPackages, and construct ReconcilePlan in memory. The plan contains
bytes, modes, removals, ownership, environment, and launch arguments. Shared plan
helpers serialize documents and expand component trees; they never write a real
or simulated home. PreparedPackages and pending activation state stay private
to the engine.
The engine validates authority, snapshots affected files, applies the plan, and
commits package activation and V4 compatibility state together. Previous ownership
permits stale cleanup but is never added to new ownership. Native migration
permissions are exact paths. Intermediate symlinks and final write symlinks are
rejected; exact authorized symlink removals are snapshotted without following the
link. Revision transactions include prior ownership before any harness commits.
Installed binaries require successful version detection. Inspection uses persisted
profiles when present; unknown profiles fail. Legacy *-v1 names explicitly alias
the implementations that preserve their previous behavior. New reconciliation
writes canonical profile names while retaining state schema 4. Cleanup without
state does not infer ownership. Installation selects the newest interval that
intersects the policy and its certified release ceiling, and includes both in
the selector; the CLI probes the installed binary again afterward.
Installation has two parts. The selected implementation produces the
policy-constrained install selector. The interactive CLI executes it only after
confirmation and verifies the same executable path it detected before repair.
Harnesses with standalone installers may resolve the selector to a concrete
published version and update that installation in place; they must not install a
second binary that remains shadowed on PATH.
Wrapped-launch update suppression is also generation-owned. Each named
Operations set declares how its harness version disables native update checks
or automatic installation. The same operation decorates both a newly reconciled
plan and the read-only launch path, preventing their environment and arguments
from diverging. If a vendor changes or removes its update control, add a new
operation set at that version boundary rather than changing a shipped set.
Every generation declares two different upper bounds. before is the optional
breaking-format boundary used for dispatch. verified_before is the mandatory
exclusive ceiling through which the implementation has been tested. Releases
at or above that ceiling fail closed even when they remain in the same breaking
generation. An organization may deliberately accept that risk only by setting
both an explicit version_requirement and allow_unverified_versions: true.
Successful reconciliation then emits a warning that vendor changes may break
the generated configuration. The server adds the
unverified_harness_versions required capability so older clients cannot
silently ignore the opt-in.
Support metadata is generation-owned. Each VersionSpec exposes its own
component rules and optional capabilities, and package adapters are validated
against every compatible generation reachable through the harness policy.
Adding a capability to one generation therefore does not falsely advertise it
for older generations.
The central harness catalog owns invariant identity, discovery, and installer
metadata only. Behavioral capabilities and component rules live exclusively in
VersionSpec; public top-level summaries are derived from those specs for
backward compatibility. Package adapters separately declare their harness
availability with introduced and optional before bounds. Layout variants
must remain inside that availability interval.
Contributor workflows
Certify another release without a breaking change
Use this path when the existing writer, paths, package placement, hooks, gateway wiring, inspection, and launch behavior still work.- Update the stable harness release in
tests/e2e/agents.lock.json. - Exercise that exact release through the harness matrix and inspect its native files and launch behavior.
- Advance only the current registration’s exclusive
verified_beforeceiling to the next patch’s-0sentinel. For a verified1.18.25, use1.18.26-0. - Update version-output fixtures and rerun registry, golden, and E2E tests.
Add a breaking version boundary
Use this path when native behavior changes across a release boundary.- Set the previous registration’s exclusive
beforeto the first affected version. - Add a version directory whose
VersionSpecbegins at that exact version. - Reuse an existing named
Operationsset when every operation remains valid. Otherwise add a new complete operation set in the family module. - Declare every optional feature as
Supported(strategy)orUnsupported(reason)and define the generation’s component rules. - Add version-output fixtures and golden plans for the release immediately below the boundary and the release at the boundary, in governance-only and gateway modes.
- Retain the previous specification and operation set so older installations continue to dispatch deterministically.
[introduced, before). The final
breaking generation may omit before, but its verified_before remains finite.
Add a new harness
- Add one catalog entry with stable identity, binary probes, and installer metadata.
- Create the adapter family, shared writer and inspection modules, initial
operations, and
v0_0_0/VersionSpec. - Implement the entire
HarnessImplementationcontract, including pure plan, launch, native update controls, gateway wiring, component validation, package placement, inspection, transcript discovery, and installation. - Add the harness to explicit documentation and E2E matrices. Runtime dispatch and API harness keys come from the compiled catalog and require no second enum.
- Add golden plans, version parsing fixtures, transaction/rollback coverage, and at least one unsupported-package assertion.
Change package compatibility
Adapter-level[introduced, before) describes when the package works with a
harness. Nested variants describe archive layout changes only inside that
availability interval. A variant-only adapter must cover the complete
availability range contiguously. A fallback layout permits gaps, but overlapping
variants are always invalid.
Governance validation intersects package availability, variants, harness policy,
breaking generations, and certified ceilings. It also checks the effective
version-selected adapters together so helper-name collisions hidden inside
variants fail before publication.
Production boundaries and evidence
- Codex:
0.145.0separates automaticSessionEndupload from the legacy implementation. The upstream introduction adds the lifecycle event; earlier inline hooks do not establish support for it. - Codex:
0.114.0separates theSessionStartboundary.SessionStartexists from0.114.0even thoughSessionEndonly arrives at0.145.0, so thecodex-v0_114_0interval declares thesession_startcapability while leavingsession_uploadunsupported. On this interval Blue records theBLUE_SESSION_ID→ native-session mapping at start and uploads the transcript fromblue run’s post-exit fallback rather than aSessionEndhook. See the upstreamSessionStarthook documentation. - Claude:
1.0.38introduces hooks and2.0.12introduces plugin packaging. The hooks-only interval accepts hook components but rejects plugin packages, standalone skills, and agents. Automatic upload is conservatively disabled throughout that interval:SessionEndarrived at1.0.85, so it is not supported uniformly. These releases are recorded in the upstream changelog. - Kimi and OpenCode retain one production interval each. Candidate transitions
and the evidence still needed are recorded in
crates/gh-config/tests/fixtures/future-boundaries.json; they are not production boundaries.
Contract tests and verification
crates/gh-config/src/contract_tests.rs covers normalized golden plans for each
interval in both operating modes, source-home purity, exact boundaries, profile
aliases, ownership, symlinks, production transitions, activation failure,
revision rollback, and a synthetic two-version definition with different paths,
schemas, component placement, hooks, and launch arguments. Adapter tests also
assert that unchanged versions reuse their family operation table and that
unsupported capabilities carry a nonempty reason. Golden paths and the Blue
executable are normalized to $HOME and $BLUE.
Update fixtures intentionally, then rerun without the environment variable:
next-patch-0 beyond the stable release pinned in
tests/e2e/agents.lock.json. Updating that lock therefore forces maintainers to
make newly verified support explicit.
Before review, verify these invariants:
- Every breaking interval is ordered, contiguous, and selects exactly one spec.
- Every
verified_beforeis exclusive and no later than the breakingbefore. - No version-dependent capability or component rule is authored in the catalog.
- Plans remain pure, and only the transaction engine writes or removes files.
- Package availability covers every harness version allowed by the organization policy, unless that package is disabled for the harness.
- Installer repair updates and rechecks the originally detected executable.
- Native update controls come from the selected operation set and match between fresh reconciliation and cached launch resolution.
- Old specs, operation sets, fixtures, and golden plans remain present.
