Skip to content

Wire the order-contract boundary into every Alpaca paper submit (local refusal before any network call) - #198

Merged
seathatflowsinourveins merged 3 commits into
mainfrom
claude/order-contract-wiring-20260924
Sep 24, 2026
Merged

seathatflowsinourveins merged 3 commits into
mainfrom
claude/order-contract-wiring-20260924

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Owner

Closes audit gap from the 2026-09-24 trading wiring audit (native-agent-stack-71).

Gap #10 is closed. Every alpaca-py submit now passes the order-contract check first. An intent that fails it is refused before any request budget is reserved and before any network call, and it is recorded as a local refusal, separate from a broker refusal.

One finding first: order_contract.py had no build_envelope(), only canonicalize(). I added build_envelope(value, *, fractional_sell_qty=False, extended_hours_allowed=False). With the defaults it gives exactly what canonicalize() gives. The engine turns on only two things the contract did not allow before: fractional sell quantities up to 9 decimals (for residual exits) and extended_hours: true when the transport is set up to allow it. Everything else stays under the contract's stricter rules.

Changes:

  • transport.py: a new OrderContractRefused error, with the not-sent reason order_contract_refused. It is never a RejectedSubmission. AlpacaPaperTransport.submit validates the fields that go to the SDK, then builds LimitOrderRequest only from the validated envelope. A refused client ID is kept as not-sent, so a replay is refused again without a lookup. The HTTP session also checks the serialized POST body against the registered envelope. A missing, dropped, added or changed field, or a float that no longer equals the exact decimal, is refused before the budget hook. order_contract_status(symbols) is a self-test that needs no network or SDK.
  • runner.py: check_order_contract_boundary() runs in main() before credentials are read. If the check fails, the run is not_started at stage order_contract; if it passes, the status is recorded in the preflight summary. The check runs again inside validate_preflight, which the mover runner also calls. Controller.bind records a contract refusal in the ledger as not_sent with reason order_contract_refused, not broker_refused.
  • Order-throughput AlpacaCapacityPort: also wired, because it submits through the same SDK client. A refusal there is not_sent with error OrderContractRefused and never reaches a client.
  • Native-fault harness: now uses FaultTransport by default. It lets only the C04 client ID's sub-penny price through; every other rule, including the POST-body check, still applies. New receipts will also record the hash of order_contract.py.

README-safety semantics are unchanged; I only added notes on the new reason code and on FaultTransport. I also updated README-transport, the order-contract README, the native-faults README and the order-throughput README.

Behaviour that changes: the contract's symbol rule refuses BRK-B, which the ledger and transport accept (BRK.B passes). A configured symbol it refuses now stops preflight. This also applies to the mover's scan symbols through validate_preflight. All shipped config symbols pass.

Receipts now bound to the older engine (none edited):

  • native-faults/receipt.json (2026-09-24): its harness, runner.py and transport.py hashes no longer match the files; safety.py is unchanged. The established native-fault-behaviour gate in catalogs/us-equities/gates-20260922.json rests on this receipt.
  • native-faults/receipt-20260923.json: already bound an older engine.
  • The four order-throughput receipts (evidence/capacity-200-20260924.json, -rth.json, -rth2.json, -rth-recover.json): they bind the old alpaca_capacity_port.py hash (e4c7bd0b...), and their transport and runner hashes were already older.
  • order-contract/receipt.json (2026-09-19): its 9-test count predates build_envelope.
  • The trials/*/frozen-*.SHA256SUMS files each bind their own frozen commit, as before.

Evidence class: local synthetic tests only. No broker or native run has exercised the new check, and there was no independent review, because a subagent cannot start a reviewer.

Tests. - Pinned runtime (adaptive-paper-20260921, Python 3.12.3, nautilus-trader 2.0.0rc5, alpaca-py 0.44.0), after the final edits and rebase: all 18 test modules that touch adaptive-paper, order-contract and order-throughput, including native-fault and order-throughput. 895 tests ran, OK, 1 skipped (test_exchange_calendars_agreement_or_absent: exchange_calendars is not installed).

  • Same set CI-style under uv (numpy, jsonschema, pyyaml; no SDK): 895 ran, OK, 229 skipped (SDK- and nautilus-dependent tests).
  • Full CI-style suite (uv run -q --no-project --python 3.12 --with numpy --with jsonschema --with pyyaml python -m unittest) after the rebase: 4052 ran, OK, 431 skipped. The earlier full run had one failure (test_general_publication_validator_passes_after_the_run) only because the evidence manifest had not been updated yet; it passes now.
  • 20 test methods were added and none removed.
  • Tests where an invalid envelope never reaches the fake broker: transport tests for a leading-underscore ID, BRK-B and a sub-penny price, where the SDK's submit_order and the HTTP layer are never called, no budget is used and a replay stays local; a runner test through the real transport where the ledger records not_sent with order_contract_refused and no broker call happens; capacity-port tests where the client is never touched.
  • Other new tests: the POST-body check (missing envelope, dropped or added field, changed value, float precision loss), order_contract_status refusing a contract that accepts everything or is not loaded, the preflight check stopping before credentials, build_envelope rules, and FaultTransport exempting only the C04 price.
  • Existing tests changed: three sub-penny 422 transport tests now use a test copy of the FaultTransport exemption. Two HTTP-session tests now register an envelope, so they still test budget deferral. The native-fault test's expected exemption string was updated.

Validation. After the rebase onto origin/main 8dd8e7a, all six required checks exit 0:

  • python3 scripts/validate.py (passed, 5285 hashed files)
  • python3 scripts/validate_catalogs.py
  • python3 scripts/landscape.py --root . (passed)
  • python3 scripts/evidence_manifest.py --check (passed)
  • python3 scripts/verdict_review_gate.py --base origin/main --root . (no verdict rows changed)
  • python3 scripts/trading_gates.py --check (passed)

blueprints/us-equities/adaptive-paper/source-hashes.json was updated by a script that changes only entries whose files differ. That was 4 entries: runner.py, transport.py, tests/test_adaptive_paper_runner.py and tests/test_adaptive_paper_transport.py. manifests/evidence.json was updated the same way for 13 changed registered files, including source-hashes.json. The three changed order-throughput files are not registered there and were left alone. Re-running the script after the rebase changed nothing.

Independent review. Severities: low, low, low, low, low, info, info, nit. No medium or high findings.

🤖 Generated with Claude Code

#10)

AlpacaPaperTransport.submit (and the order-throughput AlpacaCapacityPort)
now validate the exact SDK-bound projection of each intent with
order_contract.build_envelope() and build the LimitOrderRequest only from
the envelope. A refusal raises OrderContractRefused (a SubmissionNotSent,
never a RejectedSubmission) before any budget reservation or HTTP request;
Controller.bind records it as ledger not_sent with reason
order_contract_refused, distinct from broker_refused. GuardedSession admits
an order POST only when its serialized body equals the registered envelope.

build_envelope() equals canonicalize() by default and widens only the two
engine semantics passed explicitly: fractional sell qty (<= 9 decimals) and
extended_hours true when allowed. runner.check_order_contract_boundary is a
network-free self-test run before credentials in main() (recorded in the
preflight summary) and inside validate_preflight. The native-fault harness
defaults to FaultTransport, which exempts only the C04 id's price increment.

Evidence class: local synthetic tests only (pinned runtime 895 tests, 1 skip).
The 2026-09-24 native-fault receipt and the order-throughput capacity
receipts now bind the older engine/port; no receipt was edited.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Resolve hash-only conflicts in adaptive-paper/source-hashes.json and
manifests/evidence.json by recomputing the sha256/bytes of the merged
files (README-safety.md, test_adaptive_paper_runner.py, source-hashes.json).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@seathatflowsinourveins
seathatflowsinourveins merged commit 2b3fd57 into main Sep 24, 2026
22 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/order-contract-wiring-20260924 branch September 24, 2026 19:09
seathatflowsinourveins added a commit that referenced this pull request Sep 24, 2026
…e; first 1x leverage-ladder attempt (needs_attention) (#212)

Native-fault receipt.json is now the 2026-09-24 18:58Z run on the #198 order-contract engine (native_faults_passed, bound to main 3b7ae71, with an independent observation). The 14:39Z receipt is retained as receipt-20260924t143905.json. The first 1x leverage-ladder attempt (ladder-1x-20260924a) is retained as a failure: needs_attention after 190 s on a false-positive fill-precision refusal (the #205 class; broker FILL activities show on-grid executions), flat and reconciled, peak leverage 0.151. Rate-limit evidence regenerated (705/14). No gate status changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins pushed a commit that referenced this pull request Sep 24, 2026
…review findings

Merges origin/main (which carried #198's order-contract boundary and its
own runner.py/source-hashes.json changes) into the paper-lane
corporate-action guard branch, resolving the runner.py/source-hashes.json/
manifests/evidence.json conflicts, and folds in the independent review's
fix round for the guard itself:

- CRITICAL (1): widen the corporate-actions fetch window to anchor-7d..
  anchor+90d (Alpaca filters by process/payable date, not the ex_date this
  guard checks) and filter locally in evaluate_guard; treat a result at the
  page/limit cap as ambiguous; native re-check recorded in
  corporate-actions-native-check-20260924.json.
- HIGH (2): run the corporate-action refresh off the asyncio event loop in
  a worker thread, bounded by wait_for and an in-flight flag; pin a request
  timeout and cut retries on the underlying alpaca-py client; do the first
  fetch before run_native's tick loop starts.
- HIGH (3): a failed/stale refresh no longer overwrites a previously
  confirmed action with "lookup failed" -- the last good result is kept,
  with needs_attention added, so a confirmed flatten is never cancelled by
  a later failure.
- MEDIUM (4): evaluate_guard's date check is now an inclusive
  today<=action_date<=next_session_date range, catching a weekend/holiday
  governing date.
- MEDIUM (5): the run-outcome corporate-action guard summary
  (pending_must_flatten) is read by _honest_overnight_hold, so a symbol
  still flagged must_flatten at the run boundary forces needs_attention/
  recovery instead of a false held_overnight.
- MEDIUM (6): added the 2027 NYSE holiday/early-close calendar to
  sessions.py; a session-calendar failure now blocks-and-flags only, never
  force-flattens every holding.
- MEDIUM (7): fixed silent pass-throughs -- an omitted symbol defaults to
  lookup-failed; the refresh throttle is now keyed on the fetch window too;
  an unmapped corporate-action type fails closed instead of being dropped;
  unit-split alternate_symbol is mapped.
- MEDIUM (8): the guard is wired into the strategy only when
  overnight_holds is enabled; failures retry on a short ~60s interval
  instead of the full refresh interval; a guard summary is added to the
  run outcome.
- LOW (9): a symbol flagged by both the corporate-action guard and the
  gap-risk stop now gets exactly one sell action.
- LOW (10): a resting buy order for a symbol newly blocked this tick is
  cancelled.
- NIT (11): the decision event only carries the corporate_action_* keys
  when the guard is actually wired in (restores the byte-identical-when-off
  claim); a guard event is only re-emitted when the decision changes.

Adds targeted tests for each finding (corporate_actions.py's
CorporateActionMonitor/evaluate_guard/AlpacaCorporateActionsSource,
native_strategy.py's rebalance() wiring, and runner-level tests of the
fetch window, wiring decision, and threaded/bounded refresh scheduling).
Recomputed blueprints/us-equities/adaptive-paper/source-hashes.json and the
matching manifests/evidence.json entries programmatically from the changed
files' actual on-disk content.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Sep 24, 2026
… fill-precision branch

Conflicts were registries and counts only: took main's copies, regenerated the
rate-limit evidence (1693 trading, 16 data headers), re-pinned this branch's five
sources in source-hashes.json and re-registered its files in the evidence manifest.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Sep 25, 2026
…-09-24/25 merges (#225)

Updates four checkpoint entries: the paper lane, the simulation lane, alpaca-paper-operational and corporate-action-data. They now reflect #198, #199, #212, #218, #219 and #222. tests.test_grand_dashboard passes, and all state strings satisfy progress.py's public-token rule.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant