Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt

Use this file to discover all available pages before exploring further.

Normative reference for the Managed Rule envelope — the signed wire format the AEGIS promoter writes to Workers KV and R2 and the gateway reads at request time. This is the wire surface the gateway consumes during failover; it is not a customer-side verification surface (see §4 below). The canonical implementation is in mnemom-api/src/composition/envelope-signer.ts (signer) and mnemom-platform/gateway/src/aegis-recipes.ts (verifier). Both envelopes — the KV variant and the R2 variant — share the same shape; only the signing key (key_id) differs.

1. Top-level structure

{
  "recipes": [ /* array of recipe row objects, see §3 */ ],
  "signature": "<base64url(ed25519(<key_id>.<signed_at>.<sha256_hex(canonical_json(recipes))>))>",
  "key_id": "<kid; matches one entry in the corresponding JWKS>",
  "signed_at": "<ISO-8601 UTC>"
}
FieldTypeRequiredNotes
recipesarrayYesArray of recipe row objects. See §3.
signaturestringYesBase64url-encoded Ed25519 signature over the canonical-hash message.
key_idstringYesIdentifier of the signing key; matches the rotation cohort.
signed_atstringYesISO-8601 UTC timestamp at which the envelope was signed.

Canonical-hash message

The signature is computed over the UTF-8 bytes of the dotted message:
<key_id>.<signed_at>.<sha256-hex(canonical_json(recipes))>
where canonical_json recursively sorts object keys and emits compact JSON (no whitespace, no insignificant separators). The resulting digest is the SHA-256 hash in lowercase hex. The signature wraps key_id and signed_at in the message, so an attacker that obtained the per-row recipe payload but did not produce the signature cannot replay the envelope under a different signed_at.

2. The two envelope variants

The promoter writes two parallel envelopes in the same canonical recipe set. They differ only in the key they use:
VariantStorageSigning keyGateway tier
KV envelopeWorkers KV key sh:aegis-recipes:v1RECIPE_KV_SIGNING_KEYPrimary read path; 300 s TTL
R2 envelopeR2 bucket aegis-recipes-failover, key composed-recipe-set/latestRECIPE_R2_SIGNING_KEYSecondary read path; per-promotion refresh
The two signing chains are independent. KV poisoning degrades gracefully to R2; the gateway’s tiered read pipeline (see Managed Rules) verifies each tier with its own JWKS binding and fails over on signature failure.

3. Per-recipe row shape

Each entry in recipes carries the wire-readable subset of the recipe row. Customer-readable fields are limited to:
FieldTypeNotes
recipe_idstringStable identifier for the recipe; survives version bumps.
composition_scopeenum"platform" | "org" | "team" | "agent" | null. Drives the card cascade target.
surfacestring[]The screening surfaces the recipe applies to (incoming, outgoing, tool_calls, tool_responses).
severity_penum"p0" | "p1" | "p2" | null. See terminology note.
scopeenum"arena_only" | "canary" | "production".

Terminology note: severity_p vs “tier”

Concept-level docs (for example Managed Rules and AEGIS) use the words tier 1, tier 2, tier 3. The database canonical is the column severity_p with values p0 / p1 / p2. The two vocabularies refer to the same dimension; spec pages use the database canonical so wire-format consumers can map directly. The bridge is fixed:
Concept-page labelseverity_p value
Tier 1 (would block prod; highest severity)p0
Tier 2 (would block prod; high severity)p1
Tier 3 (low blast radius; observe / nudge default)p2

Per-row promotion signature

Each recipe row also carries a per-row Ed25519 signature, written into the internal detection_recipes.promotion_signature column. The signature is computed over the canonical-hash inputs recipe_id, version, composition_scope, surface, severity_p, scope, created_by, created_at. The per-row signature is not carried inline in the envelope; the envelope signature wraps the recipe set, and the gateway re-checks the per-row signature against the canonical inputs after envelope verification succeeds. Internal detection-routing fields are out of scope for this spec. The detection-engine internal vocabulary (the per-checkpoint detection routing fields) persists on the internal detection_recipes table but is not part of the wire-format envelope; the spec documents what the gateway reads from the envelope, not what the platform writes into the internal table.

4. Signature verification — internal-resilience, not customer-side

At GA, the envelope signature exists for gateway-internal verification only. There is no public JWKS endpoint at which customers can independently verify a Managed Rule envelope signature.
The verification model and what it does and does not provide:
  • What the envelope signature provides. Defense in depth between the KV and R2 read tiers. The gateway verifies on every read; a poisoned KV envelope (whose signature does not verify against kvVerifyJwks) falls through to R2 (a different signing chain). A poisoned R2 envelope falls through to the last-known-good in-isolate cache.
  • What it does not provide. Customer-side cryptographic attestation. The verify halves — kvVerifyJwks and r2VerifyJwks — are passed in as worker bindings; they are secrets in the gateway’s worker environment, not customer-reachable URLs.
  • The customer-facing transparency surface. The append-only audit chain on recipe_review_actions is the recipe-level provenance trail, verifiable via the admin API surface. The published /trust/slos describe propagation, freshness, and failover commitments. The advisory and IoC surfaces describe the network-level signal output.
  • /v1/.well-known/jwks.json publishes a different set of keys. That endpoint publishes AAP attestation keys (the aap_signing_keys table). Recipe-set signing keys are escrowed in 1Password under the operator’s rotation policy and are not part of the public JWKS.
A future public JWKS surface for recipe-set verification keys is not currently on the roadmap; if and when one ships, this section is updated and a customer-side verification guide lands.

5. Three independent signing chains

The full rule plane uses three Ed25519 keys, each rotated under Class A annual rotation (90-day JWKS overlap):
KeyWhat it signsWhere it sits
RECIPE_PROMOTION_SIGNING_KEYPer-row promotion signature (detection_recipes.promotion_signature)1Password operator vault
RECIPE_KV_SIGNING_KEYThe KV envelope (§2)1Password operator vault
RECIPE_R2_SIGNING_KEYThe R2 envelope (§2)1Password operator vault
Three independent compromise paths required to fully poison the pipeline. KV poisoning degrades gracefully to R2 (different signing chain). KV + R2 compromise is still defeated by the per-row promotion signature: the gateway re-checks each row against the promotion signature after envelope verification, and a forged row will not match.

6. Failover behavior

The gateway’s tiered read pipeline at request time:
  1. In-isolate memory cache — fresh entries (< 60 s) served from in-isolate state.
  2. Workers KV primary — 300 s TTL; signed with RECIPE_KV_SIGNING_KEY.
  3. R2 secondary — per-promotion refresh; signed with RECIPE_R2_SIGNING_KEY (independent chain).
  4. Last-known-good in-isolate — staleness up to 24 hours; fail-closed on safety-critical checkpoints at 24 h.
  5. Fail-closed 503 with X-Mnemom-Reason: aegis-data-plane-unavailable.
Customers MUST NOT depend on the failover path; the SLO is rule-set freshness P99 ≤ 5 min under normal operation. See /trust/slos for the published commitments.
Honest GA disclosure. The production R2 binding deploys at the Phase 4 production cutover (2026-05-29). Until then the R2 tier is staging-bound; the KV tier is the primary production path. The published SLOs apply once the R2 binding is live.

7. Failover alert tags

The gateway emits stable alert tags on the failover path. These are operator-facing diagnostic tags drawn from the cell-matrix vocabulary; customers may see the corresponding SLO impact on /trust/slos but do not consume these tag values directly.
TagSeverityCondition
P1_kv_unreachableP1KV read returned an unreachable error.
P0_kv_sig_failP0KV envelope signature did not verify.
P0_r2_unreachableP0R2 fallback read returned an unreachable error.
P0_r2_sig_failP0R2 envelope signature did not verify.
P1_isolate_staleP1Last-known-good in-isolate cache exceeded freshness target.
P0_isolate_stale_24hP0Last-known-good in-isolate cache exceeded 24 h staleness; fail-closed on safety-critical checkpoints.
P0_coordinated_attackP0Both KV and R2 signatures failed in a single read — the layered-defense signal.
P0_data_plane_unavailableP0All read tiers exhausted; gateway returns 503.

8. Example — a signed envelope at GA

The Day-1 envelope carries the five GA-seeded synthetic Managed Rules. Signatures, identifiers, and signed-at are placeholder-shaped here; production envelopes carry the real cryptographic values.
{
  "recipes": [
    {
      "recipe_id": "rec_synthetic_001",
      "composition_scope": "platform",
      "surface": ["incoming"],
      "severity_p": "p2",
      "scope": "production"
    },
    {
      "recipe_id": "rec_synthetic_002",
      "composition_scope": "platform",
      "surface": ["incoming", "tool_responses"],
      "severity_p": "p2",
      "scope": "production"
    }
    /* ... three more synthetic seed entries ... */
  ],
  "signature": "<base64url ed25519>",
  "key_id": "rkv-2026-q2-a",
  "signed_at": "2026-05-30T00:00:00Z"
}

9. Validation notes

  • Versioning. key_id includes the rotation cohort. The gateway verifies against the JWKS bound in its worker env, never a hardcoded key.
  • Signature failure is loud. The gateway emits P0_kv_sig_fail or P0_r2_sig_fail on signature failure and falls through to the next tier. It does not silently accept an envelope whose signature did not verify.
  • Replay defense. The signed message includes key_id and signed_at — an envelope captured at time T cannot be replayed under a different signed_at because the signature would not verify.

See also