> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Substrate Guard (lite)

> Deterministic input bounds and DoS hardening for the JCS substrate: runs before canonicalization and fails closed on resource hostile payloads. Apache 2.0.

[![Keystone Enabled](https://img.shields.io/badge/Keystone-enabled-5cb9f8)](/keystone)

The substrate already fails closed on **malformed** input. But a payload can be perfectly valid JSON and still be hostile by **resource**: megabytes of data, nested ten thousand deep, millions of keys, an 8 MB string, a number outside the safe-integer range. Those pass "is it well formed?" and land in your canonicalizer and hasher, which is exactly where a cheap denial of service lives.

**Substrate Guard (lite)** is the front door that stops them. It is a deterministic input-bounds gate that runs **before** any RFC 8785 JCS or SHA-256 work touches the payload. It either accepts, or rejects with a named code (`REJECT_OVER_DEPTH`, `REJECT_TOO_MANY_KEYS`, and so on). It never truncates and never repairs: no silent mangling, no ambiguous half-processing. It is **strictly additive over the frozen Layer 1**: it changes no hash and adds no cryptographic primitive.

<Info>
  **Apache-2.0 open source.** Install via `pip install algovoi-substrate-guard` or `npm install @algovoi/substrate-guard`. Python and TypeScript reject the same hostile inputs with the same code and compute the same `profile_ref`, byte for byte. This is the **lite** tier: a structural validator plus a content-addressed profile. It is not cryptography, and not rate limiting or replay windows. Those live in the runtime verifier layer.
</Info>

## How it works

Two pieces, both using the RFC 8785 JCS canonicalisation and SHA-256 already in the substrate:

```
profile_ref = "sha256:" + SHA-256(JCS(profile))
guard(value, profile)  ->  accept, or raise a named code, BEFORE canonicalization
```

* **`profile_ref`** content-addresses the limits in force. The same discipline as [Policy Binding](/policy-binding): a record can carry the `profile_ref` it was admitted under, so a verifier can prove which bounds were enforced, not just that "some validation happened." Key order does not matter (JCS sorts), so the reference is invariant to how the profile was constructed.
* **`guard(value, profile)`** validates in a single pass: structural bounds first (cheap, fail fast), then the canonical-size bound last, on an already-bounded value, so the size check cannot itself blow up.

## Default profile `guard-receipt-v1`

| Limit                                        | Default | Reject code                                                                 |
| -------------------------------------------- | ------- | --------------------------------------------------------------------------- |
| `max_bytes` (UTF-8 of canonical form)        | 65536   | `REJECT_OVER_SIZE`                                                          |
| `max_depth` (nesting, root = 1)              | 32      | `REJECT_OVER_DEPTH`                                                         |
| `max_object_keys` (per object)               | 256     | `REJECT_TOO_MANY_KEYS`                                                      |
| `max_array_length`                           | 1024    | `REJECT_OVER_ARRAY`                                                         |
| `max_string_length` (per string and per key) | 8192    | `REJECT_OVER_STRING`                                                        |
| `max_total_nodes`                            | 4096    | `REJECT_OVER_NODES`                                                         |
| `number_safety`                              | on      | `REJECT_UNSAFE_NUMBER` (outside the JSON safe-integer range, or non-finite) |

The default profile addresses to `sha256:a4791b13c67a16109b85ef67fc65700ea902b6ad40dad44d8556632c3d5524a6`. Pin it, or content-address your own profile.

## What a verifier can check

| Verifier holds                                | What they can check                                                                    |
| --------------------------------------------- | -------------------------------------------------------------------------------------- |
| A `profile_ref` + the profile                 | That the bounds in force are exactly these (`profile_ref` recomputes)                  |
| A record carrying its admitting `profile_ref` | Which limits the record was admitted under, provably, after the fact                   |
| A reject code + the value + the profile       | That the named bound is the one exceeded, identically in any implementation            |
| The same profile, keys reordered              | The `profile_ref` is unchanged (JCS sorts), so the address is construction-independent |

No issuer call. No registry lookup. No AlgoVoi service. RFC 8785 JCS, SHA-256, and a JSON parser are the entire dependency. Every bound is a pure structural property of the parsed value (depth, count, length), so independent implementations enforce it identically. The guard **enables** rejection; acting on a mismatch is a runtime decision, not a property of the construction.

## Use

```python theme={null}
from algovoi_substrate_guard import guard, profile_ref, GuardError, Profile

try:
    guard(value)                  # default profile guard-receipt-v1; accept or raise
    # ... then your existing action_ref(...) / decision_ref(...) / a receipt
except GuardError as e:
    print("rejected:", e.code)    # e.g. REJECT_OVER_DEPTH

profile_ref()                                       # "sha256:a4791b13…c3d5524a6"
profile_ref(Profile(max_depth=8, max_object_keys=16))   # your own pinnable profile
```

```ts theme={null}
import { guard, profileRef, GuardError, DEFAULT_PROFILE } from '@algovoi/substrate-guard';

try {
  guard(value);
} catch (e) {
  if (e instanceof GuardError) console.log('rejected:', e.code);
}

profileRef();                                       // "sha256:a4791b13…c3d5524a6"
profileRef({ ...DEFAULT_PROFILE, max_depth: 8 });   // your own pinnable profile
```

## Conformance

The `substrate_guard_v1` vector set (15 vectors) is published in the public corpus,
[chopmob-cloud/algovoi-jcs-conformance-vectors](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors),
with Python and Node runners. It covers the two profile\_ref vectors, the accept controls (including the safe-integer boundary), one isolated rejection per bound (each value exceeds exactly one limit by one, and must reject with the named code), and the key-order invariance of `profile_ref`. Python and TypeScript reproduce every value byte for byte.

## Honest scope

A deterministic structural validator plus a content-addressed profile. It is **not** cryptography, and it is **not** rate limiting or replay windows. Rate limiting and replay protection stay in the runtime verifier layer, and are never claimed as a property of the substrate. This page documents the open, lite tier of the AlgoVoi hardening layer.

## Lite vs commercial

|            | Lite (this package)                        | Commercial verifier layer                               |
| ---------- | ------------------------------------------ | ------------------------------------------------------- |
| Licence    | Apache-2.0, open                           | Commercial OEM                                          |
| Protection | structural input bounds, fail closed       | the same, plus runtime rate limiting and replay windows |
| Scope      | per-payload, pre-canonicalization          | per-caller / per-window, at the edge                    |
| Verifier   | recompute `profile_ref` offline            | maintained verifier                                     |
| Best for   | open integrations, hardening the substrate | regulated production, enterprise terms                  |

## The decision chain

Substrate Guard composes in one line with everything already built on the canonicalisation substrate. Call `guard(value)` before your existing reference construction, for example before an [Agent Passport](/agent-passport) reference, a [Spend Guardrail (lite)](/spend-guardrail-lite) decision, or a [Compliance Gate (lite)](/compliance-gate-lite) verdict. Because it changes no hash, every reference downstream gets the protection for free, with no format change.

## Adopters

If you build on `algovoi-substrate-guard`, pin `==0.1.0`, anchor a canonical `profile_ref` hash from `substrate_guard_v1` (for example `a4791b13…` for guard-receipt-v1), and keep the `NOTICE`, you qualify for a free **v0 licence key** for `algovoi-mandate-auditor`. The gate is `scripts/check_v0_adoption.py` (dependency + canonical hash anchor + NOTICE + version pin, all four pass, then ISSUE\_V0\_KEY). Apply: email [chopmob@gmail.com](mailto:chopmob@gmail.com).

## Relationship to the open substrate

Substrate Guard (lite) sits directly in front of the open [JCS Canonicalisation Substrate](/canonicalisation-substrate) and composes with [Policy Binding](/policy-binding), [Compliance Gate (lite)](/compliance-gate-lite), [Spend Guardrail (lite)](/spend-guardrail-lite), and the [Retention Chain](/retention-chain-substrate). It uses the same RFC 8785 JCS and SHA-256 primitives, with no additional cryptographic dependencies.

## Specification

Substrate Guard is the resource-bounds edition of input validation. It anchors to the existing input-validation section of IETF Internet-Draft [`draft-hopley-x402-retention-chain`](https://datatracker.ietf.org/doc/draft-hopley-x402-retention-chain/) (§7.5, the same section the `adversarial_isolation_v1` set anchors to), where the prior set covers malformed input and Substrate Guard covers well-formed but resource-hostile input. No new draft section is asserted. The normative byte-level artifact for this construction is the published [`substrate_guard_v1`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors/tree/main/vectors/substrate_guard_v1) conformance set. Additive over the frozen canonicalisation substrate, sole AlgoVoi authorship.
