← neurobrick
The money-path boundary

Intelligence proposes.
It is never allowed to arm.

How AI helps without touching the production money path — the code that enforces it, the code that doesn't, and the receipts for both. Every claim below is scoped to the deployed branch (neuropublic@main) and cites file:line you can open.

01 — The claim, scoped honestly

Intelligence — LLM brains, automation, AI-written code — may propose capital deployment but cannot arm it. The precise version, defended line by line below: live order authority requires two deliberate human acknowledgements that no committed code path supplies; the executor forces paper on any doubt; and de-risking is always allowed on purpose.

We will not tell you “the AI literally cannot place an order.” That's false, and you'd catch us: once the operator arms both acks, proposed orders go live. The real, verifiable discipline is narrower and stronger — the AI cannot open live capital, expand exposure, or grant itself authority; only the operator can — and we show you exactly where that is a machine gate and where it is a human convention. (What the machine can arm on its own — only risk-reducing guardrails — is the next section.)

Who can arm what

Not everything that “arms” is a trade. Arming runs on a tiered taxonomy (state/arm-taxonomy.json): the safe direction may auto-arm; the risky direction always escalates to a human.

  • The machine may self-arm a bounded safe subset inside an already-human-armed envelope — turn a guardrail from observe to enforce, shrink live sizing (a coded never-expand invariant), enable a dead-man alert. Deterministic, evidence-gated, auto-reversible.
  • A human arms every live-capital authority — opening the live envelope (CONFIRM_LIVE + AUTO_LIVE_CONFIRM), expanding exposure, clearing a kill, real order-cancel. Tagged human_only; the risk direction never auto-arms.
  • An off-box audit (AUTONOMY=0, scanner/arm_audit.py) checks the taxonomy itself — that no surface tagged human_only is ever reclassified as auto-armable — and exits non-zero on drift. The complementary runtime check (that none was actually self-armed) is built but runs in spec-only mode until the decision ledger it reads exists — so we state it as pending, not done.
  • The arming rules are also formally model-checked: over the full reachable state space, no automatic transition ever arms a human_only surface, opens live, or loosens a cap, and a risk-reducing close stays reachable from every state — invariants INV1–INV4, zero violations (scanner/arm_model_check.py, with a TLA+ companion, run in CI on every change to the arming model plus a daily gate). A proof of the design; that the code matches the model is the property tests' job, not this one's.
  • The one surface that would let a machine grant itself live authority is permanently sealedhuman_only_SEALED, excluded from every auto path by construction.

So the machine can tighten its own guardrails; it cannot open live, expand exposure, or grant itself authority. That asymmetry — safe direction may automate, risk direction stays human — is the honest version of “only a human arms.”

02 — Two rules explain every row

Asymmetry

Risk-increasing opens are gated. Risk-reducing closes are deliberately never stranded behind a gate — an automated exit must never be trapped.

Doubt defaults to paper

On any uncertainty — a missing ack, an import error, a corrupt ledger — the default is paper, not live. The one exception, stated plainly below, is the kill switch.

03 — The boundary map

Machine gate (CODE) Human convention (PROCESS)
Arm live capital (paper → live)
MIXED · Yes — absence / typo / empty → paper
Dual live-gate: CONFIRM_LIVE=yes + AUTO_LIVE_CONFIRM set to an exact, deliberately-long confirmation phrase — live_gate.py:118

The decision function is CODE; that the second ack lives only in the operator’s .env (never committed code) is enforced by review AND a CI grep-gate (test_no_baked_live_ack.py). The barrier is not the secrecy of a phrase — it is that no checked-in code supplies the second ack.

KIS equity — submit live OPEN
CODE · Yes — gate fail / import error / caller omits dry_run → forced paper
_executor_paper_backstop() below every KIS caller, over the dual gate — kis_order_executor.py:1598

The genuine gate. Fires even for a daemon that hardcodes dry_run=False. This forced-paper backstop is KIS-specific (see 04).

Binance futures / options / spot — submit live OPEN
CODE · Yes for opens — both acks required
Same two-ack invariant re-checked at each venue’s pretrade point — pretrade_check_futures/options; inline for direct spot openers

Not one shared function on the opener path. PR #2623 unified the three Binance pretrade checks to one authority (live_gate_passed(), core/utils/live_gate.py) and closed a spot-open gap; the standalone opener daemons still carry their own inline copy of the same two acks. The invariant is shared, not one call site.

De-risk / CLOSE (SELL, reduce_only)
PROCESS · No — always allowed, by design
Intentionally exempt from the dual gate and soft halts — _binance_pretrade_gate.py:1548

Truthful degradation: an automated exit is never stranded. The AI can execute a risk-reducing SELL without the live ack. Intentional and safe — but a real carve-out we name rather than hide.

Intra-account transfer (spot ↔ futures)
CODE · Blocked when the fleet is killed
master_kill_active() check before transfer — adapters/binance/client.py:80

Was ungated. Audited and closed (PR #2623): a killed fleet can no longer move funds between wallets.

External withdrawal
CODE · n/a — impossible in-code
No withdrawal endpoint exists in the code

The strongest honest property: funds cannot leave the account through any code path here. A guarantee by absence.

Kill switch / master_kill (file-flag)
CODE · No — fail-OPEN, deliberately
Presence check + file-flag cascade — emergency_kill_switch.py

A corrupt or missing kill flag does NOT halt trading, so a bad flag can’t freeze the fleet. It is a positive stop signal, not a fail-closed gate. We will never call it fail-closed.

arm_store fenced ledger
CODE · Yes — absent / corrupt / forked / expired → DISARMED
Hash-chained, generation-fenced, append-only authority when ARM_STORE_ENABLED

The enforcing path is now built and POSIX-fenced, with a migration doc and an arm CLI (PR #2632) — but it ships default OFF: the live authority today is still the .env dual gate. A rollout that is ready, not the current posture. The fcntl fence is a no-op on Windows, so the guarantee is mac/POSIX-only.

Off-box challenge / decision-replay
PROCESS · n/a
Re-derives + re-executes the real gate off-box; holds no actuator

Independent verification of governance and determinism — propose-only by construction. NOT a gate on the order path; presenting it as one would overclaim.

Dead-man safe-halt
PROCESS · Never auto-halts
NOTIFY mode: pages the operator on absence

Even in fire mode it is authority-removing only (engage kill / disarm) — no liquidate verb exists in code.

04 — What is a machine gate

  • The dual-gate decision function fails to paper unless both acks are exact — live_gate.py:118, pinned by test_live_gate_arm_store.py.
  • On KIS, the gate sits below every caller: _executor_paper_backstop() @ kis_order_executor.py:1598 forces paper even for a daemon that hardcodes dry_run=False. Proven by test_executor_paper_backstop.py.
  • That forced-paper backstop is KIS-specific. Binance opener daemons each carry their own inline two-ack gate instead; the shared Binance order-enforcer ships off by default and can reject an order but not force it to paper. So on Binance the barrier is the per-daemon gate, not a backstop beneath it — the two acks are still required to open, at each venue's own checkpoint.
  • The fenced arm ledger is deny-by-default: absent, tampered, forked, or expired evidence all read DISARMED — test_arm_store.py, ~25 cases. (Opt-in; not today's default posture — see 07.)
  • Funds have no code path out of the account: there is no withdrawal endpoint in the adapter. A guarantee by absence.
  • The off-box challenge brain holds no actuator and imports no gate; a committed test — deadman/test_isolation.py — proves the observer cannot reach the one component that can act.

05 — How we verify it — re-executing the real gate off-box

We don't ask you to trust the gate; we re-run it. decision_replay.py pulls the real gate source (sha-pinned), re-executes it on a separate box against inputs rebuilt from the audit ledger alone, and diffs its allow/veto verdict byte-for-byte against what actually happened live.

2026-07-15 · stable-code window: 1326 / 1326 decisions matched · 14 / 14 vetoes byte-identical · 0 divergences

Over the full span, 11 divergences — every one traced to a single dated bug-fix (7f65d92), none to nondeterminism. Gates that read state we can't independently reconstruct are excluded and named, not faked into the match rate.

Fail-closed proofs are example-based unit tests, not assertions: test_executor_paper_backstop.py (clear either ack → forced paper), test_kill_switch_durability.py (corrupt file fails open, by design), test_reduce_only_exit_guarantee.py (a halt blocks BUYs but lets risk-reducing SELLs through).

06 — What we audited and closed

Writing this page began with a code audit of our own boundary. It found real gaps. We closed them before publishing — the audit trail is the point, not a clean-looking omission:

  • Binance spot opens had no dual-ack (futures/options did). Added, at parity — PR #2623.
  • The crypto pre-trade gate was a parallel re-implementation. Unified: the three Binance pre-trade checks now delegate to one authority (live_gate_passed()) and gained the arm_store ledger — PR #2623. The shared pretrade path and the two-ack invariant are unified; the standalone opener daemons still carry their own inline copy of the same check (see 04).
  • Intra-account transfers had no kill check. A killed fleet can no longer move funds — PR #2623.
  • The second ack was once hardcoded in several shell wrappers. PR #2603 de-baked it to a pass-through, and a CI + pytest gate now fails the build if any scripts/*.sh wrapper re-bakes the literal value — test_no_baked_live_ack.py, PR #2619. It guards shell wrappers, not Python; reading the ack from the environment at runtime is the intended pattern.

07 — What is still process, not a machine

Expert credibility is the whole point of this page, so here is what a machine still does not guarantee:

  • The fenced ledger ships OFF by default. Today's live authority is the plain .env dual gate. The ledger is the stronger mechanism — built and tested — but it is a rollout, not the current posture.
  • The kill switch is fail-open by design. A corrupt kill flag does not halt trading — so a bad flag can't freeze the fleet. A positive stop signal, not a fail-closed gate.
  • “Invariance checked before merge” is a regression + anti-regression-sentinel suite staying green — not a semantic behavior-diff proof. We used to note here that the gates had no property tests; they now do — a Hypothesis suite, run as a dedicated CI step, asserts that across a generated input space (near-miss acks, tampered / forked / expired ledgers, halt-flag combinations) no input makes a gate return live without both exact acks, and that a risk-reducing close is never blocked. That is property-tested over generated inputs, still not a formal proof; and whether a red CI blocks merge is a branch-protection setting, not something the repo proves.
  • The dead-man safe-halt runs in NOTIFY mode — it pages the operator on absence and halts nothing. Even in fire mode it can only remove authority; it cannot liquidate.
  • Risk-reducing sells bypass the gate on purpose. The AI can act to reduce exposure without the live ack. Intentional — an exit is never trapped — but a real carve-out.

08 — Verify me

Every file:line above is real. The repos are private, so this is a citation, not an invitation to clone: an outsider can hold this page to its own specificity and internal consistency, not re-run the named tests or read the drill receipts in drills/*/state/. That is the honest limit of reading it. The claim this page makes is exactly as strong as the code — no stronger. Where it is a human convention, we said so.