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-contractsmain@1f05fff— modulequery::{QueryRequest, QueryKind, QueryReply}+ subjectsquery.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).QueryKindserde = internally-tagged + flattened, same as thePricingdiscriminator. (Rebased onto the connector’s ops/telegram commit4c7a54f, no force-push.)- Responder:
cohort_algomain@5d5bb48— newquery-respondersubcommand (src/pmv2/query_responder.rs). Core-subscribesquery.request, dispatches onkindto the ported pipelines, JetStream-publishesquery.resultswithNats-Msg-Id = "{request_id}-result"(dedup-safe), body echoesrequest_id. Dormant-safe (noNATS_URL→ no-op), reconnect loop, per-request spawn.- Connector side:
telegram_connectorgit-depspmv2-contracts 1f05fff, adds/topbets [eq:cat|neq:cat],/consensus <category> [N] [K],/filters(all Viewer), correlating replies on bodyrequest_idlike/status. Builds once the contract pin lands (babylon #466).- Deploy: needs a
query.request/query.resultsJetStream stream + NKey permits (cohort SUB request / PUB results; connector inverse) + run thequery-responderservice (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_holdersSQL + row types (repo.rs); atopbets_filtermodule (eq:/neq:parse_topbets_filter+ anOption-basedCategoryFilter, kept in its OWN module to avoid colliding with cohort’s existing gatingCategoryFilterincategory.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 addedCONSENSUS_CACHE_WINDOW_SECS = 600+ the handler logic. 4 parity tests already present. See category-consensus. - filters:
category_counts/tag_countsrepo queries + afilters_body(staticeq:/neq:help + live cached category/tag counts).
Gotchas / lessons
Dedup-safe reply Nats-Msg-Id
The responder JetStream-publishes the reply to
query.resultswithNats-Msg-Id = "{request_id}-result"— DISTINCT from the request id. Ifquery.request+query.resultsshare one JetStream stream with a dedup window, an identical msg-id would be silently dedup-dropped (same class as position_manager’s #427ops.resultsbug).
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_betsplain 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-contractshit 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.
Related
category-consensus · category-leaderboard-api · pmv2-onchain-watch-crate-extraction · position-manager-interface-design