The three operator reporting commands /topbets, /consensus <category>, and /filters existed in the legacy polymarket_fetch monolith but were dropped in the pmv2 split — the cohort_algo carve deleted “bet/market scoring” (topbets) and the bot, and the new telegram_connector only re-implemented the 5 operator ops commands (/autotrade, /halt, /status, /enable, /disable). So /topbets returned “unknown command”. Operator (Andras) wanted them back with 1:1 EXACT behavior. Restored by porting the algos verbatim into cohort_algo (the data owner) and exposing them over a new NATS request/reply query channel — cohort’s first inbound NATS surface.

For Agents — state at a glance

  • Contract: shared crate wowjeeez/pmv2-contracts main @ 1f05fff — module query::{QueryRequest, QueryKind, QueryReply} + subjects query.request / query.results. QueryRequest{request_id, actor, kind}; QueryKind = TopBets{filters: Vec<String>, limit} | Consensus{category, top, min_overlap} | Filters; QueryReply{request_id, rendered} (rendered = ready-to-send Telegram HTML). QueryKind serde = internally-tagged + flattened, same as the Pricing discriminator. (Rebased onto the connector’s ops/telegram commit 4c7a54f, no force-push.)
  • Responder: cohort_algo main @ 5d5bb48 — new query-responder subcommand (src/pmv2/query_responder.rs). Core-subscribes query.request, dispatches on kind to the ported pipelines, JetStream-publishes query.results with Nats-Msg-Id = "{request_id}-result" (dedup-safe), body echoes request_id. Dormant-safe (no NATS_URL → no-op), reconnect loop, per-request spawn.
  • Connector side: telegram_connector git-deps pmv2-contracts 1f05fff, adds /topbets [eq:cat|neq:cat], /consensus <category> [N] [K], /filters (all Viewer), correlating replies on body request_id like /status. Builds once the contract pin lands (babylon #466).
  • Deploy: needs a query.request/query.results JetStream stream + NKey permits (cohort SUB request / PUB results; connector inverse) + run the query-responder service (babylon #467).
  • Status (2026-06-24): cohort + contract shipped, gated green. Awaiting @connector building the commands + @deploy provisioning infra & running the responder. Plan: cohort_algo/docs/superpowers/plans/2026-06-24-topbets-port.md.

Architecture — Option A (cohort owns data + rendering)

/cmd → connector publishes query.request → cohort query-responder runs the exact ported pipeline → query.results (JetStream) → connector sends rendered HTML. The connector owns the bot surface (dispatch, roles, setMyCommands, rate-limit); cohort is a pure responder. PM is uninvolved (own subject).

What was ported (verbatim, 1:1) — parity-locked by the monolith’s own tests

  • topbets: all_cohort_holders SQL + row types (repo.rs); a topbets_filter module (eq:/neq: parse_topbets_filter + an Option-based CategoryFilter, kept in its OWN module to avoid colliding with cohort’s existing gating CategoryFilter in category.rs); the scoring core (BetScore/BetHolder+conviction, ranking, format_top_bets_telegram + ~17 formatters); model::confidence_emoji. 10 monolith parity tests ported unchanged.
  • consensus: the compute+format core (category_consensus.rs) was already byte-identical in cohort (it’s leaderboard-API based — top-N by monthly PNL — NOT cohort-DB). Only added CONSENSUS_CACHE_WINDOW_SECS = 600 + the handler logic. 4 parity tests already present. See category-consensus.
  • filters: category_counts / tag_counts repo queries + a filters_body (static eq:/neq: help + live cached category/tag counts).

Gotchas / lessons

Dedup-safe reply Nats-Msg-Id

The responder JetStream-publishes the reply to query.results with Nats-Msg-Id = "{request_id}-result" — DISTINCT from the request id. If query.request + query.results share one JetStream stream with a dedup window, an identical msg-id would be silently dedup-dropped (same class as position_manager’s #427 ops.results bug).

One-shot request/reply adaptation for /consensus

The monolith sent “running consensus algo…” then pushed the result as a second message when the recompute finished. Over one-shot request/reply that’s impossible, so the cache-miss path spawns a recompute-to-cache and replies “running… re-run in a moment” — the re-run hits the fresh cache and renders identically. Same compute, same output; only in-progress delivery differs (operator-confirmed OK).

Verbatim/1:1 outranks a lint

An implementer subagent deleted two genuinely-unused-in-cohort but verbatim-ported items (format_top_bets plain variant + BetHolder.avg_bet_size) just to satisfy a zero-warning clippy gate. That violated the explicit 1:1 requirement. Fix: restore the verbatim code and use narrow #[allow(dead_code)] instead. An explicit user constraint (verbatim) beats a secondary gate (zero warnings); handle dead-but-intentional code with #[allow], not deletion.

Shared-crate push discipline

Pushing the query types to pmv2-contracts hit a non-fast-forward because the connector had pushed ops/telegram types first. Resolved by rebasing on top (no force-push) + re-vendoring the full canonical into cohort’s path-dep copy so it’s a true mirror.

category-consensus · category-leaderboard-api · pmv2-onchain-watch-crate-extraction · position-manager-interface-design