deadlatch 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deadlatch-0.1.0/CONTRIBUTING.md +81 -0
- deadlatch-0.1.0/DISCLAIMER.md +68 -0
- deadlatch-0.1.0/LICENSE +21 -0
- deadlatch-0.1.0/MANIFEST.in +19 -0
- deadlatch-0.1.0/PKG-INFO +305 -0
- deadlatch-0.1.0/README.md +268 -0
- deadlatch-0.1.0/README.zh-CN.md +236 -0
- deadlatch-0.1.0/SECURITY.md +67 -0
- deadlatch-0.1.0/docs/assets/agent-blocked.gif +0 -0
- deadlatch-0.1.0/docs/quickstart/cli.sh +101 -0
- deadlatch-0.1.0/docs/quickstart/mcp_client.py +126 -0
- deadlatch-0.1.0/docs/quickstart/python.py +116 -0
- deadlatch-0.1.0/pyproject.toml +76 -0
- deadlatch-0.1.0/setup.cfg +4 -0
- deadlatch-0.1.0/src/deadlatch/__init__.py +32 -0
- deadlatch-0.1.0/src/deadlatch/_decimal.py +37 -0
- deadlatch-0.1.0/src/deadlatch/_resources.py +33 -0
- deadlatch-0.1.0/src/deadlatch/_timeutil.py +25 -0
- deadlatch-0.1.0/src/deadlatch/_validation.py +176 -0
- deadlatch-0.1.0/src/deadlatch/audit.py +325 -0
- deadlatch-0.1.0/src/deadlatch/cli.py +201 -0
- deadlatch-0.1.0/src/deadlatch/direction.py +115 -0
- deadlatch-0.1.0/src/deadlatch/engine.py +256 -0
- deadlatch-0.1.0/src/deadlatch/exposure.py +161 -0
- deadlatch-0.1.0/src/deadlatch/guard.py +151 -0
- deadlatch-0.1.0/src/deadlatch/mcp_server.py +582 -0
- deadlatch-0.1.0/src/deadlatch/migrations.py +196 -0
- deadlatch-0.1.0/src/deadlatch/model.py +172 -0
- deadlatch-0.1.0/src/deadlatch/report.py +135 -0
- deadlatch-0.1.0/src/deadlatch/rules/__init__.py +6 -0
- deadlatch-0.1.0/src/deadlatch/rules/base.py +40 -0
- deadlatch-0.1.0/src/deadlatch/rules/cash_margin_check.py +169 -0
- deadlatch-0.1.0/src/deadlatch/rules/data_freshness.py +48 -0
- deadlatch-0.1.0/src/deadlatch/rules/input_validity.py +57 -0
- deadlatch-0.1.0/src/deadlatch/rules/kill_switch.py +51 -0
- deadlatch-0.1.0/src/deadlatch/rules/max_daily_loss.py +47 -0
- deadlatch-0.1.0/src/deadlatch/rules/max_drawdown.py +49 -0
- deadlatch-0.1.0/src/deadlatch/rules/max_order_quantity.py +37 -0
- deadlatch-0.1.0/src/deadlatch/rules/max_order_value.py +44 -0
- deadlatch-0.1.0/src/deadlatch/rules/max_symbol_exposure.py +95 -0
- deadlatch-0.1.0/src/deadlatch/rules/max_total_exposure.py +82 -0
- deadlatch-0.1.0/src/deadlatch/rules/missing_data_fail_closed.py +132 -0
- deadlatch-0.1.0/src/deadlatch/rules/order_time_validity.py +62 -0
- deadlatch-0.1.0/src/deadlatch/rules/registry.py +111 -0
- deadlatch-0.1.0/src/deadlatch/rules/stubs.py +47 -0
- deadlatch-0.1.0/src/deadlatch/schemas/audit-record.schema.json +86 -0
- deadlatch-0.1.0/src/deadlatch/schemas/order.schema.json +143 -0
- deadlatch-0.1.0/src/deadlatch/schemas/policy.schema.json +138 -0
- deadlatch-0.1.0/src/deadlatch/schemas/portfolio.schema.json +143 -0
- deadlatch-0.1.0/src/deadlatch/schemas/result.schema.json +148 -0
- deadlatch-0.1.0/src/deadlatch/schemas/shadow-report.schema.json +110 -0
- deadlatch-0.1.0/src/deadlatch.egg-info/PKG-INFO +305 -0
- deadlatch-0.1.0/src/deadlatch.egg-info/SOURCES.txt +55 -0
- deadlatch-0.1.0/src/deadlatch.egg-info/dependency_links.txt +1 -0
- deadlatch-0.1.0/src/deadlatch.egg-info/entry_points.txt +3 -0
- deadlatch-0.1.0/src/deadlatch.egg-info/requires.txt +24 -0
- deadlatch-0.1.0/src/deadlatch.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for considering contributing to Deadlatch. This project follows a
|
|
4
|
+
second-auditor acceptance loop: changes are verified on disk by an independent
|
|
5
|
+
reviewer before any commit/tag/release. Keep the working tree reviewable.
|
|
6
|
+
|
|
7
|
+
## Local environment
|
|
8
|
+
|
|
9
|
+
- Python 3.10+ (develop on 3.11; CI tests 3.10/3.11/3.12).
|
|
10
|
+
- Create the virtualenv and install editable with test/build/docs extras:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
python3 -m venv .venv
|
|
14
|
+
.venv/bin/pip install -e ".[dev]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Verification commands (must all pass)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
.venv/bin/python -m pytest -p no:cacheprovider tests/ -q # full suite
|
|
21
|
+
.venv/bin/python tools/validate_schemas.py # schema + meta-schema
|
|
22
|
+
.venv/bin/python tools/scan_sensitive.py # sensitive-data scan
|
|
23
|
+
COVERAGE_FILE=/tmp/deadlatch.coverage .venv/bin/python -m pytest -p no:cacheprovider \
|
|
24
|
+
--cov-branch --cov=deadlatch --cov-report=term tests/ -q # branch coverage ≥90%
|
|
25
|
+
git diff --check
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- No `skip`, no `xfail`. Branch coverage must stay ≥ 90%.
|
|
29
|
+
- Packaging verification after changing runtime resources:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
.venv/bin/python -m build
|
|
33
|
+
.venv/bin/python tools/verify_wheel.py dist/*.whl
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
After version or documentation changes, regenerate the public hash
|
|
37
|
+
manifest so the root file cannot stay stale:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
.venv/bin/python tools/make_release_candidate.py --out /tmp/deadlatch-candidate --sync-source
|
|
41
|
+
.venv/bin/python tools/verify_hash_manifest.py /tmp/deadlatch-candidate
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Local and ordinary CI wheel/sdist hashes are not the PyPI upload
|
|
45
|
+
identity. Only the `release.yml` publish job's pre-upload
|
|
46
|
+
`name size sha256` lines, matched against the PyPI JSON readback, are
|
|
47
|
+
the published artifacts.
|
|
48
|
+
|
|
49
|
+
## Rule discipline
|
|
50
|
+
|
|
51
|
+
- **Schema is the contract.** Rule behavior, exit codes (0/2/3/4/5), and
|
|
52
|
+
decision synthesis follow `rules-spec.md` and the versioned schemas in
|
|
53
|
+
`schemas/`. The packaged copies under `src/deadlatch/schemas/` must
|
|
54
|
+
stay byte-identical to the repo copies (`tests/test_resources.py` enforces it).
|
|
55
|
+
- **Decimal, never float, for money.** All amounts and ratios go through
|
|
56
|
+
`as_decimal` (S-7 single intake).
|
|
57
|
+
- **Fail-closed.** Missing/malformed data → BLOCK/3; input errors → 4;
|
|
58
|
+
internal errors → 5. Never report an uncertain state as PASS.
|
|
59
|
+
- **No network, no broker.** Business code must not open sockets, register
|
|
60
|
+
HTTP/SSE routes, or import broker/network stacks.
|
|
61
|
+
- **No secrets, no drift.** Error text must never echo caller-supplied values
|
|
62
|
+
(use the shared safe constructors in `_validation.py`). Tests must never
|
|
63
|
+
contain real accounts, positions, tokens, paths, or logs — use string
|
|
64
|
+
concatenation for sensitive-looking probes so the scanner stays clean.
|
|
65
|
+
|
|
66
|
+
## Test change discipline (NEW-11)
|
|
67
|
+
|
|
68
|
+
- Every test **added**, **rewritten**, or **deleted** must be declared in
|
|
69
|
+
`CHANGELOG.md` with the reason, exactly like a design change.
|
|
70
|
+
- Do not weaken or delete existing assertions to make a suite green; if a test
|
|
71
|
+
expectation is wrong, justify the correction in the changelog.
|
|
72
|
+
- Do not use `try/except: return` or `assume()` to discard generated samples,
|
|
73
|
+
and do not delete fuzz samples to force green.
|
|
74
|
+
|
|
75
|
+
## What never goes in a commit
|
|
76
|
+
|
|
77
|
+
Real account numbers, holdings, credentials, tokens, cookies, absolute local
|
|
78
|
+
paths, audit JSONL, coverage output, or local policy/portfolio/order files.
|
|
79
|
+
The sensitive-data scanner (`tools/scan_sensitive.py`) runs in CI and fails
|
|
80
|
+
the build on any un-exempted hit; do not broaden its allowlist to mask
|
|
81
|
+
documented private paths.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Disclaimer
|
|
2
|
+
|
|
3
|
+
**Read this in full before using Deadlatch.** A short summary is provided
|
|
4
|
+
in the README; this document is the authoritative statement.
|
|
5
|
+
|
|
6
|
+
## Not investment advice
|
|
7
|
+
|
|
8
|
+
Deadlatch is a technical risk-evaluation tool. It does not provide
|
|
9
|
+
investment, financial, legal, or tax advice. Nothing in this repository, its
|
|
10
|
+
documentation, examples, or outputs constitutes a recommendation to buy, sell,
|
|
11
|
+
or hold any security. No rule threshold, policy example, or default limit in
|
|
12
|
+
this repository is advice about how you should trade.
|
|
13
|
+
|
|
14
|
+
## No guarantee against loss
|
|
15
|
+
|
|
16
|
+
Deadlatch evaluates orders against the policy you configure. It cannot
|
|
17
|
+
predict market moves, and it cannot prevent losses — including losses caused by
|
|
18
|
+
orders it evaluated as allowed (PASS or WARN), by orders placed without calling
|
|
19
|
+
it, by orders that ignored its BLOCK, or by incorrect inputs or configurations.
|
|
20
|
+
**The tool is a gate, not an insurance policy.** Do not trade capital you are
|
|
21
|
+
not prepared to lose.
|
|
22
|
+
|
|
23
|
+
## You are responsible for your inputs and rules
|
|
24
|
+
|
|
25
|
+
The guard evaluates exactly what you give it:
|
|
26
|
+
|
|
27
|
+
- **Inputs:** order, portfolio snapshot, and policy are provided by you. A
|
|
28
|
+
stale, fabricated, or malformed snapshot can produce a wrong verdict.
|
|
29
|
+
Validate your data sources yourself.
|
|
30
|
+
- **Rules:** the 12 rules and their thresholds come from the policy you write.
|
|
31
|
+
You are responsible for configuring limits that match your actual account,
|
|
32
|
+
instruments, and risk tolerance.
|
|
33
|
+
- **Fail-closed is not correctness:** BLOCK on missing data is safe-by-default,
|
|
34
|
+
but a policy that is too loose, or inputs that are wrong in ways the schema
|
|
35
|
+
cannot detect, are outside this tool's control.
|
|
36
|
+
|
|
37
|
+
## The guard never places orders
|
|
38
|
+
|
|
39
|
+
Deadlatch has no broker connectivity, no order routing, and no execution
|
|
40
|
+
capability. It only evaluates. Any order submission is performed exclusively by
|
|
41
|
+
you or by the system you integrate it into.
|
|
42
|
+
|
|
43
|
+
## Advisory-only and bypass
|
|
44
|
+
|
|
45
|
+
Deadlatch is advisory. It cannot force an agent that never calls it to
|
|
46
|
+
call it, and it cannot stop an agent that ignores a BLOCK from submitting
|
|
47
|
+
orders elsewhere. Whether the agent calls the guard and honors the result is
|
|
48
|
+
the integrator's decision. Do not assume the guard can stop a fully bypassing
|
|
49
|
+
agent.
|
|
50
|
+
|
|
51
|
+
## Examples are fictional
|
|
52
|
+
|
|
53
|
+
All tickers, orders, portfolios, policies, and numbers in examples, quick
|
|
54
|
+
starts, tests, and generated artifacts are fictional. They exist to demonstrate
|
|
55
|
+
mechanics, not to suggest real instruments, positions, or strategies. Any
|
|
56
|
+
resemblance to real securities or accounts is coincidental.
|
|
57
|
+
|
|
58
|
+
## Test before live trading
|
|
59
|
+
|
|
60
|
+
The project is early `0.1.0` software. Before using it with real
|
|
61
|
+
capital, simulate, backtest, and verify behavior on your own data and against
|
|
62
|
+
your own broker semantics. Do not deploy it for live trading based solely on
|
|
63
|
+
this documentation.
|
|
64
|
+
|
|
65
|
+
## No SLA
|
|
66
|
+
|
|
67
|
+
This project is provided as-is without any support or service-level commitment.
|
|
68
|
+
See the MIT [LICENSE](LICENSE) for the full warranty disclaimer.
|
deadlatch-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Deadlatch contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# §二.5:sdist 只含发布物——排除 tests/工具/示例/CI/运行数据。
|
|
2
|
+
# FIX-006-1:docs 资产(演示 GIF + 三个 Quick Start)必须随 sdist 发布。
|
|
3
|
+
include LICENSE
|
|
4
|
+
include README.md
|
|
5
|
+
include README.zh-CN.md
|
|
6
|
+
include SECURITY.md
|
|
7
|
+
include CONTRIBUTING.md
|
|
8
|
+
include DISCLAIMER.md
|
|
9
|
+
include pyproject.toml
|
|
10
|
+
recursive-include src/deadlatch/schemas *.json
|
|
11
|
+
recursive-include docs *.md *.py *.sh *.gif
|
|
12
|
+
prune tests
|
|
13
|
+
prune tools
|
|
14
|
+
prune examples
|
|
15
|
+
prune .github
|
|
16
|
+
global-exclude *.py[cod]
|
|
17
|
+
global-exclude __pycache__
|
|
18
|
+
global-exclude .DS_Store
|
|
19
|
+
global-exclude *.audit.jsonl
|
deadlatch-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: deadlatch
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Local-first pre-trade risk evaluation library and CLI for AI trading agents. Advisory-only: whether the agent calls the guard and honors its result is the integrator's decision. Broker-agnostic, fully auditable.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: trading,risk,pre-trade,guardrail,advisory,fail-closed,audit,mcp,agent
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: jsonschema>=4.0
|
|
19
|
+
Requires-Dist: PyYAML>=6.0
|
|
20
|
+
Requires-Dist: mcp<3,>=2.0
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
23
|
+
Requires-Dist: pytest-cov>=5.0; extra == "test"
|
|
24
|
+
Requires-Dist: hypothesis>=6.100; extra == "test"
|
|
25
|
+
Requires-Dist: build>=1.0; extra == "test"
|
|
26
|
+
Requires-Dist: Pillow>=10.0; extra == "test"
|
|
27
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "test"
|
|
28
|
+
Provides-Extra: build
|
|
29
|
+
Requires-Dist: build>=1.0; extra == "build"
|
|
30
|
+
Provides-Extra: docs
|
|
31
|
+
Requires-Dist: Pillow>=10.0; extra == "docs"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: deadlatch[test]; extra == "dev"
|
|
34
|
+
Requires-Dist: deadlatch[build]; extra == "dev"
|
|
35
|
+
Requires-Dist: deadlatch[docs]; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# Deadlatch
|
|
39
|
+
|
|
40
|
+
**The pre-trade latch for your trading agent.** Advisory-only.
|
|
41
|
+
|
|
42
|
+
Three things you need to know before anything else:
|
|
43
|
+
|
|
44
|
+
1. **You need an independent, cross-broker gate that you control.** If an agent can place orders on your account, the last check between the agent and the broker should not be the agent itself — and it should not be locked to one broker's UI or rules.
|
|
45
|
+
2. **Deadlatch does not predict, does not recommend, and does not place orders.** It answers one question only: *is this order allowed right now?* It is not a signal generator and it is not a broker.
|
|
46
|
+
3. **Every answer comes with reasons, evidence, and a local audit record.** PASS / WARN / BLOCK is never a bare verdict — you can see which rule hit, why, and what was evaluated, and every check is appended to a local JSONL audit log.
|
|
47
|
+
|
|
48
|
+
**Honest boundary (please read):** Deadlatch is advisory. It cannot force an agent that never calls it to call it, and it cannot stop an agent that ignores a BLOCK from submitting the order somewhere else. Whether the agent calls the guard and honors the result is the integrator's decision. Do not rely on this tool as a guarantee against loss — it is a gate, not an insurance policy.
|
|
49
|
+
|
|
50
|
+
- **License:** MIT — see [LICENSE](LICENSE).
|
|
51
|
+
- **中文文档:** [README.zh-CN.md](README.zh-CN.md)
|
|
52
|
+
- **Security:** [SECURITY.md](SECURITY.md) · **Contributing:** [CONTRIBUTING.md](CONTRIBUTING.md) · **Disclaimer:** [DISCLAIMER.md](DISCLAIMER.md)
|
|
53
|
+
|
|
54
|
+
## Start here
|
|
55
|
+
|
|
56
|
+
<!-- mcp-name: io.github.Diabloluo/deadlatch -->
|
|
57
|
+
|
|
58
|
+
`0.1.0` is the first stable version line. **PyPI and the MCP Registry are not published yet.** Do not treat the commands below as live until https://pypi.org/p/deadlatch shows `deadlatch==0.1.0`. Until then, install the current GitHub pre-release wheel: [v0.1.0.dev1](https://github.com/Diabloluo/deadlatch/releases/tag/v0.1.0.dev1).
|
|
59
|
+
|
|
60
|
+
**Intended one-line install (after PyPI readback):**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install deadlatch==0.1.0
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**MCP-first start (after that same readback):**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uvx --from deadlatch==0.1.0 deadlatch-mcp --policy policy.yaml --portfolio portfolio.json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`--policy` and `--portfolio` are required local files. `--audit-path` and `--kill-switch-path` are optional. Use fictional or your own simulated inputs only. Deadlatch is advisory-only: it never places orders and cannot stop an agent that never calls it. Option orders must use the broker's unique full contract code as `symbol`.
|
|
73
|
+
|
|
74
|
+
Then:
|
|
75
|
+
|
|
76
|
+
1. **Run a fictional-data Quick Start** below (Python, CLI, or MCP). Confirm `PASS` → `BLOCK` → local audit.
|
|
77
|
+
2. **Request a 20-minute integration assessment** only if you already have an order-intent or simulated execution path: [open the assessment form](https://github.com/Diabloluo/deadlatch/issues/new?template=integration-assessment.yml).
|
|
78
|
+
|
|
79
|
+
That GitHub issue is **public**. Do not paste accounts, positions, orders, API keys, tokens, customer names, or private paths. Security defects must go through [GitHub Security Advisories](https://github.com/Diabloluo/deadlatch/security/advisories), not a public issue.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Quick Start (60 seconds each)
|
|
84
|
+
|
|
85
|
+
All three quick starts use fictional data and a temporary audit path. They are executed from the same source scripts by the test suite, so they cannot drift from the documentation.
|
|
86
|
+
|
|
87
|
+
### 1. Python API
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install dist/deadlatch-*.whl # or: pip install -e .
|
|
91
|
+
python docs/quickstart/python.py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Shows `Guard.from_policy(...)` → `Order` / `Portfolio` → `guard.check(...)`:
|
|
95
|
+
a valid order returns `PASS / 0`; an oversized order returns `BLOCK / 3` with the
|
|
96
|
+
hit rules; on `BLOCK` the example caller stops — no broker call is ever made.
|
|
97
|
+
|
|
98
|
+
### 2. CLI
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
bash docs/quickstart/cli.sh # requires `deadlatch` on PATH
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Creates fresh inputs in a temp directory (dynamic timestamps — never goes stale),
|
|
105
|
+
then runs `deadlatch check` for PASS (`exit 0`), BLOCK (`exit 3`), an input
|
|
106
|
+
error (`exit 4`), and a `--json` check, plus `shadow report --json` over the audit.
|
|
107
|
+
|
|
108
|
+
### 3. MCP (stdio)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
python docs/quickstart/mcp_client.py # requires `deadlatch` installed
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Starts `deadlatch-mcp` as a real subprocess over stdio, lists the five tools,
|
|
115
|
+
and calls `check_order` once for PASS and once for BLOCK. `policy` / `portfolio` /
|
|
116
|
+
`audit` paths are **server startup configuration** — an agent cannot swap them as
|
|
117
|
+
tool arguments. BLOCK is a constraint the caller must honor; technically the guard
|
|
118
|
+
cannot force a fully bypassing agent to call it.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## What it is / is not
|
|
123
|
+
|
|
124
|
+
| Deadlatch **is** | Deadlatch **is not** |
|
|
125
|
+
|---|---|
|
|
126
|
+
| A local, deterministic risk gate evaluated before you submit | A signal generator, recommender, or portfolio optimizer |
|
|
127
|
+
| A library, a CLI, and a stdio MCP server — no broker connectivity, no policy mutation | A broker adapter, an execution engine, or a market feed |
|
|
128
|
+
| An auditable check: every evaluation is written to a local JSONL log | A cloud service, a database, or a telemetry sink |
|
|
129
|
+
| USD-only, single-leg orders, one snapshot per check (v0.1) | Multi-leg, multi-currency, Greeks/IV-aware (see limitations) |
|
|
130
|
+
|
|
131
|
+
## Who should use it
|
|
132
|
+
|
|
133
|
+
- Teams that already have an order-intent or simulated execution path and
|
|
134
|
+
want an independent, deterministic pre-trade gate with a local audit trail.
|
|
135
|
+
- Developers who want a small, dependency-light, fail-closed building block they
|
|
136
|
+
can integrate into their own execution pipeline.
|
|
137
|
+
- Anyone who wants to evaluate orders against a *policy they control*, expressed
|
|
138
|
+
as plain YAML.
|
|
139
|
+
|
|
140
|
+
**Who should not use it:** anyone expecting a profit guarantee, a backtest engine,
|
|
141
|
+
a portfolio manager, or a tool that enforces itself. If the agent never calls the
|
|
142
|
+
guard, or ignores a BLOCK, nothing in this repository can stop it.
|
|
143
|
+
|
|
144
|
+
## Core security boundary
|
|
145
|
+
|
|
146
|
+
- **Local:** everything runs on your machine; no account credentials are ever
|
|
147
|
+
stored, read, or transmitted.
|
|
148
|
+
- **No network core path:** the library, CLI, and MCP server never open a socket,
|
|
149
|
+
never register an HTTP/SSE route, and never call out for quotes or anything else
|
|
150
|
+
(the MCP SDK's HTTP stack is a transitive dependency that business code never imports).
|
|
151
|
+
- **Never places orders:** the core package (library, CLI, MCP server) has
|
|
152
|
+
no broker connectivity and never submits orders. Experimental read-only
|
|
153
|
+
mapping examples exist only in the development workspace; they are not
|
|
154
|
+
included in the public candidate or the wheel, and they are not
|
|
155
|
+
live-verified integrations.
|
|
156
|
+
- **Fail-closed:** missing or malformed data → BLOCK (`exit 3`); input/config errors →
|
|
157
|
+
`exit 4`; internal errors → `exit 5`. An uncertain state is never reported as PASS.
|
|
158
|
+
- **Direction is snapshot-derived:** order-side text is never accepted as proof of a
|
|
159
|
+
close. Stock and option closing intent is recognized only when a fresh portfolio
|
|
160
|
+
snapshot contains a matching, opposite-side position with sufficient quantity.
|
|
161
|
+
For options, `symbol` must be the broker's unique full contract code; never reuse
|
|
162
|
+
an underlying ticker across different expiries, strikes, or rights.
|
|
163
|
+
- **USD-only (v0.1):** any currency mismatch (order, portfolio, positions) is an
|
|
164
|
+
input error (`exit 4`); the MCP account-status tool fail-closes on mismatch.
|
|
165
|
+
|
|
166
|
+
**Write surface:** the tool never modifies `policy`, `portfolio`, or
|
|
167
|
+
kill-switch state, never connects to a broker, and never places an order.
|
|
168
|
+
Two kinds of intentional local file writes exist:
|
|
169
|
+
|
|
170
|
+
1. **Audit subsystem:** `Guard.check()` / `check_order` append one sanitized
|
|
171
|
+
record to the local audit JSONL (30-day retention); the shadow-report
|
|
172
|
+
entry point (`deadlatch shadow report`) triggers the same retention
|
|
173
|
+
pruning, which atomically rewrites the audit file when expired records
|
|
174
|
+
exist; the audit implementation uses lock/tmp files and `os.replace` to
|
|
175
|
+
make each transaction atomic.
|
|
176
|
+
2. **Explicit migration output:** `deadlatch migrate --output <file>`
|
|
177
|
+
writes the migrated document only when you explicitly pass `--output`.
|
|
178
|
+
|
|
179
|
+
## The 12 rules (v0.1)
|
|
180
|
+
|
|
181
|
+
| # | Rule | What it guards |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| R1 | `kill_switch` | Global switch: `off` / `full` (block everything) / `reduce_only` (allow only inferred closing orders) |
|
|
184
|
+
| R2 | `input_validity` | Order passes schema, version gate, currency consistency, finite amounts (violations → `exit 4`) |
|
|
185
|
+
| R3 | `max_order_quantity` | Single-order quantity limit |
|
|
186
|
+
| R4 | `max_order_value` | Single-order notional limit (options: price × multiplier × quantity) |
|
|
187
|
+
| R5 | `max_symbol_exposure` | Exposure per underlying (options by strike × multiplier × quantity) |
|
|
188
|
+
| R6 | `max_total_exposure` | Portfolio gross exposure ratio |
|
|
189
|
+
| R7 | `cash_margin_check` | Post-trade cash floor and short-option margin |
|
|
190
|
+
| R8 | `max_daily_loss` | Daily loss ratio (PnL / day-start equity) |
|
|
191
|
+
| R9 | `max_drawdown` | Drawdown ratio from peak |
|
|
192
|
+
| R10 | `order_time_validity` | Order age / future timestamps (unparseable → fail-closed BLOCK) |
|
|
193
|
+
| R11 | `data_freshness` | Portfolio snapshot freshness (future snapshot → fail-closed) |
|
|
194
|
+
| R12 | `missing_data_fail_closed` | Missing/null/ill-formed portfolio data → `exit 3` (data unusable = risk) |
|
|
195
|
+
|
|
196
|
+
Optional rules (R3–R7) are toggled by their config keys in `policy.yaml`; a missing
|
|
197
|
+
optional key must be declared in `acknowledged_disabled` or the policy is rejected
|
|
198
|
+
(`exit 4`). Mandatory rules (R1, R2, R8–R12) can never be disabled.
|
|
199
|
+
|
|
200
|
+
## Exit codes
|
|
201
|
+
|
|
202
|
+
| Code | Meaning |
|
|
203
|
+
|---|---|
|
|
204
|
+
| `0` | PASS — the order is allowed as given |
|
|
205
|
+
| `2` | WARN — proceed only if your execution policy explicitly allows warnings |
|
|
206
|
+
| `3` | BLOCK — the order must not be submitted (risk rule or fail-closed data) |
|
|
207
|
+
| `4` | Input / configuration error — the caller misused the API, not a risk event |
|
|
208
|
+
| `5` | Internal / rule exception — treated as BLOCK (fail-closed) |
|
|
209
|
+
|
|
210
|
+
In shadow mode the internal verdict is recorded (`shadow_verdict`) while the
|
|
211
|
+
external projection is `PASS / 0`; kill-switch hits and `exit 4/5` are never
|
|
212
|
+
projected away.
|
|
213
|
+
|
|
214
|
+
## Data contracts & migration
|
|
215
|
+
|
|
216
|
+
Schemas are versioned JSON Schema 2020-12 files shipped inside the package:
|
|
217
|
+
`order`, `portfolio`, `policy`, `result`, `audit-record`, `shadow-report`.
|
|
218
|
+
Explicit offline migration is available for legacy documents:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
deadlatch migrate --kind order --input order_v1.json [--output out.json]
|
|
222
|
+
deadlatch migrate --kind policy --input policy_v1.json [--output out.json]
|
|
223
|
+
deadlatch migrate --kind portfolio --input portfolio_v1.json [--output out.json]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Migration converts only adjudicated fields (e.g. policy v1 boolean kill switch →
|
|
227
|
+
`off`/`full`); it never guesses business fields. Normal evaluation entries reject
|
|
228
|
+
old versions (`exit 4`) rather than silently migrating.
|
|
229
|
+
|
|
230
|
+
## Audit log
|
|
231
|
+
|
|
232
|
+
Every `Guard.check()` appends one record to a local JSONL audit file (default
|
|
233
|
+
`~/.deadlatch/audit.jsonl`, overridable via `--audit-path` /
|
|
234
|
+
`DEADLATCH_AUDIT_PATH`). Records are schema-validated, sanitized (no
|
|
235
|
+
credentials, cookies, or absolute paths in plaintext), and pruned to a **30-day
|
|
236
|
+
retention** window inside the same locked transaction as the append. If the audit
|
|
237
|
+
write fails, the returned result is degraded **severity-only-up**: PASS/0 → WARN/2;
|
|
238
|
+
BLOCK/3/4/5 keeps its decision and just attaches an `audit_write_failed` warning —
|
|
239
|
+
the disk and the returned Result never contradict each other.
|
|
240
|
+
|
|
241
|
+
## MCP server
|
|
242
|
+
|
|
243
|
+
`deadlatch-mcp` is a **stdio-only** MCP server (no TCP listener, no
|
|
244
|
+
HTTP/SSE routes). The five tools are **read-only**: none of them can modify
|
|
245
|
+
`policy`, `portfolio`, or kill-switch state (those paths are startup
|
|
246
|
+
configuration, not tool arguments). Policy changes are validated and loaded
|
|
247
|
+
automatically on the next tool call. An optional independent kill-switch file is
|
|
248
|
+
read on every call and can only make the policy more restrictive. Note the server still appends each
|
|
249
|
+
`check_order` evaluation to the local audit log — that is by design, not a
|
|
250
|
+
tool capability. Five tools:
|
|
251
|
+
|
|
252
|
+
| Tool | Purpose |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `check_order` | Evaluate one order; returns full `result` (decision, exit code, violations, evidence) |
|
|
255
|
+
| `get_account_status` | Snapshot freshness, equity, cash, PnL, drawdown, exposure utilization |
|
|
256
|
+
| `get_policy` | Read-only projection of the effective policy |
|
|
257
|
+
| `kill_switch_status` | Current kill-switch mode (read-only; no tool can change it) |
|
|
258
|
+
| `recent_decisions` | Recent audit records (oldest-first, optional `since`/`limit`) |
|
|
259
|
+
|
|
260
|
+
Start it with:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
deadlatch-mcp --policy policy.yaml --portfolio portfolio.json \
|
|
264
|
+
[--audit-path audit.jsonl] [--kill-switch-path kill-switch]
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
The path arguments are startup configuration only; their file contents remain
|
|
268
|
+
live local state. A configured kill-switch file must contain exactly `off`,
|
|
269
|
+
`reduce_only`, or `full`. It cannot weaken a stricter mode already present in the
|
|
270
|
+
policy. A missing, malformed, or concurrently unstable live policy/switch fails
|
|
271
|
+
closed: tool errors are `isError=true` + `fail_closed`, and configuration errors
|
|
272
|
+
carry `input_error=true` + `exit_code=4`.
|
|
273
|
+
|
|
274
|
+
## Demo
|
|
275
|
+
|
|
276
|
+
An agent calls `check_order` with an oversized order; the guard returns
|
|
277
|
+
`BLOCK / 3` with the hit rules; the agent stops instead of calling any broker
|
|
278
|
+
tool. Generated from a real local MCP stdio run with fictional data
|
|
279
|
+
(`tools/make_demo_gif.py`):
|
|
280
|
+
|
|
281
|
+

|
|
282
|
+
|
|
283
|
+
## Known limitations (v0.1)
|
|
284
|
+
|
|
285
|
+
- Naked short-call upside risk is unlimited. v0.1 uses a strike-based exposure
|
|
286
|
+
approximation and does not model that unlimited tail; do not treat it as a
|
|
287
|
+
conservative bound for short calls.
|
|
288
|
+
- Short-sell cash outflow is modeled as `0` (documented simplification).
|
|
289
|
+
- No Greeks, IV, multi-leg strategies, or multi-currency books.
|
|
290
|
+
- Audit cross-process locking relies on POSIX `fcntl`; on non-POSIX platforms the
|
|
291
|
+
lock degrades to a process-local lock (no cross-process guarantee).
|
|
292
|
+
- The guard cannot prevent complete bypass: an agent that never calls it, or that
|
|
293
|
+
ignores a BLOCK and calls the broker directly, cannot be stopped by this tool.
|
|
294
|
+
- Examples in the repository use fictional tickers and data only.
|
|
295
|
+
|
|
296
|
+
## Governance
|
|
297
|
+
|
|
298
|
+
- [SECURITY.md](SECURITY.md) — supported versions, vulnerability scope, reporting.
|
|
299
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md) — environment, test/schema/scan/coverage commands, rule discipline.
|
|
300
|
+
- [DISCLAIMER.md](DISCLAIMER.md) — full legal/risk disclaimer (summary below).
|
|
301
|
+
- [README.zh-CN.md](README.zh-CN.md) — 中文文档.
|
|
302
|
+
|
|
303
|
+
**Disclaimer (summary):** not investment advice; no guarantee against losses;
|
|
304
|
+
verify inputs and rules yourself; the guard never places orders; all examples are
|
|
305
|
+
fictional; test before trading real capital; no SLA. See [DISCLAIMER.md](DISCLAIMER.md) in full.
|