plans(012): revise Step 3 after executor STOP — lifecycle events never carried limit/stop; enrich client-side via client_order_id join to d.orders

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
momentum devandClaude Fable 5 committed 2026-07-17 06:05:26 -05:00
1 parent 33708ffe6a
commit 5f2cbc4909
1 file changed
+32 -15
+32 -15
View File
@@ -93,10 +93,9 @@ and removes the dead columns.
## Scope
**In scope** (the only files you should modify):
- `api/static/dashboard.html`
- `storage/projections.py` (ONLY `query_order_lifecycle_snapshot`, only to pass
through fields that already exist in the event payloads)
- `tests/unit/api/` (extend an existing test file if a projection changes)
- `api/static/dashboard.html` (after the 2026-07-17 Step-3 revision this is
the ONLY file that changes)
- `tests/unit/api/` (only if a Python change sneaks back in — it should not)
**Out of scope** (do NOT touch):
- `api/static/admin.html`, anything under `archive/`
@@ -139,18 +138,36 @@ the Symbol cell. Update the `table([...])` header array to match.
### Step 3: Order Lifecycle — split "Price" into Limit / Stop / Fill and drop the order-id column
- If `query_order_lifecycle_snapshot` in `storage/projections.py` does not
already emit `limit_price`, `stop_price`, `filled_avg_price`, and `type`,
add them as pass-throughs from the payload (same pattern as the existing
fields in that function).
- Change the table columns to: `Symbol, Side, Type, Qty, Limit, Stop, Fill,
Status, Updated`. Drop the `Order` (truncated order-id) column — move the
full `order_id` into a `title` attribute on the Symbol cell so it is
hover-recoverable, not gone.
- Coerce string prices (`+o.limit_price` etc.) before `fmt`.
> **REVISED 2026-07-17** after an executor STOP: the lifecycle EVENTS
> (`order_submitted`/`order_filled`, see `query_order_lifecycle_snapshot`,
> `storage/projections.py:280`) never captured `limit_price`/`stop_price`/
> `type` — there is nothing to pass through, and adding fields to the
> emitters is an out-of-scope write-path change. The rich fields live in the
> BROKER snapshot the dashboard already receives as `d.orders`
> (`account_orders_updated`, flattened in `alpaca_paper/sync.py:135-153`),
> and the join key exists: `alpaca_paper/execution.py:116` sends the internal
> `order_id` as the broker `client_order_id` (`request.order_id[:48]`; the
> ids are 36-char uuids so the truncation never bites). Enrich CLIENT-SIDE —
> do NOT modify `storage/projections.py` at all.
**Verify**: `python3 -m pytest tests/unit/api/ -q` behaves identically to a
pre-change stash run; `node --check` → exit 0.
- In `render(d)` next to the leg maps from Step 1, build
`brokerByClientId = {}`: scan `d.orders` snapshots and map
`o.client_order_id` → `{type: o.type, limit: +o.limit_price || null,
stop: +o.stop_price || null, fill: +o.filled_avg_price || null}` (first
snapshot wins, same idiom as `stopBy`).
- In the Order Lifecycle rows, look up `brokerByClientId[o.order_id]`; change
the table columns to: `Symbol, Side, Type, Qty, Limit, Stop, Fill, Status,
Updated`. `Fill` falls back to the event-sourced `o.fill_price` when the
broker join misses. Old lifecycle rows without a broker match render
em-dashes for Type/Limit/Stop — acceptable (the broker snapshot covers the
recent orders the panel shows).
- Drop the `Order` (truncated order-id) column — move the full `order_id`
into a `title` attribute on the Symbol cell so it is hover-recoverable,
not gone.
**Verify**: `node --check` → exit 0. (No Python change in this step — the
pytest stash comparison is unnecessary unless some other step touched
`storage/projections.py`.)
### Step 4: Approval queue — drop the dead "Mode" column, show explicit numbers