Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions docs/architecture/contracts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Cross-runtime contracts
description: Versioned Neural objects shared with hosted consumers
---

Neural owns the JSON Schema for six versioned objects used across Python and
TypeScript runtimes:

- `MarketSnapshot`
- `ResearchEvidenceRef`
- `ExecutionIntent`
- `RiskDecision`
- `PaperOrder`
- `PostTradeReview`

The authoritative bundle is
`neural/contracts/schemas/neural-contracts-v1.schema.json`. Pydantic validators,
golden fixtures, and the digest manifest are derived from that source. A
consumer must pin the manifest digests rather than reinterpret the contract.

## Validate an object

```python
from neural.contracts import validate_contract

validated = validate_contract(candidate)
```

Validation rejects unknown schema names, unknown versions, extra fields, and
malformed lineage. Decimal probabilities and prices use strings so canonical
JSON bytes are stable across runtimes.

This layer is a structural transport boundary. It validates shape, canonical
hashes, exact lineage identities, and transport safety. It does not decide
market coherence, risk approval, order-fill correctness, temporal business
ordering, redaction policy, or realized PnL. Consumers must run their owning
domain validator before treating a structurally valid object as actionable.

## Verify a signed envelope

```python
from datetime import datetime, timezone

from neural.contracts import InMemoryNonceReplayGuard, verify_envelope

contract = verify_envelope(
envelope,
secrets={"consumer-key-v1": secret},
replay_guard=InMemoryNonceReplayGuard(),
now=datetime.now(timezone.utc),
)
```

Verification fails closed on schema, payload hash, lifetime, key identity,
HMAC signature, and nonce replay. Inject a durable replay guard in a hosted
consumer; the in-memory guard is intended for local and test use.

Signing does not grant execution authority. Risk policy and order execution
remain consumer-owned gates.
2 changes: 1 addition & 1 deletion docs/architecture/meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"title": "Architecture",
"pages": ["start-here", "overview", "stability"]
"pages": ["start-here", "overview", "contracts", "stability"]
}
51 changes: 51 additions & 0 deletions neural/contracts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Versioned cross-runtime contracts for Neural consumers."""

from .canonical import (
ContractEnvelopeError,
InMemoryNonceReplayGuard,
canonical_json,
contract_payload_hash,
sign_envelope,
verify_envelope,
with_payload_hash,
)
from .registry import (
CONTRACT_NAMES,
CONTRACT_VERSION,
ContractValidationError,
ExecutionIntent,
MarketSnapshot,
PaperOrder,
PostTradeReview,
ResearchEvidenceRef,
RiskDecision,
contract_model,
load_contract_bundle,
schema_for,
validate_contract,
validate_json_schema,
)

__all__ = [
"CONTRACT_NAMES",
"CONTRACT_VERSION",
"ContractEnvelopeError",
"ContractValidationError",
"ExecutionIntent",
"InMemoryNonceReplayGuard",
"MarketSnapshot",
"PaperOrder",
"PostTradeReview",
"ResearchEvidenceRef",
"RiskDecision",
"canonical_json",
"contract_model",
"contract_payload_hash",
"load_contract_bundle",
"schema_for",
"sign_envelope",
"validate_contract",
"validate_json_schema",
"verify_envelope",
"with_payload_hash",
]
192 changes: 192 additions & 0 deletions neural/contracts/canonical.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
"""Canonical serialization and signed-envelope verification."""

from __future__ import annotations

import hashlib
import hmac
import json
from collections.abc import Mapping
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any

from .registry import validate_contract, validate_json_schema


class ContractEnvelopeError(ValueError):
"""A signed contract envelope failed a named fail-closed check."""

def __init__(self, code: str, detail: str) -> None:
self.code = code
self.detail = detail
super().__init__(f"{code}: {detail}")


def canonical_json(value: Any) -> str:
"""Serialize JSON data with stable UTF-8 cross-runtime bytes."""
_reject_lone_surrogates(value)
try:
return json.dumps(
value,
allow_nan=False,
ensure_ascii=False,
separators=(",", ":"),
sort_keys=True,
)
except (TypeError, ValueError) as exc:
raise ContractEnvelopeError("canonicalization_failed", str(exc)) from exc


def _reject_lone_surrogates(value: Any) -> None:
if isinstance(value, str):
if any(0xD800 <= ord(character) <= 0xDFFF for character in value):
raise ContractEnvelopeError(
"canonicalization_failed",
"lone surrogate code points are not valid contract text",
)
return
if isinstance(value, Mapping):
for key, item in value.items():
_reject_lone_surrogates(key)
_reject_lone_surrogates(item)
return
if isinstance(value, (list, tuple)):
for item in value:
_reject_lone_surrogates(item)


def contract_payload_hash(contract: Mapping[str, Any]) -> str:
"""Hash a contract after excluding its self-referential payloadHash."""
unsigned = dict(contract)
unsigned.pop("payloadHash", None)
return hashlib.sha256(canonical_json(unsigned).encode("utf-8")).hexdigest()
Comment thread
hudsonaikins marked this conversation as resolved.


def with_payload_hash(contract: Mapping[str, Any]) -> dict[str, Any]:
"""Return a detached contract with its canonical payload hash."""
result = json.loads(canonical_json(contract))
result["payloadHash"] = contract_payload_hash(result)
return result


def _unsigned_envelope(envelope: Mapping[str, Any]) -> dict[str, Any]:
unsigned = dict(envelope)
unsigned.pop("signature", None)
return unsigned


def _signature(envelope: Mapping[str, Any], secret: str) -> str:
digest = hmac.new(
secret.encode("utf-8"),
canonical_json(_unsigned_envelope(envelope)).encode("utf-8"),
hashlib.sha256,
).hexdigest()
return f"sha256={digest}"


def sign_envelope(
contract: Mapping[str, Any],
*,
secret: str,
key_id: str,
issued_at: str,
expires_at: str,
nonce: str,
) -> dict[str, Any]:
"""Build and sign one v1 transport envelope."""
if not secret:
raise ContractEnvelopeError("unknown_key", key_id)
expected_hash = contract_payload_hash(contract)
if not hmac.compare_digest(str(contract.get("payloadHash", "")), expected_hash):
raise ContractEnvelopeError("payload_hash_mismatch", "contract payloadHash is invalid")
validated = validate_contract(contract)
issued = _timestamp(issued_at, field_name="issuedAt")
expires = _timestamp(expires_at, field_name="expiresAt")
if issued >= expires:
raise ContractEnvelopeError("lifetime_invalid", "issuedAt must precede expiresAt")
envelope: dict[str, Any] = {
"algorithm": "hmac-sha256-v1",
"contract": validated,
"envelopeSchemaName": "SignedContractEnvelope",
"envelopeVersion": "1.0.0",
"expiresAt": expires_at,
"issuedAt": issued_at,
"keyId": key_id,
"nonce": nonce,
}
envelope["signature"] = _signature(envelope, secret)
validate_json_schema("SignedContractEnvelope", envelope)
Comment thread
hudsonaikins marked this conversation as resolved.
return envelope


@dataclass
class InMemoryNonceReplayGuard:
"""Deterministic injected replay guard for local and test consumers."""

_seen: set[tuple[str, str]] = field(default_factory=set)

def consume(self, key_id: str, nonce: str) -> bool:
"""Return false for a replay; otherwise retain the nonce."""
identity = (key_id, nonce)
if identity in self._seen:
return False
self._seen.add(identity)
return True


def _timestamp(value: str, *, field_name: str) -> datetime:
try:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError as exc:
raise ContractEnvelopeError("timestamp_invalid", field_name) from exc
if parsed.tzinfo is None or parsed.utcoffset() is None:
raise ContractEnvelopeError("timestamp_invalid", field_name)
return parsed.astimezone(timezone.utc)


def verify_envelope(
envelope: Mapping[str, Any],
*,
secrets: Mapping[str, str],
replay_guard: InMemoryNonceReplayGuard,
now: datetime,
) -> dict[str, Any]:
"""Verify schema, hash, lifetime, signature, and nonce exactly once."""
try:
validated_envelope = validate_json_schema("SignedContractEnvelope", dict(envelope))
except ValueError as exc:
raise ContractEnvelopeError("schema_invalid", str(exc)) from exc

raw_contract = validated_envelope["contract"]
expected_hash = contract_payload_hash(raw_contract)
if not hmac.compare_digest(str(raw_contract["payloadHash"]), expected_hash):
raise ContractEnvelopeError("payload_hash_mismatch", "contract payloadHash is invalid")
try:
contract = validate_contract(raw_contract)
except ValueError as exc:
raise ContractEnvelopeError("schema_invalid", str(exc)) from exc

if now.tzinfo is None or now.utcoffset() is None:
raise ContractEnvelopeError("timestamp_invalid", "now")
current = now.astimezone(timezone.utc)
issued_at = _timestamp(str(validated_envelope["issuedAt"]), field_name="issuedAt")
expires_at = _timestamp(str(validated_envelope["expiresAt"]), field_name="expiresAt")
if issued_at >= expires_at:
raise ContractEnvelopeError("lifetime_invalid", "issuedAt must precede expiresAt")
if current < issued_at:
raise ContractEnvelopeError("not_yet_valid", "envelope issuedAt is in the future")
if current >= expires_at:
raise ContractEnvelopeError("expired", "envelope lifetime ended")

key_id = str(validated_envelope["keyId"])
secret = secrets.get(key_id)
if not secret:
raise ContractEnvelopeError("unknown_key", key_id)
Comment thread
hudsonaikins marked this conversation as resolved.
expected_signature = _signature(validated_envelope, secret)
if not hmac.compare_digest(str(validated_envelope["signature"]), expected_signature):
raise ContractEnvelopeError("bad_signature", "signature verification failed")

nonce = str(validated_envelope["nonce"])
if not replay_guard.consume(key_id, nonce):
raise ContractEnvelopeError("nonce_replay", nonce)
return contract
Loading
Loading