feat(analytics): report to collect.mindshub.ai and send an identifying agent (ENG-1355) - #333
feat(analytics): report to collect.mindshub.ai and send an identifying agent (ENG-1355)#333lucas-koontz wants to merge 1 commit into
Conversation
…g agent The baked default was a raw execute-api id belonging to an AWS account nobody can deploy to, so the endpoint could not be changed without shipping a release to every install. Points it at a hostname we own instead, where the collector is in a repo and behind CI. Also corrects this module's own docstring, which stated that every extra kwarg became a queryable PostHog property and that this was not an allowlist. That was false for as long as it had been written: the collector copied five property names and dropped everything else, so turn_completed reached PostHog carrying one of its 28 properties, and only when its action name happened to match a lowercase prefix. The claim is true now, minus a denylist, and the docstring says which. The request carries an explicit user agent because urllib's default Python-urllib/3.x is answered with 403 by the bot protection on the mindshub.ai zone, and _fire discards its response, so an event blocked for looking like a script would vanish with no trace. Lucas Koontz ENG-1355 - Analytics collector lambda silently drops turn_completed and its properties Refs: ENG-1355
EntelligenceAI PR SummaryAnalytics now sends events to the hostname-controlled flowchart TD
classDef newBehavior fill:#dcfce7,stroke:#16a34a,color:#14532d;
Config["AntonSettings analytics_url"] --> SendEvent["send_event builds event URL"]
SendEvent --> Fire["_fire sends asynchronous HTTP request"]
Fire --> Collector["collect.mindshub.ai collector"]
Collector --> PostHog["PostHog preserves event properties"]
class Config,SendEvent,Fire,Collector newBehavior;
Review Scorecard
Safe to merge with a minor test follow-up — the Medium blast radius is appropriately contained, and the analytics change cleanly preserves opt-out and asynchronous fire-and-forget behavior while adding the controlled collector endpoint and identifying User-Agent. The only issue is that the URL regression test in Key Findings:
Evaluated against
Files requiring special attention
|
User story
As a harness engineer who shipped per-turn cost accounting last week
I want anton's
turn_completedevent to reach a collector that keeps its propertiesSo that ENG-1286's spend ceiling can be set from real turn costs instead of guessed at
Why this matters
turn_completedhas never arrived in PostHog. The collector it was pointed at matched a lowercaseanton_/ds_connect_prefix on the action name and copied five known property names, discarding everything else and answering HTTP 200 either way.send_eventis fire-and-forget behind a bareexcept, so nothing reported it. Theturn_costlog line worked the whole time, which is what made it look healthy.This is the client half of the fix. The collector half is mindsdb/mindshub_services#186.
What happens today
sequenceDiagram participant S as anton session participant A as anton/analytics.py participant L as zoomInfoCollector participant P as PostHog 355390 S->>A: send_event("turn_completed", 28 props) A->>L: GET ?action=turn_completed&... L--xP: action fails the prefix filter, nothing relayed L-->>A: HTTP 200 A->>A: response discarded, no error raised Note over S,P: The log line is complete.<br/>The sink is empty. Nothing says so.What should happen
sequenceDiagram participant S as anton session participant A as anton/analytics.py participant L as collect.mindshub.ai participant P as PostHog 355390 S->>A: send_event("turn_completed", 28 props) A->>L: GET ?action=turn_completed&... (User-Agent set) L->>P: capture, all properties minus a denylist L-->>A: HTTP 200, relayed true A->>A: response discarded, as before Note over L,P: A drop or a relay failure now<br/>increments a counter and alarms.What changed
anton/config/settings.pyanalytics_urldefault is nowhttps://collect.mindshub.ai/collect. Still overridable withANTON_ANALYTICS_URL.anton/analytics.py_firesendsUser-Agent: anton-analytics/1.0instead of urllib's default.anton/analytics.pyextrakwarg became a queryable property and that this was not an allowlist. Both halves were false.tests/test_analytics.pyexecute-apiid.On the docstring. It is worth reading the diff on it rather than skimming. The old text told any author that no collector work was needed to add a property, which is a plausible reason this defect reached Passed QA. The new text says what the collector actually does, notes that it was different before 2026-08-11, and tells a reader to check the collector before assuming a missing property is the caller's fault.
On the user agent. Cloudflare's bot protection answers
Python-urllib/3.xwith 403 on the mindshub.ai zone. The collector host is deliberately not proxied, so this is a second line rather than the only one, but_firediscards its response either way and a blocked event would disappear with nothing reporting it.Acceptance criteria
turn_completedrow in project 355390 whose properties match that turn'sturn_costlog line, with the per-role token sums reconciling totokens_totalandunknown_tokensat 0.ANTON_ANALYTICS_URLstill overrides the default.ANTON_ANALYTICS_ENABLED=falsestill suppresses the event entirely.send_eventraises nothing when the endpoint is unreachable, refuses the request, or returns a non-200.How to test
collect.mindshub.aianswers. Confirm withcurl -s "https://collect.mindshub.ai/collect?action=anton_probe&aid=qaprobe1355"returningrelayed: true.ANTON_ANALYTICS_ENABLED=false.turn_costline for that turn from~/Library/Logs/anton/cowork-server.log.select * from events where event = 'turn_completed' and properties.conversation_id = '<the session id from step 3>'. Expect exactly one row.planning_tokens + coding_tokens + router_tokens + unknown_tokensmust equaltokens_total.ANTON_ANALYTICS_URL=https://example.test/collectand check the request goes there instead.ANTON_ANALYTICS_ENABLED=falseand check nothing is sent.where properties.aid not like '%probe1288%' and properties.aid not like '%probe1355%'.Verified locally
pytest tests/(full suite)pytest tests/test_analytics.py tests/test_settings.pyafter rebase onto currentstagingNote on rollout
The endpoint reaches the fleet through a normal release plus the sidecar auto-updater, so no flag day. Installs older than that release keep reporting to the previous collector, which stays running and relays into the same PostHog project, so there is no gap in the event stream while the tail drains. Rows are told apart by their
sourceproperty.Ships with
Refs ENG-1355