{"id":"phoenix-observability","title":"Phoenix: Making the Research Loop Observable","subtitle":"Why we wired Phoenix, the Cloudflare edge limit we proved, and how to get more value from it.","category":"changelog","tags":["phoenix","observability","evals","featured"],"source":"articles/docs/phoenix-observability.md","lang":"en","words":579,"readMinutes":3,"toc":[{"depth":2,"text":"Why","id":"why"},{"depth":2,"text":"What we did","id":"what-we-did"},{"depth":2,"text":"What we proved (the hard part)","id":"what-we-proved-the-hard-part"},{"depth":2,"text":"Results","id":"results"},{"depth":2,"text":"Suggested next steps — getting more value from this tool","id":"suggested-next-steps-getting-more-value-from-this-tool"}],"html":"<h1 id=\"phoenix-making-the-research-loop-observable\">Phoenix: Making the Research Loop Observable</h1><p><strong>Featured.</strong> This is the story of wiring <a href=\"https://phoenix.arize.com\">Arize Phoenix</a>\ninto the Lupine research loop — why we did it, what broke, what we proved, and how to\nget more value out of it next. It is the first instrument that lets us ask whether the\nloop is actually getting better, instead of assuming it is.</p>\n<h2 id=\"why\">Why</h2><p>The Lupine research loop runs hypotheses through an LLM-driven pipeline: harvest →\ncomprehend → conjecture → evaluate → close. For months it ran <strong>blind</strong>. We could see\nthat it produced output; we could not see whether the output was <em>improving</em>, which\nmodel actually served a request, or where latency and cost went. A self-improving\nsystem you cannot measure is just a system that changes.</p>\n<p>Observability is the precondition for the entire north-star plan: the hypothesis\nlifecycle is the unit of optimization, Phoenix evals are the fitness function, and the\nEvolver is the actuator. Without the fitness function wired in, the Evolver has nothing\nto climb.</p>\n<h2 id=\"what-we-did\">What we did</h2><ol>\n<li><strong>Diagnosed the two disconnected halves.</strong> Phoenix configuration was split: GitHub\nrepo secrets fed the hourly evaluation workflow, while wrangler secrets fed the\nCloudflare Worker&#39;s trace exporter. Neither was set by deploy automation, so\n<strong>0 / 300 spans</strong> reached Phoenix Cloud. We set both halves.</li>\n<li><strong>Consolidated to one LLM path.</strong> <code>glim-think</code> had two LLM code paths; the gateway\none was dead (it produced none of the 300 spans). We deleted it and kept a single\nAI-SDK-native path so telemetry reflects reality.</li>\n<li><strong>Wired OpenInference telemetry</strong>, golden datasets and a functional eval runner via\nthe Phoenix REST API, a per-model performance scorecard reading live-path\nattribution (<code>ai.telemetry.functionId</code>), and finally <strong>closed the eval→routing\nloop</strong> so model selection is driven by measured performance.</li>\n</ol>\n<h2 id=\"what-we-proved-the-hard-part\">What we proved (the hard part)</h2><p>The Worker still showed zero spans even with valid secrets. We proved a <strong>hard\ninfrastructure limit</strong>: a Cloudflare Worker cannot export OTLP directly to Phoenix\nCloud. The Cloudflare edge black-holes the Worker→external subrequest and returns a\n<strong>fabricated <code>200</code></strong> — <code>curl</code> from outside gets the real <code>server: uvicorn</code>, the Worker\ngets a fake <code>server: cloudflare</code>. The Phoenix key was valid the entire time. The fix is\nnot a config tweak; it requires a GCP egress relay (mirroring <code>deploy-otlp-relay.yml</code>).\nNaming the limit precisely is itself a result — it stopped weeks of key-rotation\nguesswork.</p>\n<h2 id=\"results\">Results</h2><ul>\n<li>Telemetry is now <strong>truthful</strong>: the scorecard reads the path that actually executed,\nnot a path that never ran.</li>\n<li>The eval→routing loop selects models on real measured performance.</li>\n<li>The exact egress limitation is documented and bounded, with a known fix shape.</li>\n</ul>\n<h2 id=\"suggested-next-steps-getting-more-value-from-this-tool\">Suggested next steps — getting more value from this tool</h2><p>Phoenix is wired; the leverage now is in <em>using</em> it:</p>\n<ol>\n<li><strong>Stand up the GCP OTLP relay</strong> so Worker spans actually land — until then the\nrichest traces (the live research loop) are still dark.</li>\n<li><strong>Make the hypothesis lifecycle a first-class trace.</strong> One trace per hypothesis,\nspanning harvest→close, so a reader can replay <em>why</em> a conjecture moved. This is the\nsubstrate the Evolver optimizes against.</li>\n<li><strong>Promote scientific-throughput evals</strong> (did a round produce a literature-anchored,\nnon-trivial, falsifiable claim?) to the loop&#39;s fitness function — not just latency\nand cost.</li>\n<li><strong>Feed the scorecard into the Evolver&#39;s model-selection actuation</strong>, keeping\nstructural change PR-gated and prompt/rubric/criteria change autonomous.</li>\n<li><strong>Regression-gate every Evolver change</strong> against the golden datasets so the loop can\nonly ratchet forward.</li>\n</ol>\n<p>The goal is not dashboards. It is a measurable fitness function on the hypothesis\nlifecycle, so &quot;the loop is improving&quot; becomes a claim we can check instead of hope.</p>\n"}