Task 7 of the autotrade foundation: five new async functions and one struct added to repo.rs to support the upcoming exit-monitoring pass (Task 8). All items are annotated #[allow(dead_code)] until Task 8 wires them into the exit-detection loop.

File

crates/polymarket-fetch/src/pmv2/repo.rs lines 1270–1359 — branch autotrade-foundation

New Items

AutotradeExitEventRow (struct)

Derives sqlx::FromRow. Maps a row from the pmv2_position_events ⋈ pmv2_autotrade_orders join used by autotrade_exit_events:

FieldTypeSource column
proxy_walletStringpmv2_position_events.proxy_wallet
condition_idStringpmv2_position_events.condition_id
outcome_indexi32pmv2_position_events.outcome_index
event_slugStringpmv2_position_events.event_slug
slugStringpmv2_position_events.slug
detected_tsi64pmv2_position_events.detected_ts

For Agents

pmv2_position_events column set confirmed from the watcher migration (20260603000000_pmv2_overlap) plus the overlap/pnl extension migrations: proxy_wallet, condition_id, outcome_index, event_slug, slug, detected_ts are all present. AutotradeExitEventRow selects exactly this set — do not assume additional columns exist without checking migrations.

autotrade_exits_cursor

pub async fn autotrade_exits_cursor(pool: &PgPool) -> Result<i64>

Reads the last_check_at value for key 'autotrade_exits' from pm_detection_cursors. Returns 0 if no row exists yet (first run). This cursor is separate from:

  • 'pmv2_exit_alert' — used by the notifier in exits.rs
  • 'overlap_watcher' — used by the overlap detector in overlap_watcher.rs

advance_autotrade_exits_cursor

pub async fn advance_autotrade_exits_cursor(pool: &PgPool, ts: i64) -> Result<()>

Upserts pm_detection_cursors with detector = 'autotrade_exits' and the given timestamp. Uses ON CONFLICT (detector) DO UPDATE SET last_check_at = EXCLUDED.last_check_at — the EXCLUDED. alias pattern that matches the rest of this codebase (not $1).

Upsert style

This codebase uses EXCLUDED.<column> in ON CONFLICT DO UPDATE, not a $N re-bind. Deviating from this breaks codebase consistency and risks confusion with the parameter index.

autotrade_exit_events

pub async fn autotrade_exit_events(pool: &PgPool, since_ts: i64) -> Result<Vec<AutotradeExitEventRow>>

Reads pmv2_position_events rows with kind = 'EXITED' and detected_ts > since_ts, joined to pmv2_autotrade_orders on (condition_id, outcome_index) to confirm an autotrade order exists for that position. Returns Vec<AutotradeExitEventRow> ordered by detected_ts ASC.

autotrade_open_orders_for_origin

pub async fn autotrade_open_orders_for_origin(
    pool: &PgPool,
    condition_id: &str,
    outcome_index: i32,
    origin_ref: &str,
) -> Result<Vec<AutotradeOrderRow>>

Fetches rows from pmv2_autotrade_orders where condition_id = $1 AND outcome_index = $2 AND origin_ref = $3 AND status = 'open'. Used to look up live orders that need to be closed when an exit event fires. AutotradeOrderRow is an existing type in repo.rs (not introduced in T7).

For Agents

pmv2_autotrade_orders column set confirmed from 20260614000000_pmv2_autotrade.sql: origin_ref, condition_id, outcome_index, status are all present. origin_ref is the tracker key linking an autotrade order back to the source signal’s origin_ref field on TradeSignal.

autotrade_source_enabled

pub async fn autotrade_source_enabled(pool: &PgPool, source_id: &str) -> Result<bool>

Returns the enabled flag for a given source_id from pmv2_autotrade_sources. Returns false if no row exists (fail-closed). pmv2_autotrade_sources has columns source_id (TEXT PK) and enabled (BOOL), confirmed from 20260614000000_pmv2_autotrade.sql.

#[allow(dead_code)] Annotation

All five functions and the struct carry #[allow(dead_code)]. This is a temporary suppression — Task 8 will wire these into the exit-detection loop at which point the allows are removed. The same pattern was used for the category resolver in T3.

Cursor Key Separation

Three separate cursor keys coexist in pm_detection_cursors:

KeyOwned byPurpose
'overlap_watcher'overlap_watcher.rsCohort ENTER/EXIT events for operator overlap alerts
'pmv2_exit_alert'exits.rsExit events for Telegram “TRADE EXITED” alerts to operator
'autotrade_exits'T7/T8 (upcoming)Exit events for the autotrade engine to close its own orders

These cursors advance independently so the notifier and the autotrade engine can run at different cadences without interfering.

Gate

253 polymarket-fetch tests + 87 polymarket-data tests, 0 failures, 0 clippy errors. No commits made.