tree: 3e9ddd7f8d2882fb82d61b66c32331a05b812fab
  1. base64-length-allocation.json
  2. client-capability-entity-id-boundary.json
  3. client-capability-tool-decoder-share.json
  4. connection-onboarding-create-identity.json
  5. credential-rotation-operations.json
  6. host-activity-idle-predicate.json
  7. plan-control-error-codes.json
  8. project-catalog-path-limit-unexport.json
  9. project-directory-root-spec.json
  10. README.md
  11. registration-websocket-endpoints.json
  12. session-catalog-deep-research-import.json
  13. session-context-ref-reader.json
  14. session-turns-strict-decoder.json
packages/runtime-host/protocol-compatible-changes/README.md

Compatible protocol changes

RUNTIME_HOST_COMPATIBILITY_EPOCH is the generation Client and Host exchange at handshake; a mismatch rejects the connection. The guard in scripts/protocol-epoch-check.mjs therefore treats every touched file under packages/runtime-host/src/protocol/ as a protocol change and demands an epoch the base branch has not seen. That proxy is deliberately coarse: a needless bump costs a number, a missed one ships two incompatible protocols under one epoch (#3313).

A file here is the exemption, for a change the wire provably cannot observe:

{
  "epoch": 121,
  "files": ["packages/runtime-host/src/protocol/codec.ts"],
  "reason": "Renames a local helper without changing any codec or message shape"
}
  • epoch pins the declaration to the epoch your branch carries. When another change moves it first, re-pin, and re-read the reason: it has to still hold.
  • files must name every protocol file your branch changed, or the guard fails on the ones it does not cover.
  • reason is read by a human. Nothing checks it, so it earns its keep only by being specific about why no peer can tell the difference.

Legitimate: renaming or un-exporting an internal helper, moving a constant, tightening a decoder to reject what it already rejected. Not legitimate: any new or removed field, key, error code, or accepted value — those move the epoch, whatever the intent.

CI checks the whole branch against its base, so one declaration covers the PR. When a later commit touches another protocol file, amend this file rather than adding a second one. Declarations are read only while they are new to the branch; once landed they are history, which is why the older files here still pin long-past epochs.