Metadata-Version: 2.4
Name: alelyon-mock
Version: 0.1.0
Summary: A local mock of the Alelyon read-only v1 API — deterministic synthetic data, no hosting required.
Author: Alelyon
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/TLace03/Alelyon-Dev-Tools
Project-URL: Repository, https://github.com/TLace03/Alelyon-Dev-Tools
Project-URL: Issues, https://github.com/TLace03/Alelyon-Dev-Tools/issues
Keywords: alelyon,mock-server,api-mock,openapi,testing,fixtures
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Framework :: FastAPI
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing :: Mocking
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.115
Requires-Dist: uvicorn[standard]>=0.30
Provides-Extra: certified
Requires-Dist: alelyon-verify>=0.1; extra == "certified"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: alelyon-sdk>=0.1; extra == "dev"
Requires-Dist: alelyon-verify>=0.1; extra == "dev"
Dynamic: license-file

# alelyon-mock

A local stand-in for the Alelyon read-only v1 API. All 20 routes, deterministic
synthetic data, no hosting.

```bash
pip install "alelyon-mock[certified]"
alelyon-mock                      # http://127.0.0.1:8710
```

Then point the SDK at it:

```python
from alelyon_sdk import AlelyonClient

with AlelyonClient("http://127.0.0.1:8710") as c:
    c.health()
    c.bars("AAPL", lookback_days=90)
    c.screener(["AAPL", "MSFT"])
```

## Why this exists

`alelyon-sdk` is a client, and there is no public Alelyon endpoint. The real API
reads a proprietary capture store and runs proprietary engines, so it is never going
to be hosted for the public. Without something to connect to, the SDK is a library
you can read but not run.

This is the same answer Stripe reached with `stripe-mock`: ship the fake. It costs
nothing to run, exposes nothing, works on a plane, and — because it is deterministic —
it cannot break your CI on a Tuesday because a data provider hiccupped.

## What it is not

- **Not market data.** Every price, yield and spread is seeded noise. It is not a
  feed, not a backtest input, and not investment advice.
- **Not the engine.** No signal generation, no execution, no broker. `/v1/answer`
  refuses rather than fabricate, because a mock that invented an answer would be
  exactly the dishonesty the certified pipeline exists to prevent.
- **Not a conformance oracle.** It follows [`spec/openapi.json`](../../spec/openapi.json),
  which is the contract of record. Where they disagree, the spec wins and the mock has
  a bug.

## Determinism

Every value derives from a seeded generator keyed by a stable hash of the scope, and
every date derives from a frozen `ASOF` constant. The same request returns the same
bytes on every machine, forever. `tests/test_determinism.py` enforces it, including
across separate processes — Python's built-in `hash()` is salted per process, so a
fixture seeded with it would drift between restarts and nowhere else.

The fixture universe is closed: twelve tickers and eight FRED series. Anything else
returns 404, so your error handling is exercised too.

## Certificates behave like the real thing

Certificates are the point of the API, and the mock's are physically coherent rather
than decorative. Each column's quantization step is derived from that column's actual
magnitude at 24 bits, and the error variance is `Δ²/12`. That reproduces the trap the
[certificates guide](../../docs/certificates.md) warns about:

```python
cert = c.bars("AAPL")["certificate"]
cert["delta_max"]                         # ~6      -- the VOLUME column's bound
cert["columns"]["close"]["delta_max"]     # ~2.5e-5 -- the actual price bound
```

If you learn to read a certificate against this mock, you will read a real one
correctly.

## Real signatures, offline

With the `[certified]` extra, `/v1/certified/*` issues **genuinely Ed25519-signed**
Certified Number Envelopes through `alelyon-verify`'s reference producer. The whole
trust loop closes on your laptop:

```python
from alelyon_sdk import AlelyonClient
from alelyon_verify import verify_envelope

with AlelyonClient("http://127.0.0.1:8710") as c:
    key = c.certified_pubkey()["public_key"]
    env = c.certify(program='show mean(returns(price("AAPL")))')["envelope"]

verify_envelope(env, my_series, public_key_hex=key)["ok"]    # True
```

Tamper with the envelope and it stops verifying, exactly as it would against a real
issuer. Without the extra those routes return 503 naming the extra to install — the
mock will not fake a signature, because a fake signature is worse than no endpoint.

The signing key is generated into a temporary directory at startup and is different
every run, deliberately: a mock's key must never look like something to trust.

## Auth

Mirrors the real service, so you can develop client auth offline.

| `ALELYON_API_KEY` | Behaviour |
| --- | --- |
| unset | Open mode — serves loopback clients only; a non-local peer gets 403 |
| set | Every request needs `Authorization: Bearer <key>`; otherwise 401 |

The check is middleware on every path, including `/docs` and `/openapi.json`.

## CLI

```
alelyon-mock [--host 127.0.0.1] [--port 8710] [--reload] [--log-level warning]
```

It refuses to bind beyond loopback without a key set, matching the real runner.
Interactive docs are at `/docs`.

## Licence

Apache-2.0.
