Skip to content

docs(adr-0015): accept rotation event envelope placement (credentialSubject.keyRotation)#458

Merged
ojongerius merged 9 commits into
mainfrom
claude/spec-rotation-event-format
May 19, 2026
Merged

docs(adr-0015): accept rotation event envelope placement (credentialSubject.keyRotation)#458
ojongerius merged 9 commits into
mainfrom
claude/spec-rotation-event-format

Conversation

@ojongerius
Copy link
Copy Markdown
Contributor

@ojongerius ojongerius commented May 18, 2026

Context

ADR-0015 (Key Rotation, BYOK, External Anchoring) defines a key_rotated event with seven fields (event_type, new_public_key, old_key_fingerprint, new_key_fingerprint, old_algorithm, new_algorithm, signed_with) but explicitly defers where they live in the verifier-facing AgentReceipt envelope:

Wire-format placement is out of scope for this ADR.

ADR-0017 names "rotation event canonical wire format" as a precondition for hub implementation. This PR pins that placement so the hub re-verifier and three SDKs can plan against a fixed wire shape.

Placement decision: option (a) credentialSubject.keyRotation — accepted 2026-05-19.

The one-pager: three placement options

The fields and their semantics from ADR-0015 are unchanged. The only question is the envelope-side carriage.

(a) credentialSubject.keyRotation extension namespace — accepted

Rotation events live in a dedicated sub-object on credentialSubject, additive to today's principal / action / outcome / chain siblings. Action and outcome semantics stay clean (they continue to describe external tool calls); rotation gets its own vocabulary.

Crucially, today's spec/schema/agent-receipt.schema.json declares additionalProperties: false on the root and on most nested objects, but the credentialSubject $def (line 372) omits that constraint. ADR-0003 §"Subset compliance" calls this out explicitly: extension fields within credentialSubject are permitted by the schema. The fixture in this PR validates against the current schema today — confirmed with ajv validate -s spec/schema/agent-receipt.schema.json -d spec/test-vectors/rotation-event/example.json --spec=draft2020 -c ajv-formatsvalid. Schema tightening (adding a normative keyRotation $ref) is a follow-up, not a blocker.

(b) Reuse action.type = "key_rotated"

Why not: action today represents external tool calls — it carries target.system, target.resource, parameters_hash, risk_level, timestamp, and (in 0.2.0) outcome.response_hash. Reusing it as a polymorphic envelope erodes the type's clarity — target and parameters_hash have no meaning for a rotation. Daemon-internal events and tool calls are different vocabularies; collapsing them is the wrong abstraction.

(c) New top-level field on the receipt envelope

Why not: the schema's root does set additionalProperties: false (line 17). A top-level keyRotation field forces every verifier in the wild to bump its allowed-keys set or fail closed — the biggest possible blast radius for what is conceptually a sub-namespace of the existing credential subject. Reserve top-level extension for cases where a sub-namespace genuinely cannot represent the semantics; rotation events are not that case.

What's in this PR

  • docs/adr/0015-key-rotation-byok-anchoring.md — appended ## Amendments section with one entry dated 2026-05-18, accepted 2026-05-19. The original decision sections are untouched. The amendment contains: the placement decision and rationale, the seven-field table mapped into keyRotation, the verifier-side traversal restated as four normative steps, backward-compatibility rules ("absence means no rotation, not malformed"), and the schema-version recommendation.
  • spec/test-vectors/rotation-event/example.json — one worked rotation receipt in pretty-printed form (the README documents the canonical-form bytes alongside). Signed end-to-end with RFC 8032 §7.1 TEST 2 (outgoing) over the canonicalised body. All values are deterministically recomputable from the test keys.
  • spec/test-vectors/rotation-event/README.md — the test-key origin, derived fingerprints, the canonical-bytes SHA-256 (sha256:6983c9bd6fb24e844b90f7616315a914fdedc5fef8126e11d46149ba2f320457), and what is deliberately out of scope.

What's deliberately NOT in this PR

  • No changes to spec/schema/agent-receipt.schema.json. Schema integration (adding a keyRotation $ref and bumping the version enum from ["0.1.0","0.2.0","0.2.1"] to include "0.3.0") is a follow-up gated on the placement being accepted. The fixture already validates against today's schema unchanged, so this PR commits to nothing schema-side.
  • No code. No SDK changes, no daemon changes, no hub changes. This is a wire-format pin.
  • No runnable cross-SDK harness wiring. The fixture is human-reviewable; promoting it into cross-sdk-tests/ waits on SDK implementations.
  • No changes to ADR-0009 canonicalisation rules. RFC 8785 governs unchanged.

Schema version

Recommend a 0.2.1 → 0.3.0 bump when schema integration lands. Rationale matches ADR-0008's 0.1.0 → 0.2.0 precedent: schema version as a security signal — 0.3.0 tells a verifier the issuer operates in an environment where rotation events are expressible. Receipts that pre-date the bump are unaffected (their canonical bytes do not change) and remain valid under their original version.

Sibling spec PRs

This is one of three coordinated spec PRs derisking ADR-0017's preconditions:

  • claude/spec-did-key-resolutiondid:key value shape and resolution algorithm.
  • claude/spec-disclosure-envelope — ADR-0012 disclosure envelope canonical shape.
  • claude/spec-rotation-event-format — this PR.

Each pins a wire shape independently; no cross-PR dependencies.

Test plan

  • Placement decision: option (a) credentialSubject.keyRotation accepted 2026-05-19.
  • Canonical-bytes SHA-256 in the README independently verified: sha256:6983c9bd6fb24e844b90f7616315a914fdedc5fef8126e11d46149ba2f320457.
  • proofValue verified under the RFC 8032 §7.1 TEST 2 public key.
  • ajv validate -s spec/schema/agent-receipt.schema.json -d spec/test-vectors/rotation-event/example.json --spec=draft2020 -c ajv-formats passes.
  • Follow-up PR: schema $ref integration + version enum bump to "0.3.0".

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Pins a proposed canonical wire-format placement for ADR-0015 rotation events by adding an amendment that specifies credentialSubject.keyRotation, plus a worked receipt test vector intended to let verifiers/SDKs plan against a stable envelope shape.

Changes:

  • Adds a Proposed amendment to ADR-0015 specifying rotation-event placement at credentialSubject.keyRotation and verifier traversal steps.
  • Introduces a rotation-event example receipt JSON fixture under spec/test-vectors/rotation-event/.
  • Documents the fixture, derived values, and expected canonical-body SHA-256 in a new README.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
docs/adr/0015-key-rotation-byok-anchoring.md Adds a proposed amendment defining rotation event envelope placement and verification steps.
spec/test-vectors/rotation-event/example.json Adds a worked example receipt containing credentialSubject.keyRotation.
spec/test-vectors/rotation-event/README.md Documents the rotation-event fixture inputs/derived values and intended usage.

Comment thread spec/test-vectors/rotation-event/README.md Outdated
Comment thread spec/test-vectors/rotation-event/example.json Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread spec/test-vectors/rotation-event/README.md
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md
ojongerius pushed a commit that referenced this pull request May 18, 2026
…r hygiene, ADR-0017 links)

Four substantive fixes from PR #458 Copilot review pass. Two
comments about `||`-prefixed markdown tables were false positives
(no such pattern exists in the files; verified with grep) and are
not addressed.

* **Chain position made replayable.** The fixture was
  `sequence: 42` with an all-zero `previous_receipt_hash`, which
  is not a valid chain link — there is no real predecessor whose
  canonical hash is all zeros. Changed to genesis position
  (`sequence: 1`, `previous_receipt_hash: null`) so the linkage
  semantics are sound end-to-end without shipping a separate
  predecessor receipt. Canonical-bytes SHA-256 and Ed25519
  signature recomputed using sdk/go's existing `Canonicalize`
  helper to keep the README's "recomputable from the keys above"
  claim accurate:
  - Old hash `sha256:17e1...b517` → new
    `sha256:6983c9bd6fb24e844b90f7616315a914fdedc5fef8126e11d46149ba2f320457`.
  - Signature updated accordingly.
* **Secret-scanner hygiene.** Removed the inlined outgoing seed
  hex (RFC 8032 §7.1 TEST 2). Reviewers reproduce the signature
  by fetching the seed from the RFC directly; secret scanners no
  longer trip on a raw 32-byte hex literal that "looks like" a
  key regardless of provenance.
* **ADR-0017 links.** The two `./0017-central-receipt-hub.md`
  relative links rendered as broken on `main` because ADR-0017
  is not yet merged. Switched both to the full GitHub URL on the
  draft branch (`claude/draft-adr-0017-Ko7cn`) with an inline
  note that the relative form is restored once ADR-0017 lands.
ojongerius pushed a commit that referenced this pull request May 18, 2026
…er hygiene, table swap, supersession note)

Six fixes from PR #459 Copilot review pass.

Schema tightening:

* Add base64url `pattern` and exact-43-char length constraint to
  recipient `enc` (the encoded size of a 32-byte X25519 ephemeral
  public key — load-bearing, not a range).
* Add base64url `pattern` and `minLength: 22` to `ct` — accepts
  any AEAD output but rejects `=` padding, `+`, `/`. minLength
  floors at the 16-byte GCM tag's encoded size.

Test-vector hygiene:

* Remove inlined X25519 `private_key_hex` from both
  `test_recipients` entries and remove
  `decrypt_with_private_key_hex` from each vector's `round_trip`.
  Even RFC-published private keys trip secret-scanning tooling
  and encourage cargo-cult reuse. Reviewers running the
  decryption round-trip fetch the private keys from RFC 7748 §6.1
  directly; the README points there explicitly.

Placeholder / shape-invariants reconciliation:

* The `<enc-bytes-base64url-unpadded>` placeholders are
  syntactically invalid base64url by design (so copy-pasting into
  production fails loudly). Reword `shape_invariants` to scope
  the rules to SDK-produced envelopes, and add an explicit
  `computed_values_status` → `"computed"` flip-rule explaining
  when the rules begin applying to a specific vector. The
  envelope README's "Reproducibility" section is updated to
  match. The placeholders themselves stay angle-bracket form
  rather than syntactically-valid-but-fake base64url, to keep
  the fail-loud property.

Table correction:

* The "Phase C migration cost" row in the HPKE-vs-sealed-box
  comparison had the columns swapped — high migration cost was
  shown under HPKE; it belongs under sealed-box (since shipping
  sealed-box for v1 is what creates the cost). Reworded the row
  label to drop the awkward "if v1 ships sealed-box" conditional
  and swapped the cells so each column reflects its own choice.

Supersession note:

* The original ADR-0012 *Forward-compatible envelope shape*
  illustration uses `v: 1` (integer), includes `nonce`, and
  names the field `encap`. Added an explicit supersession note
  in the amendment's *Scope* paragraph so readers don't
  implement the outdated sketch.

ADR-0017 cross-references repointed to the draft branch URL
(matches the equivalent fix on PR #458) since ADR-0017 is not
yet on `main`.
…entialSubject.keyRotation)

Proposes `credentialSubject.keyRotation` as the wire-format placement for
the rotation event ADR-0015 itself explicitly deferred. The placement is
flagged for human sign-off before merge — the three placement options
(a/b/c) are compared in the PR body and (a) is the leading recommendation,
not yet locked in.

Adds:
- ADR-0015 amendment formalising the proposed placement and the
  verifier-side rotation traversal against it (no change to the original
  decision sections; appended under a new Amendments heading).
- spec/test-vectors/rotation-event/example.json — a worked rotation
  receipt in canonical form, signed with the RFC 8032 §7.1 TEST 2 key.
- spec/test-vectors/rotation-event/README.md — keys, derived values,
  scope.

Deliberately NOT in this PR:
- No changes to spec/schema/agent-receipt.schema.json. The current schema
  already permits the fixture because `credentialSubject` omits
  `additionalProperties: false` (verified with ajv against the example).
  Tightening the schema with a normative `keyRotation` `$ref` is a
  follow-up gated on the placement being accepted.

Unblocks ADR-0017 Preconditions item 2 (rotation event canonical wire
format).
…r hygiene, ADR-0017 links)

Four substantive fixes from PR #458 Copilot review pass. Two
comments about `||`-prefixed markdown tables were false positives
(no such pattern exists in the files; verified with grep) and are
not addressed.

* **Chain position made replayable.** The fixture was
  `sequence: 42` with an all-zero `previous_receipt_hash`, which
  is not a valid chain link — there is no real predecessor whose
  canonical hash is all zeros. Changed to genesis position
  (`sequence: 1`, `previous_receipt_hash: null`) so the linkage
  semantics are sound end-to-end without shipping a separate
  predecessor receipt. Canonical-bytes SHA-256 and Ed25519
  signature recomputed using sdk/go's existing `Canonicalize`
  helper to keep the README's "recomputable from the keys above"
  claim accurate:
  - Old hash `sha256:17e1...b517` → new
    `sha256:6983c9bd6fb24e844b90f7616315a914fdedc5fef8126e11d46149ba2f320457`.
  - Signature updated accordingly.
* **Secret-scanner hygiene.** Removed the inlined outgoing seed
  hex (RFC 8032 §7.1 TEST 2). Reviewers reproduce the signature
  by fetching the seed from the RFC directly; secret scanners no
  longer trip on a raw 32-byte hex literal that "looks like" a
  key regardless of provenance.
* **ADR-0017 links.** The two `./0017-central-receipt-hub.md`
  relative links rendered as broken on `main` because ADR-0017
  is not yet merged. Switched both to the full GitHub URL on the
  draft branch (`claude/draft-adr-0017-Ko7cn`) with an inline
  note that the relative form is restored once ADR-0017 lands.
@ojongerius ojongerius marked this pull request as ready for review May 19, 2026 09:08
@ojongerius ojongerius requested a review from Copilot May 19, 2026 09:09
ojongerius added a commit that referenced this pull request May 19, 2026
…er hygiene, table swap, supersession note)

Six fixes from PR #459 Copilot review pass.

Schema tightening:

* Add base64url `pattern` and exact-43-char length constraint to
  recipient `enc` (the encoded size of a 32-byte X25519 ephemeral
  public key — load-bearing, not a range).
* Add base64url `pattern` and `minLength: 22` to `ct` — accepts
  any AEAD output but rejects `=` padding, `+`, `/`. minLength
  floors at the 16-byte GCM tag's encoded size.

Test-vector hygiene:

* Remove inlined X25519 `private_key_hex` from both
  `test_recipients` entries and remove
  `decrypt_with_private_key_hex` from each vector's `round_trip`.
  Even RFC-published private keys trip secret-scanning tooling
  and encourage cargo-cult reuse. Reviewers running the
  decryption round-trip fetch the private keys from RFC 7748 §6.1
  directly; the README points there explicitly.

Placeholder / shape-invariants reconciliation:

* The `<enc-bytes-base64url-unpadded>` placeholders are
  syntactically invalid base64url by design (so copy-pasting into
  production fails loudly). Reword `shape_invariants` to scope
  the rules to SDK-produced envelopes, and add an explicit
  `computed_values_status` → `"computed"` flip-rule explaining
  when the rules begin applying to a specific vector. The
  envelope README's "Reproducibility" section is updated to
  match. The placeholders themselves stay angle-bracket form
  rather than syntactically-valid-but-fake base64url, to keep
  the fail-loud property.

Table correction:

* The "Phase C migration cost" row in the HPKE-vs-sealed-box
  comparison had the columns swapped — high migration cost was
  shown under HPKE; it belongs under sealed-box (since shipping
  sealed-box for v1 is what creates the cost). Reworded the row
  label to drop the awkward "if v1 ships sealed-box" conditional
  and swapped the cells so each column reflects its own choice.

Supersession note:

* The original ADR-0012 *Forward-compatible envelope shape*
  illustration uses `v: 1` (integer), includes `nonce`, and
  names the field `encap`. Added an explicit supersession note
  in the amendment's *Scope* paragraph so readers don't
  implement the outdated sketch.

ADR-0017 cross-references repointed to the draft branch URL
(matches the equivalent fix on PR #458) since ADR-0017 is not
yet on `main`.
@ojongerius ojongerius force-pushed the claude/spec-rotation-event-format branch from e120369 to 9d3adc0 Compare May 19, 2026 09:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

Comment thread spec/test-vectors/rotation-event/README.md Outdated
Comment thread spec/test-vectors/rotation-event/README.md
Comment thread spec/test-vectors/rotation-event/example.json
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

docs/adr/0015-key-rotation-byok-anchoring.md:206

  • This section is internally inconsistent: it declares the amendment Accepted, but later calls the keyRotation field mapping “normative, pending sign-off”. Please make the status and normative language consistent (either remove the “pending sign-off” language, or change the amendment status/wording to Proposed throughout).
**What lives in `keyRotation` (normative, pending sign-off).**

| Field | Type | Description |
|---|---|---|
| `event_type` | string | Constant `"key_rotated"`. |
| `new_public_key` | string | Incoming public key inline, raw bytes per the algorithm's canonical encoding, multibase-`u`-prefixed base64url (per ADR-0001). For Ed25519, the 32 raw bytes per RFC 8032 §5.1.5. |
| `old_key_fingerprint` | string | `sha256:<lowercase hex>` of the outgoing public key (raw bytes — *not* SPKI/PEM, *not* a backend handle). |
| `new_key_fingerprint` | string | `sha256:<lowercase hex>` of the incoming public key (same canonical-bytes rule). |
| `old_algorithm` | string | Algorithm tag of the outgoing key (e.g. `"ed25519"`). |
| `new_algorithm` | string | Algorithm tag of the incoming key. Equal to `old_algorithm` for same-algorithm rotations. |
| `signed_with` | string | Constant `"old"`. The receipt's `proof.proofValue` is computed with the outgoing key. |

`keyRotation` is **optional**. A receipt that is not a rotation event MUST NOT include it. A receipt that is a rotation event MUST include all seven fields.

The receipt's `action.type` SHOULD be `"agent.key.rotate"` (taxonomy entry to be registered alongside the schema-integration follow-up) so that downstream filters can locate rotation receipts without parsing `credentialSubject.keyRotation`. The presence of `keyRotation` is authoritative; `action.type` is the index hint.

docs/adr/0015-key-rotation-byok-anchoring.md:183

  • The ADR links to a draft on a named branch (blob/claude/...). This is likely to rot once the branch is deleted or rebased. Consider linking to a stable reference (issue/PR, or a commit permalink), and/or keep the relative link commented as a TODO once ADR-0017 lands on main.
**Status of this amendment:** *Accepted* (2026-05-19). Placement option (a) `credentialSubject.keyRotation` is the wire format for rotation events. The fields above (`event_type`, `new_public_key`, `old_key_fingerprint`, `new_key_fingerprint`, `old_algorithm`, `new_algorithm`, `signed_with`) and their semantics are unchanged by this amendment — only their envelope-side carriage is pinned. This amendment closes the gap the original *Rotation event schema* section flagged with "Wire-format placement is out of scope for this ADR." See [ADR-0017 (draft)](https://github.com/agent-receipts/ar/blob/claude/draft-adr-0017-Ko7cn/docs/adr/0017-central-receipt-hub.md) *Preconditions* (rotation-event canonical wire format) for the consumer that requires this pin. The ADR-0017 file is not yet on `main` — the relative link will be repointed at `./0017-central-receipt-hub.md` once ADR-0017 lands.

Comment thread docs/adr/0015-key-rotation-byok-anchoring.md
Comment thread spec/test-vectors/rotation-event/README.md Outdated
@ojongerius ojongerius changed the title docs(adr-0015): pin rotation event envelope placement (proposed: credentialSubject.keyRotation) docs(adr-0015): accept rotation event envelope placement (credentialSubject.keyRotation) May 19, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread spec/test-vectors/rotation-event/README.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

spec/test-vectors/rotation-event/README.md:33

  • The markdown table here starts each row with ||, which introduces an empty first column and renders the table misaligned on GitHub. Use a single leading | for each row (consistent with other ADR tables in this repo).
| Role | RFC 8032 vector | Public key (hex) |
|---|---|---|
| Outgoing (signs the rotation) | TEST 2 | `3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c` |
| Incoming | TEST 3 | `fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025` |

Comment thread docs/adr/0015-key-rotation-byok-anchoring.md
Comment thread spec/test-vectors/rotation-event/README.md Outdated
@ojongerius ojongerius requested a review from Copilot May 19, 2026 10:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

docs/adr/0015-key-rotation-byok-anchoring.md:197

  • The reference to ADR-0001 here is misleading: ADR-0001 specifies multibase-u base64url encoding for proof.proofValue, but it does not currently define an encoding for public keys. Consider either (1) updating the citation to the normative place that defines new_public_key encoding, or (2) explicitly stating that new_public_key reuses the same multibase/base64url encoding as proofValue and documenting that rule normatively (in this ADR/spec).
| `event_type` | string | Constant `"key_rotated"`. |
| `new_public_key` | string | Incoming public key inline, raw bytes per the algorithm's canonical encoding, multibase-`u`-prefixed base64url (per ADR-0001). For Ed25519, the 32 raw bytes per RFC 8032 §5.1.5. |

Comment thread spec/test-vectors/rotation-event/README.md Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
@ojongerius ojongerius requested a review from Copilot May 19, 2026 10:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
@ojongerius ojongerius requested a review from Copilot May 19, 2026 10:18
ojongerius added a commit that referenced this pull request May 19, 2026
…KE) (#459)

* docs(adr-0012): pin disclosure envelope canonical shape (proposed: HPKE)

* docs(adr-0012): address Copilot review (schema patterns, secret-scanner hygiene, table swap, supersession note)

Six fixes from PR #459 Copilot review pass.

Schema tightening:

* Add base64url `pattern` and exact-43-char length constraint to
  recipient `enc` (the encoded size of a 32-byte X25519 ephemeral
  public key — load-bearing, not a range).
* Add base64url `pattern` and `minLength: 22` to `ct` — accepts
  any AEAD output but rejects `=` padding, `+`, `/`. minLength
  floors at the 16-byte GCM tag's encoded size.

Test-vector hygiene:

* Remove inlined X25519 `private_key_hex` from both
  `test_recipients` entries and remove
  `decrypt_with_private_key_hex` from each vector's `round_trip`.
  Even RFC-published private keys trip secret-scanning tooling
  and encourage cargo-cult reuse. Reviewers running the
  decryption round-trip fetch the private keys from RFC 7748 §6.1
  directly; the README points there explicitly.

Placeholder / shape-invariants reconciliation:

* The `<enc-bytes-base64url-unpadded>` placeholders are
  syntactically invalid base64url by design (so copy-pasting into
  production fails loudly). Reword `shape_invariants` to scope
  the rules to SDK-produced envelopes, and add an explicit
  `computed_values_status` → `"computed"` flip-rule explaining
  when the rules begin applying to a specific vector. The
  envelope README's "Reproducibility" section is updated to
  match. The placeholders themselves stay angle-bracket form
  rather than syntactically-valid-but-fake base64url, to keep
  the fail-loud property.

Table correction:

* The "Phase C migration cost" row in the HPKE-vs-sealed-box
  comparison had the columns swapped — high migration cost was
  shown under HPKE; it belongs under sealed-box (since shipping
  sealed-box for v1 is what creates the cost). Reworded the row
  label to drop the awkward "if v1 ships sealed-box" conditional
  and swapped the cells so each column reflects its own choice.

Supersession note:

* The original ADR-0012 *Forward-compatible envelope shape*
  illustration uses `v: 1` (integer), includes `nonce`, and
  names the field `encap`. Added an explicit supersession note
  in the amendment's *Scope* paragraph so readers don't
  implement the outdated sketch.

ADR-0017 cross-references repointed to the draft branch URL
(matches the equivalent fix on PR #458) since ADR-0017 is not
yet on `main`.

* docs(adr-0012): accept HPKE as v1 primitive (sign-off received)

* docs(adr-0012): replace branch-specific ADR-0017 URLs with stable text references

* docs(adr-0012): address third Copilot review (phase label, HPKE status, comment accuracy)

* fix(schema): enforce decodable base64url length in ct pattern

* fix(schema): raise ct minLength from 22 to 24 (v1 plaintext minimum is {} = 2 bytes)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread docs/adr/0015-key-rotation-byok-anchoring.md Outdated
Comment thread spec/test-vectors/rotation-event/README.md
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@ojongerius ojongerius merged commit 25fbe20 into main May 19, 2026
15 checks passed
@ojongerius ojongerius deleted the claude/spec-rotation-event-format branch May 19, 2026 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants