Compare commits
No commits in common. "wkt/fsp_backfill_sync" and "main" have entirely different histories.
wkt/fsp_ba
...
main
|
|
@ -1,174 +0,0 @@
|
||||||
---
|
|
||||||
name: piker-clearing-expert
|
|
||||||
description: >
|
|
||||||
Piker clearing, EMS/order-control, accounting, position, and
|
|
||||||
trade-ledger expertise. Apply when changing or debugging Order,
|
|
||||||
Status, Brokerd* protocols, live or paper fills, dark orders,
|
|
||||||
order IDs, TransactionLedger persistence, Account/Position/PPU,
|
|
||||||
FQME/bs_mktid identity, SymbologyCache lookups, or broker trade
|
|
||||||
normalization.
|
|
||||||
compatibility: >
|
|
||||||
Requires a piker checkout and familiarity with Python, trio,
|
|
||||||
tractor, msgspec Structs, and backend-specific trading APIs.
|
|
||||||
metadata:
|
|
||||||
author: goodboy
|
|
||||||
version: "1.0"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Piker Clearing Expert
|
|
||||||
|
|
||||||
Use this mental model before touching order control or accounting:
|
|
||||||
|
|
||||||
```text
|
|
||||||
OrderClient / UI
|
|
||||||
-> emsd routes intent and owns order-dialog state
|
|
||||||
-> live brokerd OR paperboi executes and reports events
|
|
||||||
-> executing backend owns fill-to-accounting integration
|
|
||||||
-> emsd translates and broadcasts broker events
|
|
||||||
-> UI consumes order state and position summaries
|
|
||||||
```
|
|
||||||
|
|
||||||
The EMS is not the trade ledger. It correlates IDs, runs dark
|
|
||||||
predicates, and relays lifecycle events. Paper and accounting-aware
|
|
||||||
live backends may normalize fills into transactions, update local
|
|
||||||
ledger/account state, and emit `BrokerdPosition` summaries. Inspect
|
|
||||||
each live backend; this integration is not uniform.
|
|
||||||
|
|
||||||
## Runtime ownership
|
|
||||||
|
|
||||||
- `OrderClient` owns client intent and local sent-order tracking.
|
|
||||||
- `emsd` owns `Router`, `DarkBook`, active `Status` dialogs,
|
|
||||||
subscribers, and `oid <-> reqid` correlation.
|
|
||||||
- `brokerd.<broker>` owns credentialed live order control.
|
|
||||||
- `paperboi.<broker>` owns simulated execution and paper accounting.
|
|
||||||
- `TransactionLedger` owns trade-record persistence, not order state.
|
|
||||||
- `Account` owns positions keyed by backend-system market identity.
|
|
||||||
- UI `Position.update_from_msg()` is a summary reset, not durable
|
|
||||||
transaction accounting.
|
|
||||||
|
|
||||||
For daemon placement, context streams, cancellation, and actor-local
|
|
||||||
state, also load `piker-conc-expert`.
|
|
||||||
|
|
||||||
## Event lifecycle
|
|
||||||
|
|
||||||
1. A client sends `Order` or `Cancel` through `OrderClient`.
|
|
||||||
2. `process_client_order_cmds()` creates or updates EMS `Status`.
|
|
||||||
3. EMS routes a `BrokerdOrder` or stores a dark trigger predicate.
|
|
||||||
4. The executing backend acknowledges with `BrokerdOrderAck`.
|
|
||||||
5. EMS records the current `oid <-> reqid` relation.
|
|
||||||
6. Accepted, ack-correlated status/fill events become client updates.
|
|
||||||
7. The backend integrates fills into accounting when supported.
|
|
||||||
8. A resulting `BrokerdPosition` is relayed through EMS to clients.
|
|
||||||
|
|
||||||
Cancellation may arrive before acknowledgement. Preserve
|
|
||||||
`Status.cancel_called`; once the ack supplies `reqid`, EMS can issue
|
|
||||||
the deferred `BrokerdCancel`.
|
|
||||||
|
|
||||||
## Identifier namespaces
|
|
||||||
|
|
||||||
Never substitute one namespace merely because two values happen to
|
|
||||||
match in a backend:
|
|
||||||
|
|
||||||
| ID | Owner and invariant |
|
|
||||||
|---|---|
|
|
||||||
| `oid` | Stable client/EMS order-dialog ID across submit, modify, cancel |
|
|
||||||
| `reqid` | Backend order-control ID established by an ack; it may change |
|
|
||||||
| venue order ID | Native API identity; may differ from both IDs above |
|
|
||||||
| `tid` | Stable clear ID used to deduplicate position events and TOML keys |
|
|
||||||
| `fqme` | Piker-normalized market address and symcache lookup key |
|
|
||||||
| `bs_fqme` | FQME without its final broker suffix |
|
|
||||||
| `bs_mktid` | Backend-system market key and `Account.pps` key |
|
|
||||||
|
|
||||||
Normalize every durably persisted `tid` to a stable string. Although
|
|
||||||
`Transaction.tid` permits integers, TOML mapping keys do not.
|
|
||||||
|
|
||||||
Paper transactions commonly set `Transaction.bs_mktid` to the full
|
|
||||||
FQME. The embedded `Position.mkt.bs_mktid` can still retain the
|
|
||||||
provider-native market ID. Check the concrete object and table owner
|
|
||||||
before asserting key equality.
|
|
||||||
|
|
||||||
## Accounting invariants
|
|
||||||
|
|
||||||
- `Transaction.size` is signed; preserve side semantics during
|
|
||||||
broker normalization.
|
|
||||||
- `Transaction` is the normalized in-memory interchange. Live ledger
|
|
||||||
records may remain backend-native and normalize through
|
|
||||||
`mod.norm_trade()` when read.
|
|
||||||
- `Position._events` is keyed by `tid`; `add_clear()` is the
|
|
||||||
idempotence boundary.
|
|
||||||
- `Position.ppu` and `Position.cumsize` are derived from transaction
|
|
||||||
events, not independent mutable truth.
|
|
||||||
- Normalized accounting transactions need a stable, non-null
|
|
||||||
`bs_mktid`; `Account.pps` uses it as the position key.
|
|
||||||
- `Account.update_from_ledger()` resolves market metadata from
|
|
||||||
`SymbologyCache.mktmaps` or its explicit fallback table.
|
|
||||||
- UI position messages are projections. Do not feed their synthetic
|
|
||||||
reset event back into durable broker accounting.
|
|
||||||
|
|
||||||
## Persistence contracts
|
|
||||||
|
|
||||||
Trade ledgers live under the accounting ledger directory as
|
|
||||||
`trades_<broker>_<account>.toml`. Top-level keys are transaction IDs;
|
|
||||||
record schemas are backend-specific unless the paper engine wrote a
|
|
||||||
normalized transaction dictionary.
|
|
||||||
|
|
||||||
`open_trade_ledger()` writes on context exit when its data comparison
|
|
||||||
detects a change or `rewrite=True`. Its snapshot is shallow, so nested
|
|
||||||
in-place record mutation can evade dirty detection. Explicit writes can
|
|
||||||
also fail inside fill handlers. Treat all persistence points as part of
|
|
||||||
the live execution path.
|
|
||||||
|
|
||||||
Accounts persist active positions. `dump_active()` separates open and
|
|
||||||
net-zero positions. Do not assume `minimized_clears()` safely preserves
|
|
||||||
size/PPU: current sign-transition and longer net-zero slicing lacks
|
|
||||||
round-trip coverage and can retain the wrong event subset.
|
|
||||||
|
|
||||||
## Market identity and symcache
|
|
||||||
|
|
||||||
`SymbologyCache` has three distinct key-addressed mappings:
|
|
||||||
|
|
||||||
- `assets`: provider asset ID to `Asset`;
|
|
||||||
- `pairs`: native `bs_mktid` to backend pair `Struct`;
|
|
||||||
- `mktmaps`: searchable FQME or explicit alias to normalized
|
|
||||||
`MktPair`.
|
|
||||||
|
|
||||||
Search mapping keys, then resolve values. RapidFuzz treats mapping
|
|
||||||
values as choices; passing `mktmaps` directly makes it operate on
|
|
||||||
`MktPair` objects. Preserve in-memory aliases because IB can store both
|
|
||||||
native IDs and FQMEs for one `MktPair`. Do not persist such aliases
|
|
||||||
without fixing reload: `from_dict()` currently requires every key to
|
|
||||||
equal `mkt.fqme`.
|
|
||||||
|
|
||||||
## Change workflow
|
|
||||||
|
|
||||||
Before editing:
|
|
||||||
|
|
||||||
1. Identify the owning layer: client, EMS, executor, accounting, or UI.
|
|
||||||
2. Write down every ID/key transition across that boundary.
|
|
||||||
3. Trace both normal and cancel-before-ack event ordering.
|
|
||||||
4. Determine whether records are native, normalized, or summaries.
|
|
||||||
5. Check actor-local caches and context-exit writes.
|
|
||||||
6. Add a deterministic regression at the narrowest broken contract.
|
|
||||||
7. Run live/backend tests only when their credentials and side effects
|
|
||||||
are explicitly authorized.
|
|
||||||
|
|
||||||
Do not fix an accounting defect by adding state to EMS, or fix an EMS
|
|
||||||
correlation defect by rewriting durable transaction history.
|
|
||||||
|
|
||||||
## Canonical source map
|
|
||||||
|
|
||||||
- `piker/clearing/_messages.py`: client and brokerd protocol types.
|
|
||||||
- `piker/clearing/_client.py`: `OrderClient` and `open_ems()`.
|
|
||||||
- `piker/clearing/_ems.py`: router, dark book, ID mapping, translation.
|
|
||||||
- `piker/clearing/_paper_engine.py`: simulated execution/accounting.
|
|
||||||
- `piker/accounting/_ledger.py`: transactions and ledger persistence.
|
|
||||||
- `piker/accounting/_pos.py`: positions, accounts, PPU event state.
|
|
||||||
- `piker/accounting/_mktinfo.py`: `Asset`, `MktPair`, FQME schema.
|
|
||||||
- `piker/data/_symcache.py`: provider symbology mappings and search.
|
|
||||||
- `piker/accounting/calc.py`: transaction ordering and PPU/PnL math.
|
|
||||||
- `piker/brokers/*/broker.py`: backend order-control integration.
|
|
||||||
- `piker/brokers/*/ledger.py`: backend trade normalization.
|
|
||||||
|
|
||||||
See [architecture.md](architecture.md) for complete flows,
|
|
||||||
[gotchas.md](gotchas.md) for symptom-driven diagnosis, and
|
|
||||||
[test-map.md](test-map.md) for verification choices.
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
# Clearing And Accounting Architecture
|
|
||||||
|
|
||||||
## Protocol direction
|
|
||||||
|
|
||||||
Client-facing messages and broker-facing messages intentionally differ.
|
|
||||||
|
|
||||||
```text
|
|
||||||
client -> EMS
|
|
||||||
Order, Cancel
|
|
||||||
|
|
||||||
EMS -> executor
|
|
||||||
BrokerdOrder, BrokerdCancel
|
|
||||||
|
|
||||||
executor -> EMS
|
|
||||||
BrokerdOrderAck, BrokerdStatus, BrokerdFill,
|
|
||||||
BrokerdError, BrokerdPosition
|
|
||||||
|
|
||||||
EMS -> subscribed clients
|
|
||||||
Status, BrokerdPosition
|
|
||||||
```
|
|
||||||
|
|
||||||
`Order` carries the client `oid`, account, market, price, size, action,
|
|
||||||
and execution mode. `BrokerdOrderAck` establishes the executor's
|
|
||||||
`reqid`; subsequent broker messages should carry that ID so EMS can
|
|
||||||
resolve the client dialog.
|
|
||||||
|
|
||||||
`Status` is mutable current dialog state, not a history envelope. Exact
|
|
||||||
client states include `pending`, `open`, `dark_open`, `triggered`,
|
|
||||||
`fill`, `closed`, `canceled`, and `error`. Audit existing translation
|
|
||||||
before adding a state; backend `BrokerdStatus` vocabulary is narrower
|
|
||||||
and current producers are not fully conformant.
|
|
||||||
|
|
||||||
## EMS routing
|
|
||||||
|
|
||||||
`_emsd_main()` serves each client/market context. The actor-local
|
|
||||||
`Router` owns books, subscribers, order dialogs, and cached live trades
|
|
||||||
relays. Paper mode opens per-symbol relay contexts under the same broker
|
|
||||||
key, a current overwrite/pop hazard for concurrent paper symbols.
|
|
||||||
|
|
||||||
`open_brokerd_dialog()` is the session live-versus-paper selection
|
|
||||||
point:
|
|
||||||
|
|
||||||
- live execution talks to `brokerd.<broker>`;
|
|
||||||
- paper execution talks to `paperboi.<broker>`;
|
|
||||||
- chart-only and paper sessions should not boot credentialed brokerd.
|
|
||||||
|
|
||||||
Do not infer paper execution from each order's `exec_mode`. Session
|
|
||||||
mode selects the executor; per-order mode primarily distinguishes dark
|
|
||||||
from immediately routed orders, despite incomplete literal annotations.
|
|
||||||
|
|
||||||
`process_client_order_cmds()` handles submit, modify, cancel, dark,
|
|
||||||
and alert intent. It updates EMS dialog state before routing broker
|
|
||||||
commands. `translate_and_relay_brokerd_events()` applies acks, statuses,
|
|
||||||
fills, errors, and positions to dialogs and subscribers.
|
|
||||||
|
|
||||||
The `DarkBook` stores local predicates and watches quote ticks. When a
|
|
||||||
predicate triggers, `clear_dark_triggers()` emits the live broker order
|
|
||||||
and updates the existing client dialog rather than inventing a second
|
|
||||||
order identity.
|
|
||||||
|
|
||||||
## Ack and cancel ordering
|
|
||||||
|
|
||||||
Required actionable ordering is submit, ack, open, zero or more fills,
|
|
||||||
then terminal status. EMS handles cancel-before-ack, but it does not
|
|
||||||
buffer arbitrary status-before-ack events; those currently fall through
|
|
||||||
as unhandled. Backends must ack before actionable statuses.
|
|
||||||
|
|
||||||
The important race is:
|
|
||||||
|
|
||||||
```text
|
|
||||||
client Cancel(oid)
|
|
||||||
-> EMS has no reqid yet
|
|
||||||
-> mark Status.cancel_called
|
|
||||||
BrokerdOrderAck(oid, reqid)
|
|
||||||
-> install mapping
|
|
||||||
-> send deferred BrokerdCancel(reqid)
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not drop a pre-ack cancel and do not send a broker cancel with an
|
|
||||||
`oid` unless the backend explicitly uses that value as its `reqid`.
|
|
||||||
|
|
||||||
## Paper execution
|
|
||||||
|
|
||||||
`PaperBoi` maintains simulated orders, opens the market feed, and fills
|
|
||||||
orders when L1 ask/bid quotes cross their prices. `trade`/`last` ticks
|
|
||||||
zip buy and sell iterators, so a lone resting side currently may not
|
|
||||||
fill from those tick types. `fake_fill()` is the core fill-to-account
|
|
||||||
path:
|
|
||||||
|
|
||||||
1. emit `BrokerdFill`;
|
|
||||||
2. emit terminal `BrokerdStatus` for the simulated order;
|
|
||||||
3. construct a signed normalized `Transaction`;
|
|
||||||
4. `TransactionLedger.update_from_t()`;
|
|
||||||
5. `Account.update_from_ledger()`;
|
|
||||||
6. persist the ledger and account;
|
|
||||||
7. emit `BrokerdPosition` with current size and PPU.
|
|
||||||
|
|
||||||
The protocol notifications and persistence occur in one task but are
|
|
||||||
not a database transaction. If persistence fails after fill/status
|
|
||||||
publication, restart/reconciliation behavior matters. Do not reorder
|
|
||||||
the sequence casually.
|
|
||||||
|
|
||||||
Partial fills currently reuse `oid` as `tid`. A later partial therefore
|
|
||||||
overwrites the paper ledger record and is rejected by position-event
|
|
||||||
dedupe. Fix unique fill IDs before relying on paper partial-fill math.
|
|
||||||
|
|
||||||
`open_trade_dialog()` opens symcache, paper ledger, account, and feed
|
|
||||||
resources under structured concurrency. An exception from any nested
|
|
||||||
resource, including ledger context exit, cancels the dialog and its feed
|
|
||||||
stream.
|
|
||||||
|
|
||||||
## Live backend variation
|
|
||||||
|
|
||||||
There is no universal live-broker accounting implementation:
|
|
||||||
|
|
||||||
- IB normalizes execution/commission events, updates ledger/account
|
|
||||||
state, and emits position updates.
|
|
||||||
- Kraken has backend trade normalization and position reconstruction,
|
|
||||||
but its live path writes account state without inserting every new
|
|
||||||
trade into `TransactionLedger`.
|
|
||||||
- Binance currently relays venue order/position events and does not
|
|
||||||
share every local `TransactionLedger`/`Account` path.
|
|
||||||
|
|
||||||
Inspect the backend's `broker.py`, `ledger.py`, and `norm_trade()` before
|
|
||||||
moving generic logic. A paper behavior is not automatically a live
|
|
||||||
backend contract.
|
|
||||||
|
|
||||||
## Ledger normalization
|
|
||||||
|
|
||||||
`TransactionLedger.data` is the durable record mapping. For paper it
|
|
||||||
contains transaction-like dictionaries. For live brokers it can contain
|
|
||||||
raw provider records.
|
|
||||||
|
|
||||||
`iter_txns()` sorts records and chooses normalization:
|
|
||||||
|
|
||||||
- paper uses `_paper_engine.norm_trade()`;
|
|
||||||
- live accounts use `brokermod.norm_trade()`.
|
|
||||||
|
|
||||||
Normalizer output should carry datetime, signed size, price, cost,
|
|
||||||
FQME, backend market ID, and transaction ID. Some normalizers return
|
|
||||||
`None` for unusable records; `iter_txns()` does not filter it, while
|
|
||||||
`to_txns()` does. Audit direct iterator consumers.
|
|
||||||
|
|
||||||
`write_config()` sorts records for stable persistence. Paper rewrite
|
|
||||||
logic migrates old symbol fields and qualifies legacy FQMEs through the
|
|
||||||
symcache. Search can return no matches; callers which select the first
|
|
||||||
result need an explicit fallback or a descriptive failure policy.
|
|
||||||
|
|
||||||
## Position event model
|
|
||||||
|
|
||||||
`Position` holds a market and a transaction-event mapping. New clears
|
|
||||||
are deduplicated by `tid`. Current size and PPU are recomputed from the
|
|
||||||
event sequence.
|
|
||||||
|
|
||||||
`Account.update_from_ledger()`:
|
|
||||||
|
|
||||||
1. receives normalized transactions;
|
|
||||||
2. resolves each market through `mktmaps` or a fallback table;
|
|
||||||
3. looks up or creates the position by `Transaction.bs_mktid`;
|
|
||||||
4. adds unseen clears;
|
|
||||||
5. returns visited positions, including duplicates whose clear was
|
|
||||||
rejected by `add_clear()`.
|
|
||||||
|
|
||||||
`minimized_clears()` intends to discard irrelevant history after
|
|
||||||
net-zero or sign transitions, but current slicing is not proven safe
|
|
||||||
and can reconstruct the wrong active size/PPU. Treat it as a known bug
|
|
||||||
surface until sign-transition round trips are covered.
|
|
||||||
|
|
||||||
`Position.update_from_msg()` serves UI summaries by replacing local
|
|
||||||
event state with a synthetic clear representing reported size and PPU.
|
|
||||||
That projection is intentionally lossy.
|
|
||||||
|
|
||||||
## Symbology contracts
|
|
||||||
|
|
||||||
`MktPair.fqme` is a normalized endpoint address assembled from pair,
|
|
||||||
venue, expiry/contract information, and broker. `MktPair.bs_fqme`
|
|
||||||
drops the broker suffix. `MktPair.bs_mktid` is the provider-native
|
|
||||||
market identity.
|
|
||||||
|
|
||||||
`SymbologyCache.load()` attempts to obtain provider assets and pair
|
|
||||||
structs, calls `get_mkt_info()`, and populates conventional mappings.
|
|
||||||
Assets are optional; missing/empty pair support returns early.
|
|
||||||
|
|
||||||
```text
|
|
||||||
assets[provider_asset_id] -> Asset
|
|
||||||
pairs[pair.bs_mktid] -> backend Pair Struct
|
|
||||||
mktmaps[mkt.fqme] -> MktPair
|
|
||||||
```
|
|
||||||
|
|
||||||
Some backends add aliases such as `mktmaps[bs_mktid]`. Search must
|
|
||||||
return the matched mapping key rather than rebuilding a key from the
|
|
||||||
value, otherwise aliases silently collapse. Current serialization then
|
|
||||||
writes aliases which reload rejects because `from_dict()` asserts each
|
|
||||||
key equals `mkt.fqme`.
|
|
||||||
|
|
||||||
## Persistence boundaries
|
|
||||||
|
|
||||||
`open_trade_ledger()` loads account TOML and compares a shallow snapshot
|
|
||||||
in `finally`. Top-level additions/replacements trigger writes; nested
|
|
||||||
in-place mutation may not. `open_account()` similarly mediates account
|
|
||||||
state. These contexts run inside actor tasks, so serialization errors
|
|
||||||
are runtime failures, not merely offline maintenance failures.
|
|
||||||
|
|
||||||
When changing schemas:
|
|
||||||
|
|
||||||
- preserve backend-native records unless migration is explicit;
|
|
||||||
- keep old paper field migration deterministic;
|
|
||||||
- avoid fuzzy qualification when an exact `bs_mktid`/FQME exists;
|
|
||||||
- test context exit, not only in-memory updates;
|
|
||||||
- inspect emitted positions after disk round trips.
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
||||||
# Clearing And Ledger Gotchas
|
|
||||||
|
|
||||||
## Trade dialog dies immediately after a fill
|
|
||||||
|
|
||||||
Likely cause: an explicit ledger/account write in the fill handler, or
|
|
||||||
a later context-exit write, raised after event publication.
|
|
||||||
|
|
||||||
Inspect, in order:
|
|
||||||
|
|
||||||
1. the first non-cancellation exception in the actor traceback;
|
|
||||||
2. `PaperBoi.fake_fill()` or the live backend fill handler;
|
|
||||||
3. explicit and context-exit `write_config()` calls;
|
|
||||||
4. FQME/`bs_mktid` qualification and TOML-compatible values;
|
|
||||||
5. the persisted ledger/account files for a partial update.
|
|
||||||
|
|
||||||
Tractor cancellation logs are often the consequence. Root-cause the
|
|
||||||
inner serialization, lookup, or normalization exception first.
|
|
||||||
|
|
||||||
## `MktPair` has no `len()` in RapidFuzz
|
|
||||||
|
|
||||||
Cause: a mapping of string keys to `MktPair` values was passed directly
|
|
||||||
to `rapidfuzz.process.extract()`. Mapping values become fuzzy choices.
|
|
||||||
|
|
||||||
Fix: search a list/view of string keys and resolve matched keys back
|
|
||||||
through the original mapping. Do not add sequence methods to `MktPair`
|
|
||||||
and do not use `processor=str` when aliases must be preserved.
|
|
||||||
|
|
||||||
## Fuzzy qualification raises `IndexError`
|
|
||||||
|
|
||||||
Cause: the caller selected the first match from an empty result after
|
|
||||||
the score cutoff rejected every key.
|
|
||||||
|
|
||||||
Decide explicitly whether to retain the input identity, reject the
|
|
||||||
record with a descriptive exception, or obtain missing market metadata.
|
|
||||||
Do not lower the cutoff blindly; the wrong market corrupts accounting.
|
|
||||||
|
|
||||||
## Cancel is ignored or sent with the wrong ID
|
|
||||||
|
|
||||||
Cause: confusion between client `oid` and backend `reqid`, commonly
|
|
||||||
during cancel-before-ack ordering.
|
|
||||||
|
|
||||||
Verify the ack installed both mapping directions and that
|
|
||||||
`Status.cancel_called` survives until `reqid` exists. Log both IDs and
|
|
||||||
the actor/backend account at every transition.
|
|
||||||
|
|
||||||
## Fills appear but positions do not move
|
|
||||||
|
|
||||||
Check these boundaries:
|
|
||||||
|
|
||||||
- the backend emitted `BrokerdFill` but never normalized a transaction;
|
|
||||||
- transaction size lost its buy/sell sign;
|
|
||||||
- `tid` collided with an existing position event;
|
|
||||||
- `Transaction.bs_mktid` selected a different `Account.pps` key;
|
|
||||||
- `mktmaps` lacked the exact transaction identity;
|
|
||||||
- position publication happened before accounting update;
|
|
||||||
- the backend intentionally reports venue positions instead of local
|
|
||||||
ledger-derived positions.
|
|
||||||
|
|
||||||
## Duplicate or inflated position size
|
|
||||||
|
|
||||||
Do not deduplicate by price/time alone. Confirm stable transaction IDs,
|
|
||||||
chronological sorting, and `Position.add_clear()` idempotence. Broker
|
|
||||||
execution IDs and order IDs are not interchangeable.
|
|
||||||
|
|
||||||
For partial fills, several `tid`s may correctly share one order
|
|
||||||
`reqid`. Collapsing them loses clears; replaying one `tid` twice
|
|
||||||
inflates nothing only if the dedupe boundary is preserved.
|
|
||||||
|
|
||||||
Current paper fills use `tid=oid`, so later partials overwrite the
|
|
||||||
ledger record and are deduplicated out of the position. Treat paper
|
|
||||||
partial fills as broken until each clear receives a stable unique ID.
|
|
||||||
|
|
||||||
## Paper and live state disagree
|
|
||||||
|
|
||||||
Paper uses normalized local transactions and can use the full FQME as
|
|
||||||
its account position key. A live backend may use native IDs, raw ledger
|
|
||||||
records, or venue-reported positions.
|
|
||||||
|
|
||||||
Compare normalized `Transaction`s and emitted `BrokerdPosition`s, not
|
|
||||||
raw TOML dictionaries across backends.
|
|
||||||
|
|
||||||
## Account appears under the wrong name
|
|
||||||
|
|
||||||
Separate UI/EMS account aliases from backend account IDs and ledger file
|
|
||||||
names. Backends may prefix account names for routing while persistence
|
|
||||||
uses an unprefixed native account key.
|
|
||||||
|
|
||||||
Trace account identity through `open_ems()`, broker dialog startup,
|
|
||||||
ledger opening, and `BrokerdPosition.account` before changing naming.
|
|
||||||
|
|
||||||
## A module-global cache is unexpectedly empty
|
|
||||||
|
|
||||||
Symcache, clients, contracts, and order tables are actor-local. Data
|
|
||||||
loaded in `datad` is not automatically available in `brokerd` or
|
|
||||||
`paperboi`. Also, `_symcache._caches` is currently read but never
|
|
||||||
populated, so do not assume repeated `open_symcache()` calls hit it.
|
|
||||||
|
|
||||||
Load `piker-conc-expert` and audit actor-local globals, async caches,
|
|
||||||
and dialog startup warming. Never rely on an import side effect from a
|
|
||||||
sibling actor.
|
|
||||||
|
|
||||||
## Teardown emits a cancellation storm
|
|
||||||
|
|
||||||
Find the first application exception. Structured cancellation then
|
|
||||||
closes feed streams, broker streams, and nested contexts. Avoid masking
|
|
||||||
the originating exception with broad cancellation handling.
|
|
||||||
|
|
||||||
For stream ownership and context cancellation semantics, use
|
|
||||||
`piker-conc-expert`.
|
|
||||||
|
|
||||||
## Broker status is logged as unhandled
|
|
||||||
|
|
||||||
EMS currently accepts only ack-correlated `open`, `closed`, and
|
|
||||||
`canceled` broker statuses. Declared `pending` and backend-produced
|
|
||||||
`fill`/`filled` variants fall through, as do statuses arriving before
|
|
||||||
ack. Verify producer vocabulary and ack ordering before adding another
|
|
||||||
consumer branch.
|
|
||||||
|
|
||||||
## Another client sees order or position events
|
|
||||||
|
|
||||||
Current translation broadcasts order updates by FQME and positions to
|
|
||||||
all attached clients; `Router.dialogs` is not used as an event privacy
|
|
||||||
filter. Treat subscriber isolation as incomplete, not guaranteed.
|
|
||||||
|
|
||||||
## Debug breadcrumb
|
|
||||||
|
|
||||||
Capture one row per event with:
|
|
||||||
|
|
||||||
```text
|
|
||||||
actor, backend, account, fqme, bs_mktid,
|
|
||||||
oid, reqid, venue_order_id, tid,
|
|
||||||
message_type, status, action, signed_size, price, timestamp
|
|
||||||
```
|
|
||||||
|
|
||||||
Then compare:
|
|
||||||
|
|
||||||
1. client command order;
|
|
||||||
2. EMS status history;
|
|
||||||
3. broker event order;
|
|
||||||
4. normalized transactions;
|
|
||||||
5. position event IDs and computed size/PPU;
|
|
||||||
6. ledger/account disk state;
|
|
||||||
7. emitted position summaries.
|
|
||||||
|
|
||||||
This separates protocol loss, identity skew, accounting math, and
|
|
||||||
persistence failure without guessing from UI state.
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
# Clearing And Accounting Test Map
|
|
||||||
|
|
||||||
## Deterministic first-pass tests
|
|
||||||
|
|
||||||
Use the narrowest test that owns the broken contract:
|
|
||||||
|
|
||||||
| Area | First target |
|
|
||||||
|---|---|
|
|
||||||
| Ledger/account persistence | targeted node in `tests/test_accounting.py` |
|
|
||||||
| EMS bad-backend handling | `tests/test_ems.py::test_ems_err_on_bad_broker` |
|
|
||||||
| IB request/response routing | `tests/test_ib_method_proxy.py` |
|
|
||||||
| IB history normalization | `tests/test_ib_history.py` |
|
|
||||||
| Service/actor startup | targeted node in `tests/test_services.py` |
|
|
||||||
|
|
||||||
Known missing high-value regressions include paper partial-fill IDs,
|
|
||||||
status-before-ack handling, `minimized_clears()` sign-transition round
|
|
||||||
trips, nested ledger dirty detection, and symcache alias reload.
|
|
||||||
|
|
||||||
For `SymbologyCache.search()` and paper ledger qualification, cover:
|
|
||||||
|
|
||||||
- real `Asset` and `MktPair` values;
|
|
||||||
- a native-ID alias and canonical FQME key;
|
|
||||||
- the actual `TransactionLedger.write_config()` path;
|
|
||||||
- persisted TOML fields after the round trip;
|
|
||||||
- no use of live APIs or user configuration.
|
|
||||||
|
|
||||||
## Side-effectful tests
|
|
||||||
|
|
||||||
Do not run these without explicit authorization and the repository test
|
|
||||||
harness guidance:
|
|
||||||
|
|
||||||
- paper EMS tests which open live market/symbology feeds;
|
|
||||||
- live Binance/Kraken feed suites;
|
|
||||||
- IB account tests using configured accounts;
|
|
||||||
- tests which write tracked ledger/account fixtures;
|
|
||||||
- broker dialogs requiring credentials or venue connectivity.
|
|
||||||
|
|
||||||
After any accounting test using `tests/_inputs`, inspect its diff. Some
|
|
||||||
context managers can rewrite fixture ledgers on exit.
|
|
||||||
|
|
||||||
## Regression design
|
|
||||||
|
|
||||||
Prefer a direct contract regression over a full actor test when the
|
|
||||||
failure is synchronous and deterministic. Use an actor-level test when
|
|
||||||
the bug depends on:
|
|
||||||
|
|
||||||
- ack/cancel or fill/status interleaving;
|
|
||||||
- context cancellation or stream ownership;
|
|
||||||
- actor-local state/cache separation;
|
|
||||||
- daemon selection or startup;
|
|
||||||
- publication ordering across EMS and broker streams.
|
|
||||||
|
|
||||||
Every regression should document the original failure, triggering
|
|
||||||
state, violated invariant, arrangement, and proof of the fix.
|
|
||||||
|
|
||||||
## Verification layers
|
|
||||||
|
|
||||||
1. `git diff --cached --check` for the exact staged boundary.
|
|
||||||
2. Ruff with the repository's intended rule profile.
|
|
||||||
3. A deterministic unit/filesystem regression.
|
|
||||||
4. Adjacent accounting or EMS tests which do not require live state.
|
|
||||||
5. Explicitly authorized backend/actor integration tests.
|
|
||||||
|
|
||||||
Do not interpret a passing ellipsis-body or hard-skipped test as
|
|
||||||
behavioral coverage. Read the selected node before using it as a gate.
|
|
||||||
|
|
||||||
## Manual reconciliation check
|
|
||||||
|
|
||||||
For production-only failures, compare one fill end to end:
|
|
||||||
|
|
||||||
```text
|
|
||||||
BrokerdFill
|
|
||||||
-> normalized Transaction
|
|
||||||
-> ledger record
|
|
||||||
-> Position._events[tid]
|
|
||||||
-> Position.cumsize / ppu
|
|
||||||
-> account TOML
|
|
||||||
-> BrokerdPosition
|
|
||||||
-> UI summary
|
|
||||||
```
|
|
||||||
|
|
||||||
All identities, sign, price, and account values should remain explainable
|
|
||||||
at each arrow. A mismatch identifies the owning boundary for the next
|
|
||||||
focused test.
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
---
|
|
||||||
name: piker-fsp-expert
|
|
||||||
description: Piker financial signal processing expertise. Apply when changing or debugging FSP definitions, Cascade execution, derived shared-memory arrays, history/realtime handoff, backfill synchronization, FSP graph composition, online financial algorithms, or FSP chart lifecycle and scaling.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Piker FSP Expertise
|
|
||||||
|
|
||||||
Treat financial signal processing as causal, revision-aware processing of
|
|
||||||
event-time market data, not as generic batch array manipulation.
|
|
||||||
|
|
||||||
## Start Here
|
|
||||||
|
|
||||||
1. Identify the source `Flume`, timeframe, event clock, and writer actor.
|
|
||||||
2. State whether the operation is historical bootstrap, backfill revision,
|
|
||||||
current-sample mutation, or sample-step append.
|
|
||||||
3. Record source and destination absolute SHM bounds before reasoning from
|
|
||||||
lengths or `ShmArray.index`.
|
|
||||||
4. Separate compute, SHM publication, IPC wakeup, and graphics costs before
|
|
||||||
optimizing.
|
|
||||||
5. Preserve causality, warm-up behavior, missing-data semantics, and output
|
|
||||||
schema in every implementation and test.
|
|
||||||
|
|
||||||
Read [architecture.md](architecture.md) before modifying runtime code. Read
|
|
||||||
[signal-processing.md](signal-processing.md) before adding an algorithm. Use
|
|
||||||
[roadmap-and-research.md](roadmap-and-research.md) for design and dependency
|
|
||||||
work, and [test-map.md](test-map.md) for verification.
|
|
||||||
|
|
||||||
## Core Contracts
|
|
||||||
|
|
||||||
- `piker.data` owns provider ingestion, source `Flume`s, history publication,
|
|
||||||
quote fan-out, OHLC mutation, and `samplerd` step events.
|
|
||||||
- `piker.fsp` owns operator declarations, historical computation, realtime
|
|
||||||
state updates, and destination SHM publication.
|
|
||||||
- `piker.ui._fsp.FspAdmin` currently owns FSP worker selection, destination
|
|
||||||
allocation, cascade lifetime, and chart attachment.
|
|
||||||
- One logical writer owns each destination FSP array.
|
|
||||||
- Output event time and absolute indices derive from the source series, not
|
|
||||||
task scheduling or quote arrival order.
|
|
||||||
- A source prepend changes historical provenance even when the current sample
|
|
||||||
index is unchanged. Recompute or patch the affected destination range.
|
|
||||||
- One-step destination lag is normal between source sampling and destination
|
|
||||||
append. A destination lead or unexplained bound shift is not.
|
|
||||||
- Backfill notifications are source and timeframe specific even though the
|
|
||||||
current sampler transport broadcasts them globally.
|
|
||||||
- Only graphics backed by a rebuilt destination should refresh. Never use an
|
|
||||||
FSP update as an unconditional whole-chart redraw request.
|
|
||||||
|
|
||||||
## Editing Workflow
|
|
||||||
|
|
||||||
1. Trace the operator from `@fsp` declaration through `cascade()`,
|
|
||||||
`connect_streams()`, destination SHM, `FspAdmin`, and every consuming
|
|
||||||
`Viz`.
|
|
||||||
2. Write an event-order table covering source writes, bound publication,
|
|
||||||
notifications, cancellation, recomputation, and destination publication.
|
|
||||||
3. Add deterministic tests for history and realtime phases independently.
|
|
||||||
4. Add a controlled interleaving test for every race fix.
|
|
||||||
5. Profile representative visible ranges and feed rates before adding a
|
|
||||||
dependency or native boundary.
|
|
||||||
|
|
||||||
## Companion Skills
|
|
||||||
|
|
||||||
- Use `piker-conc-expert` for Tractor contexts, actor topology, cancellation,
|
|
||||||
service ownership, and cross-actor state.
|
|
||||||
- Use `timeseries-optimization` for NumPy/Polars lookup and vectorization.
|
|
||||||
- Use `piker-profiling` for distributed performance measurements.
|
|
||||||
- Use `pyqtgraph-optimization` for renderer and graphics batching work.
|
|
||||||
- Use `piker-clearing-expert` when a derived signal reaches EMS or accounting.
|
|
||||||
|
|
||||||
## Do Not
|
|
||||||
|
|
||||||
- Do not hide a historical mismatch merely to stop a resync log.
|
|
||||||
- Do not infer a complete synchronization state from array length alone.
|
|
||||||
- Do not run Python loops over historical numeric arrays without evidence.
|
|
||||||
- Do not apply regular-grid DSP blindly to irregular tick arrival times.
|
|
||||||
- Do not introduce an external stream runtime that duplicates Tractor before
|
|
||||||
measuring an isolated protocol or kernel prototype.
|
|
||||||
- Do not route strategy signals directly around EMS order-state, risk, or
|
|
||||||
accounting contracts.
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
# FSP Runtime Architecture
|
|
||||||
|
|
||||||
## Current Topology
|
|
||||||
|
|
||||||
```text
|
|
||||||
provider backend
|
|
||||||
-> datad feed bus
|
|
||||||
-> source Flume
|
|
||||||
-> rt ShmArray (typically 1 second)
|
|
||||||
-> hist ShmArray (typically 60 seconds)
|
|
||||||
-> samplerd sample and backfill events
|
|
||||||
|
|
||||||
chart actor
|
|
||||||
-> FspAdmin
|
|
||||||
-> chart.fsp_N worker actor
|
|
||||||
-> cascade()
|
|
||||||
-> connect_streams()
|
|
||||||
-> destination Flume / ShmArray
|
|
||||||
-> targeted Viz updates
|
|
||||||
```
|
|
||||||
|
|
||||||
The source path is implemented mainly by `piker.data.feed`,
|
|
||||||
`piker.data.flows`, `piker.data._sampling`, and `piker.tsp._history`. The FSP
|
|
||||||
path is implemented by `piker.fsp._api`, `piker.fsp._engine`, and operator
|
|
||||||
modules such as `_volume` and `_momo`. Worker and graphics lifecycle currently
|
|
||||||
live in `piker.ui._fsp` and `piker.ui._display`.
|
|
||||||
|
|
||||||
## Operator Contract
|
|
||||||
|
|
||||||
`@fsp` wraps an async generator. Its first yield is historical output computed
|
|
||||||
from the source array. Later yields are `(field, value)` realtime mutations.
|
|
||||||
`connect_streams()` converts the first yield into the destination structured
|
|
||||||
array, aligns time and absolute bounds, then updates the current destination
|
|
||||||
row from realtime quote events.
|
|
||||||
|
|
||||||
`samplerd` owns row advancement. At a new source sample, the cascade copies or
|
|
||||||
zeros the previous destination row and aligns destination timestamps to the
|
|
||||||
source. Quote-time mutations and sample-time appends are distinct operations.
|
|
||||||
|
|
||||||
## SHM Synchronization
|
|
||||||
|
|
||||||
Treat each array as an absolute half-open range:
|
|
||||||
|
|
||||||
```text
|
|
||||||
[first, last)
|
|
||||||
```
|
|
||||||
|
|
||||||
For a normal source history prepend:
|
|
||||||
|
|
||||||
```text
|
|
||||||
before: src=[10000, 12000) dst=[10000, 12000)
|
|
||||||
after: src=[ 8000, 12000) dst=[10000, 12000)
|
|
||||||
```
|
|
||||||
|
|
||||||
The current step is unchanged, but destination history is missing 2,000 rows.
|
|
||||||
The destination must be recomputed or incrementally repaired.
|
|
||||||
|
|
||||||
For a normal one-step source lead:
|
|
||||||
|
|
||||||
```text
|
|
||||||
src=[8000, 12001) dst=[8000, 12000)
|
|
||||||
```
|
|
||||||
|
|
||||||
The cascade should append exactly one destination row, not recompute history.
|
|
||||||
|
|
||||||
Use `_first.value` and `_last.value` for synchronization. `ShmArray.index` is
|
|
||||||
the last bound modulo capacity and is not a complete absolute position.
|
|
||||||
Snapshot bounds once per check; shared first and last counters do not form a
|
|
||||||
transactional pair.
|
|
||||||
|
|
||||||
## Backfill Event Ordering
|
|
||||||
|
|
||||||
1. `start_backfill()` receives an older provider frame.
|
|
||||||
2. `shm_push_in_between()` writes the frame and publishes the earlier first
|
|
||||||
bound.
|
|
||||||
3. `notify_backfill()` asks `samplerd` to broadcast the market and timeframe.
|
|
||||||
4. Relevant cascades treat the event as a history revision. A prepend changes
|
|
||||||
bounds; an in-place gap repair may not.
|
|
||||||
5. Each cascade cancels its current compute task and waits for completion.
|
|
||||||
6. The historical phase recomputes against the newest readable source range.
|
|
||||||
7. Destination bounds are published and the UI receives an `fsp_update`.
|
|
||||||
8. Only `Viz` objects backed by that destination token redraw.
|
|
||||||
|
|
||||||
Multiple provider frames may arrive while a recomputation runs. The cascade
|
|
||||||
must reject mixed-bound bootstrap results, replay in-place revisions, recheck
|
|
||||||
bounds after restart, and converge on the newest source range.
|
|
||||||
|
|
||||||
## Actor-Local State
|
|
||||||
|
|
||||||
`Fsp._flow_registry`, attached SHM handles, caches, and nurseries are local to
|
|
||||||
each actor. Never assume worker siblings share warmed registries or Python
|
|
||||||
objects. Graph dependencies currently rely on startup order, as demonstrated
|
|
||||||
by `flow_rates` starting only after `dolla_vlm`.
|
|
||||||
|
|
||||||
## Cross-Subsystem Boundaries
|
|
||||||
|
|
||||||
- Data ingest should normalize identity and event-time semantics before an FSP
|
|
||||||
consumes a stream.
|
|
||||||
- UI renderers should consume revision/range information without controlling
|
|
||||||
computation correctness.
|
|
||||||
- Clearing may consume a derived signal, but EMS remains responsible for order
|
|
||||||
intent, status, routing, fills, positions, and accounting.
|
|
||||||
- FSP output exposed as a feed needs the same fan-out, identity, lifecycle,
|
|
||||||
and backpressure contracts as provider feeds.
|
|
||||||
|
|
||||||
## Architectural Gaps
|
|
||||||
|
|
||||||
The current protocol infers history revisions from shared bounds. A future
|
|
||||||
revision message should carry at least:
|
|
||||||
|
|
||||||
```text
|
|
||||||
(fqme, timeframe, revision, first, last, start_ts, end_ts)
|
|
||||||
```
|
|
||||||
|
|
||||||
Destination publication should identify the source revision used. This allows
|
|
||||||
coalescing, range repair, stale-result rejection, and deterministic graph
|
|
||||||
dependency startup without turning every prepend into a global wakeup.
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
# Roadmap and Research
|
|
||||||
|
|
||||||
Issue states change. Re-read each tracker before planning work and preserve
|
|
||||||
human ownership of issue and checklist state.
|
|
||||||
|
|
||||||
## Guiding Roadmap
|
|
||||||
|
|
||||||
- [piker #270](https://github.com/pikers/piker/issues/270): typed,
|
|
||||||
stream-composable FSP graph and DSL direction.
|
|
||||||
- [piker #107](https://github.com/pikers/piker/issues/107): cross-actor shared
|
|
||||||
memory tick/ring-buffer direction.
|
|
||||||
- [piker #216](https://github.com/pikers/piker/issues/216): exposing FSP output
|
|
||||||
through feed-like interfaces.
|
|
||||||
- [piker #325](https://github.com/pikers/piker/issues/325): faster streaming
|
|
||||||
y-range computation and overlap with FSP reductions.
|
|
||||||
- [piker #536](https://github.com/pikers/piker/issues/536): Arrow/Parquet data
|
|
||||||
ingest and columnar boundaries.
|
|
||||||
- [piker #98](https://github.com/pikers/piker/issues/98): older realtime feed
|
|
||||||
architecture discussion. Treat it as likely superseded; compare every idea
|
|
||||||
against current `Flume`, feed-bus, history, and sampler code.
|
|
||||||
- [Tractor #339](https://github.com/goodboy/tractor/issues/339): shared-memory
|
|
||||||
array and localhost IPC evolution.
|
|
||||||
- [hotbaud issues](https://github.com/guilledk/hotbaud/issues): experimental
|
|
||||||
high-throughput local transport and ring-buffer work.
|
|
||||||
|
|
||||||
## Near-Term Protocol Research
|
|
||||||
|
|
||||||
Prototype an explicit source revision envelope and measure it with two FSPs
|
|
||||||
and two overlaid feeds. The prototype should prove source-specific wakeups,
|
|
||||||
coalescing of consecutive prepends, stale-result rejection, and targeted UI
|
|
||||||
range updates. Keep the protocol independent of the final IPC transport.
|
|
||||||
|
|
||||||
Characterize historical repair strategies:
|
|
||||||
|
|
||||||
1. Full replay from the new first bound.
|
|
||||||
2. Prefix-only calculation for pointwise operators.
|
|
||||||
3. Replay from an operator checkpoint for stateful recurrences.
|
|
||||||
4. Bounded overlap repair for finite-window operators.
|
|
||||||
|
|
||||||
An FSP declaration eventually needs repair metadata describing locality,
|
|
||||||
state checkpointability, warm-up/overlap, and whether old inputs can alter all
|
|
||||||
later outputs.
|
|
||||||
|
|
||||||
## Candidate Libraries
|
|
||||||
|
|
||||||
Candidates are experiments, not dependency recommendations.
|
|
||||||
|
|
||||||
### Bounded Near-Term Prototypes
|
|
||||||
|
|
||||||
- [Bottleneck](https://github.com/pydata/bottleneck): compare rolling min/max,
|
|
||||||
rank, and moving-window kernels against NumPy/Numba for chart y-ranges and
|
|
||||||
finite-window FSPs.
|
|
||||||
- [River](https://github.com/online-ml/river): study stateful online estimator
|
|
||||||
APIs, drift detectors, and reference semantics. Do not assume its object
|
|
||||||
model belongs in the hottest tick path.
|
|
||||||
- [nanoarrow](https://github.com/apache/arrow-nanoarrow): evaluate lightweight
|
|
||||||
Arrow C data interfaces at native/process boundaries already motivated by
|
|
||||||
`pyarrow` and piker #536.
|
|
||||||
- [DuckDB](https://github.com/duckdb/duckdb): use for historical Parquet query,
|
|
||||||
replay slicing, and validation, outside realtime tick execution.
|
|
||||||
|
|
||||||
### Watchlist
|
|
||||||
|
|
||||||
- [hotbaud](https://github.com/guilledk/hotbaud): track API and correctness
|
|
||||||
maturity for localhost SHM/ring transport.
|
|
||||||
- [iceoryx2](https://github.com/eclipse-iceoryx/iceoryx2): study zero-copy
|
|
||||||
pub/sub ownership and lifecycle, but avoid competing with Tractor without a
|
|
||||||
narrow adapter benchmark.
|
|
||||||
- [DataFusion Python](https://github.com/apache/datafusion-python): Arrow-native
|
|
||||||
historical query and expression execution if existing Polars paths cannot
|
|
||||||
meet a demonstrated need.
|
|
||||||
- [Feldera](https://github.com/feldera/feldera): study DBSP/incremental-view
|
|
||||||
semantics for revision-aware graphs; its service/SQL runtime is not a direct
|
|
||||||
piker integration target.
|
|
||||||
- [Bytewax](https://github.com/bytewax/bytewax) and
|
|
||||||
[Arroyo](https://github.com/ArroyoSystems/arroyo): study dataflow semantics,
|
|
||||||
watermarking, and recovery, not as replacements for the actor tree.
|
|
||||||
|
|
||||||
GPU stacks such as JAX and CuPy are poor defaults for low-batch per-tick work
|
|
||||||
because transfer, compilation, and scheduling can dominate. Reconsider only
|
|
||||||
for measured large-batch research or many-market matrix workloads.
|
|
||||||
|
|
||||||
## Benchmark Design
|
|
||||||
|
|
||||||
Report separate distributions for:
|
|
||||||
|
|
||||||
- provider decode and normalization;
|
|
||||||
- source SHM write and bound publication;
|
|
||||||
- historical kernel and realtime recurrence;
|
|
||||||
- actor notification and stream fan-out;
|
|
||||||
- destination publication;
|
|
||||||
- visible-range formatting and Qt paint.
|
|
||||||
|
|
||||||
Use p50, p95, p99, maximum, allocation rate, and resident-memory growth. Test
|
|
||||||
steady state, burst load, backfill overlap, cancellation, and slow consumers.
|
|
||||||
Throughput without event-time correctness and bounded teardown is not a win.
|
|
||||||
|
|
||||||
## Medium-Term Sequence
|
|
||||||
|
|
||||||
First establish revisioned range messages and operator repair semantics. Then
|
|
||||||
decouple FSP orchestration from chart ownership and expose destination flows
|
|
||||||
through feed-like subscriptions. Next benchmark localhost transport adapters
|
|
||||||
behind the same protocol. Only after those contracts stabilize should graph
|
|
||||||
placement, fusion, worker scaling, and remote partitioning be automated.
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
# Financial Signal Processing
|
|
||||||
|
|
||||||
## Model the Clock First
|
|
||||||
|
|
||||||
Market inputs can be quote events, trades, book changes, fixed-time bars, or
|
|
||||||
revised historical bars. Name both event time and processing time. For
|
|
||||||
irregular events, either use time-aware recurrences or define the resampling
|
|
||||||
and interpolation policy explicitly.
|
|
||||||
|
|
||||||
Never let backfilled information leak into a value presented as historically
|
|
||||||
tradable. Distinguish corrected analysis history from the signal values that a
|
|
||||||
live strategy could have observed.
|
|
||||||
|
|
||||||
## Useful Technique Families
|
|
||||||
|
|
||||||
### Online Moments and Robust Statistics
|
|
||||||
|
|
||||||
Use Welford/Chan recurrences for stable online moments, compensated summation
|
|
||||||
for long accumulations, and mergeable summaries when partitioning actors.
|
|
||||||
Rolling median, quantiles, MAD, and winsorized measures are useful under heavy
|
|
||||||
tails, but exact rolling order statistics need more state than moments.
|
|
||||||
|
|
||||||
### Time-Aware Exponential Filters
|
|
||||||
|
|
||||||
For irregular event intervals, derive decay from elapsed time:
|
|
||||||
|
|
||||||
```text
|
|
||||||
alpha(dt) = 1 - exp(-dt / tau)
|
|
||||||
y_t = y_prev + alpha(dt) * (x_t - y_prev)
|
|
||||||
```
|
|
||||||
|
|
||||||
Record initialization, session reset, gap, and backfill behavior. A fixed
|
|
||||||
sample alpha is valid only after an explicit regularization policy.
|
|
||||||
|
|
||||||
### State-Space Models
|
|
||||||
|
|
||||||
Kalman and robust state-space filters fit latent price, spread, volatility,
|
|
||||||
and lead/lag estimates. Prefer square-root or Joseph-form covariance updates
|
|
||||||
when conditioning is poor. State revisions after backfill require replay from
|
|
||||||
a checkpoint or a bounded smoother; silently prepending observations without
|
|
||||||
replaying state is incorrect.
|
|
||||||
|
|
||||||
### Point Processes and Microstructure
|
|
||||||
|
|
||||||
Trade and quote arrivals are events, not merely sampled amplitudes. Consider
|
|
||||||
intensity, duration, signed order flow, imbalance, spread, queue change, and
|
|
||||||
self-excitation models. Validate against provider-specific aggregation and
|
|
||||||
duplicate/out-of-order behavior before interpreting a statistic.
|
|
||||||
|
|
||||||
### Volatility and Covariance
|
|
||||||
|
|
||||||
Realized variance, bipower variation, EW covariance, and range estimators can
|
|
||||||
be updated online. Asynchronous cross-market covariance needs synchronization
|
|
||||||
or estimators designed for non-synchronous observations; naive row alignment
|
|
||||||
creates lead/lag and Epps-effect artifacts.
|
|
||||||
|
|
||||||
### Spectral and Multiscale Methods
|
|
||||||
|
|
||||||
FFT methods assume a regular grid and a window. Declare detrending, tapering,
|
|
||||||
overlap, normalization, and latency. For tick data, resample deliberately or
|
|
||||||
use irregular-time methods. Wavelets and multiresolution filters can separate
|
|
||||||
horizons, but boundary handling and causal delay must be visible to strategy
|
|
||||||
code.
|
|
||||||
|
|
||||||
### Change and Anomaly Detection
|
|
||||||
|
|
||||||
CUSUM, Page-Hinkley, sequential likelihood ratios, and robust z-scores are
|
|
||||||
cheap online tools. Calibrate false alarms under dependence and regime shifts;
|
|
||||||
do not treat IID thresholds as market guarantees.
|
|
||||||
|
|
||||||
## Numerical Implementation Order
|
|
||||||
|
|
||||||
1. Establish a scalar reference with explicit state and semantics.
|
|
||||||
2. Vectorize historical bootstrap with NumPy.
|
|
||||||
3. Keep realtime updates as O(1) recurrences where possible.
|
|
||||||
4. Use Numba for measured numeric kernels with stable dtypes and no Python
|
|
||||||
object traffic.
|
|
||||||
5. Use Polars or Arrow for columnar historical transforms and interchange,
|
|
||||||
not automatically for each tick.
|
|
||||||
6. Partition by independent market/operator state before adding threads or a
|
|
||||||
new distributed runtime.
|
|
||||||
|
|
||||||
## Existing Stack
|
|
||||||
|
|
||||||
- NumPy 2.x: canonical dense and structured-array kernels.
|
|
||||||
- Numba: compiled CPU loops and recurrences that do not vectorize cleanly.
|
|
||||||
- Polars: parallel/lazy columnar history preparation and validation.
|
|
||||||
- PyArrow: columnar interchange, storage, and ingest boundaries.
|
|
||||||
- Tractor/Trio: structured distributed execution and lifecycle.
|
|
||||||
- PyQtGraph: visible-range rendering, not a compute scheduler.
|
|
||||||
|
|
||||||
## Algorithm Acceptance Criteria
|
|
||||||
|
|
||||||
Every new FSP should define:
|
|
||||||
|
|
||||||
- input fields, clock, ordering, duplicate, gap, and revision policy;
|
|
||||||
- output dtype, units, identity, and parameterization;
|
|
||||||
- warm-up length and initialization bias;
|
|
||||||
- causal latency and strategy-visible publication point;
|
|
||||||
- historical/realtime equivalence tolerance;
|
|
||||||
- reset and session-boundary behavior;
|
|
||||||
- complexity, state size, and representative throughput;
|
|
||||||
- replay behavior when historical source data changes.
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
# FSP Test Map
|
|
||||||
|
|
||||||
## Operator Tests
|
|
||||||
|
|
||||||
- Historical output schema, dtype, units, and source timestamp alignment.
|
|
||||||
- Realtime update equivalence with the final row of a batch recomputation.
|
|
||||||
- Warm-up, NaN, zero, gap, duplicate, and out-of-order behavior.
|
|
||||||
- Session reset and elapsed-time behavior.
|
|
||||||
- Parameter and source identity isolation.
|
|
||||||
|
|
||||||
## Engine Tests
|
|
||||||
|
|
||||||
- Equal absolute source/destination bounds.
|
|
||||||
- Normal one-step destination lag.
|
|
||||||
- Destination lead and lag greater than one step.
|
|
||||||
- Source prepend by one, two, and a full provider frame.
|
|
||||||
- In-place gap repair with unchanged source bounds.
|
|
||||||
- Equal lengths with shifted absolute bounds.
|
|
||||||
- Source change during historical recomputation and convergence afterward.
|
|
||||||
- Cancellation while the quote stream, sample stream, or compute generator is
|
|
||||||
blocked.
|
|
||||||
- Foreign FQME and timeframe backfill broadcasts.
|
|
||||||
|
|
||||||
## Graph and Actor Tests
|
|
||||||
|
|
||||||
- Dependency startup before downstream operator lookup.
|
|
||||||
- Actor-local flow registry isolation.
|
|
||||||
- One destination writer and multiple readers.
|
|
||||||
- Consumer cancellation without orphaned cascade or worker tasks.
|
|
||||||
- Worker failure propagation and SHM cleanup.
|
|
||||||
- Feed-like fan-out with a slow or disconnected consumer.
|
|
||||||
|
|
||||||
## UI Tests
|
|
||||||
|
|
||||||
- An `fsp_update` redraws every field visualization sharing its destination
|
|
||||||
token and no unrelated market, OHLC, or FSP visualization.
|
|
||||||
- A prepend outside the visible range does not move or re-range the live view.
|
|
||||||
- A revised value inside the visible range invalidates only required formatter
|
|
||||||
and graphics caches.
|
|
||||||
- Hidden charts defer rendering without stopping compute correctness.
|
|
||||||
|
|
||||||
## Performance Tests
|
|
||||||
|
|
||||||
- Historical bootstrap across realistic SHM capacities.
|
|
||||||
- O(1) realtime recurrence cost under bursty quotes.
|
|
||||||
- Consecutive provider-frame prepends with two or more cascades.
|
|
||||||
- Multi-market sampler broadcasts and targeted wakeups.
|
|
||||||
- Visible-range redraw cost at several units-per-pixel levels.
|
|
||||||
|
|
||||||
Prefer deterministic local arrays and controlled Trio task interleavings.
|
|
||||||
Use live providers only as a separate integration layer because credentials,
|
|
||||||
rate limits, sessions, and changing history make poor regression oracles.
|
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
"allow": [
|
"allow": [
|
||||||
"Bash(chmod:*)",
|
"Bash(chmod:*)",
|
||||||
"Bash(/tmp/piker_commits.txt)",
|
"Bash(/tmp/piker_commits.txt)",
|
||||||
"Bash(python:*)",
|
"Bash(python:*)"
|
||||||
"Bash(ls:*)"
|
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
---
|
||||||
|
name: commit-msg
|
||||||
|
description: >
|
||||||
|
Generate piker-style git commit messages from
|
||||||
|
staged changes or prompt input, following the
|
||||||
|
style guide learned from 500 repo commits.
|
||||||
|
argument-hint: "[optional-scope-or-description]"
|
||||||
|
disable-model-invocation: true
|
||||||
|
allowed-tools: Bash(git *), Read, Grep, Glob, Write
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current staged changes
|
||||||
|
!`git diff --staged --stat`
|
||||||
|
|
||||||
|
## Recent commit style reference
|
||||||
|
!`git log --oneline -10`
|
||||||
|
|
||||||
|
# Piker Git Commit Message Generator
|
||||||
|
|
||||||
|
Generate a commit message from the staged diff above
|
||||||
|
following the piker project's conventions (learned from
|
||||||
|
analyzing 500 repo commits).
|
||||||
|
|
||||||
|
If `$ARGUMENTS` is provided, use it as scope or
|
||||||
|
description context for the commit message.
|
||||||
|
|
||||||
|
For the full style guide with verb frequencies,
|
||||||
|
section markers, abbreviations, piker-specific terms,
|
||||||
|
and examples, see
|
||||||
|
[style-guide-reference.md](./style-guide-reference.md).
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
- **Subject**: ~50 chars, present tense verb, use
|
||||||
|
backticks for code refs
|
||||||
|
- **Body**: only for complex/multi-file changes,
|
||||||
|
67 char line max
|
||||||
|
- **Section markers**: Also, / Deats, / Other,
|
||||||
|
- **Bullets**: use `-` style
|
||||||
|
- **Tone**: technical but casual (piker style)
|
||||||
|
|
||||||
|
## Claude-code Footer
|
||||||
|
|
||||||
|
When the written **patch** was assisted by
|
||||||
|
claude-code, include:
|
||||||
|
|
||||||
|
```
|
||||||
|
(this patch was generated in some part by [`claude-code`][claude-code-gh])
|
||||||
|
[claude-code-gh]: https://github.com/anthropics/claude-code
|
||||||
|
```
|
||||||
|
|
||||||
|
When only the **commit msg** was written by
|
||||||
|
claude-code (human wrote the patch), use:
|
||||||
|
```
|
||||||
|
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
|
||||||
|
[claude-code-gh]: https://github.com/anthropics/claude-code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output Instructions
|
||||||
|
|
||||||
|
When generating a commit message:
|
||||||
|
|
||||||
|
1. Analyze the staged diff (injected above via
|
||||||
|
dynamic context) to understand all changes.
|
||||||
|
2. If `$ARGUMENTS` provides a scope (e.g.,
|
||||||
|
`.ib.feed`) or description, incorporate it into
|
||||||
|
the subject line.
|
||||||
|
3. Write the subject line following verb + backtick
|
||||||
|
conventions from the
|
||||||
|
[style guide](./style-guide-reference.md).
|
||||||
|
4. Add body only for multi-file or complex changes.
|
||||||
|
5. Write the message to a file in the repo's
|
||||||
|
`.claude/` subdir with filename format:
|
||||||
|
`<timestamp>_<first-7-chars-of-last-commit-hash>_commit_msg.md`
|
||||||
|
where `<timestamp>` is from `date --iso-8601=seconds`.
|
||||||
|
Also write a copy to
|
||||||
|
`.claude/git_commit_msg_LATEST.md`
|
||||||
|
(overwrite if exists).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Analysis date:** 2026-01-27
|
||||||
|
**Commits analyzed:** 500 from piker repository
|
||||||
|
**Maintained by:** Tyler Goodlet
|
||||||
|
|
@ -150,18 +150,21 @@ Common in piker commits (33.0% use colons):
|
||||||
- File:line references not used (0 occurrences)
|
- File:line references not used (0 occurrences)
|
||||||
- No WIP commits in analyzed set
|
- No WIP commits in analyzed set
|
||||||
|
|
||||||
### Coding-harness Footer
|
### Claude-code Footer
|
||||||
When a coding harness assisted with the written patch,
|
When the written **patch** was assisted by claude-code,
|
||||||
identify the active harness, model, and provider:
|
include:
|
||||||
|
|
||||||
```
|
```
|
||||||
(this patch was generated in some part by `<harness>` using `<model>` (`<provider>`))
|
(this patch was generated in some part by [`claude-code`][claude-code-gh])
|
||||||
|
[claude-code-gh]: https://github.com/anthropics/claude-code
|
||||||
```
|
```
|
||||||
|
|
||||||
When it generated only the commit message, use:
|
When only the **commit msg** was written by claude-code
|
||||||
|
(human wrote the patch), use:
|
||||||
|
|
||||||
```
|
```
|
||||||
(this commit msg was generated in some part by `<harness>` using `<model>` (`<provider>`))
|
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
|
||||||
|
[claude-code-gh]: https://github.com/anthropics/claude-code
|
||||||
```
|
```
|
||||||
|
|
||||||
## Piker-Specific Terms
|
## Piker-Specific Terms
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../.agents/skills/piker-clearing-expert
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
---
|
|
||||||
name: piker-conc-expert
|
|
||||||
description: >
|
|
||||||
Distributed-runtime and structured-concurrency
|
|
||||||
expertise for piker's `tractor` actor-tree. Apply
|
|
||||||
when working on daemon/service architecture, actor
|
|
||||||
spawning/discovery, cross-actor RPC (ctx/stream
|
|
||||||
eps), `to_asyncio` integration, cancellation
|
|
||||||
semantics, or debugging hangs/wedges/skews in the
|
|
||||||
actor system.
|
|
||||||
compatibility: >
|
|
||||||
Requires a piker checkout and familiarity with Python,
|
|
||||||
trio, and tractor.
|
|
||||||
metadata:
|
|
||||||
author: goodboy
|
|
||||||
version: "1.0"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Piker Concurrency & Runtime Expertise
|
|
||||||
|
|
||||||
The distilled mental model for piker's distributed
|
|
||||||
runtime: a `trio`-structured actor tree supervised by
|
|
||||||
`tractor` (pinned to git main) where every long-lived
|
|
||||||
subsystem is a named daemon-actor talking over
|
|
||||||
ctx/stream IPC.
|
|
||||||
|
|
||||||
## Actor tree & daemon taxonomy
|
|
||||||
|
|
||||||
```
|
|
||||||
pikerd root supervisor + registry
|
|
||||||
├── datad.<broker> feed bus, shm writers, tsp
|
|
||||||
│ history, symbol search
|
|
||||||
├── brokerd.<broker> live order-ctl ONLY; lazily
|
|
||||||
│ spawned by emsd, credentialed
|
|
||||||
├── emsd dark-clearing + order routing
|
|
||||||
│ └── paperboi.<broker> sim-clearing (paper mode)
|
|
||||||
└── samplerd singleton OHLC clock/increment
|
|
||||||
```
|
|
||||||
|
|
||||||
Key invariants:
|
|
||||||
- `datad` hosts all `piker.data.validate._eps['datad']`
|
|
||||||
eps; `brokerd` only the `['brokerd']` (order-ctl)
|
|
||||||
ones. The `_eps` table in `piker/data/validate.py`
|
|
||||||
is the authoritative contract; `get_eps(mod, kind)`
|
|
||||||
introspects a backend's support.
|
|
||||||
- `brokerd.<broker>` is booted in EXACTLY one place:
|
|
||||||
`open_brokerd_dialog()` in `piker/clearing/_ems.py`
|
|
||||||
(with a `portal:` override for the `piker ledger`
|
|
||||||
ad-hoc actor). Chart-only + paper sessions run with
|
|
||||||
ZERO brokerd procs. Never add a data-path spawn!
|
|
||||||
- backends declare per-daemon-kind submods via
|
|
||||||
`_datad_mods`/`_brokerd_mods` in their
|
|
||||||
`__init__.py` (fallback: `__enable_modules__`).
|
|
||||||
|
|
||||||
## Daemon lifecycle conventions
|
|
||||||
|
|
||||||
Every daemon-kind follows the same trio of fns (see
|
|
||||||
`piker/brokers/_daemon.py` + `piker/data/_daemon.py`
|
|
||||||
as the canonical pair):
|
|
||||||
|
|
||||||
- `_setup_persistent_<kind>()`: a `@tractor.context`
|
|
||||||
"lifetime fixture" run via
|
|
||||||
`Services.start_service_task()`; does console-log
|
|
||||||
setup ONCE for the actor, allocs any actor-global
|
|
||||||
state (eg. datad's `_FeedsBus`), then
|
|
||||||
`await ctx.started()` + `trio.sleep_forever()`.
|
|
||||||
- `<kind>_init()`: builds `enable_modules` + actor
|
|
||||||
name `f'<kind>.{brokername}'` and copies backend
|
|
||||||
`_spawn_kwargs` (CRITICAL: `ib` needs
|
|
||||||
`infect_asyncio=True` in EVERY daemon-kind).
|
|
||||||
- `spawn_<kind>()` + `maybe_spawn_<kind>()`: thin
|
|
||||||
wrappers over `Services.actor_n.start_actor()` and
|
|
||||||
`piker.service.maybe_spawn_daemon()` (registry
|
|
||||||
find-or-spawn w/ per-service-name locking).
|
|
||||||
|
|
||||||
Caps-sec model: `enable_modules` gates RPC entry ONLY
|
|
||||||
— python imports are unrestricted in-proc. Keep each
|
|
||||||
daemon's enable set minimal; the (credentialed)
|
|
||||||
`brokerd` must never RPC-enable `piker.data.*` feed
|
|
||||||
mods.
|
|
||||||
|
|
||||||
## Actor-local state: the #1 split hazard
|
|
||||||
|
|
||||||
Module-globals and instance caches are PER-ACTOR.
|
|
||||||
Anything that "just worked" because two subsystems
|
|
||||||
shared a process will break when they're split into
|
|
||||||
sibling actors. Canonical example: `ib`'s
|
|
||||||
`Client._contracts` was warmed by feed-side
|
|
||||||
`get_mkt_info()` in-proc; post datad/brokerd-split
|
|
||||||
the trading actor must warm it itself (eagerly at
|
|
||||||
`open_trade_dialog()` startup for open pps/orders +
|
|
||||||
lazily per order request via
|
|
||||||
`symbols.cache_contract()`).
|
|
||||||
|
|
||||||
When moving code across actor boundaries ALWAYS audit:
|
|
||||||
- module-global registries (`feed._bus`,
|
|
||||||
`_accounts2clients`, `_client_cache`, ..)
|
|
||||||
- `@async_lifo_cache`/`maybe_open_context` caches
|
|
||||||
(NOTE: `async_lifo_cache` keys on POSITIONAL args
|
|
||||||
only; a cache-hit SKIPS the fn body and thus any
|
|
||||||
side-effect writes!)
|
|
||||||
- logging handler placement (see gotchas.md)
|
|
||||||
|
|
||||||
## tractor primitives as used here
|
|
||||||
|
|
||||||
- `@tractor.context` eps: `await ctx.started(val)`
|
|
||||||
unblocks the caller w/ `val`; long-lived eps then
|
|
||||||
`ctx.open_stream()` or `sleep_forever()`.
|
|
||||||
- discovery: `tractor.find_actor()` via
|
|
||||||
`piker.service.find_service()`;
|
|
||||||
`wait_for_actor(name, registry_addr=...)`;
|
|
||||||
`query_actor(name, regaddr=...)` yields
|
|
||||||
`(sockaddr, portal)`. Addrs are wrapped
|
|
||||||
`tractor.discovery._addr.Address` types — use
|
|
||||||
`wrap_address()` to normalize raw tuples and
|
|
||||||
`.unwrap()` for comparisons.
|
|
||||||
- runtime-vars: `_runtime_vars['piker_vars']` is
|
|
||||||
inherited down the spawn tree; used eg. for
|
|
||||||
`piker_test_dir` config isolation — read LAZILY at
|
|
||||||
use-time, never at import time (subactors only get
|
|
||||||
vars post runtime-boot).
|
|
||||||
- cancellation semantics (modern tractor): a
|
|
||||||
`ContextCancelled` whose `.canceller` is your own
|
|
||||||
actor is ABSORBED (clean exit, nothing raised);
|
|
||||||
single-exc groups collapse (`collapse_eg`) so eg.
|
|
||||||
a KBI propagates bare. Exc attrs:
|
|
||||||
`RemoteActorError.boxed_type` (not `.type`).
|
|
||||||
|
|
||||||
## `to_asyncio` (infect-asyncio) integration
|
|
||||||
|
|
||||||
For `ib` (and `deribit`) the backend client runs on
|
|
||||||
an embedded `asyncio` loop via
|
|
||||||
`tractor.to_asyncio.open_channel_from()` +
|
|
||||||
`LinkedTaskChannel`.
|
|
||||||
|
|
||||||
Rules learned the hard way:
|
|
||||||
- a shared req/resp channel MUST correlate responses
|
|
||||||
to requests (see `MethodProxy._run_method()`'s
|
|
||||||
`mid` protocol in `piker/brokers/ib/api.py`):
|
|
||||||
caller cancellation (eg. `move_on_after` timeouts)
|
|
||||||
otherwise orphans a response and silently skews
|
|
||||||
every later result off-by-one.
|
|
||||||
- the aio-side relay must catch + ship back ALL
|
|
||||||
(non-cancel) exceptions as `{'exception': err}`
|
|
||||||
resps; an escaping error kills the relay task ->
|
|
||||||
channel -> proxy nursery -> the whole dialog,
|
|
||||||
bypassing every caller-side guard.
|
|
||||||
- `TrioTaskExited` ("child asyncio task is still
|
|
||||||
running?") on teardown is a known wart family;
|
|
||||||
prefer upstream `tractor` fixes over piker-side
|
|
||||||
bandaids.
|
|
||||||
|
|
||||||
See [gotchas.md](gotchas.md) for the symptom->cause
|
|
||||||
registry and [debug-recipes.md](debug-recipes.md) for
|
|
||||||
forensics techniques.
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
# Debug recipes: actor-system forensics
|
|
||||||
|
|
||||||
Field-tested techniques for diagnosing hangs, wedges
|
|
||||||
and cross-actor state bugs WITHOUT a debugger attached
|
|
||||||
(or when `py-spy` ain't installed).
|
|
||||||
|
|
||||||
## Wedged actor triage (no REPL)
|
|
||||||
|
|
||||||
1. find the tree:
|
|
||||||
`ps -eo pid,etime,args | grep -E 'pytest|tractor._child'`
|
|
||||||
— long-`etime` `tractor._child` procs w/ a stuck
|
|
||||||
parent = wedge.
|
|
||||||
2. kernel state:
|
|
||||||
`cat /proc/<pid>/wchan` + `status | grep -E
|
|
||||||
'State|Threads'` — `do_epoll_wait` + sleeping =
|
|
||||||
idle event loop, NOT cpu-spin.
|
|
||||||
3. **the money read** — socket queues:
|
|
||||||
`ss -tnp | grep <pid>`
|
|
||||||
- `Recv-Q > 0` on the parent-IPC conn = the actor
|
|
||||||
STOPPED CONSUMING its msg loop (runtime bug),
|
|
||||||
parent is waiting on it.
|
|
||||||
- zero external (api/ws) conns = wedged before/
|
|
||||||
without provider IO; don't blame the network.
|
|
||||||
- `CLOSE-WAIT` lingerers = unclean peer teardown.
|
|
||||||
4. cleanup: `pkill -f tractor._child` (NB: in
|
|
||||||
compound shell cmds `pkill`'s exit code poisons
|
|
||||||
`&&` chains — run it standalone).
|
|
||||||
|
|
||||||
## Hang-proof test gating
|
|
||||||
|
|
||||||
- per-suite, never combined (cross-suite session
|
|
||||||
state interacts w/ the 2nd-boot wedge):
|
|
||||||
`timeout -k 5 300 python -m pytest tests/<one>.py -q`
|
|
||||||
- rc 124/143 = hang-kill -> retry ONCE before
|
|
||||||
investigating.
|
|
||||||
- isolate a flaky test w/ a 3x loop; ~50% hit-rate
|
|
||||||
signatures match the known 2nd-boot wedge (see
|
|
||||||
gotchas.md).
|
|
||||||
|
|
||||||
## Regression vs pre-existing attribution
|
|
||||||
|
|
||||||
When a failure appears mid-refactor:
|
|
||||||
1. `git stash -u` (or checkout the file subset) and
|
|
||||||
re-run the EXACT failing case at baseline.
|
|
||||||
2. if baseline can't even run, selectively revert
|
|
||||||
ONLY the suspect layer:
|
|
||||||
`git diff <files> > /tmp/x.patch;
|
|
||||||
git checkout <files>` -> test ->
|
|
||||||
`git apply /tmp/x.patch`.
|
|
||||||
3. flake-rate compare (3x runs) beats single-shot
|
|
||||||
conclusions.
|
|
||||||
|
|
||||||
## Off-by-one / stale IPC resp detection
|
|
||||||
|
|
||||||
Mismatched query->result content in logs (resp
|
|
||||||
payload obviously for a prior request) = shared
|
|
||||||
req/resp channel w/o correlation + a cancelled
|
|
||||||
caller. Grep the ep for `move_on_after`/`fail_after`
|
|
||||||
around proxied calls. Fix = req-id (`mid`) tagging,
|
|
||||||
never "just a lock" (cancellation still orphans).
|
|
||||||
|
|
||||||
## Logging-chain audits
|
|
||||||
|
|
||||||
When records double-print or go bare (see gotchas.md):
|
|
||||||
|
|
||||||
```python
|
|
||||||
import logging
|
|
||||||
l = logging.getLogger('piker.brokers.ib.broker')
|
|
||||||
while l:
|
|
||||||
print(l.name, l.level, l.handlers, l.propagate)
|
|
||||||
l = l.parent
|
|
||||||
```
|
|
||||||
|
|
||||||
Exactly ONE stderr handler should exist in the chain,
|
|
||||||
attached by the actor's daemon fixture.
|
|
||||||
|
|
||||||
## Live actor-tree smoke (headless)
|
|
||||||
|
|
||||||
Boot against an ALT registry port so a user's running
|
|
||||||
stack is untouched; script in a REAL file (tractor
|
|
||||||
children re-exec `__main__` from path — stdin scripts
|
|
||||||
crash w/ `FileNotFoundError: .../<stdin>`):
|
|
||||||
|
|
||||||
```python
|
|
||||||
async with maybe_open_pikerd(
|
|
||||||
registry_addrs=[('127.0.0.1', 6979)],
|
|
||||||
):
|
|
||||||
async with open_feed(['xbtusdt.kraken']) as feed:
|
|
||||||
assert await check_for_service('datad.kraken')
|
|
||||||
assert not await check_for_service(
|
|
||||||
'brokerd.kraken'
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## In-proc fail-fast unit checks
|
|
||||||
|
|
||||||
Spawn-path guards that raise BEFORE touching the
|
|
||||||
runtime can be tested w/ a bare `trio.run()` (eg
|
|
||||||
`spawn_brokerd('kucoin')` raising the datad-only
|
|
||||||
error) — no pikerd needed.
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
# Known gotchas: symptom -> cause -> fix
|
|
||||||
|
|
||||||
A registry of distributed-runtime failure modes hit
|
|
||||||
(and diagnosed) in the field; check here FIRST when a
|
|
||||||
log/traceback matches.
|
|
||||||
|
|
||||||
## "Can not order ..., no qualified contract cached"
|
|
||||||
|
|
||||||
- **Symptom**: `RuntimeError` from
|
|
||||||
`ib.api.Client.submit_limit()` w/ empty
|
|
||||||
`Client._contracts` in `brokerd.ib`.
|
|
||||||
- **Cause**: per-actor cache never warmed; feed-side
|
|
||||||
qualification now lives in `datad.ib`.
|
|
||||||
- **Fix(ed)**: eager warmup at `open_trade_dialog()`
|
|
||||||
start + lazy per-order `get_mkt_info()` +
|
|
||||||
`cache_contract()` (writes BOTH `mkt.bs_fqme` and
|
|
||||||
`mkt.fqme` keys; different consumers read each!).
|
|
||||||
|
|
||||||
## Search returns results for the WRONG pattern
|
|
||||||
|
|
||||||
- **Symptom**: fqme search for 'gld' returns nvda
|
|
||||||
results; next query returns the prior query's set.
|
|
||||||
- **Cause**: `MethodProxy` channel off-by-one — a
|
|
||||||
caller cancelled (search `move_on_after` timeout)
|
|
||||||
after sending its request orphans the response;
|
|
||||||
every later caller consumes the previous resp.
|
|
||||||
- **Fix(ed)**: `mid` req-id correlation in
|
|
||||||
`_run_method()` + relay; stale resps are dropped w/
|
|
||||||
a "Dropping stale method-resp" warning. If that
|
|
||||||
warning spams, some caller is being cancelled
|
|
||||||
mid-call habitually — find + fix its timeout.
|
|
||||||
|
|
||||||
## One bad request crashes a whole dialog/actor
|
|
||||||
|
|
||||||
- **Symptom**: `TrioTaskExited` storm + nursery
|
|
||||||
teardown after a single method error (eg ambiguous
|
|
||||||
contract `AttributeError`).
|
|
||||||
- **Cause**: exception escaped the aio-side relay
|
|
||||||
loop (`open_aio_client_method_relay()`) killing
|
|
||||||
channel + proxy nursery; caller-side `try/except`
|
|
||||||
CANNOT catch it.
|
|
||||||
- **Fix(ed)**: relay catches `Exception` -> ships
|
|
||||||
`{'exception': err, 'mid': ...}` resp; order
|
|
||||||
handler converts to EMS `BrokerdError` msgs.
|
|
||||||
|
|
||||||
## Ambiguous ib contracts -> `NoneType` attr errors
|
|
||||||
|
|
||||||
- **Symptom**: `'NoneType' object has no attribute
|
|
||||||
'primaryExchange'` in `find_contracts()`.
|
|
||||||
- **Cause**: `qualifyContractsAsync()` returns `None`
|
|
||||||
entries for ambiguous (eg venue-less stonk fqme
|
|
||||||
matching multiple listings: 'gld' -> ARCA/USD +
|
|
||||||
VENTURE/CAD).
|
|
||||||
- **Fix(ed)**: filter `None`s + raise descriptive
|
|
||||||
`ValueError` ("use 'gld.arca.ib'").
|
|
||||||
|
|
||||||
## Double-printed log records (same task id, 2x)
|
|
||||||
|
|
||||||
- **Symptom**: every record from some subsys printed
|
|
||||||
twice w/ identical task ids.
|
|
||||||
- **Cause**: stderr handlers attached at TWO levels
|
|
||||||
of one logger-propagation chain (eg daemon fixture
|
|
||||||
on `piker.brokers.ib` + an ep calling
|
|
||||||
`get_console_log(name=__name__)` on the child).
|
|
||||||
tractor's handler-dedup only checks the SAME
|
|
||||||
logger, not ancestors.
|
|
||||||
- **Rule**: console handlers are attached ONCE per
|
|
||||||
actor in the `_setup_persistent_*()` fixture; eps
|
|
||||||
needing a different level use `log.setLevel()`
|
|
||||||
ONLY, never `get_console_log()`.
|
|
||||||
|
|
||||||
## Bare/non-colorized log lines
|
|
||||||
|
|
||||||
- **Symptom**: records w/ no timestamp/actor prefix.
|
|
||||||
- **Cause**: NO handler anywhere in the emitting
|
|
||||||
logger's chain -> stdlib `logging.lastResort`. Post
|
|
||||||
actor-splits, a daemon fixture may only cover its
|
|
||||||
own subsys subtree (eg datad's `piker.data.*` but
|
|
||||||
not the backend's `piker.brokers.<broker>.*`).
|
|
||||||
- **Fix(ed)**: `_setup_persistent_datad()` enables
|
|
||||||
BOTH `piker.data.<broker>` and
|
|
||||||
`piker.brokers.<broker>` subtrees.
|
|
||||||
|
|
||||||
## 2nd in-proc runtime boot wedges (~50%)
|
|
||||||
|
|
||||||
- **Symptom**: test hangs when one test proc boots a
|
|
||||||
2nd `pikerd` (eg `test_multi_fill_positions`'s
|
|
||||||
persistence re-check); a zombie `*.{broker}` child
|
|
||||||
lingers w/ unread bytes in its parent-IPC Recv-Q.
|
|
||||||
- **Cause**: pre-existing `tractor`-main runtime
|
|
||||||
teardown bug (confirmed independent of piker-layer
|
|
||||||
changes via revert-testing 2026-06).
|
|
||||||
- **Mitigation**: run suites per-file wrapped in
|
|
||||||
`timeout -k 5 300 ...`; retry once on rc 124/143.
|
|
||||||
Do NOT chase as a regression of unrelated changes.
|
|
||||||
|
|
||||||
## ib client-id collisions post-split
|
|
||||||
|
|
||||||
- **Symptom**: 2nd ib daemon burns the full
|
|
||||||
conn-timeout retry cycle connecting to gw/tws.
|
|
||||||
- **Cause**: `datad.ib` + `brokerd.ib` both default
|
|
||||||
`client_id=6116` w/ linear `+i` retries.
|
|
||||||
- **Fix(ed)**: role-based offsets in
|
|
||||||
`load_aio_clients()`: datad +16, ad-hoc (test/cli)
|
|
||||||
actors +32.
|
|
||||||
|
|
||||||
## `async_lifo_cache` skipped side-effects
|
|
||||||
|
|
||||||
- **Symptom**: a fn's cache-write side effect
|
|
||||||
(eg `get_mkt_info()` -> `_contracts`) missing for
|
|
||||||
a 2nd client/proxy.
|
|
||||||
- **Cause**: cache keys on POSITIONAL args only; a
|
|
||||||
hit skips the body entirely.
|
|
||||||
- **Rule**: never rely on cached-fn side effects;
|
|
||||||
perform required writes explicitly at the call
|
|
||||||
site (eg `cache_contract()` after `get_mkt_info`).
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../.agents/skills/piker-fsp-expert
|
|
||||||
|
|
@ -5,11 +5,7 @@ description: >
|
||||||
across distributed actor systems. Apply when
|
across distributed actor systems. Apply when
|
||||||
adding profiling, debugging perf regressions, or
|
adding profiling, debugging perf regressions, or
|
||||||
optimizing hot paths in piker code.
|
optimizing hot paths in piker code.
|
||||||
compatibility: >
|
user-invocable: false
|
||||||
Requires a piker checkout and Python profiling work.
|
|
||||||
metadata:
|
|
||||||
author: goodboy
|
|
||||||
version: "1.0"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Piker Profiling Subsystem
|
# Piker Profiling Subsystem
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,7 @@ description: >
|
||||||
ethos. Apply when communicating with piker devs,
|
ethos. Apply when communicating with piker devs,
|
||||||
writing commit messages, code review comments, or
|
writing commit messages, code review comments, or
|
||||||
any collaborative interaction.
|
any collaborative interaction.
|
||||||
compatibility: >
|
user-invocable: false
|
||||||
Harness-independent communication guidance.
|
|
||||||
metadata:
|
|
||||||
author: goodboy
|
|
||||||
version: "1.0"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Piker Slang & Communication Style
|
# Piker Slang & Communication Style
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ that's why it's like 1000x faster ya know?"
|
||||||
- Wrap all code symbols: `function()`,
|
- Wrap all code symbols: `function()`,
|
||||||
`ClassName`, `field_name`
|
`ClassName`, `field_name`
|
||||||
- File paths: `piker/ui/_remote_ctl.py`
|
- File paths: `piker/ui/_remote_ctl.py`
|
||||||
- Commands: `git status`, `piker store shm`
|
- Commands: `git status`, `piker store ldshm`
|
||||||
|
|
||||||
**Explain like you're pair programming:**
|
**Explain like you're pair programming:**
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,7 @@ description: >
|
||||||
for piker's UI. Apply when optimizing graphics
|
for piker's UI. Apply when optimizing graphics
|
||||||
performance, adding new chart annotations, or
|
performance, adding new chart annotations, or
|
||||||
working with `QGraphicsItem` subclasses.
|
working with `QGraphicsItem` subclasses.
|
||||||
compatibility: >
|
user-invocable: false
|
||||||
Requires a piker checkout with PyQtGraph and Qt source
|
|
||||||
available for inspection.
|
|
||||||
metadata:
|
|
||||||
author: goodboy
|
|
||||||
version: "1.0"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# PyQtGraph Rendering Optimization
|
# PyQtGraph Rendering Optimization
|
||||||
|
|
|
||||||
|
|
@ -1,291 +0,0 @@
|
||||||
# Test Harness Reference: piker
|
|
||||||
|
|
||||||
This repository-local file supplements the canonical `/run-tests` skill.
|
|
||||||
Keep shared execution, worktree, failure-inspection, and cleanup policy in the
|
|
||||||
canonical `SKILL.md`; keep Piker commands, paths, fixtures, and known outcomes
|
|
||||||
here.
|
|
||||||
|
|
||||||
## Project And Environment
|
|
||||||
|
|
||||||
- Project/import: `piker`
|
|
||||||
- Test root: `tests/`
|
|
||||||
- Supported Python: `>=3.12,<3.14`
|
|
||||||
- Preferred complete environment: worktree-local `py313` inside the current
|
|
||||||
`nix develop` shell
|
|
||||||
- The flake shell pins CPython 3.13 and sets
|
|
||||||
`UV_PROJECT_ENVIRONMENT=py313`.
|
|
||||||
- Verify the interpreter, package resolution, and dependency import before
|
|
||||||
running tests. A bare `py313` may lack the Qt binding supplied by Nix.
|
|
||||||
|
|
||||||
Use an already-provisioned `py313` only when `import piker` succeeds:
|
|
||||||
|
|
||||||
```text
|
|
||||||
py313/bin/python -m pytest -p no:xonsh
|
|
||||||
```
|
|
||||||
|
|
||||||
If direct environment paths are unavailable, an existing uv environment can
|
|
||||||
be used without changing it, subject to the same import check:
|
|
||||||
|
|
||||||
```text
|
|
||||||
UV_PROJECT_ENVIRONMENT=py313 uv run --frozen --no-sync python -m pytest -p no:xonsh
|
|
||||||
```
|
|
||||||
|
|
||||||
Ask before running provisioning commands such as:
|
|
||||||
|
|
||||||
```text
|
|
||||||
UV_PROJECT_ENVIRONMENT=py313 uv sync --dev --all-extras --no-group lint
|
|
||||||
nix develop
|
|
||||||
nix-shell default.nix
|
|
||||||
```
|
|
||||||
|
|
||||||
`nix develop` is the current Wayland/Qt 6 shell. `default.nix` is the current
|
|
||||||
X11 shell. Do not use `develop.nix` for current testing; it retains the old
|
|
||||||
Python 3.11, Poetry, and Qt 5 stack.
|
|
||||||
|
|
||||||
The current root-checkout `py313` resolves `piker` locally but fails
|
|
||||||
`import piker` outside Nix because PyQtGraph cannot import PyQt or PySide. Do
|
|
||||||
not treat that environment as test-ready and do not enter `nix develop`
|
|
||||||
without approval: its shell hook may recreate and sync `py313`.
|
|
||||||
|
|
||||||
Plain `uv sync` does not include the testing group. The `dbs` dependency group
|
|
||||||
is also absent from normal dev-shell provisioning.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
Base command in the preferred environment:
|
|
||||||
|
|
||||||
```text
|
|
||||||
py313/bin/python -m pytest -p no:xonsh
|
|
||||||
```
|
|
||||||
|
|
||||||
The explicit `-p no:xonsh` is required. The tracked comments-only
|
|
||||||
`pytest.ini` takes precedence over `pyproject.toml`, so the intended
|
|
||||||
`addopts = "-p no:xonsh"` and `testpaths = ["tests"]` are inactive.
|
|
||||||
Always pass a test path or node ID explicitly.
|
|
||||||
|
|
||||||
Package-resolution check that does not import Piker's dependencies:
|
|
||||||
|
|
||||||
```text
|
|
||||||
py313/bin/python -c 'import importlib.util, pathlib, sys; root = pathlib.Path.cwd().resolve(); spec = importlib.util.find_spec("piker"); mod = pathlib.Path(spec.origin).resolve(); print(sys.executable); print(mod); assert mod.is_relative_to(root)'
|
|
||||||
```
|
|
||||||
|
|
||||||
Dependency import check, required before collection or execution:
|
|
||||||
|
|
||||||
```text
|
|
||||||
py313/bin/python -c 'import pathlib, piker, sys; root = pathlib.Path.cwd().resolve(); mod = pathlib.Path(piker.__file__).resolve(); print(sys.executable); print(mod); assert mod.is_relative_to(root)'
|
|
||||||
```
|
|
||||||
|
|
||||||
Safe core collection check:
|
|
||||||
|
|
||||||
```text
|
|
||||||
py313/bin/python -m pytest -p no:xonsh -q --collect-only tests/test_watchlists.py tests/test_accounting.py tests/test_services.py tests/test_ems.py tests/test_feeds.py tests/test_cli.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Default first-pass flags are `-q -x --tb=short --no-header` unless the user
|
|
||||||
requests otherwise. For actor-heavy tests, use one file or node per process
|
|
||||||
with an outer timeout:
|
|
||||||
|
|
||||||
```text
|
|
||||||
timeout -k 5 300 py313/bin/python -m pytest -p no:xonsh -q <one-file-or-node>
|
|
||||||
```
|
|
||||||
|
|
||||||
If an actor-heavy command exits `124` or `143`, retry that exact command once
|
|
||||||
and report both attempts. Never convert a retry pass into an unconditional
|
|
||||||
pass, and do not retry assertion, import, collection, or configuration
|
|
||||||
failures.
|
|
||||||
|
|
||||||
## Scope And Path Resolution
|
|
||||||
|
|
||||||
Resolve bare test filenames beneath `tests/`. Preserve complete node IDs and
|
|
||||||
apply `-k` only within explicitly selected paths. There is no marker-based
|
|
||||||
offline/full-suite split, so never use `pytest tests` as a deterministic
|
|
||||||
default.
|
|
||||||
|
|
||||||
Deterministic or local first-pass targets:
|
|
||||||
|
|
||||||
- `tests/test_watchlists.py`
|
|
||||||
- `tests/test_storage_audit.py`
|
|
||||||
- `tests/test_store_cli.py`
|
|
||||||
- `tests/test_backfill_audit_snippet.py`
|
|
||||||
- `tests/test_ib_history.py`
|
|
||||||
- `tests/test_ib_method_proxy.py`
|
|
||||||
- `tests/test_history_backfill.py`
|
|
||||||
- `tests/test_ldshm.py`
|
|
||||||
- `tests/test_accounting.py::test_account_file_default_empty`
|
|
||||||
- `tests/test_services.py::test_runtime_boot`
|
|
||||||
- `tests/test_services.py::test_datad_spawn`
|
|
||||||
- `tests/test_ems.py::test_ems_err_on_bad_broker`
|
|
||||||
|
|
||||||
Require explicit authorization before running:
|
|
||||||
|
|
||||||
- `tests/test_feeds.py` - live Binance/Kraken feeds;
|
|
||||||
- `tests/test_services.py::test_ensure_datafeed_actors` - live Kraken feed;
|
|
||||||
- `tests/test_services.py::test_ensure_ems_in_paper_actors` - paper EMS with
|
|
||||||
live Kraken symbology/feed access;
|
|
||||||
- `tests/test_ems.py::test_multi_fill_positions` - live backend setup and
|
|
||||||
persisted state;
|
|
||||||
- `tests/test_accounting.py::test_paper_ledger_position_calcs` - tracked
|
|
||||||
fixtures plus possible live symcache generation;
|
|
||||||
- `tests/test_accounting.py::test_ib_account_with_duplicated_mktids` - active
|
|
||||||
broker/account configuration and state writes;
|
|
||||||
- `tests/test_dpi_font.py` - Qt/UI import and user-config side effects;
|
|
||||||
- `tests/test_docker_services.py` - optional dependencies and containers;
|
|
||||||
- `tests/test_questrade.py` - obsolete credentialed imports.
|
|
||||||
|
|
||||||
`tests/test_cli.py` is currently hard-skipped. It is not an active CLI
|
|
||||||
regression gate.
|
|
||||||
|
|
||||||
Never execute `piker store anal` or `piker store shm --write-parquet`
|
|
||||||
as tests. They are mutating or interactive operational commands.
|
|
||||||
|
|
||||||
## Project-Specific Flags And Backend Matrix
|
|
||||||
|
|
||||||
| Flag | Purpose |
|
|
||||||
|---|---|
|
|
||||||
| `--ll LEVEL` | Piker log level |
|
|
||||||
| `--confdir PATH` | Override `piker.config._config_dir` |
|
|
||||||
| `--spawn-backend trio|mp_spawn|mp_forkserver` | Tractor process backend |
|
|
||||||
| `--tpt-proto PROTO` | Tractor transport; one protocol per session |
|
|
||||||
| `--tpdb` / `--debug-mode` | Tractor plugin debug mode |
|
|
||||||
| `--pdb` | Standard pytest debugger |
|
|
||||||
| `-s` | No capture; required with `--pdb` and `open_test_pikerd` |
|
|
||||||
|
|
||||||
Do not invent `network`, `offline`, `docker`, `gui`, or `broker` markers; none
|
|
||||||
currently exists. `CI=1` is not an offline selector: feed tests still leave a
|
|
||||||
live Kraken case enabled. Current Piker tests exercise TCP; do not assume the
|
|
||||||
whole suite supports UDS merely because the Tractor plugin exposes it.
|
|
||||||
|
|
||||||
## Fixture Invariants
|
|
||||||
|
|
||||||
- The session `confdir` fixture does nothing unless `--confdir` is passed.
|
|
||||||
Its claimed `tests/data` fallback is not implemented and that directory is
|
|
||||||
absent.
|
|
||||||
- Function-scoped `tmpconfdir` changes process-global config state and does
|
|
||||||
not restore the previous path. Use separate pytest processes when
|
|
||||||
diagnosing state leakage.
|
|
||||||
- `open_test_pikerd` passes the temporary config path to child actors through
|
|
||||||
`tractor_runtime_overrides`.
|
|
||||||
- `tests/_inputs/trades_binance_paper.toml` and
|
|
||||||
`tests/_inputs/account.binance.paper.toml` are used in place. Accounting
|
|
||||||
contexts can write them on exit. Inspect `git diff -- tests/_inputs` after
|
|
||||||
any selected accounting case.
|
|
||||||
- Importing `tests/test_dpi_font.py` constructs module-global font objects
|
|
||||||
before fixtures can isolate config. If explicitly requested, isolate
|
|
||||||
`XDG_CONFIG_HOME` before Python starts and use the proper Qt/Nix shell.
|
|
||||||
- Piker and the installed Tractor pytest plugin do not provide a
|
|
||||||
repository-local process or socket reaper. Never apply historical broad
|
|
||||||
`pkill -f tractor._child` guidance automatically.
|
|
||||||
- The function-scoped autouse `shm_leak_tracker` fixture wraps Tractor's
|
|
||||||
current-process `SharedMemory` factory. It tracks only successful
|
|
||||||
`create=True` calls, restores the pre-test `_known_tokens` cache, and
|
|
||||||
unlinks exact surviving names before failing the leaking test. It never
|
|
||||||
scans `/dev/shm` or unlinks attachments created by another process.
|
|
||||||
|
|
||||||
## Test Layout
|
|
||||||
|
|
||||||
```text
|
|
||||||
tests/
|
|
||||||
conftest.py Piker options, config fixtures, Tractor plugin
|
|
||||||
_inputs/ tracked ledger/account fixtures
|
|
||||||
test_accounting.py config, ledgers, accounts, and position math
|
|
||||||
test_cli.py legacy CLI suite; hard-skipped
|
|
||||||
test_docker_services.py container integrations; optional deps, skipped
|
|
||||||
test_dpi_font.py Qt DPI/font behavior
|
|
||||||
test_ems.py actor, EMS, and paper-position behavior
|
|
||||||
test_feeds.py live Binance/Kraken feeds and shared memory
|
|
||||||
test_ib_history.py deterministic IB history request formatting
|
|
||||||
test_ib_method_proxy.py deterministic IB asyncio proxy routing
|
|
||||||
test_history_backfill.py deterministic history/SHM orchestration
|
|
||||||
test_ldshm.py SHM unpublished-slot guard
|
|
||||||
test_questrade.py obsolete credentialed tests; skipped
|
|
||||||
test_services.py pikerd/datad/feed/EMS actor lifecycle
|
|
||||||
test_store_cli.py storage command help and diagnostics UX
|
|
||||||
test_storage_audit.py read-only NativeDB audit and JSON CLI
|
|
||||||
test_backfill_audit_snippet.py
|
|
||||||
disposable xonsh qualification helpers
|
|
||||||
test_watchlists.py deterministic watchlist JSON operations
|
|
||||||
```
|
|
||||||
|
|
||||||
## Change-To-Test Mapping
|
|
||||||
|
|
||||||
| Changed area | Run first | Caveat |
|
|
||||||
|---|---|---|
|
|
||||||
| `piker/watchlists/` | `tests/test_watchlists.py` | CLI suite is skipped |
|
|
||||||
| `piker/storage/_audit.py`, `piker/storage/cli.py` | `tests/test_storage_audit.py` | direct Typer app, no actor |
|
|
||||||
| `piker/storage/cli.py` command UX | `tests/test_store_cli.py` | fake SHM/runtime, no mutation |
|
|
||||||
| `snippets/nativedb_backfill_audit.xsh` | `tests/test_backfill_audit_snippet.py` | disposable paths only |
|
|
||||||
| `piker/brokers/ib/api.py`, `feed.py` history | `tests/test_ib_history.py` | fake client, no network |
|
|
||||||
| `piker/brokers/ib/api.py` method proxy | `tests/test_ib_method_proxy.py` | fake channel, no network |
|
|
||||||
| `piker/tsp/_history.py` | `tests/test_history_backfill.py` | fake provider/storage/SHM |
|
|
||||||
| `piker/storage/cli.py` SHM null-slot guard | `tests/test_ldshm.py` | synthetic timestamps, no SHM mutation |
|
|
||||||
| `piker/config.py` | `test_account_file_default_empty` | root-network test has a known mismatch |
|
|
||||||
| `piker/accounting/` | targeted accounting node | some cases use live/configured state |
|
|
||||||
| `piker/ui/_style.py`, `piker/ui/qt.py` | `tests/test_dpi_font.py` | GUI/config-isolated opt-in |
|
|
||||||
| `piker/service/_actor_runtime.py`, `_registry.py`, `_mngr.py` | `test_runtime_boot` | then `test_datad_spawn` |
|
|
||||||
| `piker/service/`, `piker/data/_daemon.py` | `test_datad_spawn` | feed lifecycle cases are live |
|
|
||||||
| `piker/data/feed.py`, `flows.py`, `_sharedmem.py`, `_sampling.py` | collect first | feed execution needs live permission |
|
|
||||||
| `piker/clearing/` | `test_ems_err_on_bad_broker` | multi-fill case is live/persisted |
|
|
||||||
| `piker/brokers/binance/`, `kraken/` | selected feed/accounting node | live network |
|
|
||||||
| `piker/brokers/ib/` | duplicated-market-ID node | controlled account config required |
|
|
||||||
| Docker/service adapters | `tests/test_docker_services.py` | optional deps and containers |
|
|
||||||
| project, lock, or Nix files | import check and safe collection | full collection is not safe by default |
|
|
||||||
|
|
||||||
Prefer deterministic filesystem/config tests, then local actor-runtime nodes,
|
|
||||||
then explicitly approved live broker, GUI, or container coverage.
|
|
||||||
|
|
||||||
## Quick Checks
|
|
||||||
|
|
||||||
```text
|
|
||||||
py313/bin/python -c 'import importlib.util, pathlib, sys; root = pathlib.Path.cwd().resolve(); spec = importlib.util.find_spec("piker"); mod = pathlib.Path(spec.origin).resolve(); print(sys.executable); print(mod); assert mod.is_relative_to(root)'
|
|
||||||
py313/bin/python -c 'import pathlib, piker, sys; root = pathlib.Path.cwd().resolve(); mod = pathlib.Path(piker.__file__).resolve(); print(sys.executable); print(mod); assert mod.is_relative_to(root)'
|
|
||||||
py313/bin/python -m pytest -p no:xonsh -q tests/test_watchlists.py
|
|
||||||
py313/bin/python -m pytest -p no:xonsh -q tests/test_accounting.py::test_account_file_default_empty
|
|
||||||
timeout -k 5 300 py313/bin/python -m pytest -p no:xonsh -q tests/test_services.py::test_runtime_boot
|
|
||||||
timeout -k 5 300 py313/bin/python -m pytest -p no:xonsh -q tests/test_services.py::test_datad_spawn
|
|
||||||
timeout -k 5 300 py313/bin/python -m pytest -p no:xonsh -q tests/test_ems.py::test_ems_err_on_bad_broker
|
|
||||||
```
|
|
||||||
|
|
||||||
## Known Outcomes
|
|
||||||
|
|
||||||
- The current root-checkout `py313` fails `import piker` outside the Nix shell
|
|
||||||
with `ImportError: PyQtGraph requires one of PyQt5, PyQt6, PySide2 or
|
|
||||||
PySide6`. This is an incomplete environment, not an application regression.
|
|
||||||
- `tests/test_accounting.py::test_root_conf_networking_section` currently
|
|
||||||
expects `network.tsdb`, which is absent from the tracked config template.
|
|
||||||
Match the current `KeyError: 'tsdb'` before classifying it as the known
|
|
||||||
repository mismatch.
|
|
||||||
- `tests/test_docker_services.py` is marked skipped but imports
|
|
||||||
`elasticsearch` first. Without the `dbs` group it fails collection rather
|
|
||||||
than skipping.
|
|
||||||
- `tests/test_questrade.py` is marked skipped but imports undeclared `asks`
|
|
||||||
through the legacy broker module before marks apply.
|
|
||||||
- `test_open_orders_reloaded` and `test_dark_order_clearing` in
|
|
||||||
`tests/test_ems.py` contain only ellipsis bodies. A pass does not verify the
|
|
||||||
named behavior.
|
|
||||||
- Treat `.pytest_cache` feed IDs using old FQME forms as stale historical
|
|
||||||
cache, not current known failures.
|
|
||||||
|
|
||||||
Do not classify every `TooSlowError`, timeout, or child survivor as the known
|
|
||||||
Tractor teardown wedge. Match the selected node and the documented
|
|
||||||
second-runtime/lingering-child signature.
|
|
||||||
|
|
||||||
## Tractor Runtime Notes
|
|
||||||
|
|
||||||
The suite loads `tractor._testing.pytest`. Defaults are the `trio` spawn
|
|
||||||
backend and TCP transport. Registry addresses are normally session-unique,
|
|
||||||
except `tests/test_services.py::test_runtime_boot`, which binds
|
|
||||||
`127.0.0.1:6666`. Check that fixed port only for that node; ordinary tests do
|
|
||||||
not require Piker's production `127.0.0.1:6116` registry address.
|
|
||||||
|
|
||||||
Current repository concurrency notes document an intermittent second
|
|
||||||
in-process `pikerd` boot wedge with a lingering broker child and unread parent
|
|
||||||
IPC bytes. Use the outer timeout for actor-heavy nodes. Retry an exact command
|
|
||||||
once only after status `124` or `143`, and report both attempts.
|
|
||||||
|
|
||||||
Ordinary actor tests support normal capture. Diagnose a capture-dependent hang
|
|
||||||
by retrying only the exact node with `-s`. Standard `--pdb` with
|
|
||||||
`open_test_pikerd` requires `-s`; Tractor's `--tpdb` is a separate option.
|
|
||||||
|
|
||||||
After abnormal exit, inspect only descendants, sockets, and shared-memory
|
|
||||||
objects attributable to the exact pytest session. Ask before signaling or
|
|
||||||
unlinking anything.
|
|
||||||
|
|
@ -6,12 +6,7 @@ description: >
|
||||||
with OHLCV arrays, timestamp lookups, gap
|
with OHLCV arrays, timestamp lookups, gap
|
||||||
detection, or any array/dataframe operations in
|
detection, or any array/dataframe operations in
|
||||||
piker.
|
piker.
|
||||||
compatibility: >
|
user-invocable: false
|
||||||
Requires a piker checkout with NumPy and optionally
|
|
||||||
Polars.
|
|
||||||
metadata:
|
|
||||||
author: goodboy
|
|
||||||
version: "1.0"
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Timeseries Optimization: NumPy & Polars
|
# Timeseries Optimization: NumPy & Polars
|
||||||
|
|
@ -66,14 +61,11 @@ ts_array = np.array(timestamps)
|
||||||
# binary search for all timestamps at once
|
# binary search for all timestamps at once
|
||||||
indices = np.searchsorted(time_arr, ts_array)
|
indices = np.searchsorted(time_arr, ts_array)
|
||||||
|
|
||||||
# bounds check before indexing: searchsorted may return
|
# bounds check and exact match verification
|
||||||
# len(time_arr) for values above the final timestamp
|
valid_mask = (
|
||||||
in_bounds = indices < len(time_arr)
|
(indices < len(array))
|
||||||
valid_mask = np.zeros(indices.shape, dtype=bool)
|
&
|
||||||
valid_mask[in_bounds] = (
|
(time_arr[indices] == ts_array)
|
||||||
time_arr[indices[in_bounds]]
|
|
||||||
==
|
|
||||||
ts_array[in_bounds]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
valid_indices = indices[valid_mask]
|
valid_indices = indices[valid_mask]
|
||||||
|
|
|
||||||
|
|
@ -110,12 +110,6 @@ ENV/
|
||||||
.claude/*_commit_*.md
|
.claude/*_commit_*.md
|
||||||
.claude/*_commit*.toml
|
.claude/*_commit*.toml
|
||||||
|
|
||||||
# ai.skillz/commit-msg
|
|
||||||
.claude/skills/commit-msg/msgs/
|
|
||||||
.claude/skills/commit-msg/conf.toml
|
|
||||||
.claude/git_commit_msg_LATEST.md
|
|
||||||
.opencode/skills/commit-msg/SKILL.md
|
|
||||||
|
|
||||||
# nix develop --profile .nixdev
|
# nix develop --profile .nixdev
|
||||||
.nixdev*
|
.nixdev*
|
||||||
|
|
||||||
|
|
@ -136,173 +130,3 @@ gitea/
|
||||||
|
|
||||||
# LLM conversations that should remain private
|
# LLM conversations that should remain private
|
||||||
docs/conversations/
|
docs/conversations/
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:run-tests
|
|
||||||
/.claude/skills/run-tests/SKILL.md
|
|
||||||
# END ai.skillz: direct:symlink:claude:run-tests
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:run-tests
|
|
||||||
/.opencode/skills/run-tests/SKILL.md
|
|
||||||
# END ai.skillz: direct:symlink:opencode:run-tests
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:command:run-tests
|
|
||||||
/.opencode/commands/run-tests.md
|
|
||||||
# END ai.skillz: direct:symlink:opencode:command:run-tests
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:close-wkt
|
|
||||||
/.claude/skills/close-wkt
|
|
||||||
# END ai.skillz: direct:symlink:claude:close-wkt
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:close-wkt
|
|
||||||
/.opencode/skills/close-wkt
|
|
||||||
# END ai.skillz: direct:symlink:opencode:close-wkt
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: runtime:code-review-changes
|
|
||||||
.claude/review_context.md
|
|
||||||
.claude/review_regression.md
|
|
||||||
# END ai.skillz: runtime:code-review-changes
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:code-review-changes
|
|
||||||
/.claude/skills/code-review-changes
|
|
||||||
# END ai.skillz: direct:symlink:claude:code-review-changes
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:code-review-changes
|
|
||||||
/.opencode/skills/code-review-changes
|
|
||||||
# END ai.skillz: direct:symlink:opencode:code-review-changes
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: runtime:commit-msg
|
|
||||||
.claude/skills/commit-msg/msgs/
|
|
||||||
.claude/skills/commit-msg/conf.toml
|
|
||||||
.claude/git_commit_msg_LATEST.md
|
|
||||||
# END ai.skillz: runtime:commit-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:commit-msg
|
|
||||||
/.claude/skills/commit-msg/SKILL.md
|
|
||||||
# END ai.skillz: direct:symlink:claude:commit-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:commit-msg
|
|
||||||
/.opencode/skills/commit-msg/SKILL.md
|
|
||||||
# END ai.skillz: direct:symlink:opencode:commit-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:dep-supersede-scan
|
|
||||||
/.claude/skills/dep-supersede-scan
|
|
||||||
# END ai.skillz: direct:symlink:claude:dep-supersede-scan
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:dep-supersede-scan
|
|
||||||
/.opencode/skills/dep-supersede-scan
|
|
||||||
# END ai.skillz: direct:symlink:opencode:dep-supersede-scan
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:gish
|
|
||||||
/.claude/skills/gish
|
|
||||||
# END ai.skillz: direct:symlink:claude:gish
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:gish
|
|
||||||
/.opencode/skills/gish
|
|
||||||
# END ai.skillz: direct:symlink:opencode:gish
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:inter-skill-review
|
|
||||||
/.claude/skills/inter-skill-review
|
|
||||||
# END ai.skillz: direct:symlink:claude:inter-skill-review
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:inter-skill-review
|
|
||||||
/.opencode/skills/inter-skill-review
|
|
||||||
# END ai.skillz: direct:symlink:opencode:inter-skill-review
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: runtime:open-wkt
|
|
||||||
.claude/wkts/
|
|
||||||
claude_wkts
|
|
||||||
/wkts/
|
|
||||||
# END ai.skillz: runtime:open-wkt
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:open-wkt
|
|
||||||
/.claude/skills/open-wkt
|
|
||||||
# END ai.skillz: direct:symlink:claude:open-wkt
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:open-wkt
|
|
||||||
/.opencode/skills/open-wkt
|
|
||||||
# END ai.skillz: direct:symlink:opencode:open-wkt
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:plan-io
|
|
||||||
/.claude/skills/plan-io
|
|
||||||
# END ai.skillz: direct:symlink:claude:plan-io
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:plan-io
|
|
||||||
/.opencode/skills/plan-io
|
|
||||||
# END ai.skillz: direct:symlink:opencode:plan-io
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: runtime:pr-msg
|
|
||||||
.claude/skills/pr-msg/msgs/
|
|
||||||
.claude/skills/pr-msg/pr_msg_LATEST.md
|
|
||||||
# END ai.skillz: runtime:pr-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:pr-msg
|
|
||||||
/.claude/skills/pr-msg/SKILL.md
|
|
||||||
/.claude/skills/pr-msg/references
|
|
||||||
/.claude/skills/pr-msg/scripts
|
|
||||||
# END ai.skillz: direct:symlink:claude:pr-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:pr-msg
|
|
||||||
/.opencode/skills/pr-msg/SKILL.md
|
|
||||||
/.opencode/skills/pr-msg/references
|
|
||||||
/.opencode/skills/pr-msg/scripts
|
|
||||||
# END ai.skillz: direct:symlink:opencode:pr-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:prompt-io
|
|
||||||
/.claude/skills/prompt-io
|
|
||||||
# END ai.skillz: direct:symlink:claude:prompt-io
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:prompt-io
|
|
||||||
/.opencode/skills/prompt-io
|
|
||||||
# END ai.skillz: direct:symlink:opencode:prompt-io
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:py-codestyle
|
|
||||||
/.claude/skills/py-codestyle
|
|
||||||
# END ai.skillz: direct:symlink:claude:py-codestyle
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:py-codestyle
|
|
||||||
/.opencode/skills/py-codestyle
|
|
||||||
# END ai.skillz: direct:symlink:opencode:py-codestyle
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:resolve-conflicts
|
|
||||||
/.claude/skills/resolve-conflicts
|
|
||||||
# END ai.skillz: direct:symlink:claude:resolve-conflicts
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:resolve-conflicts
|
|
||||||
/.opencode/skills/resolve-conflicts
|
|
||||||
# END ai.skillz: direct:symlink:opencode:resolve-conflicts
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: runtime:taken-export
|
|
||||||
.ai/taken/exports/
|
|
||||||
# END ai.skillz: runtime:taken-export
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:taken-export
|
|
||||||
/.claude/skills/taken-export
|
|
||||||
# END ai.skillz: direct:symlink:claude:taken-export
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:taken-export
|
|
||||||
/.opencode/skills/taken-export
|
|
||||||
# END ai.skillz: direct:symlink:opencode:taken-export
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:yt-url-lookup
|
|
||||||
/.claude/skills/yt-url-lookup
|
|
||||||
# END ai.skillz: direct:symlink:claude:yt-url-lookup
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:yt-url-lookup
|
|
||||||
/.opencode/skills/yt-url-lookup
|
|
||||||
# END ai.skillz: direct:symlink:opencode:yt-url-lookup
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:claude:command:branch-in-new-terminal
|
|
||||||
/.claude/commands/branch-in-new-terminal.md
|
|
||||||
# END ai.skillz: direct:symlink:claude:command:branch-in-new-terminal
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: runtime:branch-in-new-terminal
|
|
||||||
.claude/.current_session
|
|
||||||
# END ai.skillz: runtime:branch-in-new-terminal
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:command:commit-msg
|
|
||||||
/.opencode/commands/commit-msg.md
|
|
||||||
# END ai.skillz: direct:symlink:opencode:command:commit-msg
|
|
||||||
|
|
||||||
# BEGIN ai.skillz: direct:symlink:opencode:command:taken-export
|
|
||||||
/.opencode/commands/taken-export.md
|
|
||||||
# END ai.skillz: direct:symlink:opencode:command:taken-export
|
|
||||||
|
|
|
||||||
22
ai/README.md
22
ai/README.md
|
|
@ -17,21 +17,6 @@ track new integration ideas and proposals in
|
||||||
| Tool | Directory | Status |
|
| Tool | Directory | Status |
|
||||||
|------|-----------|--------|
|
|------|-----------|--------|
|
||||||
| [Claude Code](https://github.com/anthropics/claude-code) | [`claude-code/`](claude-code/) | active |
|
| [Claude Code](https://github.com/anthropics/claude-code) | [`claude-code/`](claude-code/) | active |
|
||||||
| [OpenCode](https://opencode.ai/) | [`opencode/`](opencode/) | active |
|
|
||||||
|
|
||||||
## Shared Skills
|
|
||||||
|
|
||||||
Provider-neutral skill bundles should use the portable Agent Skills
|
|
||||||
subset and live under `.agents/skills/` as their single source.
|
|
||||||
OpenCode discovers that project directory natively. Relative links in
|
|
||||||
provider directories such as `.claude/skills/` may bridge clients which
|
|
||||||
do not yet scan `.agents/skills/`; never copy the skill body.
|
|
||||||
|
|
||||||
Existing repo skills under `.claude/skills/` predate this convention
|
|
||||||
and can migrate separately without coupling their history to new skills.
|
|
||||||
|
|
||||||
Harness-specific command files should only delegate to a
|
|
||||||
shared skill. They must not duplicate the skill body.
|
|
||||||
|
|
||||||
## Adding a New Integration
|
## Adding a New Integration
|
||||||
|
|
||||||
|
|
@ -47,7 +32,7 @@ ai/
|
||||||
├── README.md # <- you are here
|
├── README.md # <- you are here
|
||||||
├── claude-code/
|
├── claude-code/
|
||||||
│ └── README.md
|
│ └── README.md
|
||||||
├── opencode/
|
├── opencode/ # future
|
||||||
│ └── README.md
|
│ └── README.md
|
||||||
└── <your-tool>/
|
└── <your-tool>/
|
||||||
└── README.md
|
└── README.md
|
||||||
|
|
@ -60,7 +45,6 @@ ai/
|
||||||
- Each integration doc should describe **what**
|
- Each integration doc should describe **what**
|
||||||
the skill does, **how** to invoke it, and any
|
the skill does, **how** to invoke it, and any
|
||||||
**output** artifacts it produces
|
**output** artifacts it produces
|
||||||
- Keep docs concise; link to the shared skill source files
|
- Keep docs concise; link to the actual skill
|
||||||
|
source files (under `.claude/skills/`, etc.)
|
||||||
rather than duplicating content
|
rather than duplicating content
|
||||||
- Keep skill bodies harness-neutral; isolate slash-command
|
|
||||||
syntax and permissions in each harness integration
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
# Claude Code Integration
|
# Claude Code Integration
|
||||||
|
|
||||||
[Claude Code](https://github.com/anthropics/claude-code)
|
[Claude Code](https://github.com/anthropics/claude-code)
|
||||||
integration for piker's shared coding-harness skills.
|
skills and workflows for piker development.
|
||||||
|
|
||||||
## Skills
|
## Skills
|
||||||
|
|
||||||
| Skill | Invocable | Description |
|
| Skill | Invocable | Description |
|
||||||
|-------|-----------|-------------|
|
|-------|-----------|-------------|
|
||||||
| [`commit-msg`](#commit-msg) | `/commit-msg` | Generate piker-style commit messages |
|
| [`commit-msg`](#commit-msg) | `/commit-msg` | Generate piker-style commit messages |
|
||||||
| `piker-clearing-expert` | auto | Clearing, order-control, and accounting invariants |
|
|
||||||
| `piker-conc-expert` | auto | Actor-tree and structured-concurrency invariants |
|
|
||||||
| `piker-profiling` | auto | `Profiler` API patterns for perf work |
|
| `piker-profiling` | auto | `Profiler` API patterns for perf work |
|
||||||
| `piker-slang` | auto | Communication style + slang guide |
|
| `piker-slang` | auto | Communication style + slang guide |
|
||||||
| `py-codestyle` | auto | Python source conventions |
|
|
||||||
| `pyqtgraph-optimization` | auto | Batch rendering patterns |
|
| `pyqtgraph-optimization` | auto | Batch rendering patterns |
|
||||||
| `timeseries-optimization` | auto | NumPy/Polars perf patterns |
|
| `timeseries-optimization` | auto | NumPy/Polars perf patterns |
|
||||||
|
|
||||||
|
|
@ -20,12 +17,8 @@ Skills marked **auto** are background knowledge
|
||||||
applied automatically when Claude detects relevance.
|
applied automatically when Claude detects relevance.
|
||||||
Only `commit-msg` is user-invoked via slash command.
|
Only `commit-msg` is user-invoked via slash command.
|
||||||
|
|
||||||
New portable skill source files live under
|
Skill source files live under
|
||||||
`.agents/skills/<skill-name>/SKILL.md`. Relative links under
|
`.claude/skills/<skill-name>/SKILL.md`.
|
||||||
`.claude/skills/` expose them to Claude Code without copying bodies.
|
|
||||||
Existing pre-migration skills can remain under `.claude/skills/`.
|
|
||||||
Claude-specific behavior belongs in command or settings files, not
|
|
||||||
shared skill bodies.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -91,7 +84,8 @@ description context. Examples:
|
||||||
**Footer** (always):
|
**Footer** (always):
|
||||||
```
|
```
|
||||||
(this patch was generated in some part by
|
(this patch was generated in some part by
|
||||||
`claude-code` using `<model>` (`<provider>`))
|
[`claude-code`][claude-code-gh])
|
||||||
|
[claude-code-gh]: https://github.com/anthropics/claude-code
|
||||||
```
|
```
|
||||||
|
|
||||||
### Output Files
|
### Output Files
|
||||||
|
|
@ -100,8 +94,7 @@ After generation, the commit message is written to:
|
||||||
|
|
||||||
```
|
```
|
||||||
.claude/
|
.claude/
|
||||||
├── skills/commit-msg/msgs/
|
├── <timestamp>_<hash>_commit_msg.md # archived
|
||||||
│ └── <timestamp>_<hash>_commit_msg.md
|
|
||||||
└── git_commit_msg_LATEST.md # latest
|
└── git_commit_msg_LATEST.md # latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -109,10 +102,18 @@ Where `<timestamp>` is ISO-8601 with seconds and
|
||||||
`<hash>` is the first 7 chars of the current
|
`<hash>` is the first 7 chars of the current
|
||||||
`HEAD` commit.
|
`HEAD` commit.
|
||||||
|
|
||||||
Use the latest file with an editor review before commit:
|
Use the latest file to feed into `git commit`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git commit --edit --file .claude/git_commit_msg_LATEST.md
|
git commit -F .claude/git_commit_msg_LATEST.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Or review/edit before committing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat .claude/git_commit_msg_LATEST.md
|
||||||
|
# edit if needed, then:
|
||||||
|
git commit -F .claude/git_commit_msg_LATEST.md
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
@ -127,32 +128,56 @@ Add `MktPair.fqme` property for symbol resolution
|
||||||
Factor `.claude/skills/` into proper subdirs
|
Factor `.claude/skills/` into proper subdirs
|
||||||
|
|
||||||
Deats,
|
Deats,
|
||||||
- use portable Agent Skills frontmatter
|
- `commit_msg/` -> `commit-msg/` w/ enhanced
|
||||||
- keep harness commands as thin delegates
|
frontmatter
|
||||||
- share supporting references across harnesses
|
- all background skills set `user-invocable: false`
|
||||||
|
- content split into supporting files
|
||||||
|
|
||||||
(this patch was generated in some part by
|
(this patch was generated in some part by
|
||||||
`claude-code` using `<model>` (`<provider>`))
|
[`claude-code`][claude-code-gh])
|
||||||
|
[claude-code-gh]: https://github.com/anthropics/claude-code
|
||||||
```
|
```
|
||||||
|
|
||||||
### Shared Frontmatter
|
### Frontmatter Reference
|
||||||
|
|
||||||
Skills use the Agent Skills fields understood by both
|
The skill's `SKILL.md` uses these Claude Code
|
||||||
Claude Code and OpenCode:
|
frontmatter fields:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
---
|
---
|
||||||
name: commit-msg
|
name: commit-msg
|
||||||
description: >
|
description: >
|
||||||
Generate piker-style git commit messages. Use when...
|
Generate piker-style git commit messages...
|
||||||
compatibility: Requires git.
|
argument-hint: "[optional-scope-or-description]"
|
||||||
metadata:
|
disable-model-invocation: true
|
||||||
author: goodboy
|
allowed-tools:
|
||||||
version: "1.0"
|
- Bash(git *)
|
||||||
|
- Read
|
||||||
|
- Grep
|
||||||
|
- Glob
|
||||||
|
- Write
|
||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
Live git context is gathered by the skill at execution
|
| Field | Purpose |
|
||||||
time. Claude-only dynamic interpolation and tool-policy
|
|-------|---------|
|
||||||
frontmatter are intentionally excluded so another harness
|
| `argument-hint` | Shows hint in autocomplete |
|
||||||
can execute the same workflow.
|
| `disable-model-invocation` | Only user can trigger via `/commit-msg` |
|
||||||
|
| `allowed-tools` | Tools the skill can use |
|
||||||
|
|
||||||
|
### Dynamic Context
|
||||||
|
|
||||||
|
The skill injects live data at invocation time
|
||||||
|
via `!`backtick`` syntax in the `SKILL.md`:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Current staged changes
|
||||||
|
!`git diff --staged --stat`
|
||||||
|
|
||||||
|
## Recent commit style reference
|
||||||
|
!`git log --oneline -10`
|
||||||
|
```
|
||||||
|
|
||||||
|
This means the staged diff stats and recent log
|
||||||
|
are always fresh when the skill runs -- no stale
|
||||||
|
context.
|
||||||
|
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
# Split `brokerd.<broker>` into trading-only `brokerd` + new `datad.<broker>`
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
Today a single `brokerd.<broker>` actor hosts BOTH concerns:
|
|
||||||
|
|
||||||
- **data feed service tasks**: the `_FeedsBus` + `open_feed_bus()` ep (`piker/data/feed.py:464`), per-symbol `allocate_persistent_feed()` tasks (shm writers via `sample_and_broadcast()`, history backfill via `piker.tsp`), plus backend eps `stream_quotes`, `open_history_client`, `open_symbol_search`, `get_mkt_info` from `piker/brokers/<backend>/feed.py`/`symbols.py`,
|
|
||||||
- **live order-control tasks**: `open_trade_dialog()` from `piker/brokers/<backend>/broker.py`, driven by `emsd`.
|
|
||||||
|
|
||||||
The codebase already anticipates this split: `piker/data/validate.py:70-91` groups backend eps into `'datad'` vs `'brokerd'` kinds, `piker/brokers/ib/__init__.py:62-70` already declares `_brokerd_mods`/`_datad_mods`, and `piker/brokers/_daemon.py:62` carries the literal TODO *"rename the daemon to datad prolly once we split up broker vs. data tasks into separate actors?"*. This work executes that split.
|
|
||||||
|
|
||||||
**User-decided constraints:**
|
|
||||||
|
|
||||||
- `datad.<broker>` is a **sibling** of `brokerd.<broker>` under `pikerd`, spawned via the existing `Services` + `maybe_spawn_daemon()` machinery (`piker/service/_daemon.py:46`).
|
|
||||||
- **Hard cutover, staged by layer** — no dual-mode runtime flag; every stage lands fully working.
|
|
||||||
- Post-split `brokerd` is **trading-only and lazily spawned solely by emsd's** `open_brokerd_dialog` path; UI/CLI/feed code never spawns it. Chart-only and paper sessions run with **zero** brokerd processes.
|
|
||||||
|
|
||||||
## Target topology
|
|
||||||
|
|
||||||
```
|
|
||||||
pikerd
|
|
||||||
├── datad.ib feed bus, shm writers, tsp history, symbol search
|
|
||||||
├── brokerd.ib open_trade_dialog only (EMS-spawned, lazy)
|
|
||||||
├── emsd
|
|
||||||
│ └── paperboi.ib (paper mode; opens its feed via datad)
|
|
||||||
└── samplerd
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key verified facts (load-bearing)
|
|
||||||
|
|
||||||
- `feed.portals` has exactly ONE trading consumer: `piker/clearing/_ems.py:671` (`portal = feed.portals[brokermod]` → handed to `open_brokerd_dialog`). This is the single coupling forcing feed + trading into one actor.
|
|
||||||
- `assert 'brokerd' in servicename` at `piker/data/feed.py:502` is the only actor-name assert in the tree.
|
|
||||||
- `piker ledger` (`piker/accounting/cli.py:100-157`) is a hidden consumer: it calls `broker_init()` directly, spawns its own ad-hoc actor, enters `_setup_persistent_brokerd`, then calls `open_brokerd_dialog(brokermod, portal, ...)` **with an explicit portal** — the new signature must keep a `portal:` override param.
|
|
||||||
- kraken's feed→broker coupling is mild: `kraken/broker.py:77-81` imports `NoBsWs`/`open_autorecon_ws` (really from `piker.data._web_bs`) and `stream_messages` (pure parser) from `feed.py`. In-process imports only — `enable_modules` gates RPC, not imports. No live shared state; each actor opens its own WS.
|
|
||||||
- ib: default `client_id=6116` (`ib/api.py:1320`) with linear retry `clientId=client_id + i` (`:1403`). Two ib actors connecting concurrently will collide → needs a role-based id offset. Both daemons need `_spawn_kwargs={'infect_asyncio': True}` (copied by both init fns).
|
|
||||||
- binance has no `symbols.py` (`get_mkt_info`/`open_symbol_search` live in `binance/feed.py`); kucoin/questrade/robinhood are flat single-file with NO `__enable_modules__`; deribit has no `broker.py`.
|
|
||||||
- `tests/test_services.py:80,185` assert `brokerd` actor names incl. the paper-mode flow asserting `brokerd.kraken` spawns (`:229,:237`) — must invert post-split.
|
|
||||||
- `_root_modules` (`piker/service/_actor_runtime.py:156`) must gain the new datad daemon mod so `pikerd_portal.run(spawn_datad, ...)` resolves.
|
|
||||||
- `piker/brokers/core.py:175` `symbol_search` does `portal.run(search_w_brokerd)` where the target fn lives in `piker.brokers.core` → that mod must stay RPC-enabled in datad.
|
|
||||||
|
|
||||||
## Module decision
|
|
||||||
|
|
||||||
New file **`piker/data/_daemon.py`** hosts all datad machinery (`_setup_persistent_datad`, `datad_init`, `spawn_datad`, `maybe_spawn_datad`, `_datad_service_mods`). Mirrors the `piker.brokers._daemon` / `piker.data._sampling` (samplerd) per-subsystem convention and satisfies the existing TODO at `brokers/_daemon.py:49` ("move this def to the `.data` subpkg"). `piker.brokers._daemon` keeps brokerd-only code, slimmed. Do NOT over-DRY the two ~40-line init fns into a shared factory yet (samplerd precedent accepts the duplication).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Stage 0 — prep: backend module grouping + ep introspection (no topology change)
|
|
||||||
|
|
||||||
1. `piker/data/validate.py`: add a `get_eps(mod, kind) -> dict[str, Callable]` helper returning the backend's defined eps for a daemon-kind from `_eps` (missing eps excluded). Used later by both init fns + fail-fast checks.
|
|
||||||
2. Declare daemon-kind module groups in each split backend's `__init__.py`, keeping `__enable_modules__` as the (deduped) union so behavior is unchanged:
|
|
||||||
- `kraken`: `_brokerd_mods = ['api', 'broker']`, `_datad_mods = ['api', 'feed', 'symbols']`
|
|
||||||
- `binance`: `_brokerd_mods = ['api', 'broker']`, `_datad_mods = ['api', 'feed']`
|
|
||||||
- `deribit`: `_brokerd_mods = []`, `_datad_mods = ['api', 'feed']`
|
|
||||||
- `ib`: adjust existing groups so each includes `'api'`
|
|
||||||
- flat backends (kucoin etc.): no attrs — init fns fall back to enabling just `modpath` (existing behavior).
|
|
||||||
3. Hygiene: `kraken/broker.py:77-81` imports `NoBsWs`/`open_autorecon_ws` from `piker.data._web_bs` directly (keep the `stream_messages` import from `.feed`).
|
|
||||||
|
|
||||||
**Gate**: full pytest green, zero behavior change.
|
|
||||||
|
|
||||||
## Stage 1 — introduce `datad` daemon machinery (additive)
|
|
||||||
|
|
||||||
New `piker/data/_daemon.py`:
|
|
||||||
|
|
||||||
- `_datad_service_mods: list[str]` — datad-always-enabled mods (successor to the data side of `_data_mods` from `brokers/_daemon.py:52`): `['piker.brokers.core', 'piker.brokers.data', 'piker.data', 'piker.data.feed', 'piker.data._sampling', 'piker.data._daemon']`.
|
|
||||||
- `_setup_persistent_datad(ctx, brokername, loglevel)` — `@tractor.context` fixture; logging boilerplate (as `_setup_persistent_brokerd:81-88`), then allocates the actor-global feed bus exactly as the brokerd fixture does today (`brokers/_daemon.py:105-121`): `assert not feed._bus`, open service nursery, `feed.get_feed_bus(brokername, service_nursery)`, `ctx.started()`, `sleep_forever()`.
|
|
||||||
- `datad_init(brokername, ...)` — mirrors `broker_init()` (`brokers/_daemon.py:132`): actor name `f'datad.{brokername}'`, copies backend `_spawn_kwargs` (**critical for ib infect_asyncio**), builds `enable_modules` from `getattr(brokermod, '_datad_mods', getattr(brokermod, '__enable_modules__', []))`.
|
|
||||||
- `spawn_datad(brokername, ...)` — mirrors `spawn_brokerd()` (`brokers/_daemon.py:202`): `Services.actor_n.start_actor(dname, enable_modules=_datad_service_mods + backend_mods, ...)` + `Services.start_service_task(dname, portal, _setup_persistent_datad, ...)`.
|
|
||||||
- `maybe_spawn_datad(brokername, ...)` — wraps `maybe_spawn_daemon(service_name=f'datad.{brokername}', service_task_target=spawn_datad, ...)` exactly like `maybe_spawn_brokerd` (`brokers/_daemon.py:256`).
|
|
||||||
|
|
||||||
Supporting edits:
|
|
||||||
|
|
||||||
- `piker/service/_actor_runtime.py:156`: add `'piker.data._daemon'` to `_root_modules` (keep `'piker.brokers._daemon'`).
|
|
||||||
- `piker/service/__init__.py`: re-export `spawn_datad`/`maybe_spawn_datad` next to the brokerd ones (`:56-57`).
|
|
||||||
- `tests/test_services.py`: new `test_datad_spawn` — `open_test_pikerd` + `maybe_spawn_datad('kraken')` + `ensure_service('datad.kraken')`. (Do NOT route a feed through it yet — `open_feed_bus`'s assert still says brokerd.)
|
|
||||||
|
|
||||||
**Gate**: suite green + new spawn test; nothing routes through datad yet.
|
|
||||||
|
|
||||||
## Stage 2 — clearing layer: emsd self-spawns brokerd (decouple from `feed.portals`)
|
|
||||||
|
|
||||||
Sequenced BEFORE the feed cutover so live trading works at every boundary (otherwise `feed.portals` would hand emsd a datad portal).
|
|
||||||
|
|
||||||
`piker/clearing/_ems.py`:
|
|
||||||
|
|
||||||
1. `open_brokerd_dialog()` (`:336`) new signature: `(brokermod, exec_mode, fqme=None, portal: tractor.Portal|None = None, loglevel=None)`. Internals: keep trades-ep detection (`:400-417`); acquire the brokerd actor ONLY when a live ep will actually open, via a small inner `@acm _acquire_live_portal()` that yields the passed `portal` if given (the `piker ledger` path) else `async with maybe_spawn_brokerd(brokermod.name, loglevel=loglevel)` — **the single place brokerd boots post-split**. Move the eager `portal.open_context(trades_endpoint, ...)` construction (`:425`) inside that block; the paper short-circuit (`:432`) never touches it.
|
|
||||||
2. `Router.maybe_open_brokerd_dialog()` (`:581`) — drop the `portal` param; `Router.open_trade_relays()` (`:640`) — delete `portal = feed.portals[brokermod]` (`:671`) and the pass-through (`:685`).
|
|
||||||
3. `piker/accounting/cli.py:144`: switch to keyword form `open_brokerd_dialog(brokermod, exec_mode=..., portal=portal, loglevel=...)`.
|
|
||||||
|
|
||||||
Pre-cutover this is a pure refactor: emsd's `maybe_spawn_brokerd` just *finds* the already-running brokerd via the registry.
|
|
||||||
|
|
||||||
**Gate**: `tests/test_ems.py` + services suite green; manual paper order on kraken; `piker ledger` smoke.
|
|
||||||
|
|
||||||
## Stage 3 — feed layer hard cutover to datad
|
|
||||||
|
|
||||||
1. `piker/data/feed.py`: import `maybe_spawn_datad` (replacing `maybe_spawn_brokerd`, `:56-58`); `open_feed()` `:895` → `maybe_spawn_datad(...)` (rename `brokerd_ctxs` → `datad_ctxs`); `open_feed_bus()` `:502` → `assert 'datad' in servicename`; comment sweep.
|
|
||||||
2. `piker/brokers/_daemon.py` `_setup_persistent_brokerd()`: slim to trading-only fixture — logging setup, `ctx.started()`, `sleep_forever()`. Drop the bus alloc, `assert not feed._bus`, the service nursery (backend `open_trade_dialog` ctxs own their task trees), the `eg.ExceptionGroup` handler, and the stale `_FeedsBus` TYPE_CHECKING import. (`piker ledger`'s ad-hoc actor enters this same slimmed fixture — exactly what it needs.)
|
|
||||||
3. Repoint remaining data-flavored spawn sites `maybe_spawn_brokerd` → `maybe_spawn_datad`:
|
|
||||||
- `piker/ui/_app.py:40,57` (symbol search; optionally rename `install_brokerd_search` → `install_datad_search`, def at `piker/data/feed.py:766`)
|
|
||||||
- `piker/brokers/core.py:33,175` (`symbol_search`)
|
|
||||||
- `piker/brokers/cli.py:38,190,320` (`brokercheck`, `record`)
|
|
||||||
- `piker/ui/cli.py:30,72,121` (legacy kivy monitor/optschain) + best-effort `piker/ui/kivy/option_chain.py:498` `wait_for_actor('brokerd')` → `'datad'`
|
|
||||||
4. `tests/test_services.py`: `:80,:185` `actor_name = 'datad'`; paper-mode test asserts `datad.kraken` + `paperboi.kraken` + `emsd` AND adds the headline negative check: `assert 'brokerd.kraken' not in services.service_tasks`.
|
|
||||||
|
|
||||||
**Gate**: full suite with inverted assertions; manual: chart on binance/kraken shows `datad.<broker>` in `piker services` and NO brokerd; paper order fills; symbol search works; history backfill sane.
|
|
||||||
|
|
||||||
## Stage 4 — caps-sec slimming, validation, ib client-id
|
|
||||||
|
|
||||||
1. `piker/brokers/_daemon.py`: delete `_data_mods` (`:52`); `spawn_brokerd()` `:236` → `enable_modules=tractor_kwargs.pop('enable_modules')`; `broker_init()` `:184` reads `getattr(brokermod, '_brokerd_mods', getattr(brokermod, '__enable_modules__', []))`. Resulting brokerd enable set has no `piker.data.*` at all.
|
|
||||||
2. Fail-fast ep validation via Stage-0 `validate.get_eps()`: `broker_init` raises a clear error when `get_eps(mod, 'brokerd')` is empty (e.g. "kucoin is datad-only — use paper mode"); `datad_init` warns analogously.
|
|
||||||
3. ib client-id mitigation in `load_aio_clients()` (`ib/api.py:~1316`): role-based offset when `client_id` is the 6116 default (e.g. `+16` when `'datad' in tractor.current_actor().name`), optionally configurable via `brokers.toml` keys.
|
|
||||||
4. Docs/comment sweep: resolve `brokers/_daemon.py:62` TODO, `piker/cli/__init__.py:253` TODO, daemon list in `piker/service/__init__.py:21` docstring.
|
|
||||||
|
|
||||||
**Gate**: full suite; audit greps clean: `grep -rn maybe_spawn_brokerd piker/` hits only `clearing/_ems.py`, `service/__init__.py`, `brokers/_daemon.py`; no spawn-path `'brokerd'` literals left in `piker/data`, `piker/ui`, `piker/brokers/cli.py`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Risk register
|
|
||||||
|
|
||||||
| Risk | Sev | Mitigation |
|
|
||||||
|---|---|---|
|
|
||||||
| ib: `datad.ib` + `brokerd.ib` both connect to TWS/gw; `client_id=6116` collision burns `connect_timeout` retries | High (live ib only) | Stage 4 role-based id offset; both daemons inherit `infect_asyncio` via `_spawn_kwargs` copy in both init fns |
|
|
||||||
| `piker ledger` ad-hoc actor path silently broken by signature change | Med | `portal:` override kept on `open_brokerd_dialog` (Stage 2); explicit smoke test |
|
|
||||||
| datad-only backends (kucoin/deribit) → useless brokerd spawn | Low | already covered: `open_brokerd_dialog` forces `exec_mode='paper'` when no trades ep (`_ems.py:413-417`) BEFORE the lazy spawn; Stage 4 fail-fast |
|
|
||||||
| brokerd in-process symbology/ledger needs (ib `broker.py` imports `.symbols`; kraken uses `stream_messages`) | None | verified pure in-process imports; `enable_modules` gates RPC only |
|
|
||||||
| paper-mode test asserts brokerd spawns (`test_services.py:237`) | Low | Stage 3 deliberately inverts it |
|
|
||||||
| doubled per-broker clients (HTTP/WS, symcache loads) | Low | each actor already opens its own WS today; symcache is disk-read-mostly |
|
|
||||||
|
|
||||||
## Verification (per stage gates above, plus end-to-end)
|
|
||||||
|
|
||||||
- `pytest tests/test_services.py tests/test_feeds.py tests/test_ems.py` at every stage (kraken/binance public endpoints, no creds needed).
|
|
||||||
- Manual smoke matrix post-Stage-3: `pikerd -l info` + `piker chart btcusdt.spot.binance` → `piker services` shows `datad.binance`, no brokerd; submit paper order → `paperboi.binance` appears, still no brokerd; symbol search; `piker ledger <broker>.paper`.
|
|
||||||
- If ib creds/gateway available: live ib chart + small live order to exercise dual-actor client-id path (Stage 4).
|
|
||||||
|
|
||||||
## Critical files
|
|
||||||
|
|
||||||
- **new** `piker/data/_daemon.py` — all datad machinery
|
|
||||||
- `piker/brokers/_daemon.py` — slimmed brokerd fixture/init/spawn
|
|
||||||
- `piker/data/feed.py` — spawn cutover + actor-name assert
|
|
||||||
- `piker/clearing/_ems.py` — emsd lazy brokerd spawn (`open_brokerd_dialog`, `Router`)
|
|
||||||
- `piker/service/_actor_runtime.py`, `piker/service/__init__.py` — root mods + re-exports
|
|
||||||
- `piker/data/validate.py` — `get_eps()` helper
|
|
||||||
- backend `__init__.py`s (kraken/binance/deribit/ib) — `_datad_mods`/`_brokerd_mods`
|
|
||||||
- `piker/accounting/cli.py` — keyword-form dialog call
|
|
||||||
- `tests/test_services.py` — inverted + new assertions
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
# OpenCode Integration
|
|
||||||
|
|
||||||
[OpenCode](https://opencode.ai/) discovers provider-neutral skills
|
|
||||||
directly from `.agents/skills/` and pre-migration piker skills from
|
|
||||||
`.claude/skills/`. There is no second copy of each skill to keep in
|
|
||||||
sync.
|
|
||||||
|
|
||||||
## Available Skills
|
|
||||||
|
|
||||||
| Skill | Activation | Specialization |
|
|
||||||
|-------|------------|----------------|
|
|
||||||
| `commit-msg` | `/commit-msg` or explicit request | Piker commit-message style and artifacts |
|
|
||||||
| `piker-clearing-expert` | automatic | Clearing, order-control, and accounting invariants |
|
|
||||||
| `piker-conc-expert` | automatic | `tractor` actor topology, RPC, and cancellation |
|
|
||||||
| `piker-profiling` | automatic | Cross-actor `Profiler` instrumentation |
|
|
||||||
| `piker-slang` | automatic | Project communication style |
|
|
||||||
| `py-codestyle` | automatic | Python source conventions |
|
|
||||||
| `pyqtgraph-optimization` | automatic | Batched Qt graphics rendering |
|
|
||||||
| `timeseries-optimization` | automatic | NumPy and Polars timeseries performance |
|
|
||||||
|
|
||||||
OpenCode's project command lives at
|
|
||||||
`.opencode/commands/commit-msg.md`. It delegates to the
|
|
||||||
shared `commit-msg` skill and only supplies command
|
|
||||||
arguments; workflow logic remains in the skill.
|
|
||||||
|
|
||||||
A user-local skill with the same name may override a repo
|
|
||||||
skill. Treat `opencode debug skill` as authoritative when
|
|
||||||
diagnosing which source is active.
|
|
||||||
|
|
||||||
## Verify Discovery
|
|
||||||
|
|
||||||
From the repository root:
|
|
||||||
|
|
||||||
```console
|
|
||||||
opencode debug skill
|
|
||||||
opencode debug config
|
|
||||||
```
|
|
||||||
|
|
||||||
`opencode debug skill` should list the piker skills from
|
|
||||||
the project checkout. Restart OpenCode after changing a
|
|
||||||
skill or command because configuration-time files are not
|
|
||||||
hot-reloaded into an active session.
|
|
||||||
|
|
||||||
## Portability Rules
|
|
||||||
|
|
||||||
- Use only portable Agent Skills frontmatter in shared
|
|
||||||
`SKILL.md` files.
|
|
||||||
- Keep harness-specific command syntax under
|
|
||||||
`.opencode/commands/`.
|
|
||||||
- Detect the active harness and model at runtime; do not
|
|
||||||
hardcode Claude Code attribution in shared workflows.
|
|
||||||
- Keep supporting references beside each shared skill so
|
|
||||||
relative links resolve in every harness.
|
|
||||||
- Put new provider-neutral bundles under `.agents/skills/`; use
|
|
||||||
relative provider links only when a harness requires one.
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:08:59Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T170859Z_75cefe10_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T170859Z_75cefe10_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Session-initiating instruction (driving all 7 commits in
|
|
||||||
this series):
|
|
||||||
|
|
||||||
> ok i want you to become the distributed runtime and
|
|
||||||
> concurrency expert for this project - namely acquire
|
|
||||||
> a deep understanding of tractor and how it's used.
|
|
||||||
> then i want you to attempt to factor our current
|
|
||||||
> brokerd service daemon into 2 daemons: a brokerd
|
|
||||||
> which only hosts live/paper trading endpoint tasks
|
|
||||||
> [..] a new `datad` subdaemon which in a separate
|
|
||||||
> subactor serves all the data feed service tasks [..]
|
|
||||||
> give me a mega detailed plan on how to approach this,
|
|
||||||
> and a staged approach for the implementation.
|
|
||||||
|
|
||||||
Proximate driver for THIS commit: during the approved
|
|
||||||
plan's stage-0 test gate the agent discovered test
|
|
||||||
subactors were writing into the user's REAL
|
|
||||||
`~/.config/piker/accounting/` files (a bogus paper fill
|
|
||||||
landed in `account.kraken.paper.toml`) because the old
|
|
||||||
test-dir override in `config.get_app_dir()` was
|
|
||||||
commented out and could never work in spawned
|
|
||||||
subactors anyway. Fix applied autonomously under the
|
|
||||||
approved plan; no explicit per-fix user prompt.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Restore `pytest` config-dir isolation by resolving the
|
|
||||||
per-test tmp dir lazily (at conf-path access time) from
|
|
||||||
`tractor` runtime-vars, which propagate down the actor
|
|
||||||
tree; route all conf-path derivation through
|
|
||||||
`config.get_conf_dir()` so the override is effective in
|
|
||||||
every (sub)actor.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/config.py` — add `_maybe_use_test_dir()`;
|
|
||||||
hook in `get_conf_dir()`; route `get_conf_path()` +
|
|
||||||
`load()` mkdir through it
|
|
||||||
- `piker/accounting/_ledger.py` — derive ledger dir
|
|
||||||
via `config.get_conf_dir()` (not the global)
|
|
||||||
- `piker/accounting/_pos.py` — same for account files
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:08:59Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T170859Z_75cefe10_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/config.py`
|
|
||||||
|
|
||||||
Generated: `config._maybe_use_test_dir()` — lazily
|
|
||||||
reads `piker_test_dir` from
|
|
||||||
`tractor.runtime._state._runtime_vars['piker_vars']`
|
|
||||||
(pre-loaded by `open_piker_runtime()` from the
|
|
||||||
`tests.conftest._open_test_pikerd()` overrides) and
|
|
||||||
calls `_override_config_dir()` when set. Hooked at the
|
|
||||||
top of `get_conf_dir()`; `get_conf_path()` and
|
|
||||||
`load()`'s dir-creation rerouted through
|
|
||||||
`get_conf_dir()`.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/accounting/_ledger.py`
|
|
||||||
> `git log -1 -p --follow -- piker/accounting/_pos.py`
|
|
||||||
|
|
||||||
Generated: ledger/account dir derivation switched from
|
|
||||||
the `config._config_dir` module global to
|
|
||||||
`config.get_conf_dir()` + `mkdir(parents=True,
|
|
||||||
exist_ok=True)` for nested tmp-dir creation.
|
|
||||||
|
|
||||||
Key diagnostic reasoning (verbatim from session):
|
|
||||||
|
|
||||||
The old (commented-out) `get_app_dir()` override gated
|
|
||||||
on `'pytest' in sys.modules` which can NEVER work in
|
|
||||||
spawned subactors (fresh procs, no pytest import); as
|
|
||||||
a result test `paperboi`/daemon actors were writing
|
|
||||||
into the user's REAL `~/.config/piker/accounting/`
|
|
||||||
files. Evidence: `account.kraken.paper.toml` gained a
|
|
||||||
single 0.001 xbtusdt clear stamped 2026-06-09T18:47Z
|
|
||||||
(a test fill), and `trades_kraken_paper.toml` (252B)
|
|
||||||
contained only that fill. The resolution must be
|
|
||||||
checked lazily at config-path access time (NOT import
|
|
||||||
time) since sub-actors only receive runtime-vars once
|
|
||||||
their `tractor` runtime has fully booted.
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:10:22Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T171022Z_4485f2b9_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Same session-initiating `brokerd`-split instruction (see
|
|
||||||
`20260610T170859Z_75cefe10_prompt_io.md`). Proximate
|
|
||||||
driver: the approved plan's per-stage test gates could
|
|
||||||
not run AT ALL — the branch base was broken vs.
|
|
||||||
`tractor` git `main` (`AttributeError: 'tuple' object
|
|
||||||
has no attribute 'unwrap'` at `pikerd` boot, stale
|
|
||||||
`arbiter_sockaddr`/`.type`/`.size` API refs). The agent
|
|
||||||
fixed forward autonomously to (re)establish the gate
|
|
||||||
baseline, continuing the `repair_tests` branch lineage
|
|
||||||
(verified already merged in ancestry via `git cherry`
|
|
||||||
during a user-requested branch-overlap survey).
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Port the service layer + test suites to current
|
|
||||||
`tractor` APIs: addr-type normalization in
|
|
||||||
`open_pikerd()`, `query_actor()`/`wait_for_actor()`
|
|
||||||
kwarg renames, modern self-cancel absorption semantics
|
|
||||||
in the cancel-method test harness, exc/position attr
|
|
||||||
renames, a paper-EMS startup-budget bump and a syntax
|
|
||||||
fix in `.deribit.api`.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/service/_actor_runtime.py` — `wrap_address()`
|
|
||||||
normalize before `.unwrap()` in `open_pikerd()`
|
|
||||||
- `piker/service/_registry.py` — `check_for_service()`
|
|
||||||
-> `query_actor(regaddr=)` + 2-tuple yield +
|
|
||||||
`open_registry(addrs=)`
|
|
||||||
- `piker/brokers/deribit/api.py` — missing comma in
|
|
||||||
`tractor.trionics` import tuple
|
|
||||||
- `tests/test_services.py` — `registry_addr=` kwarg,
|
|
||||||
raddr unwraps, cancel-semantics harness rewrite,
|
|
||||||
`fail_after` 9 -> 19s
|
|
||||||
- `tests/test_ems.py` — `.boxed_type`, `pp.cumsize`
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:10:22Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171022Z_4485f2b9_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/service/_actor_runtime.py`
|
|
||||||
|
|
||||||
Generated: normalize each registry addr via
|
|
||||||
`tractor.discovery._addr.wrap_address()` before
|
|
||||||
`.unwrap()`-ing for the `accept_addrs` bind check —
|
|
||||||
entries may be raw `tuple`s when passed in from (test)
|
|
||||||
client code. Import-path precedent taken from
|
|
||||||
`piker/cli/__init__.py:336`.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/service/_registry.py`
|
|
||||||
|
|
||||||
Generated: `check_for_service()` ported to
|
|
||||||
`tractor.query_actor(name, regaddr=...)` (kwarg was
|
|
||||||
`arbiter_sockaddr=`), unpacking the new
|
|
||||||
`(sockaddr, portal)` yield, and passing the
|
|
||||||
now-required `open_registry(addrs=Registry.addrs)`.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- tests/test_services.py`
|
|
||||||
> `git log -1 -p --follow -- tests/test_ems.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/deribit/api.py`
|
|
||||||
|
|
||||||
Key diagnostic reasoning (verbatim from session):
|
|
||||||
|
|
||||||
- the "DID NOT RAISE ContextCancelled" failure: in this
|
|
||||||
test the client actor IS pikerd (in-proc), and
|
|
||||||
current `tractor` main absorbs a `ContextCancelled`
|
|
||||||
whose canceller is your own actor — self-requested
|
|
||||||
cancels now exit cleanly instead of raising; the
|
|
||||||
'sigint' variant propagates a bare collapsed
|
|
||||||
`KeyboardInterrupt` rather than a
|
|
||||||
`BaseExceptionGroup`.
|
|
||||||
- the hard-coded `trio.fail_after(9)` startup budget is
|
|
||||||
marginal — full stack boot (pikerd -> emsd ->
|
|
||||||
brokerd.kraken -> paperboi + live kraken symbology
|
|
||||||
fetch) occasionally exceeds 9s -> bumped to 19s.
|
|
||||||
- `RemoteActorError.type` -> `.boxed_type`;
|
|
||||||
`Position.size` -> `.cumsize` (the paper engine
|
|
||||||
populates `BrokerdPosition.size` from `pp.cumsize`).
|
|
||||||
- overlap survey (user-requested): all of the
|
|
||||||
`repair_tests` branch commits are already in this
|
|
||||||
stack's ancestry; this commit finishes that branch's
|
|
||||||
port mission (its f4c4f1e2 fixed `conftest.py`'s
|
|
||||||
`arbiter_sockaddr` usage; this fixes the remaining
|
|
||||||
`test_services.py` + `check_for_service()` sites).
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:11:05Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T171105Z_bc6e18d7_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Same session-initiating `brokerd`-split instruction (see
|
|
||||||
`20260610T170859Z_75cefe10_prompt_io.md`); this is the
|
|
||||||
approved plan's "stage 0" prep. Plan-shaping user
|
|
||||||
decisions captured via in-session Q&A:
|
|
||||||
|
|
||||||
- `datad.<broker>` topology: sibling of
|
|
||||||
`brokerd.<broker>` under `pikerd` (vs. child
|
|
||||||
subactor).
|
|
||||||
- migration: hard cutover, staged by layer (no
|
|
||||||
dual-mode runtime flag).
|
|
||||||
- post-split `brokerd` scope: trading-only +
|
|
||||||
EMS-lazy-spawned (charts/CLI never touch it).
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Declare per-daemon-kind backend submod groups
|
|
||||||
(`_datad_mods`/`_brokerd_mods`) in the split-style
|
|
||||||
backends, keyed to the pre-existing
|
|
||||||
`piker.data.validate._eps` contract; add a
|
|
||||||
`validate.get_eps()` introspection helper; ws-import
|
|
||||||
hygiene in `.kraken.broker`. Zero behavior change
|
|
||||||
(`__enable_modules__` unions unchanged).
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/data/validate.py` — add `get_eps()`
|
|
||||||
- `piker/brokers/kraken/__init__.py` — mod groups
|
|
||||||
- `piker/brokers/binance/__init__.py` — mod groups
|
|
||||||
(note: no `symbols.py`; search eps live in `.feed`)
|
|
||||||
- `piker/brokers/deribit/__init__.py` — datad-only
|
|
||||||
groups (no `broker.py` yet)
|
|
||||||
- `piker/brokers/ib/__init__.py` — add `'api'` to the
|
|
||||||
pre-existing `_datad_mods`
|
|
||||||
- `piker/brokers/kraken/broker.py` — import
|
|
||||||
`NoBsWs`/`open_autorecon_ws` from
|
|
||||||
`piker.data._web_bs` directly
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:11:05Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/data/validate.py`
|
|
||||||
|
|
||||||
Generated: `get_eps(mod, kind) -> dict[str, Callable]`
|
|
||||||
returning the daemon-kind's ep funcs defined by a
|
|
||||||
backend mod, keyed by ep name, missing eps excluded;
|
|
||||||
sourced from the existing `_eps` grouping table
|
|
||||||
(`'middleware' | 'datad' | 'brokerd'`).
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/kraken/__init__.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/binance/__init__.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/deribit/__init__.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/ib/__init__.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/kraken/broker.py`
|
|
||||||
|
|
||||||
Key exploration findings driving the design (from the
|
|
||||||
planning phase, 3 parallel explore agents + 1 architect
|
|
||||||
agent):
|
|
||||||
|
|
||||||
- the codebase already anticipated this split:
|
|
||||||
`validate._eps` groups eps into 'datad' vs 'brokerd'
|
|
||||||
kinds and `ib/__init__.py` already declared
|
|
||||||
`_brokerd_mods`/`_datad_mods`; `brokers/_daemon.py`
|
|
||||||
carried the literal TODO "rename the daemon to datad
|
|
||||||
prolly once we split up broker vs. data tasks into
|
|
||||||
separate actors?".
|
|
||||||
- the feared kraken feed<->broker "shared ws state"
|
|
||||||
hazard is mild: `NoBsWs`/`open_autorecon_ws`
|
|
||||||
originate in `piker.data._web_bs` (re-exported via
|
|
||||||
`.kraken.feed`); only `stream_messages` is feed-local
|
|
||||||
and it's a pure parser — in-process imports only,
|
|
||||||
each actor opens its own ws conn.
|
|
||||||
- `enable_modules` gates RPC entry, NOT python imports,
|
|
||||||
so backend trading mods may keep importing feed-side
|
|
||||||
helpers in-process post-split.
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:11:42Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171142Z_119d2c04_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T171142Z_119d2c04_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Same session-initiating `brokerd`-split instruction (see
|
|
||||||
`20260610T170859Z_75cefe10_prompt_io.md`); this is the
|
|
||||||
approved plan's "stage 1": introduce the `datad` daemon
|
|
||||||
machinery additively (nothing routes through it yet).
|
|
||||||
User-decided constraint applied: `datad.<broker>` is a
|
|
||||||
SIBLING of `brokerd.<broker>` under `pikerd`, spawned
|
|
||||||
via the existing `Services` + `maybe_spawn_daemon()`
|
|
||||||
machinery.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
New `piker/data/_daemon.py` hosting the
|
|
||||||
`datad.<broker>` feed-only daemon-actor: lifetime
|
|
||||||
fixture owning the actor-global `_FeedsBus`, init/spawn
|
|
||||||
fns mirroring `.brokers._daemon` conventions and the
|
|
||||||
`samplerd` sub-daemon precedent, plus root-mod
|
|
||||||
registration, `piker.service` re-exports and a spawn
|
|
||||||
test.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/data/_daemon.py` — NEW:
|
|
||||||
`_setup_persistent_datad()`, `datad_init()`,
|
|
||||||
`spawn_datad()`, `maybe_spawn_datad()`,
|
|
||||||
`_datad_service_mods`
|
|
||||||
- `piker/service/_actor_runtime.py` — add
|
|
||||||
`piker.data._daemon` to `_root_modules`
|
|
||||||
- `piker/service/__init__.py` — re-export spawn eps
|
|
||||||
- `tests/test_services.py` — add `test_datad_spawn`
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:11:42Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171142Z_119d2c04_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/data/_daemon.py`
|
|
||||||
|
|
||||||
Generated symbols + key design decisions:
|
|
||||||
|
|
||||||
- `_datad_service_mods: list[str]` — datad-always
|
|
||||||
enabled mods, the data-side successor to the old
|
|
||||||
`piker.brokers._daemon._data_mods` set; kept minimal
|
|
||||||
per the caps-sec model.
|
|
||||||
- `_setup_persistent_datad()` — `@tractor.context`
|
|
||||||
lifetime fixture: console-log setup then allocates
|
|
||||||
the actor-global feed bus via
|
|
||||||
`feed.get_feed_bus(brokername, service_nursery)`
|
|
||||||
exactly as the old brokerd fixture did, pinned open
|
|
||||||
with `ctx.started()` + `sleep_forever()`.
|
|
||||||
- `datad_init()` — actor name `f'datad.{brokername}'`;
|
|
||||||
copies backend `_spawn_kwargs` (CRITICAL for `ib`'s
|
|
||||||
`infect_asyncio=True`); builds `enable_modules` from
|
|
||||||
`getattr(brokermod, '_datad_mods',
|
|
||||||
getattr(brokermod, '__enable_modules__', []))` as
|
|
||||||
the flat-backend fallback.
|
|
||||||
- `spawn_datad()` — `Services.actor_n.start_actor()` +
|
|
||||||
`Services.start_service_task()` exactly mirroring
|
|
||||||
`spawn_brokerd()`; dedup-composes enable mods via
|
|
||||||
`list(dict.fromkeys(...))`.
|
|
||||||
- `maybe_spawn_datad()` — wraps `maybe_spawn_daemon(
|
|
||||||
service_name=f'datad.{brokername}', ...)`.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/service/_actor_runtime.py`
|
|
||||||
> `git log -1 -p --follow -- piker/service/__init__.py`
|
|
||||||
> `git log -1 -p --follow -- tests/test_services.py`
|
|
||||||
|
|
||||||
Design rationale (verbatim from session):
|
|
||||||
|
|
||||||
- `_root_modules` must gain `piker.data._daemon` so
|
|
||||||
`pikerd_portal.run(spawn_datad, ...)` resolves in
|
|
||||||
the root.
|
|
||||||
- the `Services`-based impl style deliberately mirrors
|
|
||||||
`spawn_brokerd()` so the eventual `tractor.hilevel`
|
|
||||||
`ServiceMngr` port (see the `service_mng_to_tractor`
|
|
||||||
branch's d8c21d44 prep, surfaced by the
|
|
||||||
user-requested branch-overlap survey) lands
|
|
||||||
symmetrically on both spawn fns.
|
|
||||||
- mod placement (`piker/data/_daemon.py` vs.
|
|
||||||
generalizing `piker.brokers._daemon`) follows the
|
|
||||||
per-subsystem daemon-mod convention
|
|
||||||
(`.clearing._ems`, `.data._sampling`) and resolves
|
|
||||||
the existing TODO at `brokers/_daemon.py:49` ("move
|
|
||||||
this def to the `.data` subpkg").
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:12:26Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171226Z_64181219_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T171226Z_64181219_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Same session-initiating `brokerd`-split instruction (see
|
|
||||||
`20260610T170859Z_75cefe10_prompt_io.md`); this is the
|
|
||||||
approved plan's "stage 2": decouple the clearing layer
|
|
||||||
from `feed.portals` BEFORE the feed cutover so live
|
|
||||||
trading works at every stage boundary. User-decided
|
|
||||||
constraint applied: post-split `brokerd` is
|
|
||||||
trading-only and spawned LAZILY only by `emsd`'s
|
|
||||||
`open_brokerd_dialog()` path.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Kill the single coupling forcing feed + trading eps
|
|
||||||
into one actor (`Router.open_trade_relays()` pulling
|
|
||||||
its trades portal from `feed.portals[brokermod]`):
|
|
||||||
`open_brokerd_dialog()` now (maybe) spawns/finds
|
|
||||||
`brokerd.<broker>` itself and ONLY when a live
|
|
||||||
trades-ep will actually open; paper mode never touches
|
|
||||||
it. Pre-cutover this is a pure refactor (registry
|
|
||||||
lookup finds the same feed-spawned daemon).
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/clearing/_ems.py` — `open_brokerd_dialog()`
|
|
||||||
re-sig + inner `acquire_live_portal()`;
|
|
||||||
`Router.maybe_open_brokerd_dialog()` drops `portal`
|
|
||||||
param; `open_trade_relays()` drops the
|
|
||||||
`feed.portals` lookup
|
|
||||||
- `piker/accounting/cli.py` — keyword-form `portal=`
|
|
||||||
override kept for the `piker ledger` ad-hoc actor
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:12:26Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171226Z_64181219_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/clearing/_ems.py`
|
|
||||||
|
|
||||||
Generated: new `open_brokerd_dialog()` signature
|
|
||||||
`(brokermod, exec_mode, fqme=None, portal=None,
|
|
||||||
loglevel=None)` with an inner `@acm
|
|
||||||
acquire_live_portal()` that yields the caller-provided
|
|
||||||
`portal` override (the `piker ledger` path) else
|
|
||||||
`maybe_spawn_brokerd(brokermod.name)` — designated THE
|
|
||||||
one place a live, credentialed `brokerd.<broker>` gets
|
|
||||||
booted post-split. The eager
|
|
||||||
`portal.open_context(trades_endpoint, ...)`
|
|
||||||
construction moved inside that block so the paper
|
|
||||||
short-circuit never acquires a live portal.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/accounting/cli.py`
|
|
||||||
|
|
||||||
Key analysis (verbatim from session):
|
|
||||||
|
|
||||||
- `feed.portals` had exactly ONE trading consumer:
|
|
||||||
`piker/clearing/_ems.py:671` (`portal =
|
|
||||||
feed.portals[brokermod]`) — the single coupling
|
|
||||||
forcing feed + trading into one actor.
|
|
||||||
- `piker ledger` (`accounting/cli.py:100-157`) is a
|
|
||||||
hidden consumer: it calls `broker_init()` directly,
|
|
||||||
spawns its own ad-hoc actor and passes the portal
|
|
||||||
positionally — the new signature must keep an
|
|
||||||
explicit `portal:` override param for this path.
|
|
||||||
- stage sequencing: clearing decouple lands BEFORE the
|
|
||||||
feed cutover, otherwise `feed.portals` would hand
|
|
||||||
emsd a `datad` portal and live `open_trade_dialog`
|
|
||||||
RPC would fail.
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:12:59Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T171259Z_59d5d9a6_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Same session-initiating `brokerd`-split instruction (see
|
|
||||||
`20260610T170859Z_75cefe10_prompt_io.md`); this is the
|
|
||||||
approved plan's "stage 3": the feed-layer hard cutover
|
|
||||||
(user-decided: no dual-mode runtime flag, each stage
|
|
||||||
lands fully working).
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
The topology flip: all data-feed consumers route to
|
|
||||||
`datad.<broker>`; the `brokerd` lifetime fixture slims
|
|
||||||
to trading-only; UI/CLI data-flavoured spawn sites
|
|
||||||
repointed; test expectations inverted incl. an explicit
|
|
||||||
negative assert that paper sessions spawn NO
|
|
||||||
`brokerd.<broker>`.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/data/feed.py` — `open_feed()` ->
|
|
||||||
`maybe_spawn_datad()`; `open_feed_bus()` actor-name
|
|
||||||
assert -> `'datad'`; `install_brokerd_search` ->
|
|
||||||
`install_datad_search`; comment sweep
|
|
||||||
- `piker/brokers/_daemon.py` —
|
|
||||||
`_setup_persistent_brokerd()` slimmed (feed-bus
|
|
||||||
alloc moved to the datad fixture)
|
|
||||||
- `piker/ui/_app.py`, `piker/ui/cli.py`,
|
|
||||||
`piker/brokers/core.py`, `piker/brokers/cli.py`,
|
|
||||||
`piker/ui/kivy/option_chain.py` — spawn-site
|
|
||||||
repoints
|
|
||||||
- `tests/test_services.py` — datad assertions + the
|
|
||||||
no-`brokerd.kraken` negative check
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:12:59Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171259Z_59d5d9a6_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/data/feed.py`
|
|
||||||
|
|
||||||
Generated: `open_feed()` spawn cutover with the
|
|
||||||
`maybe_spawn_datad` import done "relative-direct" from
|
|
||||||
`._daemon` — NOT via `piker.service` — to dodge a
|
|
||||||
partial-init cycle: when `piker.data.feed` loads as
|
|
||||||
part of `piker.service.__init__` executing its own
|
|
||||||
`piker.data._daemon` import, the service pkg is
|
|
||||||
mid-init and its `maybe_spawn_datad` binding does not
|
|
||||||
exist yet. The `open_feed_bus()` local-state sanity
|
|
||||||
assert flips `'brokerd' in servicename` ->
|
|
||||||
`'datad' in servicename` (the only actor-name assert
|
|
||||||
in the tree, verified by grep).
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/_daemon.py`
|
|
||||||
|
|
||||||
Generated: `_setup_persistent_brokerd()` slimmed to
|
|
||||||
console-log setup + pinned-open ctx; drops the bus
|
|
||||||
alloc, the `assert not feed._bus`, the service nursery
|
|
||||||
(backend `open_trade_dialog()` ctxs own their task
|
|
||||||
trees) and the `eg.ExceptionGroup` handler. The
|
|
||||||
`piker ledger` ad-hoc actor enters this same slimmed
|
|
||||||
fixture — exactly what it needs.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/ui/_app.py`
|
|
||||||
> `git log -1 -p --follow -- piker/ui/cli.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/core.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/cli.py`
|
|
||||||
> `git log -1 -p --follow -- piker/ui/kivy/option_chain.py`
|
|
||||||
> `git log -1 -p --follow -- tests/test_services.py`
|
|
||||||
|
|
||||||
Verification (from session): per-suite gates green at
|
|
||||||
this commit (services 5-passed incl. the new negative
|
|
||||||
assert, feeds 3-passed); a headless live smoke
|
|
||||||
(`maybe_open_pikerd` + `open_feed(['xbtusdt.kraken'])`
|
|
||||||
on an alt registry port) confirmed quotes flowing via
|
|
||||||
`datad.kraken` + `samplerd` with `check_for_service(
|
|
||||||
'brokerd.kraken') is None`. Known pre-existing flake
|
|
||||||
documented: `test_multi_fill_positions`' second
|
|
||||||
in-proc runtime boot wedges ~50% (zombie subactor w/
|
|
||||||
unread parent-IPC bytes); reproduced with the split
|
|
||||||
fully reverted so NOT a regression of this work.
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:13:44Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171344Z_eee19de0_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T171344Z_eee19de0_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Same session-initiating `brokerd`-split instruction (see
|
|
||||||
`20260610T170859Z_75cefe10_prompt_io.md`); this is the
|
|
||||||
approved plan's final "stage 4": caps-sec slimming of
|
|
||||||
the (live, credentialed) trading actor + the `ib`
|
|
||||||
dual-daemon `client_id` collision mitigation flagged in
|
|
||||||
the plan's risk register.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
`brokerd` loses ALL `piker.data.*` (feed) RPC mods;
|
|
||||||
spawn fails fast for datad-only backends with a "use
|
|
||||||
paper-mode" error; `ib`'s default api-gw `client_id`
|
|
||||||
gets a per-daemon-kind offset so `datad.ib` +
|
|
||||||
`brokerd.ib` don't collide on connect.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/brokers/_daemon.py` — `_data_mods` -> minimal
|
|
||||||
`_brokerd_service_mods`; `broker_init()` reads
|
|
||||||
`_brokerd_mods` (fallback `__enable_modules__`);
|
|
||||||
`spawn_brokerd()` fail-fast via `validate.get_eps()`
|
|
||||||
- `piker/brokers/ib/api.py` — role-based `client_id`
|
|
||||||
offset in `load_aio_clients()`
|
|
||||||
- `piker/cli/__init__.py` — resolved "expose datad"
|
|
||||||
TODO
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated.
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:13:44Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171344Z_eee19de0_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); backfilled from the live dev
|
|
||||||
session transcript per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/_daemon.py`
|
|
||||||
|
|
||||||
Generated: the fail-fast originally landed in
|
|
||||||
`broker_init()` but was relocated to `spawn_brokerd()`
|
|
||||||
mid-implementation after realizing `piker ledger`
|
|
||||||
calls `broker_init()` directly even for paper accounts
|
|
||||||
on datad-only backends (would have crashed the cli);
|
|
||||||
the service-spawn path is the correct enforcement
|
|
||||||
seam. Error text:
|
|
||||||
|
|
||||||
Backend 'kucoin' offers NO `brokerd` (live
|
|
||||||
order-control) eps!? It is likely a datad-only
|
|
||||||
provider, use paper-mode for clearing instead.
|
|
||||||
|
|
||||||
(verified live via a `trio.run()` unit check.)
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/ib/api.py`
|
|
||||||
|
|
||||||
Generated: in `load_aio_clients()`, when `client_id`
|
|
||||||
is the 6116 default: `datad`-named actors offset +16
|
|
||||||
(disjoint from `brokerd`'s linear `client_id + i`
|
|
||||||
retry range), other non-`brokerd` (ad-hoc test/cli)
|
|
||||||
actors +32. Rationale from the plan's risk register:
|
|
||||||
post-split BOTH per-broker daemons connect to the same
|
|
||||||
TWS/gw endpoint; a shared default id collides and
|
|
||||||
burns up to `connect_timeout * retries` (90s) in
|
|
||||||
retry cycles.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/cli/__init__.py`
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T17:33:09Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T173309Z_f15f8178_prompt_io.md
|
|
||||||
scope: docs
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T173309Z_f15f8178_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The session-initiating instruction, verbatim (this doc
|
|
||||||
IS its "mega detailed plan" deliverable):
|
|
||||||
|
|
||||||
> ok i want you to become the distributed runtime and
|
|
||||||
> concurrency expert for this project - namely acquire
|
|
||||||
> a deep understanding of tractor and how it's used.
|
|
||||||
> then i want you to atttempt to factor our current
|
|
||||||
> brokerd service daemon into 2 daemons:
|
|
||||||
>
|
|
||||||
> - a brokerd which only hosts live/paper trading
|
|
||||||
> endoint tasks as defined namely within all
|
|
||||||
> piker/brokers/<backend>/broker.py mods
|
|
||||||
> - a new `datad` subdaemon which in a separate
|
|
||||||
> subactor serves all the data feed service tasks
|
|
||||||
> namely delivered by endpoints in
|
|
||||||
> piker/brokers/<backend>/feed.py (or similar for
|
|
||||||
> less mature backends) and as more rigorously
|
|
||||||
> defined by the validation machinery in
|
|
||||||
> piker.data.validate.
|
|
||||||
>
|
|
||||||
> give me a mega detailed plan on how to approach
|
|
||||||
> this, and a staged approach for the implementation.
|
|
||||||
|
|
||||||
Plan-shaping user decisions (in-session Q&A): sibling
|
|
||||||
topology under `pikerd`; hard cutover staged by layer;
|
|
||||||
trading-only EMS-lazy-spawned `brokerd`. The human
|
|
||||||
staged the doc copy into `ai/claude-code/plans/` and
|
|
||||||
requested this commit after the 7 implementation
|
|
||||||
commits landed.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
The staged design doc for the `brokerd` -> (`datad` +
|
|
||||||
`brokerd`) split: context, target supervision topology,
|
|
||||||
load-bearing verified facts, per-stage file-level
|
|
||||||
changes with gates, risk register and an end-to-end
|
|
||||||
verification matrix. Produced via 3 parallel explore
|
|
||||||
agents + 1 architect agent + human Q&A before any code
|
|
||||||
was written; all 7 implementation commits in this
|
|
||||||
branch reference its stages in their provenance
|
|
||||||
entries.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `ai/claude-code/plans/datad_service.md` — the design
|
|
||||||
plan doc (human-staged copy of the AI-authored plan)
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None to the doc content — committed as generated. NB:
|
|
||||||
the implementation deviated from the plan-as-written in
|
|
||||||
4 places, see the raw file's deviation log.
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T17:33:09Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T173309Z_f15f8178_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry; the AI output here is the
|
|
||||||
committed doc itself (a design plan, not code) so no
|
|
||||||
verbatim copy is duplicated:
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- ai/claude-code/plans/datad_service.md`
|
|
||||||
|
|
||||||
## Implementation deviation log
|
|
||||||
|
|
||||||
Where the landed 7-commit series differs from the plan
|
|
||||||
as written (recorded for reviewer transparency; the
|
|
||||||
plan doc is committed unmodified):
|
|
||||||
|
|
||||||
1. Commit ordering: the `pytest` config-dir isolation
|
|
||||||
fix lands BEFORE the `tractor`-API drift port. The
|
|
||||||
plan's stage gates assumed a runnable+isolated test
|
|
||||||
baseline; per-commit gating exposed that without
|
|
||||||
isolation the paper-EMS test reads the user's real
|
|
||||||
(polluted) `account.kraken.paper.toml` and reddens.
|
|
||||||
2. The plan's "stage 0: full pytest green" gate
|
|
||||||
required first repairing pre-existing branch
|
|
||||||
breakage vs `tractor` git `main` (boot
|
|
||||||
`AttributeError`, stale discovery/exc/position
|
|
||||||
APIs) — that repair became its own commit
|
|
||||||
("Port service+tests to latest `tractor` APIs")
|
|
||||||
rather than plan-stage work.
|
|
||||||
3. Stage-4 fail-fast placement: the plan said
|
|
||||||
`broker_init()` raises on brokerd-ep-less backends;
|
|
||||||
implementation moved the raise to `spawn_brokerd()`
|
|
||||||
since `piker ledger` calls `broker_init()` directly
|
|
||||||
even for paper accounts on datad-only backends.
|
|
||||||
4. `brokers/_daemon.py` change grouping: the
|
|
||||||
import-cleanup hunks (`exceptiongroup`, `_FeedsBus`
|
|
||||||
type-only import) landed with the caps-sec slim
|
|
||||||
commit instead of the fixture-slim commit, keeping
|
|
||||||
each intermediate tree import-clean without
|
|
||||||
sub-hunk surgery.
|
|
||||||
|
|
||||||
Also of record: the plan's "Verification" matrix was
|
|
||||||
executed as written (per-suite gates each stage, the
|
|
||||||
headless datad-feed smoke, the kucoin fail-fast unit
|
|
||||||
check); the known pre-existing ~50% second-runtime-boot
|
|
||||||
test wedge was characterized and excluded as a
|
|
||||||
regression via revert-testing.
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
|
||||||
timestamp: 2026-06-10T21:35:49Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T213549Z_f084e899_prompt_io.md
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260610T213549Z_f084e899_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
User bug report from live `ib` testing of the
|
|
||||||
(datad|brokerd)-split branch:
|
|
||||||
|
|
||||||
> ok doing some testing and noticing live orders do not
|
|
||||||
> work otb, pikerd show this on live submission,
|
|
||||||
> [pdb traceback: `RuntimeError("Can not order
|
|
||||||
> {symbol}, no live feed?")` at `ib/api.py:1152`
|
|
||||||
> `submit_limit()` with `self._contracts == {}` in the
|
|
||||||
> `brokerd.ib` actor + a `TrioTaskExited` teardown
|
|
||||||
> cascade]
|
|
||||||
|
|
||||||
Follow-up user direction fixing the design intent:
|
|
||||||
|
|
||||||
> i think the main thing here is that [brokerd] should
|
|
||||||
> be able to always submit orders without a live feed
|
|
||||||
> being up and registered in the same subactor right?
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Root cause: pre-split the feed code populated the
|
|
||||||
actor-local `Client._contracts` cache (via
|
|
||||||
`get_mkt_info()` writing `mkt.bs_fqme` keys) in the
|
|
||||||
SAME process as order submission; post-split the
|
|
||||||
trading actor's client is never warmed. Fix: lazily
|
|
||||||
qualify + cache the contract per order request in
|
|
||||||
`handle_order_requests()` by running the same
|
|
||||||
`get_mkt_info(fqme, proxy=...)` ep the feed side uses,
|
|
||||||
plus per-order error relay (`BrokerdError`) so one bad
|
|
||||||
submission can't crash the whole trades dialog (the
|
|
||||||
`TrioTaskExited` storm was teardown cascade from the
|
|
||||||
original raise).
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/brokers/ib/broker.py` — thread `proxies` into
|
|
||||||
`handle_order_requests()`; lazy contract qualify on
|
|
||||||
cache-miss; guard `submit_limit()` w/ `BrokerdError`
|
|
||||||
relay; uncomment the (anticipatory) `get_mkt_info`
|
|
||||||
import
|
|
||||||
- `piker/brokers/ib/api.py` — fix the non-f-string
|
|
||||||
raise msg + document the new qualification contract
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None — committed as generated. Live `ib` order retest
|
|
||||||
performed by the human post-commit.
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
---
|
|
||||||
model: claude-fable-5[1m]
|
|
||||||
service: claude
|
|
||||||
timestamp: 2026-06-10T21:35:49Z
|
|
||||||
git_ref: datad_service
|
|
||||||
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T213549Z_f084e899_prompt_io.md
|
|
||||||
---
|
|
||||||
|
|
||||||
NOTE: diff-ref mode entry (code committed in the same
|
|
||||||
commit as this log); recorded from the live debug
|
|
||||||
session per the `/prompt-io` skill rules.
|
|
||||||
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/ib/broker.py`
|
|
||||||
> `git log -1 -p --follow -- piker/brokers/ib/api.py`
|
|
||||||
|
|
||||||
Key diagnostic chain (from session):
|
|
||||||
|
|
||||||
- pdb showed `Client._contracts == {}` inside
|
|
||||||
`brokerd.ib`'s `submit_limit()`; the cache has
|
|
||||||
exactly TWO write sites: `Client.find_contracts()`
|
|
||||||
(api.py, keys `f'{sym}.{exch}.ib'`) and
|
|
||||||
`symbols.get_mkt_info()` (key `mkt.bs_fqme`, eg.
|
|
||||||
'nvda.nasdaq' — NO `.ib` suffix).
|
|
||||||
- `BrokerdOrder.symbol` arrives as the bs_fqme form
|
|
||||||
('nvda.nasdaq') so ONLY the `get_mkt_info()` write
|
|
||||||
site produces the key `submit_limit()` reads —
|
|
||||||
ie. pre-split it was the feed's in-proc
|
|
||||||
`get_mkt_info(sym, proxy=proxy)` call keeping orders
|
|
||||||
working, NOT `find_contracts()`.
|
|
||||||
- the existing TODO at `symbols.py:642-644` literally
|
|
||||||
predicted this: "this is going to be problematic
|
|
||||||
if/when we split out the datad vs. brokerd actors
|
|
||||||
since the mktmap lookup table will now be
|
|
||||||
inaccessible.."
|
|
||||||
- instance identity verified: `proxy._aio_ns` IS the
|
|
||||||
same `Client` obj as `_accounts2clients[account]`
|
|
||||||
(both sourced from the `load_aio_clients()` cache via
|
|
||||||
`open_client_proxies()`), so a brokerd-side
|
|
||||||
`get_mkt_info(fqme, proxy=proxies[account])` warms
|
|
||||||
exactly the dict `submit_limit()` reads. It also
|
|
||||||
populates `client._cons2mkts` which the
|
|
||||||
position-audit path (`broker.py` backup-table code)
|
|
||||||
needs in this actor anyway.
|
|
||||||
- the `TrioTaskExited` storm in the user's log
|
|
||||||
(`recv_trade_updates`, `open_aio_client_method_relay`
|
|
||||||
aio tasks) is teardown cascade: the raise crashed
|
|
||||||
`handle_order_requests` -> nursery teardown ripped
|
|
||||||
the trio sides of still-running aio relay tasks.
|
|
||||||
Hence the added per-order try/except ->
|
|
||||||
`BrokerdError` relay hardening so a single bad
|
|
||||||
submission degrades to an EMS error msg instead of
|
|
||||||
killing the backend's entire order-ctl dialog.
|
|
||||||
|
|
||||||
Verification: `tests/test_services.py` (5 passed) +
|
|
||||||
`tests/test_ems.py` (6 passed) regression-green; live
|
|
||||||
`ib` submission retest delegated to the human (needs a
|
|
||||||
running TWS/gw).
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
# AI Prompt I/O Log — claude
|
|
||||||
|
|
||||||
This directory tracks prompt inputs and model
|
|
||||||
outputs for AI-assisted development using
|
|
||||||
`claude` (claude-code CLI).
|
|
||||||
|
|
||||||
## Policy
|
|
||||||
|
|
||||||
Prompt logging follows the
|
|
||||||
[NLNet generative AI policy][nlnet-ai].
|
|
||||||
All substantive AI contributions are logged
|
|
||||||
with:
|
|
||||||
- Model name and version
|
|
||||||
- Timestamps
|
|
||||||
- The prompts that produced the output
|
|
||||||
- Unedited model output (`.raw.md` files)
|
|
||||||
|
|
||||||
[nlnet-ai]: https://nlnet.nl/foundation/policies/generativeAI/
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Entries are created by the `/prompt-io` skill
|
|
||||||
or automatically via `/commit-msg` integration.
|
|
||||||
|
|
||||||
Each commit carrying AI-generated changes links
|
|
||||||
to its provenance entry via a `Prompt-IO:`
|
|
||||||
commit-msg trailer; entries use "diff-ref mode"
|
|
||||||
(pointers into `git log -p` instead of verbatim
|
|
||||||
code copies) to avoid duplicating committed
|
|
||||||
code.
|
|
||||||
|
|
||||||
Human contributors remain accountable for all
|
|
||||||
code decisions. AI-generated content is never
|
|
||||||
presented as human-authored work.
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-6 (exact variant not exposed)
|
|
||||||
service: codex
|
|
||||||
session: fsp-session-recovery-takeover-20260915
|
|
||||||
timestamp: 2026-09-15T15:52:29Z
|
|
||||||
git_ref: fadab3d2
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260915T155229Z_fadab3d2_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Recover the interrupted OpenCode FSP session and take over its ongoing
|
|
||||||
work. The recovered child instruction records human authorization for
|
|
||||||
the minimal EMA omitted-default fix followed by a complete commit plan.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Removed the eager Numba signature that rejected Python's omitted
|
|
||||||
default arguments. Preserved nopython/nogil compilation and numerical
|
|
||||||
behavior. Added nine numerical regressions and verified all 38 focused
|
|
||||||
FSP cases. Rebuilt planning artifacts separately from production code.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/fsp/_momo.py`: drop the eager signature and unused type imports.
|
|
||||||
- `tests/test_fsp_momo.py`: omitted/explicit argument and seed coverage.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
The human identified the omitted-default limitation in the earlier
|
|
||||||
session, authorized the minimal lazy-specialization approach, and
|
|
||||||
requested this takeover after OpenCode failed. Existing source changes
|
|
||||||
and older OpenCode provenance were retained. The new fix remains
|
|
||||||
unstaged and awaits human review; no acceptance is inferred.
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-6 (exact variant not exposed)
|
|
||||||
service: codex
|
|
||||||
timestamp: 2026-09-15T15:52:29Z
|
|
||||||
git_ref: fadab3d2
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
> i'm thinking maybe you can just take over that work and we can
|
|
||||||
> abandon that oc dialog for now?
|
|
||||||
|
|
||||||
Recovered child-session instructions describe the earlier human
|
|
||||||
authorization to remove EMA's eager Numba signature while retaining
|
|
||||||
`jit(nopython=True, nogil=True)`, verify defaults, and finish the commit
|
|
||||||
plan without staging or committing. This is recovered context, not a
|
|
||||||
verbatim quote of the earlier human authorization.
|
|
||||||
|
|
||||||
## Response
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/fsp/_momo.py`
|
|
||||||
|
|
||||||
Removed EMA's eager Numba signature and now-unused Numba type imports.
|
|
||||||
Retained nopython/nogil compilation, the numerical kernel, historical
|
|
||||||
comments, and pre-existing staged and unstaged edits.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_fsp_momo.py`
|
|
||||||
|
|
||||||
Added production-dispatcher regressions for omitted positional and
|
|
||||||
keyword arguments, explicit None and numeric parameters, and the
|
|
||||||
previously corrected one-sample continuation. Expected outputs are
|
|
||||||
hand-computed recurrences, rather than the Python implementation.
|
|
||||||
|
|
||||||
Before the fix, the first case failed with:
|
|
||||||
|
|
||||||
```text
|
|
||||||
TypeError: No matching definition for argument type(s)
|
|
||||||
array(float64, 1d, C), omitted(default=None), omitted(default=None)
|
|
||||||
```
|
|
||||||
|
|
||||||
After the fix, the focused run outside the socket-restricted sandbox
|
|
||||||
reported:
|
|
||||||
|
|
||||||
```text
|
|
||||||
38 passed in 0.66s
|
|
||||||
```
|
|
||||||
|
|
||||||
Ruff passed for the modified momentum module and new regression file.
|
|
||||||
Combined-worktree results do not attest to isolated commit boundaries.
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
# AI Prompt I/O Log — codex
|
|
||||||
|
|
||||||
This directory tracks prompts and outputs for AI-assisted development
|
|
||||||
using Codex. Substantive contributions include model identification,
|
|
||||||
prompt context, output records, and human contribution accounting.
|
|
||||||
|
|
||||||
Code output uses Git diff references; non-code output is retained in
|
|
||||||
the paired `.raw.md` file. Human contributors remain responsible for
|
|
||||||
review and acceptance. Entries follow the
|
|
||||||
[NLNet generative AI policy](https://nlnet.nl/foundation/policies/generativeAI/).
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-21T20:52:28Z
|
|
||||||
git_ref: 58ffe487
|
|
||||||
scope: config
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260721T205228Z_58ffe487_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user asked to scan Claude's repo-local skills and
|
|
||||||
documentation, summarize their specializations, and then
|
|
||||||
rework repo-specific skills for use across coding
|
|
||||||
harnesses, particularly OpenCode. The user intends to
|
|
||||||
choose one of Claude's unfinished tasks afterward.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Standardized the tracked piker skills on portable Agent
|
|
||||||
Skills frontmatter, made `commit-msg` harness-aware,
|
|
||||||
documented OpenCode discovery and command delegation, and
|
|
||||||
fixed an unsafe `np.searchsorted()` example found during
|
|
||||||
the audit. Preserved the existing `.claude` artifact path
|
|
||||||
as a shared legacy location to avoid breaking established
|
|
||||||
commit workflows.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `.claude/skills/commit-msg/SKILL.md` - portable,
|
|
||||||
harness-aware commit-message workflow
|
|
||||||
- `.claude/skills/commit-msg/style-guide-reference.md` -
|
|
||||||
generic coding-harness attribution
|
|
||||||
- `.claude/skills/piker-conc-expert/SKILL.md` - portable
|
|
||||||
frontmatter
|
|
||||||
- `.claude/skills/piker-profiling/SKILL.md` - portable
|
|
||||||
frontmatter
|
|
||||||
- `.claude/skills/piker-slang/SKILL.md` - portable
|
|
||||||
frontmatter
|
|
||||||
- `.claude/skills/pyqtgraph-optimization/SKILL.md` -
|
|
||||||
portable frontmatter
|
|
||||||
- `.claude/skills/timeseries-optimization/SKILL.md` -
|
|
||||||
portable frontmatter and safe search bounds handling
|
|
||||||
- `ai/README.md` - shared-skill integration model
|
|
||||||
- `ai/claude-code/README.md` - cross-harness Claude Code
|
|
||||||
documentation
|
|
||||||
- `ai/opencode/README.md` - OpenCode usage and discovery
|
|
||||||
documentation
|
|
||||||
- `.opencode/commands/commit-msg.md` - thin OpenCode
|
|
||||||
command delegating to the shared skill
|
|
||||||
- `ai/prompt-io/opencode/README.md` - OpenCode provenance
|
|
||||||
policy
|
|
||||||
- `ai/prompt-io/opencode/20260721T205228Z_58ffe487_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260721T205228Z_58ffe487_prompt_io.md`
|
|
||||||
- provenance metadata and summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not yet been reviewed or
|
|
||||||
edited by the human.
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-21T20:52:28Z
|
|
||||||
git_ref: 58ffe487
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The repo-local skill inventory contains seven domains:
|
|
||||||
commit-message generation, actor-runtime concurrency,
|
|
||||||
distributed profiling, project communication style,
|
|
||||||
Python source style, PyQtGraph rendering, and NumPy/Polars
|
|
||||||
timeseries optimization.
|
|
||||||
|
|
||||||
I converted the six tracked repo-specific skills to the
|
|
||||||
portable Agent Skills frontmatter subset so Claude Code
|
|
||||||
and OpenCode can load the same source files. The
|
|
||||||
commit-message workflow now gathers live git context at
|
|
||||||
execution time, uses runtime harness/model attribution,
|
|
||||||
preserves human-owned task state, and keeps the existing
|
|
||||||
message artifact paths for compatibility.
|
|
||||||
|
|
||||||
I added OpenCode integration documentation and updated
|
|
||||||
the shared and Claude Code docs to describe a single
|
|
||||||
cross-harness skill source with thin harness commands.
|
|
||||||
During validation I also corrected an out-of-bounds
|
|
||||||
`np.searchsorted()` example in the timeseries skill.
|
|
||||||
|
|
||||||
The unfinished artifacts found during the scan are a
|
|
||||||
shared-memory migration plan and a gap-annotation
|
|
||||||
performance handoff. The earlier datad split plan appears
|
|
||||||
implemented and is now captured by the concurrency skill.
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-21T21:50:55Z
|
|
||||||
git_ref: c6ec3d41
|
|
||||||
scope: docs
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260721T215055Z_c6ec3d41_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user asked to boot a plan to continue work on the
|
|
||||||
time-series gap checker and bug fixing of the history
|
|
||||||
backfiller. The user authorized prompt-I/O capture for the
|
|
||||||
plan documentation after the repository audit.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Produced a bounded repair plan based on current source,
|
|
||||||
historical issue caches, existing profiling notes, and a
|
|
||||||
test-coverage audit. The plan prioritizes reproducible
|
|
||||||
correctness failures and storage durability before venue
|
|
||||||
classification, annotation performance, or manual repair
|
|
||||||
UX.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `plans/opencode/gap-checker-backfiller-repair.md` -
|
|
||||||
phased implementation and verification plan
|
|
||||||
- `ai/prompt-io/opencode/20260721T215055Z_c6ec3d41_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260721T215055Z_c6ec3d41_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated plan has not yet been edited by the
|
|
||||||
human.
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-21T21:50:55Z
|
|
||||||
git_ref: c6ec3d41
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff -- plans/opencode/gap-checker-backfiller-repair.md`
|
|
||||||
|
|
||||||
Generated a phased implementation plan for continuing
|
|
||||||
piker's gap checker and history backfiller repairs. The
|
|
||||||
plan separates data correctness from annotation
|
|
||||||
performance and orders work by dependency: deterministic
|
|
||||||
tests, canonical frame/gap normalization, structured
|
|
||||||
backfill completion, non-destructive atomic NativeDB
|
|
||||||
writes, exact null repair, provider/venue classification,
|
|
||||||
annotation vectorization, and crash qualification.
|
|
||||||
|
|
||||||
The plan is grounded in current code paths, local issue
|
|
||||||
caches `#62`, `#71`, and `#75`, and the existing 1,285-gap
|
|
||||||
profiling handoff. It records confirmed present defects,
|
|
||||||
design invariants, per-phase acceptance gates, test
|
|
||||||
commands, commit boundaries, and explicitly deferred UX
|
|
||||||
and provider work.
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-22T00:13:57Z
|
|
||||||
git_ref: 16f3cd6f
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260722T001357Z_16f3cd6f_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Continue the gap-checker and history-backfiller repair plan. Start
|
|
||||||
with deterministic analysis characterization, then fix canonical
|
|
||||||
sorting, dedupe-derived columns, positive gap detection, and null
|
|
||||||
grouping.
|
|
||||||
|
|
||||||
During review, the user challenged the replacement null-grouping
|
|
||||||
algorithm because its initial tests did not assert exact endpoints.
|
|
||||||
The user explicitly required retaining detailed, human-oriented
|
|
||||||
algorithm documentation such as the existing ASCII segment map.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Added deterministic analysis regressions and corrected normalization
|
|
||||||
so sorting and duplicate resolution precede derived-column
|
|
||||||
calculation. Unified null grouping for NumPy and Polars inputs,
|
|
||||||
documented its exact inclusive-boundary contract with an adapted
|
|
||||||
visual map, and verified all small null layouts against an independent
|
|
||||||
state-machine oracle. Retained sorted smart-dedupe output.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/tsp/_anal.py` - canonical gap and documented null grouping
|
|
||||||
- `piker/tsp/_dedupe_smart.py` - sorted duplicate resolution
|
|
||||||
- `tests/test_tsp_analysis.py` - exact and exhaustive regressions
|
|
||||||
- `ai/prompt-io/opencode/20260722T001357Z_16f3cd6f_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260722T001357Z_16f3cd6f_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not yet been edited by the human.
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-22T00:13:57Z
|
|
||||||
git_ref: 16f3cd6f
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_anal.py`
|
|
||||||
|
|
||||||
Generated canonical gap and null-segment normalization. Derived
|
|
||||||
datetime and delta columns are recomputed after final sorting and
|
|
||||||
duplicate resolution, and negative deltas no longer become ordinary
|
|
||||||
gaps.
|
|
||||||
|
|
||||||
NumPy and Polars null grouping share one implementation while
|
|
||||||
retaining the human-oriented visual map of contiguous zero runs. The
|
|
||||||
documented contract defines absolute inclusive endpoints, margin
|
|
||||||
expansion, frame boundary clamping, contiguous-index validation, and
|
|
||||||
requested-column selection.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_dedupe_smart.py`
|
|
||||||
|
|
||||||
Adjusted smart dedupe to honor sorted output and resolve duplicate
|
|
||||||
timestamps without retaining stale order.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_tsp_analysis.py`
|
|
||||||
|
|
||||||
Added deterministic synthetic OHLCV coverage for sorted dedupe, fresh
|
|
||||||
derived columns, and positive gap detection. Null grouping is checked
|
|
||||||
against readable endpoint examples and an independent state-machine
|
|
||||||
oracle over every layout through six rows, three margin widths, and
|
|
||||||
both NumPy and Polars inputs.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
`timeout -k 5 30 python -m pytest -q tests/test_tsp_analysis.py`
|
|
||||||
|
|
||||||
Result: 11 passed.
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-22T00:13:58Z
|
|
||||||
git_ref: 16f3cd6f
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260722T001358Z_16f3cd6f_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Continue the structured backfill phase after the analysis regressions.
|
|
||||||
Characterize provider exhaustion and genuinely empty frames, then remove
|
|
||||||
completion paths that can hang after child-task exit.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Removed orphan-prone completion events from the structured nursery flow
|
|
||||||
and checked empty provider frames before indexing timestamp endpoints.
|
|
||||||
Added deterministic timeout-bounded regressions for both exit paths.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/tsp/_history.py` - structured completion and empty-frame fixes
|
|
||||||
- `tests/test_history_backfill.py` - deterministic exit regressions
|
|
||||||
- `ai/prompt-io/opencode/20260722T001358Z_16f3cd6f_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260722T001358Z_16f3cd6f_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not yet been edited by the human.
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-22T00:13:58Z
|
|
||||||
git_ref: 16f3cd6f
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_history.py`
|
|
||||||
|
|
||||||
Removed redundant completion events whose consumers waited only after
|
|
||||||
their owning nurseries had joined. Added empty provider-frame handling
|
|
||||||
before timestamp endpoint indexing so provider exhaustion exits cleanly.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_history_backfill.py`
|
|
||||||
|
|
||||||
Added bounded, actor-free regressions for `DataUnavailable` and empty
|
|
||||||
provider-frame completion.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
`timeout -k 5 60 python -m pytest -q tests/test_history_backfill.py`
|
|
||||||
|
|
||||||
Result: 2 passed.
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-22T02:41:33Z
|
|
||||||
git_ref: 3a4f6737
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260722T024133Z_3a4f6737_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user challenged the analysis commit message's claim that only
|
|
||||||
positive sample-step gaps are detected and asked whether out-of-order
|
|
||||||
timestamps were simply ignored. After confirming the missing separate
|
|
||||||
reporting path, the user instructed the agent to implement the fix.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Separated missing-history gaps from timestamp-ordering errors without
|
|
||||||
changing the existing `dedupe()` return shape. Added a structured
|
|
||||||
detector and made normalization warn before sorting removes evidence of
|
|
||||||
duplicates or reversed timestamps.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/tsp/_anal.py` - ordering detector and dedupe reporting
|
|
||||||
- `piker/tsp/__init__.py` - public detector export
|
|
||||||
- `tests/test_tsp_analysis.py` - exact ordering-error regression
|
|
||||||
- `ai/prompt-io/opencode/20260722T024133Z_3a4f6737_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260722T024133Z_3a4f6737_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not yet been edited by the human.
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-22T02:41:33Z
|
|
||||||
git_ref: 3a4f6737
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_anal.py`
|
|
||||||
|
|
||||||
Added `detect_time_ordering_errors()` to return non-positive timestamp
|
|
||||||
steps as structured rows. `dedupe()` now warns with those rows before
|
|
||||||
sorting and duplicate removal erase the original ordering evidence.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/__init__.py`
|
|
||||||
|
|
||||||
Exported the ordering detector through the public TSP package.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_tsp_analysis.py`
|
|
||||||
|
|
||||||
Changed the negative-delta regression to verify exact predecessor,
|
|
||||||
timestamp, and delta values, confirm exclusion from missing-history
|
|
||||||
gaps, and require explicit normalization reporting.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- `tests/test_tsp_analysis.py`: 11 passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-22T02:41:34Z
|
|
||||||
git_ref: 3a4f6737
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260722T024134Z_3a4f6737_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user asked why the in-progress `piker/storage` changes were omitted
|
|
||||||
from the earlier commit plan. After receiving an inventory of unfinished
|
|
||||||
Phase 3 requirements, the user instructed the agent to complete the work.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Finished non-destructive, atomic NativeDB updates and integrated them
|
|
||||||
with history startup and reverse backfill. Expanded tests through two
|
|
||||||
adversarial review rounds that caught and corrected cross-client lock
|
|
||||||
blocking, stale temp indexing, discontinuous persisted indexes, startup
|
|
||||||
snapshot races, missing latest-frame persistence, notification wedges,
|
|
||||||
and mutable/truncated SHM persistence.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/__init__.py` - incremental storage contract
|
|
||||||
- `piker/storage/nativedb.py` - validated atomic merge persistence
|
|
||||||
- `piker/storage/marketstore/__init__.py` - non-duplicate update mode
|
|
||||||
- `piker/tsp/_history.py` - provider-delta and startup persistence
|
|
||||||
- `tests/test_storage_nativedb.py` - NativeDB durability regressions
|
|
||||||
- `tests/test_history_backfill.py` - persistence lifecycle regressions
|
|
||||||
- `ai/prompt-io/opencode/20260722T024134Z_3a4f6737_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260722T024134Z_3a4f6737_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not yet been edited by the human.
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-22T02:41:34Z
|
|
||||||
git_ref: 3a4f6737
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/__init__.py piker/storage/nativedb.py piker/storage/marketstore/__init__.py`
|
|
||||||
|
|
||||||
Added an incremental storage update contract. NativeDB now validates
|
|
||||||
canonical numeric OHLCV data, serializes writers both actor-locally and
|
|
||||||
through cancellable filesystem locks, merges with incoming-wins seam
|
|
||||||
resolution, regenerates contiguous indexes, reopens and validates a
|
|
||||||
same-directory temporary parquet, fsyncs it, atomically replaces the
|
|
||||||
target, fsyncs the directory, and publishes cache only after replacement.
|
|
||||||
|
|
||||||
NativeDB indexing ignores lock and crash-left temporary files.
|
|
||||||
MarketStore uses its non-duplicate write mode for incremental updates.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_history.py`
|
|
||||||
|
|
||||||
Separated full provider deltas from capacity-truncated SHM pushes.
|
|
||||||
Backfill persists before SHM mutation, publishes bounded notifications,
|
|
||||||
and delays latest-frame publication until the concurrent pre-update
|
|
||||||
storage snapshot completes.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_storage_nativedb.py tests/test_history_backfill.py`
|
|
||||||
|
|
||||||
Added deterministic coverage for merge preservation, conflict policy,
|
|
||||||
atomic failures, reopened-candidate validation, cache consistency,
|
|
||||||
schema and timestamp invariants, contiguous index regeneration,
|
|
||||||
separate series, stale temp indexing, cancellable file-lock contention,
|
|
||||||
full provider-delta persistence, latest-frame ordering, and bounded
|
|
||||||
notification teardown.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- deterministic analysis/backfill/storage set: 31 passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
- final adversarial review: no findings
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: ses_092a25886ffeT0nrIrdkMEcgJK
|
|
||||||
timestamp: 2026-07-24T22:01:56Z
|
|
||||||
git_ref: flake_update
|
|
||||||
scope: config
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260724T220156Z_43d7a3ed_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
After committing Piker's provider-neutral deployment, the user asked to
|
|
||||||
extract Piker-specialized `/run-tests` content from the historical
|
|
||||||
`wkt/run_tests_skill` implementation into the new deployment.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Create a repository-owned `test-harness-reference.md` for the canonical Run
|
|
||||||
base. Revalidate historical commands and assumptions against current pytest,
|
|
||||||
uv/Nix environments, tests, fixtures, and Tractor runtime behavior, retaining
|
|
||||||
only current Piker-specific guidance.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md` - define Piker's safe
|
|
||||||
commands, opt-in boundaries, mappings, known outcomes, and runtime notes.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None at generation time; pending human review.
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-24T22:01:56Z
|
|
||||||
git_ref: flake_update
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user asked to extract useful Piker-specific `/run-tests` behavior from
|
|
||||||
`wkt/run_tests_skill` after committing the provider-neutral deployment.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Generate a repository-owned harness reference rather than restoring the old
|
|
||||||
standalone `SKILL.md`. Preserve verified Piker-specific environment, command,
|
|
||||||
scope, fixture, test-layout, change-mapping, known-outcome, and Tractor-runtime
|
|
||||||
details while leaving shared execution and cleanup policy in the canonical
|
|
||||||
`ai.skillz` base.
|
|
||||||
|
|
||||||
Repository inspection found that the historical skill needs correction:
|
|
||||||
|
|
||||||
- the comments-only `pytest.ini` shadows `pyproject.toml` pytest options, so
|
|
||||||
`-p no:xonsh` must be explicit;
|
|
||||||
- no marker-based offline suite exists, and several live/GUI/container tests
|
|
||||||
are unsafe defaults;
|
|
||||||
- skipped Docker and Questrade modules can fail during import before marks;
|
|
||||||
- actor timeout retry remains relevant only for the exact timed-out command;
|
|
||||||
- `py313` and frozen no-sync `uv run` are the current local environment paths.
|
|
||||||
|
|
||||||
Validate with checkout import resolution, safe collection, and deterministic
|
|
||||||
watchlist/accounting tests. Do not run live broker, GUI, container,
|
|
||||||
credentialed, or user-config-dependent cases during harness verification.
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: unavailable
|
|
||||||
timestamp: 2026-07-27T20:47:11Z
|
|
||||||
git_ref: 84a6d47b
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260727T204711Z_84a6d47b_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user identified that `backfiller_deep_fixes` introduced persistent
|
|
||||||
`.parquet.lock` files, questioned whether Parquet or Arrow already handled
|
|
||||||
writer coordination, and clarified that piker's `tractor` structured
|
|
||||||
concurrency design already provides single-writer ownership through the
|
|
||||||
persistent `datad` feed task. The user then asked to open the backfiller
|
|
||||||
worktree and resolve the redundant locking.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Removed redundant actor-local and filesystem locking while preserving
|
|
||||||
atomic crash-safe Parquet replacement. Replaced the synthetic contention
|
|
||||||
test with regressions for the actual cross-branch failure: writes create
|
|
||||||
no lock sidecars, and legacy lock artifacts are ignored during indexing.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/nativedb.py` - rely on `datad` writer ownership
|
|
||||||
- `tests/test_storage_nativedb.py` - lock-sidecar regressions
|
|
||||||
- `ai/prompt-io/opencode/20260727T204711Z_84a6d47b_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260727T204711Z_84a6d47b_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-27T20:47:11Z
|
|
||||||
git_ref: 84a6d47b
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/nativedb.py`
|
|
||||||
|
|
||||||
Removed actor-local and filesystem writer locks from NativeDB. The
|
|
||||||
persistent `datad` feed task already owns writes for each series, while
|
|
||||||
its timeframe children write distinct files. NativeDB retains validated
|
|
||||||
temporary writes, file and directory synchronization, and atomic target
|
|
||||||
replacement for crash durability. The exact `.parquet` suffix filter is
|
|
||||||
retained so legacy lock sidecars are harmless.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_storage_nativedb.py`
|
|
||||||
|
|
||||||
Removed the synthetic cross-client lock-contention test. Added regression
|
|
||||||
coverage proving replacement and incremental writes create no lock
|
|
||||||
sidecars. Extended indexing coverage with the legacy
|
|
||||||
`.parquet.lock` artifact that caused upstream `flake_update` to crash.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- NativeDB and history regression set: 20 passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-27T21:24:54Z
|
|
||||||
git_ref: 689df816
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260727T212454Z_689df816_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user reran the known IB FQME on `backfiller_deep_fixes` and reported
|
|
||||||
that `publish_latest_frame()` still failed because NativeDB required an
|
|
||||||
`index` absent from IB's provider frame. The user called out the missed
|
|
||||||
tabular schema boundary and requested an actual end-to-end test suite
|
|
||||||
rather than storage fakes.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Repaired the IB-provider-to-NativeDB boundary by canonicalizing durable
|
|
||||||
fields and mapping reloads into provider-specific SHM buffers. Added a
|
|
||||||
local actor/SHM/Parquet integration regression covering first startup and
|
|
||||||
restart, plus focused conversion and timestamp-coercion tests. Two review
|
|
||||||
rounds found and resolved restart hydration and fractional-time hazards.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/nativedb.py` - canonical storage and SHM field mapping
|
|
||||||
- `piker/tsp/_anal.py` - name-based Polars-to-NumPy conversion
|
|
||||||
- `tests/test_history_backfill.py` - actor/SHM/Parquet integration test
|
|
||||||
- `tests/test_storage_nativedb.py` - schema conversion regressions
|
|
||||||
- `ai/prompt-io/opencode/20260727T212454Z_689df816_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260727T212454Z_689df816_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-27T21:24:54Z
|
|
||||||
git_ref: 689df816
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/nativedb.py piker/tsp/_anal.py`
|
|
||||||
|
|
||||||
Normalized index-less provider frames to NativeDB's canonical names,
|
|
||||||
order, and dtypes before merge and publication. Provider-only columns
|
|
||||||
are excluded from durable files, derived indexes are regenerated, and
|
|
||||||
fractional timestamps are rejected before integer conversion. Added a
|
|
||||||
canonical field map for hydrating provider-specific SHM buffers while
|
|
||||||
leaving provider-only fields at their defaults. Changed Polars-to-NumPy
|
|
||||||
conversion to select columns by field name rather than position.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_history_backfill.py tests/test_storage_nativedb.py`
|
|
||||||
|
|
||||||
Added deterministic coverage using IB's actual provider dtype and a real
|
|
||||||
local `tractor` root actor, IB-typed shared-memory buffers, NativeDB,
|
|
||||||
Parquet persistence, first-start publication, and restart hydration.
|
|
||||||
Added focused regressions for reordered/extra Polars columns and
|
|
||||||
fractional timestamp rejection.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- NativeDB and history integration set: 23 passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
- second adversarial review: no findings
|
|
||||||
- no live gateway or network tests run
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-27T21:59:06Z
|
|
||||||
git_ref: 689df816
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260727T215906Z_689df816_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
After the actor/SHM/Parquet integration test exposed a stale SHM triplet,
|
|
||||||
the user requested leak-cleaner machinery in the pytest harness using
|
|
||||||
Tractor's existing ownership and lifetime patterns.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Added creator-scoped SHM leak tracking to pytest without scanning
|
|
||||||
`/dev/shm` or treating attachments as owned. The fixture cooperates with
|
|
||||||
normal Tractor teardown, verifies POSIX object identity before fallback
|
|
||||||
cleanup, restores process-local token state, and fails after cleaning a
|
|
||||||
leak. Regressions cover the exact pre-actor-registration allocation window,
|
|
||||||
positional creators, and external attachment safety.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `tests/conftest.py` - creator-scoped SHM leak tracking fixture
|
|
||||||
- `tests/test_shm_cleanup.py` - ownership and failure-window regressions
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
- document current-process SHM cleanup behavior
|
|
||||||
- `ai/prompt-io/opencode/20260727T215906Z_689df816_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260727T215906Z_689df816_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-27T21:59:06Z
|
|
||||||
git_ref: 689df816
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/conftest.py tests/test_shm_cleanup.py .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Added function-scoped SHM ownership tracking around Tractor's test-process
|
|
||||||
factory. The fixture records only successful creators, removes ownership
|
|
||||||
records during normal Tractor teardown, verifies POSIX object identity
|
|
||||||
before fallback unlink, restores the token-cache baseline, and fails after
|
|
||||||
cleaning any leak. Regressions reproduce allocation failure before actor
|
|
||||||
lifetime registration and prove external attachments remain untouched.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- SHM cleanup regressions: 2 passed
|
|
||||||
- combined SHM, NativeDB, and history set: 25 passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
- final adversarial review: no findings
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: 24fb9765-a550-4570-8350-f0fc9b7e17db
|
|
||||||
timestamp: 2026-07-28T00:32:47Z
|
|
||||||
git_ref: ed85721c
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260728T003247Z_ed85721c_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Build a safe xonsh workflow for qualifying NativeDB and reverse-backfill
|
|
||||||
correctness against a known gappy IB chart, beginning with
|
|
||||||
`mnq.cme.20260918`. Cover baseline, fresh, restart, append, and expansion
|
|
||||||
testing through implementation, adversarial review, and verification.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Implemented a private disposable xonsh qualification workflow. Evidence is
|
|
||||||
tied to a fixed case, report checksum, snapshot checksum, worktree import,
|
|
||||||
and phase metadata. Added explicit path and symlink safety, source
|
|
||||||
replacement handling, xonsh child environments, and lifecycle preservation
|
|
||||||
comparisons.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `snippets/nativedb_backfill_audit.xsh` - disposable qualification helpers
|
|
||||||
- `docs/manual_backfill_qualification.rst` - operator lifecycle runbook
|
|
||||||
- `tests/test_backfill_audit_snippet.py` - xonsh and comparison regressions
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
- qualification test-harness guidance
|
|
||||||
- `ai/prompt-io/opencode/20260728T003247Z_ed85721c_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260728T003247Z_ed85721c_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-28T00:32:47Z
|
|
||||||
git_ref: ed85721c
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- snippets/nativedb_backfill_audit.xsh docs/manual_backfill_qualification.rst tests/test_backfill_audit_snippet.py .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Added sourceable xonsh helpers that create a private disposable root, bind
|
|
||||||
child processes to the reviewed worktree, capture checksum-bound phase
|
|
||||||
evidence, safely seed and clear test history, and compare lifecycle
|
|
||||||
preservation.
|
|
||||||
|
|
||||||
The workflow rejects path traversal, pre-existing symlinks, output
|
|
||||||
collisions, mismatched case/report/snapshot evidence, and same-phase
|
|
||||||
comparison. The accompanying runbook covers known-bad replay, fresh
|
|
||||||
backfill, restart, append, gap triage, and expansion cases.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- xonsh qualification helper regressions: passed
|
|
||||||
- xonsh sourceability: passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
|
|
||||||
Adversarial review drove additional evidence binding, worktree executable,
|
|
||||||
environment propagation, source replacement, and descriptor-level safety
|
|
||||||
fixes. Residual concurrent mutation risk is stated explicitly in the private
|
|
||||||
disposable-root runbook.
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: 24fb9765-a550-4570-8350-f0fc9b7e17db
|
|
||||||
timestamp: 2026-07-28T00:50:34Z
|
|
||||||
git_ref: ed85721c
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260728T005034Z_ed85721c_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Add reusable read-only tooling to qualify raw NativeDB Parquet against a
|
|
||||||
known gappy IB chart, beginning with `mnq.cme.20260918`. Preserve malformed
|
|
||||||
evidence and distinguish structural validity from unclassified positive
|
|
||||||
gaps without opening or mutating the storage runtime.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Implemented raw Parquet audit reporting with human and JSON output, bounded
|
|
||||||
cadence details, exact integer arithmetic, strict status, collision-safe
|
|
||||||
snapshot capture, and source path protections. Regressions cover malformed
|
|
||||||
schema and values, timestamp precision, gap arithmetic, corrupt bytes,
|
|
||||||
copy failures, symlinks, traversal, and read-only CLI behavior.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/_audit.py` - raw Parquet audit and snapshot implementation
|
|
||||||
- `piker/storage/cli.py` - `piker store audit` command
|
|
||||||
- `tests/test_storage_audit.py` - audit and CLI regressions
|
|
||||||
- `ai/prompt-io/opencode/20260728T005034Z_ed85721c_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260728T005034Z_ed85721c_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-28T00:50:34Z
|
|
||||||
git_ref: ed85721c
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/_audit.py piker/storage/cli.py tests/test_storage_audit.py`
|
|
||||||
|
|
||||||
Added a raw, read-only NativeDB Parquet audit with human and JSON output,
|
|
||||||
bounded cadence evidence, exact integer arithmetic, pre-parse snapshot
|
|
||||||
capture, and strict qualification status.
|
|
||||||
|
|
||||||
The command rejects unsafe FQME paths, symlinked sources and outputs,
|
|
||||||
destination collisions, non-regular source nodes, malformed canonical
|
|
||||||
schema, non-finite values, invalid timestamps, noncanonical indexes, and
|
|
||||||
sub-period cadence. Copy-failure cleanup preserves source bytes while
|
|
||||||
completed corrupt snapshots remain available for diagnosis.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- storage audit and CLI regressions: passed
|
|
||||||
- Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
- final adversarial review: no findings
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: 24fb9765-a550-4570-8350-f0fc9b7e17db
|
|
||||||
timestamp: 2026-07-28T23:27:18Z
|
|
||||||
git_ref: ed85721c
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260728T232718Z_ed85721c_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Diagnose the live `pikerd` failure where backfill publication raised
|
|
||||||
`ValueError: OHLCV timestamps must be finite and positive` while merging the
|
|
||||||
known gappy MNQ NativeDB baseline with fresh IB history. Determine whether to
|
|
||||||
commit the pending audit stack or iterate first.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Traced the primary failure through `publish_latest_frame()` to
|
|
||||||
`NativeStorageClient.update_ohlcv()`. The incoming frame was valid, but the
|
|
||||||
canonicalized persisted baseline retained its epoch-zero row and caused the
|
|
||||||
merged frame to fail validation. Added persisted-row repair before merge and
|
|
||||||
a regression using the observed legacy schema characteristics.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/nativedb.py` - drop non-positive persisted rows during merge
|
|
||||||
- `tests/test_storage_nativedb.py` - live MNQ failure-shape regression
|
|
||||||
- `ai/prompt-io/opencode/20260728T232718Z_ed85721c_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260728T232718Z_ed85721c_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-28T23:27:18Z
|
|
||||||
git_ref: ed85721c
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/nativedb.py tests/test_storage_nativedb.py`
|
|
||||||
|
|
||||||
Fixed incremental NativeDB updates against legacy persisted history with
|
|
||||||
non-positive timestamps. Incoming provider frames remain strictly validated,
|
|
||||||
while merge repair discards invalid persisted rows before concat, dedupe,
|
|
||||||
ordering, canonical-index rewrite, and atomic publication.
|
|
||||||
|
|
||||||
The regression reproduces the observed MNQ baseline shape: one epoch-zero
|
|
||||||
row, noncanonical absolute indexes, extra derived columns, and a valid fresh
|
|
||||||
IB frame. It proves the invalid row is removed while all valid old and new
|
|
||||||
bars survive with canonical indexes.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- NativeDB regressions: 18 passed
|
|
||||||
- history backfill regressions: 6 passed
|
|
||||||
- focused Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: 24fb9765-a550-4570-8350-f0fc9b7e17db
|
|
||||||
timestamp: 2026-07-29T03:41:06Z
|
|
||||||
git_ref: 922a5df8
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260729T034106Z_922a5df8_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Diagnose the live IB reverse-fill failure where
|
|
||||||
`reqHistoricalDataAsync()` raised API error 10314 because its end date,
|
|
||||||
time, or timezone was invalid.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Traced the failure to `Client.bars()`, where an unfinished EST conversion
|
|
||||||
left the original datetime for `ib_async` to serialize as
|
|
||||||
`YYYYMMDD HH:MM:SS UTC`. Converted aware boundaries explicitly to UTC and
|
|
||||||
passed IB's accepted `YYYYMMDD-HH:MM:SS` string while retaining a blank
|
|
||||||
latest-request boundary. Added exact request-argument regressions.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/brokers/ib/api.py` - explicit UTC-dash history boundary format
|
|
||||||
- `tests/test_ib_history.py` - IB request-format regressions
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
- deterministic IB history test mapping
|
|
||||||
- `ai/prompt-io/opencode/20260729T034106Z_922a5df8_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260729T034106Z_922a5df8_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-29T03:41:06Z
|
|
||||||
git_ref: 922a5df8
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/brokers/ib/api.py tests/test_ib_history.py .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Fixed IB reverse-history requests to serialize aware end boundaries with
|
|
||||||
IB's explicit UTC-dash syntax, `YYYYMMDD-HH:MM:SS`. This bypasses
|
|
||||||
`ib_async`'s trailing-`UTC` representation, which the live Gateway rejected
|
|
||||||
with API error 10314, and removes the unfinished EST comparison breakpoint.
|
|
||||||
|
|
||||||
The regression captures the exact `reqHistoricalDataAsync()` argument for
|
|
||||||
latest, stdlib-aware, Pendulum UTC, and America/New_York inputs.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- IB history request regressions: 4 passed
|
|
||||||
- focused Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
- adversarial review: no findings
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
session: 24fb9765-a550-4570-8350-f0fc9b7e17db
|
|
||||||
timestamp: 2026-07-29T04:17:23Z
|
|
||||||
git_ref: ce33deb6
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260729T041723Z_ce33deb6_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Diagnose why the chart still showed a zero first OHLCV row after the
|
|
||||||
epoch-zero timestamp repair, causing auto-y-ranging to include zero.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Audited live 60s and 1s NativeDB files and found one exact 60s first-slot
|
|
||||||
sentinel at epoch 60 with a completely zero OHLCV payload. Added narrowly
|
|
||||||
scoped read and merge repair, matching incoming validation, sentinel-only
|
|
||||||
startup handling, canonical reindexing, and explicit audit classification.
|
|
||||||
Preserved modern all-zero bars as unclassified evidence rather than assuming
|
|
||||||
all zero-priced instruments are corrupt.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/nativedb.py` - first-slot sentinel repair and validation
|
|
||||||
- `piker/storage/_audit.py` - sentinel classification and zero-row evidence
|
|
||||||
- `tests/test_storage_nativedb.py` - hydration, merge, and boundary regressions
|
|
||||||
- `tests/test_storage_audit.py` - sentinel and modern-zero audit regressions
|
|
||||||
- `ai/prompt-io/opencode/20260729T041723Z_ce33deb6_prompt_io.raw.md`
|
|
||||||
- unedited response record
|
|
||||||
- `ai/prompt-io/opencode/20260729T041723Z_ce33deb6_prompt_io.md`
|
|
||||||
- provenance metadata and response summary
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated changes have not been edited by the human.
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
model: gpt-5.6-sol
|
|
||||||
provider: openai
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-29T04:17:23Z
|
|
||||||
git_ref: ce33deb6
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/nativedb.py piker/storage/_audit.py tests/test_storage_nativedb.py tests/test_storage_audit.py`
|
|
||||||
|
|
||||||
Fixed the remaining legacy first-slot sentinel observed in live MNQ 60s
|
|
||||||
history: `time=60` with zero open, high, low, close, and volume. NativeDB now
|
|
||||||
repairs the exact sentinel before read hydration and merge, reindexes the
|
|
||||||
filtered view, and persists the repaired frame on the next valid update.
|
|
||||||
|
|
||||||
The repair remains narrowly scoped. Modern all-zero OHLC bars stay valid for
|
|
||||||
spreads or synthetic instruments, null-containing malformed rows still fail
|
|
||||||
validation, new writes can not recreate the first-slot sentinel, and a file
|
|
||||||
containing only sentinels loads as no history so fresh backfill can proceed.
|
|
||||||
|
|
||||||
The raw audit reports total all-zero price rows, classifies first-slot
|
|
||||||
sentinels as structural violations, and leaves later all-zero rows visible as
|
|
||||||
unclassified warnings.
|
|
||||||
|
|
||||||
Verification generated with the patch:
|
|
||||||
|
|
||||||
- NativeDB, audit, history, xonsh, and IB regressions: 61 passed
|
|
||||||
- focused Ruff: passed
|
|
||||||
- `git diff --check`: passed
|
|
||||||
- final adversarial review: no findings
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: 6409e3bb-1a9a-4ada-b6c4-c554115143e9
|
|
||||||
timestamp: 2026-07-29T18:54:06Z
|
|
||||||
git_ref: d359b1cb
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260729T185406Z_d359b1cb_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user reported that QQQ 60-second zeros appeared as a flat line after
|
|
||||||
reload, clarified that the outstanding concern was the prior `ldshm`
|
|
||||||
failure, and instructed the agent to implement the more focused fix.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Changed `ldshm` to classify invalid SHM snapshots before downstream
|
|
||||||
analysis. Cadence is inferred only from observed finite positive steps;
|
|
||||||
buffers containing non-finite or non-positive timestamps, or lacking a
|
|
||||||
positive cadence, are skipped rather than partially replacement-written
|
|
||||||
or reloaded. Added deterministic helper and command-level regressions.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/cli.py` - inspect cadence and reject invalid SHM snapshots before mutation.
|
|
||||||
- `tests/test_ldshm.py` - cover QQQ-like zeros, corrupt timestamps, cadence selection, degenerate buffers, and mutation prevention.
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md` - register the deterministic regression target.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated output remains uncommitted.
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-29T18:54:06Z
|
|
||||||
git_ref: d359b1cb
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user clarified that the QQQ 60-second chart now displayed a flat
|
|
||||||
forward-filled segment, then asked whether the previously reported
|
|
||||||
`piker store ldshm` failure had been fixed. After being told it had not,
|
|
||||||
the user instructed: "ok but i read above you have a more focussed fix
|
|
||||||
todo now? so have at it!"
|
|
||||||
|
|
||||||
The implementation focused on the exact failure boundary. It does not
|
|
||||||
filter invalid rows into a partial replacement and does not mutate live
|
|
||||||
SHM. Instead, `ldshm` inspects one captured Polars snapshot, infers its
|
|
||||||
cadence from observed finite positive timestamp steps, and skips the
|
|
||||||
entire buffer before analysis, persistence, or reload when any timestamp
|
|
||||||
is non-finite or non-positive.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/cli.py`
|
|
||||||
|
|
||||||
Generated `_shm_period_and_invalid_count()` and integrated its result in
|
|
||||||
`ldshm`. The helper selects the most frequent observed positive step,
|
|
||||||
using the smallest observed step as the deterministic tie-break. Short
|
|
||||||
or cadence-degenerate buffers are skipped. Invalid snapshots are logged
|
|
||||||
and cannot reach deduplication, NativeDB replacement, or SHM reload.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_ldshm.py`
|
|
||||||
|
|
||||||
Generated deterministic regressions for the QQQ-shaped interior zero
|
|
||||||
run, observed-step cadence selection, all invalid timestamp classes,
|
|
||||||
short and degenerate buffers, and command-level prevention of dedupe,
|
|
||||||
storage writes, and reload. The command-level test uses an immutable
|
|
||||||
Polars snapshot and failing spies, without live SHM mutation or timing.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Added the deterministic `ldshm` regression target and its change-to-test
|
|
||||||
mapping to the repository test harness reference.
|
|
||||||
|
|
||||||
Verification output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
.......................................................... [100%]
|
|
||||||
58 passed in 0.70s
|
|
||||||
```
|
|
||||||
|
|
||||||
`git diff --check` passed. Ruff was unavailable in the worktree's
|
|
||||||
existing environment. Three adversarial review passes found and drove
|
|
||||||
fixes for partial-replacement data loss, invented median timeframes,
|
|
||||||
mixed SHM observations, and pre-guard null-analysis failures. The final
|
|
||||||
review reported no remaining findings.
|
|
||||||
|
|
||||||
The patch intentionally does not claim that `ldshm` is safe to run as a
|
|
||||||
general concurrent repair writer. It handles invalid live snapshots by
|
|
||||||
refusing mutation rather than weakening NativeDB validation.
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: 253ade33-07ba-45b5-8839-be35d17ec164
|
|
||||||
timestamp: 2026-07-29T20:40:46Z
|
|
||||||
git_ref: ad6c560f
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260729T204046Z_ad6c560f_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user reported that the QQQ 1-second chart still contained a gap after
|
|
||||||
the `ldshm` fix, asked the agent to inspect it, and authorized continued
|
|
||||||
implementation after a short pause and shutdown of the live workspace.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Diagnosed a 653-row active RT SHM null reservation caused by inclusive IB
|
|
||||||
reverse-query overlaps and startup repair orchestration. Prevented extra
|
|
||||||
physical SHM overlap rows, serialized and bounded IB history recovery,
|
|
||||||
made blank/error responses terminate, and constrained synthetic repair to
|
|
||||||
valid interior timestamp boundaries. Added deterministic concurrency and
|
|
||||||
data-layout regressions.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/brokers/ib/feed.py` - bound and serialize IB history reset/retry behavior.
|
|
||||||
- `piker/tsp/_history.py` - prevent SHM overlap skew and safely finalize null repair.
|
|
||||||
- `tests/test_ib_history.py` - cover blank, cancellation, reset, and pacing interleavings.
|
|
||||||
- `tests/test_history_backfill.py` - cover overlap and null-repair invariants.
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md` - register deterministic coverage.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated output remains uncommitted.
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-29T20:40:46Z
|
|
||||||
git_ref: ad6c560f
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user reported that QQQ still displayed a gap on the 1-second chart
|
|
||||||
after the focused `ldshm` fix and asked the agent to inspect it. The user
|
|
||||||
then paused and resumed implementation while shutting down the live piker
|
|
||||||
trading workspace.
|
|
||||||
|
|
||||||
Read-only live inspection found the active datad generation held 653
|
|
||||||
contiguous zero-time rows in QQQ's 1-second RT SHM, while durable Parquet
|
|
||||||
contained no zero rows. The run occupied absolute indexes 168148 through
|
|
||||||
168800 between timestamps 1785348398 and 1785349051. The stale actor
|
|
||||||
generation and active 60-second history were separately identified.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_history.py`
|
|
||||||
|
|
||||||
Generated history changes that exclude each inclusive reverse-query
|
|
||||||
endpoint already present in SHM while retaining the full provider frame
|
|
||||||
for NativeDB merge. Startup null repair now runs after reverse backfill,
|
|
||||||
uses bounded UI notifications, handles provider no-data without an
|
|
||||||
interactive pause, fills only exact interior zero groups, and refuses
|
|
||||||
synthetic timestamps unless both valid boundaries establish the expected
|
|
||||||
cadence.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/brokers/ib/feed.py`
|
|
||||||
|
|
||||||
Generated IB history reset changes that make blank responses complete,
|
|
||||||
bound repeated cancellation and reset failures per request, serialize
|
|
||||||
timeout and pacing farm resets with one actor-global Trio lock, carry
|
|
||||||
explicit reset results, and coordinate pacing handoff with queued timeout
|
|
||||||
waiters.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_history_backfill.py`
|
|
||||||
|
|
||||||
Generated regressions for inclusive endpoint exclusion, full NativeDB
|
|
||||||
provider deltas, strict synthetic gap boundaries, empty-provider local
|
|
||||||
fallback, bounded notifications, and preservation of valid margin rows.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_ib_history.py`
|
|
||||||
|
|
||||||
Generated deterministic regressions for blank IB responses, cancellation
|
|
||||||
limits, stalled reset cancellation, pacing reset failure limits,
|
|
||||||
cross-request reset serialization, timeout-to-pacing handoff, and
|
|
||||||
successful handoff timeout restart.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Registered the deterministic history-backfill target and expanded the IB
|
|
||||||
history mapping to include `feed.py`.
|
|
||||||
|
|
||||||
Verification output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
........................................................................ [ 93%]
|
|
||||||
..... [100%]
|
|
||||||
77 passed in 2.12s
|
|
||||||
```
|
|
||||||
|
|
||||||
`git diff --check` passed. Multiple adversarial review rounds identified
|
|
||||||
and drove fixes for unbounded IB empty/cancellation/reset paths, stale
|
|
||||||
reset ownership, actor-global failure poisoning, concurrent farm resets,
|
|
||||||
double-counted pacing handoffs, physical endpoint overlap, and unsafe
|
|
||||||
synthetic timestamp boundaries. Final review reported no findings.
|
|
||||||
|
|
||||||
Live validation was intentionally deferred because the user shut down the
|
|
||||||
trading workspace. A fresh datad/chart startup is required to regenerate
|
|
||||||
SHM and verify that QQQ no longer contains the 653-row null run.
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-07-31T16:52:15Z
|
|
||||||
git_ref: 0846cbd4
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260731T165215Z_0846cbd4_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Evaluate and update `piker store` so bare groups and endpoints immediately
|
|
||||||
show help; prepare for eventual optional fuzzy selection in `anal` and
|
|
||||||
`ldshm`; aggregate recent time-series diagnostics into CLI endpoints. The
|
|
||||||
user selected the safe-foundation scope.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Added immediate help UX, exact NativeDB and SHM identities, read-only
|
|
||||||
`series` and `shm` diagnostics, selector-ready exact SHM names, and robust
|
|
||||||
discovery/attachment. Fixed related `ldshm` option and no-match failures.
|
|
||||||
Deferred optional `fzf` and mutation-default changes.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/cli.py` - help UX and read-only series/SHM diagnostics.
|
|
||||||
- `piker/storage/nativedb.py` - canonical compound series identities.
|
|
||||||
- `piker/tsp/_history.py` - exact SHM discovery and dtype resolution.
|
|
||||||
- `piker/data/_sharedmem.py` - attach-only existing-segment helper.
|
|
||||||
- `piker/tsp/__init__.py` - SHM identity helper exports.
|
|
||||||
- `tests/test_store_cli.py` - command UX and endpoint regressions.
|
|
||||||
- `tests/test_ldshm.py` - SHM diagnostics and operational regressions.
|
|
||||||
- `tests/test_storage_nativedb.py` - series parsing/index regressions.
|
|
||||||
- `docs/manual_backfill_qualification.rst` - triage command documentation.
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md` - test mapping.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated output remains uncommitted.
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-07-31T16:52:15Z
|
|
||||||
git_ref: 0846cbd4
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user requested an evaluation and possible update of `piker store`,
|
|
||||||
including immediate help output when a group or endpoint is invoked with
|
|
||||||
no arguments. The user also proposed eventual optional `fzf` selection for
|
|
||||||
`anal` and `ldshm`, and authorized aggregating the recent time-series and
|
|
||||||
SHM debugging work into CLI endpoints. After reviewing three scopes, the
|
|
||||||
user selected the recommended safe foundation rather than implementing
|
|
||||||
interactive fuzzy selection or changing mutation defaults immediately.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/cli.py`
|
|
||||||
|
|
||||||
Generated no-argument help behavior for the `store` group and every
|
|
||||||
endpoint. Added read-only `series` and `shm` commands, JSON and Rich output,
|
|
||||||
exact `--shm-name` plumbing, SHM cadence/invalid/order/gap summaries, and
|
|
||||||
safe corrupt-epoch formatting. Fixed existing `ldshm` no-write/no-reload
|
|
||||||
control flow and no-match debugger behavior.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/nativedb.py`
|
|
||||||
|
|
||||||
Generated canonical `NativeSeriesRef` parsing and deterministic listing.
|
|
||||||
Changed the internal index to preserve `(fqme, period)` identities while
|
|
||||||
keeping unique-FQME compatibility listing and cardinality. Hardened
|
|
||||||
malformed, sidecar, Unicode-period, symlink, and traversal handling.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_history.py`
|
|
||||||
|
|
||||||
Generated exact `ShmBufferRef` parsing and stable discovery, replacing
|
|
||||||
unsafe substring globbing. Added dtype resolution that mirrors history
|
|
||||||
allocation, exact-ref attachment, disappearance handling, and optional
|
|
||||||
exact-name iteration.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/data/_sharedmem.py`
|
|
||||||
|
|
||||||
Generated attach-only SHM access which never creates a segment when a
|
|
||||||
discovered object disappears.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/__init__.py`
|
|
||||||
|
|
||||||
Exported selector-ready SHM identity, parsing, listing, and dtype helpers.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_store_cli.py`
|
|
||||||
|
|
||||||
Generated command-level help, exact durable-series JSON, read-only SHM JSON,
|
|
||||||
and unknown exact-name regressions.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_ldshm.py`
|
|
||||||
|
|
||||||
Generated SHM identity, summary, ordering, dtype, forged-name, disabled
|
|
||||||
mutation-flag, and gap-markup regressions.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_storage_nativedb.py`
|
|
||||||
|
|
||||||
Generated compound index, canonical parser, malformed filename, and dotted
|
|
||||||
FQME regressions.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- docs/manual_backfill_qualification.rst`
|
|
||||||
|
|
||||||
Documented `store series` and `store shm` as separate read-only durable and
|
|
||||||
live-memory triage layers.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Registered the deterministic storage CLI UX target and mapping.
|
|
||||||
|
|
||||||
Verification output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
........................................................................ [ 71%]
|
|
||||||
............................. [100%]
|
|
||||||
101 passed in 1.72s
|
|
||||||
```
|
|
||||||
|
|
||||||
Real `piker store` and `piker store audit` invocations printed complete
|
|
||||||
help without `--help`, exiting with Click's normal no-args help status 2.
|
|
||||||
`git diff --check` passed. Ruff was unavailable in the existing worktree
|
|
||||||
environment.
|
|
||||||
|
|
||||||
Adversarial review drove fixes for provider dtype reconstruction, observed
|
|
||||||
versus expected cadence, exact SHM grammar, discovery races, Typer direct
|
|
||||||
defaults, malformed NativeDB periods, compound cardinality compatibility,
|
|
||||||
undefined `ldshm` reload payloads, no-match debugger hangs, ordering
|
|
||||||
corruption reporting, and dtype precedence. Final review found no issues.
|
|
||||||
|
|
||||||
Optional external `fzf` or built-in numbered selection remains deferred.
|
|
||||||
The exact series and SHM identities added here are the intended foundation
|
|
||||||
for that later patch.
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-08-01T01:53:21Z
|
|
||||||
git_ref: 74ea2152
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260801T015321Z_74ea2152_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Make `piker store ls` default to all NativeDB series as a compact counterpart
|
|
||||||
to detailed `series`, with sensible no-flag output and a visible help
|
|
||||||
description. Consolidate SHM inspection and repair under canonical `shm`,
|
|
||||||
because attachment to volatile segments is implied, and make inspection the
|
|
||||||
safe default while retaining explicit persistence and reload controls.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Replaced backend-oriented `ls` with compact NativeDB discovery and made both
|
|
||||||
listing commands default to all series. Consolidated SHM behavior under a
|
|
||||||
read-only-by-default `shm` command, guarded explicit repair options, updated
|
|
||||||
executable references and docs, and added command regressions.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/storage/cli.py` - listing defaults and unified SHM command modes.
|
|
||||||
- `tests/test_store_cli.py` - listing, help, and SHM mode regressions.
|
|
||||||
- `tests/test_ldshm.py` - explicit persistence-path regressions.
|
|
||||||
- `docs/manual_backfill_qualification.rst` - revised safe CLI workflow.
|
|
||||||
- `snippets/claude_debug_helper.py` - explicit SHM persistence commands.
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md` - safety and test map.
|
|
||||||
- `.claude/skills/piker-slang/examples.md` - canonical command example.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated output incorporates the user's design refinements.
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-01T01:53:21Z
|
|
||||||
git_ref: 74ea2152
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user requested command-surface refinements after reviewing the new
|
|
||||||
storage CLI. Bare `ls` should default to all series and act as a compact
|
|
||||||
form of detailed `series`; commands should produce sensible default output
|
|
||||||
without requiring trigger flags; and `ls` needed a parent-help description.
|
|
||||||
The user first proposed folding read-only SHM inspection into `ldshm -r`,
|
|
||||||
then clarified that `shm` is the better canonical command because attaching
|
|
||||||
to volatile segments is implied by the resource name.
|
|
||||||
|
|
||||||
The resulting design uses `piker store ls` as a compact NativeDB FQME and
|
|
||||||
period view, while `piker store series` reports each exact sub-series with
|
|
||||||
size and path details. Both default to all records and accept an optional
|
|
||||||
FQME substring.
|
|
||||||
|
|
||||||
`piker store shm FQME` is read-only by default. Persistence and reload enter
|
|
||||||
the prior repair workflow only through explicit `--write-parquet` and
|
|
||||||
`--reload-parquet-to-shm` flags. Reload requires persistence, and read-only
|
|
||||||
formatting flags are rejected in repair mode instead of being ignored.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/storage/cli.py`
|
|
||||||
|
|
||||||
Generated shared NativeDB payload collection, compact and detailed output,
|
|
||||||
numeric period ordering, default-all semantics, the canonical `shm` command,
|
|
||||||
safe mode dispatch, explicit repair validation, and debugger propagation in
|
|
||||||
read-only mode.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_store_cli.py`
|
|
||||||
|
|
||||||
Generated regressions for no-flag listing, parent-help descriptions, numeric
|
|
||||||
period display, default read-only SHM JSON, reload dependencies, and repair
|
|
||||||
versus read-only option conflicts.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_ldshm.py`
|
|
||||||
|
|
||||||
Adjusted persistence regressions for the renamed command and explicit repair
|
|
||||||
entry while preserving the historical failure rationale.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- docs/manual_backfill_qualification.rst`
|
|
||||||
|
|
||||||
Documented compact versus detailed NativeDB discovery, default read-only SHM
|
|
||||||
inspection, and the explicitly mutating repair invocation.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- snippets/claude_debug_helper.py`
|
|
||||||
|
|
||||||
Updated executable debug helper commands to select explicit SHM persistence.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Updated operational safety guidance and SHM regression mappings.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/piker-slang/examples.md`
|
|
||||||
|
|
||||||
Updated the command example to the canonical `shm` spelling.
|
|
||||||
|
|
||||||
Verification output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
........................................................................ [ 69%]
|
|
||||||
................................ [100%]
|
|
||||||
104 passed in 5.77s
|
|
||||||
```
|
|
||||||
|
|
||||||
Real command-help rendering was checked for the parent group, `ls`, `series`,
|
|
||||||
and `shm`. Real read-only `ls` and `series --json` output was also exercised
|
|
||||||
against the configured NativeDB. `git diff --check` passed.
|
|
||||||
|
|
||||||
Adversarial review identified and drove fixes for lexicographic period
|
|
||||||
ordering, stale runbook safety wording, ignored mode-specific options, and an
|
|
||||||
explicit-default `--max-gaps 10` validation bypass. Final review found no
|
|
||||||
remaining issues. Real OS-backed SHM attachment and successful repair/reload
|
|
||||||
remain integration-level validation concerns.
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-08-05T19:50:01Z
|
|
||||||
git_ref: f0f3c806
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260805T195001Z_f0f3c806_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Inspect the completed NVDA 60s SHM backfill before workspace restart, explain
|
|
||||||
the persistent zero region, and continue fixing the indexing logic so sparse
|
|
||||||
IB history does not leave physical null reservations.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Captured a 42,720-row live SHM null span whose valid margins shared the same
|
|
||||||
timestamp. Replaced wall-clock row reservation with actual provider-boundary
|
|
||||||
placement, fixed stale SHM first-index, endpoint insertion and field-map
|
|
||||||
semantics, published the final storage prepend, and added a full multi-frame
|
|
||||||
`tsdb_backfill()` regression using a real `ShmArray`.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/tsp/_history.py` - contiguous provider and NativeDB prepends.
|
|
||||||
- `tests/test_history_backfill.py` - sparse multi-frame SHM regression.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated output incorporates the user's live observations.
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-05T19:50:01Z
|
|
||||||
git_ref: f0f3c806
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user reported that a completed NVDA 60s backfill left a large zero
|
|
||||||
region in live SHM and asked for immediate inspection before restarting the
|
|
||||||
workspace. The captured buffer contained 42,720 invalid rows at absolute
|
|
||||||
indexes `3065895..3108614`. The valid rows on both sides had the identical
|
|
||||||
timestamp `1781271360`, proving the region was an erroneous physical-index
|
|
||||||
reservation rather than a real temporal gap.
|
|
||||||
|
|
||||||
The user then asked the agent to continue fixing the backfill logic.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_history.py`
|
|
||||||
|
|
||||||
Removed wall-clock-based SHM reservation from `tsdb_backfill()`. Reverse
|
|
||||||
provider frames now extend the visible `ShmArray._first` boundary on every
|
|
||||||
prepend, beginning exactly at the current first index after inclusive query
|
|
||||||
endpoints are removed. Added `_prepend_tsdb_history()` to trim storage rows
|
|
||||||
against the actual earliest provider timestamp and prepend them directly
|
|
||||||
adjacent only after reverse provider retrieval completes.
|
|
||||||
|
|
||||||
This preserves sparse venue history as ordinal samples rather than treating
|
|
||||||
every elapsed calendar period as a physical SHM row. It also prevents the
|
|
||||||
old `_first + 1` insertion point from overwriting the earliest published bar.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_history_backfill.py`
|
|
||||||
|
|
||||||
Added a full `tsdb_backfill()` regression modeled on the live NVDA failure.
|
|
||||||
It uses a real `ShmArray`, NativeDB's field map, two inclusive reverse-provider
|
|
||||||
frames, and overlapping stored history. Assertions prove the complete
|
|
||||||
timestamp sequence is contiguous and lossless, contains no non-positive
|
|
||||||
timestamps, sends complete provider frames to durable storage, and notifies
|
|
||||||
chart/FSP consumers after the final storage prepend.
|
|
||||||
|
|
||||||
Live evidence captured before workspace restart:
|
|
||||||
|
|
||||||
```text
|
|
||||||
rows 1575296 first_index 1568233 last_index 3143528
|
|
||||||
invalid_count 42720
|
|
||||||
left boundary
|
|
||||||
[(3065893, 1781271300, 204.03, 204.82)
|
|
||||||
(3065894, 1781271360, 204.81, 204.72)
|
|
||||||
(3065895, 0, 0. , 0. )]
|
|
||||||
right boundary
|
|
||||||
[(3108614, 0, 0. , 0. )
|
|
||||||
(3108615, 1781271360, 204.81, 205.44)
|
|
||||||
(3108616, 1781271420, 205.46, 205.48)]
|
|
||||||
```
|
|
||||||
|
|
||||||
Verification output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
........................................................................ [ 68%]
|
|
||||||
................................. [100%]
|
|
||||||
105 passed in 4.80s
|
|
||||||
```
|
|
||||||
|
|
||||||
Adversarial review caught stale `_first` semantics and an off-by-one
|
|
||||||
insertion point in the initial patch. The first live restart then exposed an
|
|
||||||
undefined `time_key` local at the new `tsdb_backfill()` call site, which
|
|
||||||
crashed `datad.ib` and propagated to the chart as `RemoteActorError`. The
|
|
||||||
helper now derives the source timestamp field from its field map, and the
|
|
||||||
test enters the full enclosing lifecycle so the original `NameError` can not
|
|
||||||
recur unnoticed. A final review also drove explicit publication after stored
|
|
||||||
history is prepended and deterministic final-stage synchronization. Final
|
|
||||||
review found no remaining issues; another live restart remains pending.
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: ses_0799212ebffe42arY96czXn89F
|
|
||||||
timestamp: 2026-08-11T20:58:26Z
|
|
||||||
git_ref: 06d5ea5d
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260811T205826Z_06d5ea5d_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Diagnose and fix an IB live-order failure where lazy NVDA contract
|
|
||||||
qualification raised `tractor.trionics.Lagged` after the order reached
|
|
||||||
`brokerd.ib`. Determine whether recent history changes or cancelled symbol
|
|
||||||
searches caused the stale state.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Traced the failure to competing consumers of a one-slot Trio broadcast, not
|
|
||||||
the recent SHM change or stale asyncio client state. Replaced broadcast
|
|
||||||
fan-out with one response/status demultiplexer, retained request-ID
|
|
||||||
correlation, handled cancellation and teardown, documented the task/channel
|
|
||||||
ownership model, warned on diagnostic metadata eviction, and added
|
|
||||||
deterministic proxy regressions.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/brokers/ib/api.py` - sole-reader IB proxy response routing.
|
|
||||||
- `tests/test_ib_method_proxy.py` - status, concurrency, cancellation and EOF regressions.
|
|
||||||
- `.claude/skills/run-tests/test-harness-reference.md` - proxy test mapping.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - generated output follows the user's live failure diagnosis.
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-11T20:58:26Z
|
|
||||||
git_ref: 06d5ea5d
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
The user reported that certain IB order entries might have broken and
|
|
||||||
provided a live failure for a first NVDA sell order. EMS delivered the
|
|
||||||
request to `brokerd.ib`, but lazy `get_mkt_info('nvda.nasdaq')` contract
|
|
||||||
qualification failed in `MethodProxy._run_method()` with:
|
|
||||||
|
|
||||||
```text
|
|
||||||
tractor.trionics._broadcast.Lagged:
|
|
||||||
Task `piker.brokers.ib.broker.handle_order_requests` overrun and
|
|
||||||
dropped `0` values
|
|
||||||
```
|
|
||||||
|
|
||||||
The user suspected a cancelled symbol-search task might have left stale
|
|
||||||
asyncio state. Cancellation can leave an orphaned method response, but the
|
|
||||||
observed failure was stale Trio broadcast state. `open_client_proxy()`
|
|
||||||
broadcast a one-slot `LinkedTaskChannel` to an always-running IB status relay
|
|
||||||
and an idle method receiver. Status traffic advanced only the relay, so the
|
|
||||||
first method call for an uncached symbol entered an already-lagged receiver.
|
|
||||||
Orders for eagerly cached contracts bypassed this path.
|
|
||||||
|
|
||||||
The immediately preceding sparse-history commit did not modify IB order,
|
|
||||||
symbol, or proxy code; it exposed no direct dependency on this failure.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/brokers/ib/api.py`
|
|
||||||
|
|
||||||
Generated a sole-reader message demultiplexer for each IB client proxy.
|
|
||||||
`relay_client_proxy_messages()` owns every asyncio-to-Trio receive, handles
|
|
||||||
status/error traffic, and dispatches `mid`-tagged responses into per-call
|
|
||||||
`MethodProxy` wait slots. Cancelled calls remove their pending slot, causing
|
|
||||||
late responses to be logged and dropped without skewing later calls. Clean
|
|
||||||
channel EOF is accepted during normal proxy teardown.
|
|
||||||
|
|
||||||
Follow-up review restored the masked reconnect TODO and per-message case
|
|
||||||
rationale, documented the one-reader/many-writer task hierarchy and separate
|
|
||||||
per-proxy channels, and added a warning with request method metadata when the
|
|
||||||
bounded unresolved-request diagnostic table evicts its oldest entry.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_ib_method_proxy.py`
|
|
||||||
|
|
||||||
Generated deterministic regressions for idle status traffic before first
|
|
||||||
qualification, two concurrent calls with reverse-order responses, cancelled
|
|
||||||
calls with late responses followed by a successful call, and graceful
|
|
||||||
channel EOF. Every synchronization wait is timeout-bounded.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- .claude/skills/run-tests/test-harness-reference.md`
|
|
||||||
|
|
||||||
Registered the deterministic IB method-proxy target and source mapping.
|
|
||||||
|
|
||||||
Verification output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
........................ [100%]
|
|
||||||
25 passed, 4 warnings in 3.44s
|
|
||||||
```
|
|
||||||
|
|
||||||
The warnings are existing Tractor/Trio deprecations from the EMS test.
|
|
||||||
Adversarial review drove a clean-EOF guard and bounded polling. Final review
|
|
||||||
found no actionable issues. Live IB order validation remains pending and
|
|
||||||
requires restarting `brokerd.ib`.
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: unavailable
|
|
||||||
timestamp: 2026-08-14T03:27:16Z
|
|
||||||
git_ref: 2aa66c2c
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260814T032716Z_2aa66c2c_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Prototype chart-actor-owned gap overlays from the current backfiller tip,
|
|
||||||
with actor-local startup and UI toggling. Preserve remote annotation IPC and
|
|
||||||
make the gap-specific path strict and `msgspec`-typed.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Adds a chart-local controller and vectorized SHM detector, starts historical
|
|
||||||
gap overlays with display state, toggles the focused timeframe through the
|
|
||||||
existing input loop and exposes the same renderer through a strict Tractor
|
|
||||||
payload context. Keeps all legacy remote annotation commands and separates
|
|
||||||
local graphics from each remote context's teardown ownership.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/ui/_gaps.py` - typed messages, detection and local controller.
|
|
||||||
- `piker/ui/_remote_ctl.py` - IPC clients and chart-actor endpoints.
|
|
||||||
- `piker/ui/_display.py` - actor-local startup integration.
|
|
||||||
- `piker/ui/_interaction.py` - focused `Ctrl+G` toggle.
|
|
||||||
- `piker/ui/_widget.py` - controller reference.
|
|
||||||
- `piker/ui/_annotate.py` - safe FQME-aware repositioning.
|
|
||||||
- `piker/tsp/_annotate.py` - typed annotation-client reference.
|
|
||||||
- `piker/storage/cli.py` - renamed annotation client context.
|
|
||||||
- `tests/test_gap_overlays.py` - detector and schema regression.
|
|
||||||
- `tests/test_ldshm.py` - renamed annotation-client test seams.
|
|
||||||
- `plans/opencode/chart-local-gap-overlays.md` - architecture and landing plan.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - the work remains an uncommitted disposable-worktree prototype for
|
|
||||||
human review and live chart qualification.
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-14T03:27:16Z
|
|
||||||
git_ref: 2aa66c2c
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user asked what work had been done so far, then authorized autonomous
|
|
||||||
work while AFK. The target was to scheme and prototype an actor-local gap
|
|
||||||
annotator from the `backfiller_deep_fixes` tip without mutating existing
|
|
||||||
branches. The user then clarified twice that the annotation IPC API must
|
|
||||||
remain available and should become more rigorous and `msgspec`-typed rather
|
|
||||||
than being removed.
|
|
||||||
|
|
||||||
## Generated code
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_gaps.py`
|
|
||||||
|
|
||||||
Adds tagged gap request/reply structs, render-ready gap specs, vectorized
|
|
||||||
OHLCV timestamp-gap detection and chart-local overlay ownership.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_remote_ctl.py`
|
|
||||||
|
|
||||||
Adds strict Tractor gap IPC, `AnnotClient` stream mapping/locking and
|
|
||||||
owner-scoped endpoint cleanup while retaining the legacy annotation endpoint.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_display.py`
|
|
||||||
|
|
||||||
Starts the local 60-second overlay after display-state registration.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_interaction.py`
|
|
||||||
|
|
||||||
Routes `Ctrl+G` from the focused chart's existing async input loop directly
|
|
||||||
to the local controller.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_widget.py`
|
|
||||||
|
|
||||||
Stores the chart actor's local controller reference.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_annotate.py`
|
|
||||||
|
|
||||||
Keeps redraw repositioning isolated by FQME and synchronizes arrow geometry.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/tsp/_annotate.py piker/storage/cli.py`
|
|
||||||
|
|
||||||
Renames the remote annotation control type and context manager to the
|
|
||||||
client-oriented `AnnotClient` / `open_annot_client` interface.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_gap_overlays.py`
|
|
||||||
|
|
||||||
Adds deterministic detector, directional payload-schema, typed error and
|
|
||||||
msgpack roundtrip regressions.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_ldshm.py`
|
|
||||||
|
|
||||||
Updates storage CLI test seams for the renamed annotation client context.
|
|
||||||
|
|
||||||
## Generated architecture output
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- plans/opencode/chart-local-gap-overlays.md`
|
|
||||||
|
|
||||||
Documents ownership, startup, UI, strict IPC, refresh and branch landing
|
|
||||||
semantics.
|
|
||||||
|
|
||||||
## Verification output
|
|
||||||
|
|
||||||
Source resolution points to this worktree. The targeted regression passes,
|
|
||||||
Ruff reports no changed-file findings, `compileall` succeeds, `git diff
|
|
||||||
--check` succeeds and Tractor's strict gap payload decoder initializes.
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: unavailable
|
|
||||||
timestamp: 2026-08-17T22:20:36Z
|
|
||||||
git_ref: f65df6a1
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260817T222036Z_f65df6a1_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Add end-to-end coverage for chart-local gap annotations in the existing
|
|
||||||
gap-overlay worktree without disturbing concurrent manual backfiller testing
|
|
||||||
in the root checkout.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Adds real offscreen Qt and real Tractor actor integration coverage. The tests
|
|
||||||
drive startup registration, PyQtGraph insertion/removal, focused Ctrl-G input,
|
|
||||||
history-prepend repositioning, duplicate-FQME chart identity, typed endpoint
|
|
||||||
exchange and cancellation with stale-response recovery. Defects exposed by
|
|
||||||
those tests are fixed in manager cleanup, Qt geometry notification and PyQt6
|
|
||||||
event routing.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/ui/_gaps.py` - correct PyQtGraph ownership and bounds behavior.
|
|
||||||
- `piker/ui/_annotate.py` - notify Qt before reposition geometry changes.
|
|
||||||
- `piker/ui/_display.py` - expose deterministic startup registration.
|
|
||||||
- `piker/ui/_interaction.py` - focus toggles and PyQt6 event registration.
|
|
||||||
- `tests/test_gap_overlays.py` - real Qt and Tractor integration coverage.
|
|
||||||
- `plans/opencode/chart-local-gap-overlays.md` - update coverage boundaries.
|
|
||||||
- `plans/opencode/chart-local-gap-overlays.summary.md` - update test totals.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - the changes remain uncommitted for human review.
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-17T22:20:36Z
|
|
||||||
git_ref: f65df6a1
|
|
||||||
diff_cmd: git diff f65df6a1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user asked whether the chart-local gap annotation feature had complete
|
|
||||||
end-to-end coverage, then requested implementation in the existing gap-overlay
|
|
||||||
worktree while manual NativeDB/backfiller qualification continued in the root
|
|
||||||
checkout. The user initially declined a tests-only Prompt-IO entry. Real Qt
|
|
||||||
and Tractor integration tests then exposed production lifecycle and PyQt6
|
|
||||||
event-routing defects, making the resulting patch substantive code work and
|
|
||||||
requiring this full provenance entry.
|
|
||||||
|
|
||||||
## Generated code
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_gaps.py`
|
|
||||||
|
|
||||||
Removes manager-owned graphics through their `PlotItem`, retains owning-plot
|
|
||||||
registrations, and excludes pixel-sized gap arrows from automatic data bounds.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_annotate.py`
|
|
||||||
|
|
||||||
Moves Qt geometry-change notification ahead of rectangle and arrow mutation so
|
|
||||||
scene spatial indexing follows history-prepend repositioning.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_display.py`
|
|
||||||
|
|
||||||
Extracts `_register_gap_overlays()` as the deterministic chart startup seam
|
|
||||||
which registers display states and renders default historical gap layers.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/ui/_interaction.py`
|
|
||||||
|
|
||||||
Adds focused-chart toggle routing, updates the gap keyboard path to PyQt6 event
|
|
||||||
enums, and keeps unrelated cached chart states untouched.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_gap_overlays.py`
|
|
||||||
|
|
||||||
Adds offscreen real-Qt manager, startup, keyboard, cached-chart and reposition
|
|
||||||
coverage plus a real Tractor actor endpoint/client dialog with deterministic
|
|
||||||
cancellation and stale-response recovery.
|
|
||||||
|
|
||||||
## Generated architecture output
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- plans/opencode/chart-local-gap-overlays.md plans/opencode/chart-local-gap-overlays.summary.md`
|
|
||||||
|
|
||||||
Records the automated integration boundary and remaining broker-backed manual
|
|
||||||
qualification requirements.
|
|
||||||
|
|
||||||
## Verification output
|
|
||||||
|
|
||||||
The source-isolated non-actor and related suites pass 24 tests with one actor
|
|
||||||
case deselected. The isolated actor case passes with one upstream Tractor/Trio
|
|
||||||
deprecation warning. Ruff, compileall, import resolution and whitespace checks
|
|
||||||
pass. Independent review reports no remaining P1/P2 findings.
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: unavailable
|
|
||||||
timestamp: 2026-08-18T06:43:40Z
|
|
||||||
git_ref: 09ddcf50
|
|
||||||
scope: docs
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260818T064340Z_09ddcf50_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Audit all development branches and worktrees, consolidate duplicate and
|
|
||||||
rebased histories into the smallest subsystem-scoped PRs, preserve useful
|
|
||||||
chronology, identify stale refs, omit obsolete AI-skill changes, and recover
|
|
||||||
any useful abandoned work before proposing an optimal route into `main`.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Adds a repository-wide landing plan grounded in exact branch ancestry,
|
|
||||||
patch-equivalence, worktree state, and object recovery. The plan separates
|
|
||||||
independent fixes from the runtime/datad/backfill dependency chain, reduces
|
|
||||||
the DPI branch swarm to one five-commit series, records deferred provider
|
|
||||||
work, and proposes staged cleanup only after replacement PRs land.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `plans/opencode/repo-land-plan.md` - record the audited landing sequence,
|
|
||||||
exact patch sources, blockers, worktree constraints, and cleanup groups.
|
|
||||||
- `ai/prompt-io/opencode/20260818T064340Z_09ddcf50_prompt_io.raw.md` - retain
|
|
||||||
the unedited prompt and generated-output summary.
|
|
||||||
- `ai/prompt-io/opencode/20260818T064340Z_09ddcf50_prompt_io.md` - record
|
|
||||||
structured provenance for the generated documentation.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
None - the changes remain uncommitted for human review.
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-18T06:43:40Z
|
|
||||||
git_ref: 09ddcf50
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user asked OpenCode to act as repository supervisor and audit every
|
|
||||||
development branch and worktree for an optimal route into `main`. The audit
|
|
||||||
needed to identify duplicate and rebased histories, especially the DPI/font
|
|
||||||
branches, reconstruct subsystem-scoped patch sets, preserve chronology,
|
|
||||||
propose stale-ref removal, exclude obsolete AI-skill changes, and recover any
|
|
||||||
useful abandoned commits.
|
|
||||||
|
|
||||||
The user later checked that the long-running audit was still active. OpenCode
|
|
||||||
confirmed progress and completed the worktree, branch, patch-ID, reflog,
|
|
||||||
stash, and unreachable-object sweep before writing the plan.
|
|
||||||
|
|
||||||
## Generated documentation
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- plans/opencode/repo-land-plan.md`
|
|
||||||
|
|
||||||
Creates a repository-wide landing plan based on `main` and `gitea/main` at
|
|
||||||
`1abd47609b161c4b9fd460274dc9123755211436`. It records the audit scope,
|
|
||||||
integration rules, dependency-ordered PR lanes, exact source commits, branch
|
|
||||||
cleanup groups, worktree ownership constraints, deferred histories, and the
|
|
||||||
abandoned-object recovery result.
|
|
||||||
|
|
||||||
The plan reduces aggregate development histories into independent fixes, a
|
|
||||||
five-commit DPI series, graphics/gap foundations, runtime and service ports,
|
|
||||||
the datad/brokerd split, post-datad concurrency repairs, NativeDB/backfill
|
|
||||||
work, chart-local overlays, provider follow-ups, and build/tooling changes.
|
|
||||||
It explicitly excludes generated skill deployment, prompt records from
|
|
||||||
product patches, editable dependency pins, and plan-only commits.
|
|
||||||
|
|
||||||
## Audit output
|
|
||||||
|
|
||||||
The read-only audit covers seven worktrees, 168 recent unmerged refs, eight
|
|
||||||
stash entries, patch-equivalent rebases, and 483 unreachable commits. It finds
|
|
||||||
no recovery-worthy application patch that exists only in a stash or
|
|
||||||
unreachable object. Current forge status remains a separate refresh step
|
|
||||||
because this pass uses local and cached repository state.
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
session: unavailable
|
|
||||||
timestamp: 2026-08-26T22:26:00Z
|
|
||||||
git_ref: 5f631e19
|
|
||||||
scope: code
|
|
||||||
substantive: true
|
|
||||||
raw_file: 20260826T222600Z_5f631e19_prompt_io.raw.md
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
Diagnose and fix the hanging Binance USD-M perpetual feed for
|
|
||||||
`NVDAUSDT.USDTM.PERP.BINANCE` by comparing piker with Binance's current
|
|
||||||
API and changelog. Ensure unsupported or silent websocket feeds fail
|
|
||||||
loudly into `datad` and chart consumers instead of blocking startup.
|
|
||||||
|
|
||||||
## Response summary
|
|
||||||
|
|
||||||
Migrates Binance USD-M market data from the retired legacy websocket to
|
|
||||||
the split public and market routes, handles Binance's new aggregate-trade
|
|
||||||
schema, and introduces bounded connection and first-data startup. Direct
|
|
||||||
stream URLs avoid reconnect-time subscription-ACK races, while targeted
|
|
||||||
tests preserve routing and fail-loud behavior.
|
|
||||||
|
|
||||||
## Files changed
|
|
||||||
|
|
||||||
- `piker/brokers/binance/feed.py` - route, merge, normalize, and bound
|
|
||||||
Binance quote streams.
|
|
||||||
- `piker/brokers/binance/venues.py` - define current USD-M websocket
|
|
||||||
endpoints.
|
|
||||||
- `piker/data/_web_bs.py` - support bounded websocket context startup.
|
|
||||||
- `tests/test_binance.py` - cover routes, schemas, and startup failures.
|
|
||||||
- `ai/prompt-io/opencode/20260826T222600Z_5f631e19_prompt_io.raw.md` -
|
|
||||||
retain the generated-output record.
|
|
||||||
- `ai/prompt-io/opencode/20260826T222600Z_5f631e19_prompt_io.md` - record
|
|
||||||
structured provenance for the code changes.
|
|
||||||
|
|
||||||
## Human edits
|
|
||||||
|
|
||||||
The human explicitly required fail-loud behavior rather than merely
|
|
||||||
updating the endpoint, and supplied a direct CLI reproduction proving
|
|
||||||
both `datad.binance` and the chart caller blocked. Those requirements
|
|
||||||
drove the connection and first-data deadlines and their regressions. The
|
|
||||||
changes remain uncommitted for human review.
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
---
|
|
||||||
model: openai/gpt-5.6-sol
|
|
||||||
service: opencode
|
|
||||||
timestamp: 2026-08-26T22:26:00Z
|
|
||||||
git_ref: 5f631e19
|
|
||||||
diff_cmd: git diff HEAD~1..HEAD
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompt
|
|
||||||
|
|
||||||
The user reported that selecting
|
|
||||||
`NVDAUSDT.USDTM.PERP.BINANCE` connected Binance's USD-M
|
|
||||||
websocket but never loaded the feed or downstream chart. They asked
|
|
||||||
OpenCode to compare Binance's API changelog with piker's FQME and feed
|
|
||||||
code, diagnose the failure, and solve it.
|
|
||||||
|
|
||||||
The user clarified that future provider failures must raise loudly
|
|
||||||
instead of silently blocking feed and chart startup. They also confirmed
|
|
||||||
the same hang from
|
|
||||||
`piker -l info --pdb chart nvdausdt.usdtm.perp.binance`.
|
|
||||||
|
|
||||||
## Generated code
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/brokers/binance/feed.py`
|
|
||||||
|
|
||||||
Routes USD-M book-ticker and aggregate-trade data through Binance's new
|
|
||||||
`/public` and `/market` websocket paths, merges both sockets into the
|
|
||||||
existing quote stream, accepts the new `st` aggregate-trade field, and
|
|
||||||
requires both stream classes before declaring startup complete. It also
|
|
||||||
removes the misleading missing-provider warning, derives feed mode from
|
|
||||||
resolved pair metadata, and raises `DataUnavailable` for connection or
|
|
||||||
live-data startup timeouts.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/brokers/binance/venues.py`
|
|
||||||
|
|
||||||
Defines Binance's current public and market USD-M websocket endpoints
|
|
||||||
and makes the market endpoint the regular futures websocket API root.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- piker/data/_web_bs.py`
|
|
||||||
|
|
||||||
Adds an optional connection deadline to `open_autorecon_ws()` so callers
|
|
||||||
can fail context entry when repeated websocket handshakes never become
|
|
||||||
connected.
|
|
||||||
|
|
||||||
> `git diff HEAD~1..HEAD -- tests/test_binance.py`
|
|
||||||
|
|
||||||
Adds regressions for exact Binance stream routing, silent live-data
|
|
||||||
startup, silent websocket connection startup, and the current USD-M
|
|
||||||
aggregate-trade payload schema.
|
|
||||||
|
|
||||||
## Verification output
|
|
||||||
|
|
||||||
`pytest -q tests/test_binance.py` passes all four tests. Compile checks,
|
|
||||||
focused Ruff fatal-error checks, and `git diff --check` pass. Live probes
|
|
||||||
through piker's merged stream received both required stream classes and
|
|
||||||
returned normalized trade quotes for `NVDAUSDT` USD-M and `BTCUSDT`
|
|
||||||
spot.
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue