kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
83 lines (68 loc) • 4.86 kB
Markdown
# OSS-ADR-0051 — The grade-root derivation is a versioned protocol shape (`certifiedRoot`) — extends OSS-ADR-0046
Status: accepted (2026-07-17, owner — arch-review, arch-deepening-2026-07-15)
## Context
Today the signed grade `root = sha256(canonicalize(signingPayload(fields)))` is
derived **only in the platform** (`apps/api/src/grade/signer.ts`:
`SIGNATURE_COVERED_GRADE_FIELDS` + `signingPayload`). OSS `grade()` reproduces the
NUMBERS and `canonicalize` (dependency-free protocol, OSS-ADR-0046) reproduces the
BYTES, but **no outsider-runnable step rebuilds the signed ROOT** — so recompute
stops at the numbers, not the root the trust substrate rests on.
OSS `verify.ts` deliberately checks only signature-over-root, documenting that
reproducing the root "would import control-plane grade schema into OSS." That
boundary is exactly the gap: the covered-field key set and its order — the SHAPE
the signature commits to — is private, so an outsider can recompute every number a
grade reports and still not reconstruct the thing that was signed. This ADR removes
that gap by making the schema PUBLIC dependency-free protocol, so the previously
control-plane-only derivation can be imported by the light verifier without dragging
control-plane schema along with it.
This extends OSS-ADR-0046 ("the protocol package owns the wire shapes and stays
dependency-free"): the grade-root *derivation* is one more wire shape that belongs
in `src/protocol`.
## Decision
1. **The root derivation is owned by the OSS `protocol` package as a pure function
`certifiedRoot(coveredFields)`.** The canonicalize+sha256 procedure and the named
covered-field key set + their order live in protocol as a pure function — no key,
no wall clock. Platform signer and OSS CLI both import it. The private signing key
stays platform-side; the open/closed minting seam (OSS-ADR-0001/0009) is preserved
— only the *derivation* is shared, never the key. Platform stops owning the root
SHAPE (it still owns the VALUES it feeds in and the key it signs with).
2. **The covered-field key set is versioned with `PROTOCOL_VERSION` and is
additive-optional.** An absent field reads UNKNOWN (Certified-evidence doctrine,
CONTEXT.md), so additive fields do not break prior-version recompute; a breaking
change to the set or its order is a coordinated protocol bump that **fails closed
on mismatch**, never a silent divergence.
3. **Recompute closes in TWO outsider-runnable layers.**
- `verify` (light, node-only, imports only the dependency-free protocol
`canonicalize`) checks `root == hash(canonicalize(published covered-fields))` —
binding the signature to the published numbers.
- `certify` (heavy, already reprojects the Blotter through the engine)
additionally checks `published numbers == grade(reproject(tape))` — binding the
numbers to the tape.
Together they close the previously-deferred "L3" leg: root ↔ payload ↔ tape is now
recomputable end-to-end by any outsider.
4. **`issuedAt`, `kid`, `epoch` are INPUTS to `certifiedRoot`, never generated in
OSS** — preserving determinism (no wall clock on the OSS path). `issuedAt` stays
signature-covered (attested, non-backdatable).
## Consequences
- `verify.ts`'s prior boundary comment ("does NOT reproduce the platform's canonical
grade-root derivation") is **superseded**: the schema is now public dependency-free
protocol, so importing it into the light verifier does not drag control-plane schema
in. The comment must be updated when the change lands.
- The trust substrate strengthens: an outsider can now deterministically rebuild the
signed root, not merely the numbers under it — recomputability, the property
KestrelBench rests on, extends all the way to the signature.
- Platform's grade signer shrinks to values-in / key-sign; the SHAPE it used to own
moves to protocol, and root bytes must stay **byte-identical to today** (every
previously-signed grade still verifies).
- **Prerequisite:** the shared attestation constants (bead `kestrel-s67u`) must land
first so `src/protocol/attestation.ts` exists as the home for `certifiedRoot` and
its covered-field key set.
## References
- OSS-ADR-0046 — the protocol package owns the wire shapes and stays dependency-free
(this ADR extends it: the root derivation is one more owned shape).
- OSS-ADR-0001 / OSS-ADR-0009 — the open/closed minting seam preserved (key stays
platform-side; only the derivation is shared).
- `kestrel-s67u` — shared attestation constants; prerequisite (home for the derivation).
- `apps/api/src/grade/signer.ts` (platform, `SIGNATURE_COVERED_GRADE_FIELDS` /
`signingPayload`), `src/cli/commands/verify.ts` (light verifier + boundary comment),
`src/protocol` (`canonicalize`, `PROTOCOL_VERSION`, `attestation.ts`).