Skip to content

Adaptive-paper engine P0 release: per-execution fill booking, guarded callbacks, halt/LULD state - #221

Merged
seathatflowsinourveins merged 4 commits into
mainfrom
claude/engine-p0-20260924
Sep 25, 2026
Merged

seathatflowsinourveins merged 4 commits into
mainfrom
claude/engine-p0-20260924

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Owner

Why

The 2026-09-24 RTH mover paper trial froze on cumulative_fill_precision_requires_reconciliation. The adapter had derived a per-fill price from Alpaca's rounded cumulative average during a multi-price exit (APUS: 26 @ 5.62, 2 @ 5.61, 1 @ 5.61). The freeze left SRZN open until the engine's recover sold it.

The verified data-and-execution convergence record (2026-09-24) put three items at P0: this fix, a callback guard and halt/LULD awareness.

What (blueprints/us-equities/adaptive-paper)

  1. Per-execution fill booking:
    • trade_updates fill and partial_fill events are booked as exactly those executions: TradeId = execution_id, last_px = the event price, last_qty = the event quantity.
    • Only the running quantity sum is checked; prices are never derived from averages.
    • GET /v2/account/activities/FILL (on the read allowlist) gap-fills dropped events and builds _generate_fill_reports, so a restart with fills no longer raises.
    • The ledger books exact execution prices.
  2. Guarded order and position callbacks: an exception freezes the ledger with a named reason, stops submits, runs cleanup and ends needs_attention. An AST test fails on any unwrapped handler, and a LiveNode test reproduces the upstream exception-swallowing behaviour it guards against.
  3. Halt and LULD state:
    • SIP statuses and lulds on the existing stream, with CTA and UTP codes per the CTS spec: CTA 6 is not a halt; E/F never clear a halt.
    • Out-of-order safe, with a Nasdaq RSS startup seed.
    • No entries and no exit re-pricing while halted.
    • SIP only: IEX coverage of these channels is unverified.

The source-hashes and evidence pins are regenerated, and the READMEs describe the new behaviour.

Review trail

  • The build workflow ran two independent reviews: 1 major (fixed in 1cf633e); the recheck approved with 3 minors left.
  • Merge of main (5ed8538): the conflicts were only in imports, constants and hash pins, with main's order-contract and native-fault work kept intact.

Checks

  • Pinned rc5 runtime, adaptive-paper suite (7 modules): 575 OK, 0 native skips.
  • Main's native-fault, order-contract, throughput and sim-paper modules: 215 OK.
  • scripts/validate.py: passed.
  • Full python3 -m unittest: 4,603 OK (509 skipped).
  • Guarded gitleaks: clean.

Evidence classes: synthetic fixtures in the documented schemas, plus local integration on the real LiveNode.

Open before citing gates

The native-fault receipt (18:58Z) qualifies main's engine hashes before this release. The fault plan (C01, C02, C05, C04) must re-run on paper on this engine before native-fault-behaviour is cited for it. A native paper mover session with at least 5 multi-fill orders should also show adapter_errors == [], and a 1:1 match between the booked fills and the FILL activities.

🤖 Generated with Claude Code

…alt and LULD state

Items 2-4 of the 2026-09-24 data and execution convergence record (E2-E4), as one
engine release of blueprints/us-equities/adaptive-paper.

E2, per-execution fill booking. native_adapter.observe books each fill or
partial_fill trade update that carries execution_id, qty and price as exactly that
execution (TradeId = execution_id, last_px = its price), keyed by the order's
cumulative quantity after it; no price is derived from Alpaca's 6-decimal
cumulative average (the APUS 26 @ 5.62, 2 @ 5.61, 1 @ 5.61 sell now books three
exact fills instead of freezing on a derived 5.610004). A cumulative quantity no
booked execution explains is a fill gap closed after 2 s by one read of GET
/v2/account/activities/FILL?order_id= (added to GuardedSession's read allowlist with
only order_id, asc, page_size <= 100 and an activity-id page_token), joined on
cumulative quantity; a cancel or expiry reported before its fills waits for them.
_generate_fill_reports reports adopted open orders' executions from the activities,
so a restart with fills no longer raises. The post-terminal and same-quantity guards
still freeze; every documented trade_updates event has one handling, undocumented
ones (including corrections and busts) freeze. The transport forwards a stream fill
with a new execution_id even after a REST read advanced the cumulative quantity;
safety.Ledger records executions durably and books exact execution prices when they
tile an advance, otherwise cumulative averages with a 6-decimal rounding tolerance
on the limit check.

E3, order and position callback guard. Every on_order_* / on_position_* handler of
AdaptiveStrategy, MoverStrategy and CapacityProbe is wrapped by guarded_callback: an
exception records the callback, freezes the ledger with
strategy_callback_exception_<handler>, latches faulted (no further submit), stops the
session through fault_sink (NativeSession.fail) and ends needs_attention with the
residual handed to recovery. An AST test fails on any unwrapped handler; a LiveNode
characterization test shows rc5 discarding an unguarded handler's exception
(upstream #5039) and fails if a later release surfaces it (E3's overturn).

E4, halt and LULD state. On the sip feed the quote connection also subscribes
trading statuses and LULD bands; statuses map to per-symbol halt state per Alpaca's
documented CTA and UTP codes (CTA 2 with reason M a LULD pause; 5 halts; 6, E and F
never change the state, per the CTS Pillar output specification v2.11b; UTP H, Q, P
halt, T resumes; market-wide circuit breakers labelled), out-of-order safe with a
halt winning a tie. A startup seed from one Nasdaq Trader trade halts RSS read
covers symbols already halted at subscribe time (fail-open, recorded; entries wait
at most 3 s for it). No entries and no exit re-pricing while a symbol is halted, in
both lanes. On iex neither channel is subscribed and nothing is seeded.

source-hashes.json and manifests/evidence.json re-pinned; README text updated.
Evidence: synthetic fixtures (documented trade_updates, FILL activity, trading
status, LULD and halts RSS schemas) and local integration against the real
NautilusTrader 2.0.0rc5 LiveNode. No paper session has run this release.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…, halts, rc5 startup

Follow-up to 0b49261 (items 2-4 of the 2026-09-24 data and execution convergence
record), resolving both reviews' findings in blueprints/us-equities/adaptive-paper.

Fills (E2). A cancel or expiry the broker reports before its fills are booked now
fixes the order's final quantity: pending_terminal keeps the filled quantity it
reported, and a stream row, a stream execution or a FILL activity ending above it
freezes (post_terminal_fill_requires_reconciliation) instead of being booked. Each
fill gap gets its own 2 s grace: a gap opened while another was pending, or a larger
cumulative quantity reported during the activities read, waits for its own grace
instead of failing the read. A gap still open at stop is the adapter error
fill_gap_open_at_stop (needs_attention), and receipts carry native_assertions
(fill_events_carry_execution_fields, no_fill_gap_open_at_stop) with named
overturn_signals. Startup with an adopted, partly filled order (overnight holds):
activities are read once at connect, the order report is stamped accepted no later
than the first execution (rc5 applies reconciliation events in timestamp order and
dropped the real fills, then synthesized a second order for the position; reproduced
on a real LiveNode), and fill reports honour venue_order_id/instrument_id and never
reset booked state.

Halts (E4). Exits and exit re-pricing in both lanes wait on the status stream and
startup seed only (Controller.is_halted); the quote's unverified condition flag blocks
entries only. A halt only the seed asserts expires at its resumption trade time or 12
minutes after a LULD pause began (LUDP, LUDS, M; LULD Plan Amendment 12), and a seed
row already past that is not applied. A status message with a missing or unrecognized
tape reads its code from both tables, so a documented resume still resumes. The halts
RSS body is read one socket read at a time (urllib3 read1, identity encoding) with the
deadline checked before each read.

Callbacks (E3). A faulted MoverStrategy no longer evaluates the book on quotes or
ticks. blueprints/us-equities/engine-nautilus/probes/repro_5039.py moves the #5039
reproduction into the repo (exit 0 while rc5 still discards the exception).

Also: a stale error name in mover.py, the sessions halt test skipped without the
native runtime, dated binding amendments to the native-fault-behaviour gate note,
runtime-target and native-faults README (the receipt qualifies the engine of
cbbd589), README text, source-hashes.json and manifests/evidence.json re-pinned.

Evidence: synthetic fixtures, local integration against the real NautilusTrader
2.0.0rc5 LiveNode, and a loopback HTTP server through the installed requests/urllib3.
No paper session, no network beyond read-only doc and source lookups, no orders.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Combine the engine release (per-execution fill booking from trade_updates
execution_id with FILL-activity gap-fill, guarded order/position callbacks,
SIP trading statuses/LULD halt state with the Nasdaq RSS seed) with main's
order-contract boundary (#198), the 18:58Z native-fault receipt on it and the
first 1x leverage-ladder attempt (#212).

Conflicts:
- runner.py: transport import carries both order_contract_status and
  halt_statuses_supported/nasdaq_halt_seed.
- transport.py: imports keep hashlib and importlib.util; the FILL-activity and
  execution constants sit beside the order-contract loader.
- source-hashes.json: regenerated from file bytes (same 48 keys).
- manifests/evidence.json: sha256/bytes re-registered for the nine files both
  sides changed, then sorted with scripts/evidence_manifest.py --write.
- native-faults/README.md and gates-20260922.json: main's text kept; the
  release's binding amendment now names the current 18:58Z receipt (main
  3b7ae71 engine sources), which predates the release, so the gate still
  qualifies the earlier engine until the plan is re-run on the release.
- runtime-target.json (auto-merged): the same amendment corrected from
  cbbd589 to the current receipt.

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.

…porate-action and credential guards

Main moved 19 commits since 5ed8538. The conflicts were resolved by
keeping both sides:

- native_strategy.py: AdaptiveStrategy takes both halted= (E4) and
  corporate_action_guard= (#222). The constructor keeps the halt and
  callback-fault state and the corporate-action guard state.
  cancel_expired keeps the halted-exit skip (E4) and gains #222's
  symbols= immediate-cancel set.
- runner.py: the strategy gets both halted=controller.is_halted and the
  corporate-action guard. The shutdown runs stop_halt_seed() inside
  #222's try/finally, so the corporate-action refresh cleanup still runs
  if the halt-seed stop raises.
- source-hashes.json: the union of both sides' keys, every digest
  recomputed from the merged tree.
- manifests/evidence.json: main's registry, plus the branch's new
  engine-nautilus probe, with all stale digests refreshed. The branch's
  entries for the renamed CI lock (#233) and the renamed grype fixture
  (#224) are dropped.

Checks on the merged tree:
- pinned rc5 runtime, 23 paper modules: 1,320 tests OK (2 skipped);
- full python3 -m unittest: 4,944 tests OK (600 skipped);
- validate.py, evidence_manifest.py --check, and the source-hashes
  manifest test: pass.

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

Copy link
Copy Markdown
Owner Author

Carried forward (2026-09-25, native-agent-stack-e7). This PR had been idle for about 9 hours, and no live session predates its last update. Its two review rounds were complete: one major finding fixed, and the recheck approved with 3 minor findings left as residuals. So I merged current main into the branch as a normal merge commit, 8f571ed, with no force-push.

Conflicts. main had moved 19 commits, including #222's corporate-action guard and #219's credential guard. Both sides were kept:

File Resolution
native_strategy.py AdaptiveStrategy takes halted= and corporate_action_guard=. cancel_expired keeps the halted-exit skip (E4) and gains #222's symbols= immediate cancel.
runner.py The strategy gets both. At shutdown, stop_halt_seed() runs inside #222's try/finally, so the corporate-action refresh cleanup still runs if it raises.
source-hashes.json The union of both sides' keys, with every digest recomputed from the merged tree
manifests/evidence.json Main's registry, plus this branch's new engine probe, with stale digests refreshed. Entries for the renamed CI lock (#233) and the renamed grype fixture (#224) are dropped.

Checks on the merged tree:

  • pinned rc5 runtime, 23 paper modules: 1,320 tests OK (2 skipped, the exchange_calendars agreement tests);
  • full python3 -m unittest: 4,944 tests OK;
  • validate.py, evidence_manifest.py --check and the source-hashes manifest test pass.

I'll squash-merge once CI is green. This PR's own "Open before citing gates" list still applies after the merge: the native-fault plan must re-run on paper on this engine.

🤖 Generated with Claude Code

@seathatflowsinourveins
seathatflowsinourveins merged commit 8bd4ca7 into main Sep 25, 2026
25 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/engine-p0-20260924 branch September 25, 2026 09:39
seathatflowsinourveins added a commit that referenced this pull request Sep 25, 2026
… engine merges and credential blocker (#248)

- Simulation lane: hftbacktest agrees with NautilusTrader within 0.36%
  once our driver's use-after-free is fixed (#245). The evidence
  reference points to the cross-check receipt.
- Paper lane: the engine P0 release (#221) and exact cancel identity
  (#242) merged today. The native-fault rerun and the 1x ladder attempt
  are blocked: at the open, the stored paper keys were rejected with
  HTTP 401 on the trading account and on both data feeds, so they need
  rotating through the credential terminal. No order was sent.

Co-authored-by: Scout <scout@local>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Sep 26, 2026
#242 and #284 (#350)

* Paper engine: fix the retroactive cross-family review findings on #221, #242 and #284

GPT-6 (gpt-6-astra, effort max) reviewed three merged paper-engine PRs on main ca8e37f; #243 passed.
- #221: activity-based gap recovery booked fills natively without persisting them to the durable ledger (native 3,
  durable 1); a continuing LULD pause auto-cleared after twelve minutes and let cancel_expired cancel the exit it
  protected; cash and realized P&L depended on REST-snapshot versus stream delivery order.
- #242: replay_compare scheduled a named cancel stamped before its submit and silently skipped it; cancelling the
  transport task cleared the cancel identity before the HTTP worker sent the DELETE.
- #284: a clean exporter stop released the port before deregistering, so it could remove a replacement exporter's
  target; configure.py's initialization could overwrite a concurrent registration; malformed nested labels passed
  validation and would make Prometheus reject the whole target list.

Each fix was implemented test-first by a GPT-6 implementer in its own worktree; every new regression failed before
its fix. Coordinator integration: source-hashes.json and evidence pins refreshed; the 20260923g sim-paper-compare
receipt replayed from its retained pages with the new code (identical apart from run-local fields and runner_sha256,
updated as in #242); sim-capacity's frozen replay_compare source re-pinned with a dated limitation (AST check: the
8 definitions sim-capacity uses are unchanged).

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

* Paper engine repair round: persist recovered fills through the transport's real observation hook

Independent verification of cad7faf found #221 finding 1 unresolved in production: reconcile_fills persisted recovered
fills only through a port.controller attribute that no real Alpaca port has (AlpacaPaperTransport and the native-faults
FaultTransport are wired with sink_observation=controller.observe); only the test-only SimulatedPort carried it.
- native_adapter.py: persist through the port's sink_observation (the hook the transport already uses for stream rows),
  after validating that the recovered activities tile the fill contiguously (fail closed otherwise).
- simulation.py: SimulatedPort exposes the same sink_observation hook, so tests and production share one path.
- Tests: a real-shaped port (no .controller) regression that failed on cad7faf with Decimal('1') != Decimal('3'), restart
  persistence, incomplete tiling; the two accounting-replay guards in safety.py; fast build_decisions-level tests for
  the cancel-before-submit refusal and its equality boundary.
Implemented by a GPT-6 implementer test-first; 514 tests across the five affected modules pass.

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

---------

Co-authored-by: Scout <scout@local>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Sep 26, 2026
…ealized-loss delivery-order major; follow-up to #350) (#355)

* Paper engine: fix the retroactive cross-family review findings on #221, #242 and #284

GPT-6 (gpt-6-astra, effort max) reviewed three merged paper-engine PRs on main ca8e37f; #243 passed.
- #221: activity-based gap recovery booked fills natively without persisting them to the durable ledger (native 3,
  durable 1); a continuing LULD pause auto-cleared after twelve minutes and let cancel_expired cancel the exit it
  protected; cash and realized P&L depended on REST-snapshot versus stream delivery order.
- #242: replay_compare scheduled a named cancel stamped before its submit and silently skipped it; cancelling the
  transport task cleared the cancel identity before the HTTP worker sent the DELETE.
- #284: a clean exporter stop released the port before deregistering, so it could remove a replacement exporter's
  target; configure.py's initialization could overwrite a concurrent registration; malformed nested labels passed
  validation and would make Prometheus reject the whole target list.

Each fix was implemented test-first by a GPT-6 implementer in its own worktree; every new regression failed before
its fix. Coordinator integration: source-hashes.json and evidence pins refreshed; the 20260923g sim-paper-compare
receipt replayed from its retained pages with the new code (identical apart from run-local fields and runner_sha256,
updated as in #242); sim-capacity's frozen replay_compare source re-pinned with a dated limitation (AST check: the
8 definitions sim-capacity uses are unchanged).

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

* Paper engine repair round: persist recovered fills through the transport's real observation hook

Independent verification of cad7faf found #221 finding 1 unresolved in production: reconcile_fills persisted recovered
fills only through a port.controller attribute that no real Alpaca port has (AlpacaPaperTransport and the native-faults
FaultTransport are wired with sink_observation=controller.observe); only the test-only SimulatedPort carried it.
- native_adapter.py: persist through the port's sink_observation (the hook the transport already uses for stream rows),
  after validating that the recovered activities tile the fill contiguously (fail closed otherwise).
- simulation.py: SimulatedPort exposes the same sink_observation hook, so tests and production share one path.
- Tests: a real-shaped port (no .controller) regression that failed on cad7faf with Decimal('1') != Decimal('3'), restart
  persistence, incomplete tiling; the two accounting-replay guards in safety.py; fast build_decisions-level tests for
  the cancel-before-submit refusal and its equality boundary.
Implemented by a GPT-6 implementer test-first; 514 tests across the five affected modules pass.

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

* Paper engine: book realized P&L and gross loss per exact execution in accounting replay

The accounting replay summed a status delta's executions into one notional
before computing P&L, so a sell filled at a gain and a loss inside one delta
netted the loss away, and the result depended on whether the stream or the
REST snapshot arrived first. Replay now books each execution that tiles the
delta separately (QuantConnect/Lean 985ef30: SecurityPortfolioModel.cs per-fill
closing P&L; TradeStatistics.cs accumulates losses separately), falling back to
the delta notional only while executions are incomplete.

Two regressions: mixed-profit gross loss across stream-first, REST-first,
duplicate and restart deliveries, and basis preservation at each booking.
With the fix reverted, 4 cases fail (rest_first, duplicates, restart, basis).
Paper suites (safety, runner, native, transport): 407 tests OK.
Implemented by GPT-6 (gpt-6-astra, effort max) test-first; verified by the
coordinator. Pins: source-hashes.json safety.py and manifests/evidence.json.

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

* Paper engine repair round (#355 review): replay executions in execution order, versioned marker

Independent review of c81a3d5 (needs_changes):
- Finding 1 (major): the replay booked fills in observation order. Stream fills
  now carry Alpaca's own trade_updates timestamp (event_at_ns; FILL recovery
  forwards transaction_time_ns), the ledger keeps it in a new optional
  executions.at_ns column (added on open for existing ledgers), and replay
  fills each symbol's timed execution slots in execution order, tie-broken by
  event id then cumulative quantity. Adoptions, untimed executions and
  uncovered provisional bookings keep their journal positions.
- Finding 3: the marker is execution_accounting:v2:<client_id>, so ledgers
  replayed under the observation-order rule re-derive once.
- Finding 4: a test for an uncovered REST-only booking beside another order's
  late executions.
- Finding 2 (adopted open orders) is covered by #356's startup persistence.

The A/B/C case gives cash 70, realized -15, gross loss 25, and 1 share at 115
under stream, REST-ahead, recovered, late-buy and nanosecond deliveries.
Reverting the three production files fails 10 cases (4 new tests, 2 strengthened).
Paper suites: 411 OK; trading gates 26 OK; validate.py passed.
Implemented by GPT-6 (gpt-6-astra, effort max) test-first; verified by the
coordinator. Pins: source-hashes.json (safety, transport, native_adapter) and
manifests/evidence.json.

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

* Re-pin the changed paper test files in adaptive-paper/source-hashes.json

source-hashes.json also pins test files; CI's
test_adaptive_paper_source_hashes_manifest caught the stale entries. Pins only,
no code change: the changed tests' entries and their manifests/evidence.json
registration.

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

* Reduce #355 to the reviewed-safe subset; defer execution-order replay

The re-check of cc6d7cb found two new majors in the execution-order replay:
- Moving an earlier-executed fill into another order's slot can make an
  uncovered REST-only sell go short. The replay then raises, the fill rolls
  back and the transport freezes, although the real history is consistent.
- Removing the early exit let that failure block fills in every symbol and
  added a full replay to every fill.
Under the bounded review loop (one review, one repair, then land with
residuals), this commit lands the parts both reviews confirmed.

It keeps:
- c81a3d5's per-execution P&L and gross loss within a delta;
- the versioned execution_accounting:v2 marker (F3);
- the uncovered-fallback test (F4), with its oracle stated for
  observation-order replay.

It reverts:
- the slot-substitution replay and the early-exit removal;
- the executions.at_ns column, which also avoids the unversioned schema
  change (re-check F3);
- the stream and recovery timestamp plumbing.

Execution-time ordering is a recorded follow-up, with the reviewer's
constraints: never reorder into a short (fall back to observation order), a
targeted replay trigger, and a schema version bump.

Revert checks: the v1 marker fails the F3 test; skipping the uncovered
fallback errors the F4 test. Paper suites: 409 OK; source-hashes and trading
gates: 33 OK; validate.py passed. Pins: safety.py and its test file only.

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

---------

Co-authored-by: Scout <scout@local>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
seathatflowsinourveins pushed a commit that referenced this pull request Oct 1, 2026
#221 (8bd4ca7, merged 2026-09-25) books each trade_updates fill as its own
execution and closes fill gaps from GET /v2/account/activities/FILL, so the
adapter never derives a price from a cumulative average. That supersedes
fills.py's inference (trading-lane proposal on PR #205, step 1).

- Remove blueprints/us-equities/adaptive-paper/fills.py and
  tests/test_adaptive_paper_fills.py.
- Restore native_adapter.py, tests/test_adaptive_paper_native.py and
  README-mover.md to the merge base, so the merge takes main's versions.
  The native test changes exercised fills.py's price recovery from rounded
  averages (dropped). The same-quantity average-correction test duplicates
  main's test_same_quantity_with_a_changed_average_still_freezes (dropped).
- Keep tests/test_adaptive_paper_safety.py's
  test_a_certain_limit_violation_still_halts: main's ledger still books a
  cumulative-only observation from the averages, with a rounding tolerance,
  and this is the only test that a certain violation still halts there.
- source-hashes.json: the base copy, re-pinned for the kept safety test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins pushed a commit that referenced this pull request Oct 1, 2026
…on branch

Conflicts and their resolution:
- manifests/evidence.json: main's copy, unchanged here. The branch's files
  are re-registered in the last commit (docs/lanes.md hot-file protocol).
- blueprints/us-equities/adaptive-paper/source-hashes.json: main's copy,
  re-pinned for the one file the merge leaves changed,
  tests/test_adaptive_paper_safety.py (main plus the kept
  test_a_certain_limit_violation_still_halts).

native_adapter.py, tests/test_adaptive_paper_native.py and README-mover.md
now equal main's (#221 per-execution booking; #559 FEE reconciliation).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Oct 1, 2026
…the partial-fill precision fix (#205)

* Mover mode's first paper run (Mac) and the partial-fill precision fix

Trial mover-mac-20260924a ran the mover trial mode against Alpaca paper for the
first time: five scanner-selected entries and three X2 exits filled, then GRML's
exit filled in parts at 15.00 and 15.01. Alpaca's six-decimal cumulative average
(15.000833) made the native adapter derive 15.009996 and stop with
cumulative_fill_precision_requires_reconciliation. Forced recovery sold the rest;
the account reconciled flat, P&L +0.87 USD, recover proof passed. The trial record
and its offline verifier are under trials/mac-2026-09-24-mover-a/.

native_adapter.execution_price takes each fill's own execution price from the
trade-update event when its quantity equals the new shares and it agrees with the
reported average; otherwise it rounds the derived price only when the average's
reporting bound is under half a price unit. Anything else still stops the adapter.
The new native tests reproduce the run's arithmetic and fail on the previous adapter.

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

* Register the Mac mover trial record and re-registered sources in the evidence manifest

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

* Add the mover trial's decision stream (events.jsonl is ignored by *.jsonl; force-added like the stop drill's)

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

* Count the mover trial's rate-limit headers in the order-throughput evidence (1149 trading, 14 data)

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

* Re-register the order-throughput evidence in the evidence manifest

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

* Resolve fills on the notional grid in one shared module, for the adapter and the ledger

An independent pre-merge review (Codex, a different model family) found the first
version too narrow: rounding assumed one price per snapshot delta, the tolerance came
from the normalized string's exponent, an exactly representable derived price was
accepted without an ambiguity check, a contradictory execution event was replaced by a
derived price, and the ledger's limit check still halted on rounded averages at the
limit (1 x 100.00 then 2 x 100.01 at 100.01 derives 100.0100005).

fills.resolve_execution now accepts an execution event only when its price is on the
grid and agrees with the average (else fill_event_price_requires_reconciliation), and
otherwise requires the new shares' notional to be the only whole number of ticks
strictly within filled x 0.000001 of the report, dividing into an on-grid price per
share. It computes in its own decimal context. The ledger's limit check halts only on
a violation that is certain within fills.incremental_notional_bound. Each counterexample
from the review is a test; the ledger test fails on main's safety.py.

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

* Re-register the fill-resolution sources and tests in the evidence manifest

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

* Keep the ledger's limit check unchanged; track its rounded-average false halt separately

The delta review of the previous commit found that loosening the ledger's limit check
by the rounding bound lets a real one-tick violation pass on large 4-decimal orders
(buy limit 0.9354, 99 x 0.9354 then 1 x 0.9355, reported 0.935401). A correct check
needs grid resolution of both cumulative notionals, fractional-share handling and a
chosen trade-off between false halts and missed violations, which belongs in its own
change. safety.py is back to main; the guard test that a certain violation halts stays
(it passes on main). The adapter's fill resolution (fills.py) is unchanged.

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

* Re-register the reverted ledger sources in the evidence manifest

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

* Record mover trial C (Mac, 2026-09-24 14:52 ET): X1 blocked by stale quotes, needs_attention, not flat

The second broker run of the mover mode (engine at d7a11b3, the first fill-fix version;
no partial fills occurred): four entries filled at the quoted ask; GCTK was skipped.
After a market-data websocket reconnect at 15:49, PFSA and SRZN quotes stayed stale,
the transport's 3 s required-symbol freshness froze it, and X1 at 15:58 never sent.
The hard flatten latched at 16:01:22 and GRML's sell was attempted but never reached
Alpaca (client-ID 404). Recovery fails closed on that ambiguous intent ("owned intent
absent from complete snapshot"), and after-hours quotes are too sparse for the
freshness rule even at the 30 s maximum. Four paper positions remain open pending an
operator decision. The verifier now separates integrity checks from reported outcomes,
and the order-throughput evidence counts the new headers (1629 trading, 15 data).

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

* Register mover trial C and the recounted order-throughput evidence in the evidence manifest

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

* Drop fills.py, its tests and the adapter hook; #221 books each execution

#221 (8bd4ca7, merged 2026-09-25) books each trade_updates fill as its own
execution and closes fill gaps from GET /v2/account/activities/FILL, so the
adapter never derives a price from a cumulative average. That supersedes
fills.py's inference (trading-lane proposal on PR #205, step 1).

- Remove blueprints/us-equities/adaptive-paper/fills.py and
  tests/test_adaptive_paper_fills.py.
- Restore native_adapter.py, tests/test_adaptive_paper_native.py and
  README-mover.md to the merge base, so the merge takes main's versions.
  The native test changes exercised fills.py's price recovery from rounded
  averages (dropped). The same-quantity average-correction test duplicates
  main's test_same_quantity_with_a_changed_average_still_freezes (dropped).
- Keep tests/test_adaptive_paper_safety.py's
  test_a_certain_limit_violation_still_halts: main's ledger still books a
  cumulative-only observation from the averages, with a rounding tolerance,
  and this is the only test that a certain violation still halts there.
- source-hashes.json: the base copy, re-pinned for the kept safety test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Count the 2026-09-24 mover trials' headers in the dated rate-limit record

#501 (df41236) made rate_limit_evidence.py read a fixed DATED_TRIAL_FILES
set, so that a trial committed later cannot move the 2026-09-24 totals. That
set was built on main, where this branch's two mover trials were not yet
merged. They also ran on 2026-09-24, and this branch's record already counts
them (1693 trading and 16 data headers). After the merge, --check reported
the record stale and test_rate_limit_evidence_is_current_and_matches_brief
failed (705/14 built vs 1693/16 committed).

- Append trials/mac-2026-09-24-mover-a/mover-paper.json and
  trials/mac-2026-09-24-mover-c/mover-paper.json to DATED_TRIAL_FILES.
  `--write` reproduces the committed record byte for byte, and `--check`
  passes.
- test_a_later_trial_receipt_does_not_change_the_dated_evidence: expect
  the dated totals with the mover trials (16 and 1693). A later trial
  still does not move them.

rate_limit_evidence.py is outside the brief's path list, so this change is
a separate commit. To drop it, revert this commit and restore main's
rate-limit-evidence-20260924.json, its order-throughput/README.md row and
the test_order_throughput.py totals line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Re-register this branch's files in the evidence manifest (hot-file protocol)

docs/lanes.md hot-file protocol, merge path. The merge took main's
manifests/evidence.json unchanged. This commit registers, through
scripts/host_receipts.register_file:
- the changed files main's manifest already lists:
  adaptive-paper/source-hashes.json, order-throughput/rate_limit_evidence.py,
  tests/test_adaptive_paper_safety.py and tests/test_order_throughput.py;
- the 37 new trial-record files this branch registered
  (trials/mac-2026-09-24-mover-a/ and trials/mac-2026-09-24-mover-c/).

Not re-added: order-throughput/README.md and
rate-limit-evidence-20260924.json. They are changed, not new, and main's
manifest does not list them. fills.py and tests/test_adaptive_paper_fills.py
are gone, and main's manifest never listed them.

scripts/component_matrix.py --write and scripts/new_host_grand_list.py
--write left their reports unchanged. scripts/validate.py passed
(8669 hashed files), and scripts/evidence_manifest.py --check passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Scout <scout@local>
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