<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrew Maury</title>
    <description>The latest articles on DEV Community by Andrew Maury (@andrewmaury).</description>
    <link>https://dev.to/andrewmaury</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3993629%2Fa72c3384-bc53-4d9a-9c4c-29fd4b073e94.jpg</url>
      <title>DEV Community: Andrew Maury</title>
      <link>https://dev.to/andrewmaury</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andrewmaury"/>
    <language>en</language>
    <item>
      <title>Designing a Point-in-Time Backtest You Can Actually Trust</title>
      <dc:creator>Andrew Maury</dc:creator>
      <pubDate>Mon, 20 Jul 2026 22:06:24 +0000</pubDate>
      <link>https://dev.to/andrewmaury/designing-a-point-in-time-backtest-you-can-actually-trust-10ek</link>
      <guid>https://dev.to/andrewmaury/designing-a-point-in-time-backtest-you-can-actually-trust-10ek</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://rantum.xyz/case-studies/point-in-time-backtest.html" rel="noopener noreferrer"&gt;rantum.xyz&lt;/a&gt;, which is the canonical source.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Almost any predictive model can be made to look good on historical data. The hard part is a backtest that reports what was actually knowable at decision time, so the number survives contact with production. Here is the discipline we hold every model to at Rantum, and the worked example where it walked a flattering 5.3x result down to an honest 2x.&lt;/p&gt;

&lt;h2&gt;
  
  
  The challenge
&lt;/h2&gt;

&lt;p&gt;Every predictive product is sold on a backtest: "our model would have caught X% of these events in advance." The trouble is that a backtest is the easiest thing in machine learning to fake, usually by accident. Read a feature that was only knowable after the fact, shuffle your train and test sets at random, or report accuracy on an event that almost never happens, and you can produce an impressive number that means nothing. The model then ships, and the edge that looked real on paper quietly disappears in production.&lt;/p&gt;

&lt;p&gt;The gap between a flattering backtest and a defensible one is not a modeling trick. It is a set of disciplines about &lt;em&gt;time&lt;/em&gt;: what was knowable, when, and whether the test respects that. Below is the checklist we run on every predictive engagement, and a worked example, a teardown-probability model inside &lt;a href="https://addressintel.co" rel="noopener noreferrer"&gt;AddressIntel&lt;/a&gt;, our real-estate intelligence platform, where following it changed the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we built
&lt;/h2&gt;

&lt;p&gt;A repeatable point-in-time backtesting discipline, applied here to predicting which aging houses on the San Francisco Peninsula get demolished and rebuilt. Teardowns are rare, well under 1% of parcels a year. The outcome is only visible in fragmented municipal permit records, and the features tempt you to cheat at every turn, which makes it a good stress test for a method meant to travel to any domain with rare events and messy history. Five rules do the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Score as-of T: features from data dated at or before T, nothing else
&lt;/h3&gt;

&lt;p&gt;Pick a set of historical scoring dates T, and at each one, build every feature using only information that existed on or before that date. This sounds obvious and is constantly violated, because the most predictive-looking features are exactly the ones that leak. A teardown &lt;em&gt;changes the structure&lt;/em&gt;: score a parcel as of 2018 but read its &lt;code&gt;year_built&lt;/code&gt;, square footage, or listing photos as they stand today, and every one of those attributes describes the &lt;em&gt;new&lt;/em&gt; house that replaced the old one. The feature would silently encode the answer. Only dated history, assessment rolls, sales, and permits, each stamped with the year it was true, reconstructs cleanly as-of T. Enforcing this disqualifies most of the obvious features before a single metric is computed.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Time-based folds, never random cross-validation
&lt;/h3&gt;

&lt;p&gt;Standard k-fold cross-validation shuffles rows at random into train and test sets. For anything with a time dimension, that is leakage by construction: the model trains on rows from 2020 and is tested on rows from 2018, learning from a future it would not have had. Pool observations across several as-of dates instead, and split on time: fit on T at or before 2018, test on T = 2020. Use enough distinct dates, we like six or more, that no single lucky window can carry the result, and report the metrics per fold so temporal instability shows up instead of hiding in an average.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lead with the base rate; measure lift, not accuracy
&lt;/h3&gt;

&lt;p&gt;When positives are rare, accuracy is worse than useless: a model that predicts "no teardown, ever" is 99%+ accurate and completely worthless. The honest frame is the base rate first, then &lt;strong&gt;lift&lt;/strong&gt; (how much richer the top-ranked slice is than chance), alongside precision-at-k, capture (recall) at k, and the area under the precision-recall curve. Because positives are few, bootstrap a confidence interval on every figure so you don't over-read noise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Rare positives (teardowns run &amp;lt;1% of parcels): accuracy is a trap —
# "never a teardown" scores 99%+. Lead with base rate, then lift.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;        &lt;span class="c1"&gt;# observations: (features, label), each built as-of T
&lt;/span&gt;    &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;observations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;# e.g. 0.0072
&lt;/span&gt;    &lt;span class="n"&gt;ranked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;observations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;                                         &lt;span class="c1"&gt;# top decile
&lt;/span&gt;    &lt;span class="n"&gt;precision_at_k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ranked&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;precision_at_k&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;                           &lt;span class="c1"&gt;# lift is the headline
&lt;/span&gt;
&lt;span class="c1"&gt;# Pool across as-of dates T with TIME-based folds — fit on T &amp;lt;= 2018,
# test on T = 2020. Random k-fold shuffles future rows into training: leakage.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. The label must be independent of the feature it validates
&lt;/h3&gt;

&lt;p&gt;This is the rule that saved the model from shipping a lie. The first teardown label was a cheap proxy: California's Proposition 13 caps assessed-value growth except on new construction, so a teardown-rebuild shows up as a sharp jump in a parcel's &lt;em&gt;building&lt;/em&gt; value. Scored against that label, a single heuristic (sort parcels by their land-to-improvement value ratio) looked spectacular: a 5.3x lift at the top decile, capturing over half of all "teardowns," on 17,589 observations at a 0.72% base rate. It read as an undefeated baseline.&lt;/p&gt;

&lt;p&gt;It was an artifact. The proxy label &lt;em&gt;is&lt;/em&gt; a building-value spike, and the winning feature &lt;em&gt;is&lt;/em&gt; land divided by building value. Both are functions of the same number, so scoring by the ratio was, in effect, scoring against a shadow of the label it was supposed to predict. We caught it two ways. First, a direct cross-validation: of 140 proxy-flagged rebuilds, exactly one had a confirming demolition or new-build permit at the same parcel. Second, rebuilding the label from real, independent data (actual San Jose demolition and new-single-family permits, keyed to the parcel number across a 36,896-parcel universe). On that clean, non-circular test the ratio's edge as a standalone score evaporated to no signal at all, though the underlying lot-size economics still carried a smaller, defensible signal (about 2x lift), which is the number the shipped model stands on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;5.3x&lt;/strong&gt; lift on the circular proxy label, then &lt;strong&gt;0x&lt;/strong&gt; for the same feature against an independent label.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rule generalizes past this one case: whenever a label is derived from the same source as a feature (a churn label inferred from the activity you also feed the model, a fraud label built from the rules you're scoring against), the backtest measures arithmetic, not prediction. Build the label from a source the features can't see, or the number is a mirror.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Pre-register the go/no-go, and build a gate that lets you fail cheap
&lt;/h3&gt;

&lt;p&gt;Write down the bar for success before you look at any results, so you can't move the goalposts to fit the number you got. Ours here was concrete: on out-of-sample dates, a top-decile lift of at least 5x, &lt;em&gt;and&lt;/em&gt; a material margin over the best single heuristic (not within noise), &lt;em&gt;and&lt;/em&gt; a positive median lead time so the call is early enough to act on. Just as important is a cheap feasibility gate up front. Before running any metrics, we counted teardown positives in the candidate windows; the pre-set rule was that fewer than roughly 30 to 50 positives is dead on arrival. The first pass returned zero strict positives against a ceiling of 19, so the metrics were never run on noise, and the real work, assembling an independent permit label, was correctly identified as the project rather than a detour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backtest is not the same as the live model
&lt;/h3&gt;

&lt;p&gt;The final piece of the discipline is knowing what the backtest does and does not license. The leakage that disqualifies &lt;code&gt;year_built&lt;/code&gt;, square footage, and photos is a property of scoring a parcel that was &lt;em&gt;already rebuilt&lt;/em&gt; in the historical window. Score a house that is still standing today, and those same attributes describe the actual candidate structure: no leak, and they are strong features. So the backtest validates the economic and assessment layer under strict point-in-time rules, while the live product can honestly be richer than the backtest could ever prove. Conflating the two is how teams either cripple a live model with backtest-only caution or ship a backtest number the production features quietly violate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it shows
&lt;/h2&gt;

&lt;p&gt;The unglamorous core of trustworthy predictive ML: reconstructing features as-of a decision date, splitting on time rather than at random, measuring rare events by lift instead of accuracy, keeping the label independent of what it validates, and pre-committing to a bar. None of it is exotic. All of it is routinely skipped, because skipping it produces better-looking numbers. It is the same through-line as the rest of Rantum's work (finding real signal in messy data) turned inward on the measurement itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it proves to a client
&lt;/h2&gt;

&lt;p&gt;That we will tell you whether a model works before you bet a roadmap on it. This case study is the proof: a 5.3x result that looked ready to ship as a "proprietary teardown score" got walked back to a defensible 2x lot-size signal once a clean test was possible, and we would rather deliver the smaller true number than the larger false one. Anyone can produce a flattering backtest by leaking the future into the features; the value is in the rigor that refuses to. For a business sitting on fragmented, underused data, that is the difference between a predictive product you can defend to a customer and a demo that falls apart in production. The method transfers directly to any domain with rare outcomes and messy history: insurance, lending, fraud, marketplaces, logistics, churn.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Andrew Maury is the founder of &lt;a href="https://rantum.xyz" rel="noopener noreferrer"&gt;Rantum&lt;/a&gt;, a senior data science and ML studio that turns messy, fragmented, and adversarial data into models, APIs, and products that ship. Read the full case study at &lt;a href="https://rantum.xyz/case-studies/point-in-time-backtest.html" rel="noopener noreferrer"&gt;rantum.xyz&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>python</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>From Fragmented Permit Data to a Teardown-Probability Model</title>
      <dc:creator>Andrew Maury</dc:creator>
      <pubDate>Thu, 09 Jul 2026 03:20:49 +0000</pubDate>
      <link>https://dev.to/andrewmaury/from-fragmented-permit-data-to-a-teardown-probability-model-344b</link>
      <guid>https://dev.to/andrewmaury/from-fragmented-permit-data-to-a-teardown-probability-model-344b</guid>
      <description>&lt;p&gt;&lt;em&gt;A building permit is the earliest signal that a house is about to be torn down and rebuilt. It is also some of the messiest data in real estate. This is how AddressIntel turns permits scattered across four municipal systems into a teardown-probability model — and, just as importantly, how it backtests that model without lying to itself.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv8z01v4x0k3kcrubi91i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv8z01v4x0k3kcrubi91i.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A teardown is worth knowing about early. A developer who can spot, a year or two ahead, which aging house on an outsized lot is likely to be demolished and rebuilt has a real edge over the market. The signal that precedes almost every teardown is a building permit: a demolition filing, then a new single-family-residence filing on the same parcel.&lt;/p&gt;

&lt;p&gt;The trouble is that permits are the messiest data in real estate. On the San Francisco Peninsula alone they are filed across four different portal technologies — Accela ACA (Palo Alto, Cupertino, Santa Clara), Tyler EnerGov CSS (San Mateo, San Carlos), eTRAKiT (Hillsborough, Atherton, Woodside, Burlingame), and San Jose’s open-data CKAN API. Each has its own schema, its own free-text vocabulary for what a permit &lt;em&gt;is&lt;/em&gt;, its own history depth, and no shared identifier that ties a permit to a specific parcel or listing. The hard part is not the model. It is making the underlying data joinable and trustworthy at all.&lt;/p&gt;

&lt;h4&gt;
  
  
  What we built
&lt;/h4&gt;

&lt;p&gt;A permit pipeline and a teardown-probability model inside &lt;a href="https://addressintel.co" rel="noopener noreferrer"&gt;AddressIntel&lt;/a&gt;, our predictive real-estate intelligence platform. The pipeline normalizes those four sources into one schema, resolves every record to a parcel, and classifies free-text permit types into a fixed taxonomy. On top of that sits the part most predictive PropTech skips: a label and a backtest built so the numbers can be trusted.&lt;/p&gt;

&lt;h4&gt;
  
  
  One schema, joined on the parcel APN
&lt;/h4&gt;

&lt;p&gt;The parcel Assessor’s Parcel Number (APN) is the join key that makes everything else possible. San Jose’s open-data API carries the APN natively on every permit, along with clean fields for permit type, issue and final dates, valuation, and contractor — the highest-volume market, unlocked with a free JSON call rather than a brittle scrape. For the Selenium-scraped portals, the APN is recovered from the assessor record and used to stitch permits, sales, and listings onto a single parcel timeline. Permit type descriptions, which range from "NEW SINGLE FAMILY RESIDENCE" to "Single Family (New) - New" to a bare "Demolition", are classified into a stable taxonomy (demolition, new construction, addition, remodel, roof, ADU, and so on) so a query means the same thing in every city.&lt;/p&gt;

&lt;h4&gt;
  
  
  A label that doesn’t cheat
&lt;/h4&gt;

&lt;p&gt;The first version of the label was a proxy: California’s Proposition 13 caps assessed-value growth except on new construction, so a teardown-rebuild shows up as a sharp jump in a parcel’s &lt;em&gt;building&lt;/em&gt; value. It was cheap to compute and looked plausible. We cross-validated it against real permits anyway — and it failed. Of 140 proxy-flagged rebuilds, exactly one had a confirming demolition or new-build permit at the same APN. The proxy was catching ownership resets and additions, not teardowns.&lt;/p&gt;

&lt;p&gt;So the real label comes from the permits themselves: a parcel is a teardown if it has a demolition or new-single-family permit in the forward window. Because that label is built from permits rather than assessed value, it is &lt;em&gt;independent&lt;/em&gt; of the model’s strongest feature (the land-to-improvement value ratio) — which means the backtest measures prediction, not an artifact of the label sharing arithmetic with the feature.&lt;/p&gt;

&lt;h4&gt;
  
  
  Point-in-time, or it means nothing
&lt;/h4&gt;

&lt;p&gt;A teardown changes the structure, and that is the whole trap. Score a parcel as of 2018, but read its year_built, square footage, or listing photos today, and every one of those attributes describes the &lt;em&gt;new&lt;/em&gt; house that replaced it. The features would silently encode the answer. This is the point-in-time leakage principle, and it disqualifies most of the obvious features from the backtest: only dated history — assessment rolls, sales, and permits, each stamped with the year it was true — is clean.&lt;/p&gt;

&lt;p&gt;The label construction, reduced to its essentials, makes the discipline explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Point-in-time teardown label from real permits — no lookahead, no leakage
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2016&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2018&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# historical scoring dates
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;parcel&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;universe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;roll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;assessment_asof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# land/improvement split dated &amp;lt;= T
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;roll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="n"&gt;permit_years&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;teardown_permits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parcel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# DEMO or NEW-SFR at this APN
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;permit_years&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="c1"&gt;# already torn down by T — drop it
&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;permit_years&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="c1"&gt;# Features use ONLY dated history (assessed values, sales, permits).
&lt;/span&gt;        &lt;span class="c1"&gt;# year_built, house sqft, and photos describe the *rebuilt* house — they leak.
&lt;/span&gt;        &lt;span class="n"&gt;observations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;point_in_time_features&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roll&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  What the honest number turned out to be
&lt;/h4&gt;

&lt;p&gt;The first run, scored on the proxy label before it was cross-validated, looked like a strong result: 17,589 parcel-date observations across three scoring dates, a 0.72% base rate, and a single heuristic (sort parcels by land-to-improvement value ratio) capturing about half of all “teardowns” in the top decile, a 5.3x lift. A hand-blended model, land value alone, and a cheapest-structure heuristic all trailed it. It looked like an undefeated baseline.&lt;/p&gt;

&lt;p&gt;It wasn’t. Once the label was rebuilt from real permits, a well-powered, non-circular test on 36,896 San Jose parcels and 266 confirmed teardowns, the ratio’s edge evaporated: no signal, arguably inverted, on the low-power sample (11 positives) where it could be checked. The 5.3x had been an artifact of the proxy label sharing arithmetic with the ratio. A building-value spike triggers both, so scoring by the ratio was, in effect, scoring against a shadow of the label it was supposed to predict.&lt;/p&gt;

&lt;p&gt;(You can explore this reversal yourself in the interactive chart on the&lt;a href="https://rantum.xyz/case-studies/teardown-probability-model.html" rel="noopener noreferrer"&gt;live case study&lt;/a&gt;: the proxy-label and clean permit-label backtests side by side, toggle-able by scorer.)&lt;/p&gt;

&lt;p&gt;The one signal that held up on the clean test was plainer than any of the discarded ones: parcels with an outsized lot for the neighborhood carry a real, if modest, 2.0x lift, well-powered at 266 positives. Maintenance-permit history, hoped to be a clean negative signal (an owner investing in a structure they intend to keep), added nothing blended with lot size. Neighborhood-contagion, tenure, and assessment-growth features, tested earlier against the still-trusted proxy label, had already added nothing or diluted the ratio; none of them got a second look once the ratio itself stopped being trustworthy.&lt;/p&gt;

&lt;p&gt;That is a result, not a failure, and a sharper one than the model simply beating its baselines would have been. A backtest that would have shipped as a “proprietary 5x teardown score” turned out, on closer inspection, to be measuring its own label. The honest output is a much smaller claim (an outsized lot is worth about 2x) and an explicit rule against overselling it. It also clarified where a real edge would have to come from if one exists at all: explicit seller intent in listing language (“value in the land,” “as-is,” “contractor special”) remains untested and is the cheapest next thing to try. Just as important, it clarified the line between the backtest and the live product: physical features like lot coverage and structure age leak when backtesting a rebuilt parcel, but are clean and strong when scoring a house that is still standing today.&lt;/p&gt;

&lt;h4&gt;
  
  
  What it shows
&lt;/h4&gt;

&lt;p&gt;The hard, unglamorous discipline underneath predictive ML: unifying fragmented public records onto a single joinable spine, engineering a label that is independent of the feature it validates, and enforcing point-in-time hygiene so a backtest reports what was actually knowable at scoring time. It is the same through-line as ClearTrace — finding signal in messy, real-world data — applied to civic records instead of on-chain flow.&lt;/p&gt;

&lt;h4&gt;
  
  
  What it proves to a client
&lt;/h4&gt;

&lt;p&gt;That we will tell you whether a model works before you bet a roadmap on it. This piece is itself the proof: an early 5x number looked good enough to ship, and got walked back to a smaller, defensible 2x once a cleaner test was possible. Anyone can produce a flattering backtest by leaking the future into the features; the value is in the rigor that refuses to. For a business sitting on fragmented, underused data, that means the difference between a predictive product you can defend to a customer and a demo that quietly falls apart in production. The same capability transfers to any domain with messy records and a hard-to-measure outcome: insurance, lending, marketplaces, logistics.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Andrew Maury is the founder of Rantum, a senior data science &amp;amp; ML studio that turns messy, fragmented, and adversarial data into models, APIs, and products that ship. Recent work:&lt;/em&gt; &lt;a href="https://cleartracedata.com" rel="noopener noreferrer"&gt;&lt;em&gt;ClearTrace&lt;/em&gt;&lt;/a&gt; &lt;em&gt;(on-chain execution intelligence) and&lt;/em&gt; &lt;a href="https://addressintel.co" rel="noopener noreferrer"&gt;&lt;em&gt;AddressIntel&lt;/em&gt;&lt;/a&gt; &lt;em&gt;(predictive real-estate intelligence). More at&lt;/em&gt; &lt;a href="https://andrewmaury.com" rel="noopener noreferrer"&gt;&lt;em&gt;andrewmaury.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>proptech</category>
      <category>machinelearning</category>
      <category>dataengineering</category>
      <category>datascience</category>
    </item>
    <item>
      <title>AddressIntel: Turning Fragmented Permit Data into a Predictive Real-Estate Product</title>
      <dc:creator>Andrew Maury</dc:creator>
      <pubDate>Tue, 07 Jul 2026 16:26:01 +0000</pubDate>
      <link>https://dev.to/andrewmaury/addressintel-turning-fragmented-permit-data-into-a-predictive-real-estate-product-4h91</link>
      <guid>https://dev.to/andrewmaury/addressintel-turning-fragmented-permit-data-into-a-predictive-real-estate-product-4h91</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikxyjc1nyl9edmz3p38h.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikxyjc1nyl9edmz3p38h.jpeg" width="799" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Canonical version:&lt;/em&gt; &lt;a href="https://rantum.xyz/case-studies/address-intel.html" rel="noopener noreferrer"&gt;&lt;em&gt;rantum.xyz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Predictive real-estate intelligence that fuses fragmented municipal permit records with multimodal AI to score teardown probability, flippability, and off-market opportunity.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Challenge
&lt;/h4&gt;

&lt;p&gt;The most valuable real-estate signals are buried in the messiest data. Building permits, zoning changes, and code-enforcement records are filed across dozens of municipal systems — each with its own format, portal, and lag — and almost never connected to live listing data. By the time an off-market teardown or value-add opportunity shows up in a normal feed, the developers who watch permits already know.&lt;/p&gt;

&lt;p&gt;The hard part isn’t the model; it’s making the underlying data usable at all: fragmented, civic, unstructured, and constantly changing.&lt;/p&gt;

&lt;h4&gt;
  
  
  What We Built
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://addressintel.co" rel="noopener noreferrer"&gt;AddressIntel&lt;/a&gt; is a live real-estate intelligence platform covering the San Francisco Peninsula and Nantucket Island. A Python ingestion fleet, orchestrated on GitHub Actions, continuously pulls municipal permits and public listing data; the data is normalized, fused, and scored, then served through a B2B GraphQL API.&lt;/p&gt;

&lt;p&gt;It runs on a hybrid public-benefit model — a free public transparency layer over neighborhood development trends, funded by a monetized enterprise API for developers and institutional investors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At a glance:&lt;/strong&gt; 10K+ sales records ingested, 3 predictive models in production, 2 live markets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Predictive Scoring &amp;amp; Multimodal AI
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Teardown &amp;amp; flippability models&lt;/strong&gt;  — proprietary probability scores for teardown, flippability, and bidding-war likelihood, trained on fused permit + sales history. The permit data is the signal incumbents don’t have: a demolition permit filed six months before a property hits the market is invisible to anyone watching standard listing feeds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vision-based condition scoring&lt;/strong&gt;  — Google Gemini reads listing photos to score interior and exterior property condition automatically, turning unstructured images into a model feature. No manual tagging, no scraped review data — just the photos that already exist on every listing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permit alpha&lt;/strong&gt;  — joining civic permit filings to listings surfaces off-market developer activity before it becomes visible in standard feeds. The latency between a permit filing and public awareness is weeks to months. That gap is the product.&lt;/p&gt;

&lt;h4&gt;
  
  
  Architecture
&lt;/h4&gt;

&lt;p&gt;The stack is built to be cheap to operate and easy to extend into new markets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline:&lt;/strong&gt; Python ingestion fleet on GitHub Actions cron, normalizing multi-source civic and listing data, with Gemini handling unstructured vision and NLP tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Firebase Data Connect (GraphQL over Cloud SQL Postgres) with Firebase Auth; Stripe-metered access for enterprise clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Next.js (App Router) + React on Firebase App Hosting, with Sentry edge error tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub Actions as the orchestration layer keeps infra costs near-zero for a market-coverage product where freshness matters more than sub-second latency.&lt;/p&gt;

&lt;h4&gt;
  
  
  What It Shows
&lt;/h4&gt;

&lt;p&gt;Turning messy, fragmented public records into a predictive product — and crossing domains, from data science into real estate, with point-in-time ML discipline so the scores reflect what was knowable at the time, not hindsight.&lt;/p&gt;

&lt;p&gt;It’s the same through-line as &lt;a href="https://cleartracedata.com" rel="noopener noreferrer"&gt;ClearTrace&lt;/a&gt;: find the signal in data others write off as too messy to use, ship it as infrastructure. There it’s on-chain trace data. Here it’s municipal permit filings. The skill transfers.&lt;/p&gt;

&lt;h4&gt;
  
  
  What It Proves
&lt;/h4&gt;

&lt;p&gt;That you can find signal in a data-rich space incumbents underuse, and turn it into a monetizable product — pipeline, models, API, and billing included. The same capability transfers to any business sitting on fragmented or underused data: marketplaces, fintech, insurance, logistics.&lt;/p&gt;

&lt;p&gt;The question is never whether the data exists. It’s whether anyone has built the infrastructure to make it usable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Andrew Maury is the founder of&lt;/em&gt; &lt;a href="https://rantum.xyz" rel="noopener noreferrer"&gt;&lt;em&gt;Rantum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, a senior data science &amp;amp; ML studio. He previously scaled data infrastructure at 0x Labs and contributed to Dune’s open-source Spellbook. AddressIntel is live at&lt;/em&gt; &lt;a href="https://addressintel.co" rel="noopener noreferrer"&gt;&lt;em&gt;addressintel.co&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>realestate</category>
      <category>dataengineering</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Detecting MEV &amp; Sandwich Attacks On-Chain: A Practical Methodology</title>
      <dc:creator>Andrew Maury</dc:creator>
      <pubDate>Wed, 01 Jul 2026 14:41:42 +0000</pubDate>
      <link>https://dev.to/andrewmaury/detecting-mev-sandwich-attacks-on-chain-a-practical-methodology-2dbo</link>
      <guid>https://dev.to/andrewmaury/detecting-mev-sandwich-attacks-on-chain-a-practical-methodology-2dbo</guid>
      <description>&lt;p&gt;&lt;em&gt;Canonical version:&lt;/em&gt; &lt;a href="https://rantum.xyz/case-studies/mev-sandwich-detection.html" rel="noopener noreferrer"&gt;&lt;em&gt;rantum.xyz&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A practical methodology for separating adversarial extraction from normal execution cost — and why the naive approach gets it badly wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fihz5djeorf4a90h38on8.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fihz5djeorf4a90h38on8.jpeg" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The Challenge
&lt;/h4&gt;

&lt;p&gt;Sandwich attacks are the most common form of on-chain MEV against retail traders. A bot spots a pending swap in the mempool, inserts a frontrun buy just before it and a backrun sell just after — capturing the price impact the victim caused, at the victim’s expense. The victim’s trade executes at a worse price than expected, and the difference flows to the bot.&lt;/p&gt;

&lt;p&gt;The problem for anyone trying to measure this: sandwich attacks are invisible in standard analytics. They look like normal slippage. A $10,000 swap that gets sandwiched shows up in a dashboard as “executed at 42 bps of slippage” — indistinguishable from a large trade in a thin pool. Without a methodology that isolates the adversarial component, every slippage number is a mix of real execution cost and extraction, and you cannot act on either.&lt;/p&gt;

&lt;p&gt;This matters most to DEX aggregators, L2 foundations, and grant programs that are trying to evaluate which protocols actually protect their users — and which ones quietly route flow into sandwichable positions.&lt;/p&gt;

&lt;h4&gt;
  
  
  What We Built
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://cleartracedata.com" rel="noopener noreferrer"&gt;ClearTrace&lt;/a&gt;’s MEV detection layer covers Ethereum, Base, Arbitrum, and Optimism. It identifies victim swaps, quantifies the volume sandwiched over rolling 7-day windows, and reports MEV exposure as a distinct metric — kept separate from the execution quality score so they can be read independently.&lt;/p&gt;

&lt;h4&gt;
  
  
  The v1 Mistake: tx_hash Is Not Execution Order
&lt;/h4&gt;

&lt;p&gt;The first cut at sandwich detection tried to reconstruct in-block ordering directly from dex.trades, using tx_hash comparisons as a proxy for sequencer position — treating a lower hash as an earlier transaction. That logic is wrong: tx_hash is a cryptographic hash, not a sequence number. Sorting by hash produces an arbitrary permutation of transactions, not the order they were actually included in the block. A "sandwich" identified this way is noise.&lt;/p&gt;

&lt;p&gt;The correct source is Dune’s curated dex.sandwiched table, built from Dune's Spellbook detection macro — which uses actual evt_index (on-chain event position) to reconstruct frontrun → victim → backrun triples across every block. Switching to this source eliminated the false positives entirely.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Detection Query
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;victims&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;block_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;token_pair&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tx_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tx_from&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;dex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sandwiched&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;block_time&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'7'&lt;/span&gt; &lt;span class="k"&gt;DAY&lt;/span&gt;
      &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;blockchain&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ethereum'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'base'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'arbitrum'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'optimism'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;amount_usd&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;100000000&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="n"&gt;enriched&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_attacks_7d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_sandwiched_usd_7d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;chain_attacks_7d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount_usd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;blockchain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;chain_sandwiched_usd_7d&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;victims&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;enriched&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;block_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The window columns mean the 7-day KPIs are accurate across the full dataset — not just the 500-row page — so a per-chain breakdown shows the right totals without a second query.&lt;/p&gt;

&lt;h4&gt;
  
  
  Separating MEV from Slippage
&lt;/h4&gt;

&lt;p&gt;Slippage and MEV exposure are both costs, but they have different causes and different remedies. ClearTrace scores them separately. Execution quality compares each fill’s realized price against a 1-minute VWAP oracle — both legs valued explicitly against prices.usd, avoiding the circular-pricing trap of comparing against Dune's internally derived amount_usd.&lt;/p&gt;

&lt;p&gt;The benchmark across major aggregators:&lt;/p&gt;

&lt;p&gt;| Aggregator | Median slippage vs VWAP | MEV toxicity | Revert rate | | — -| — -| — -| — -| | CoW Swap | −0.1 bps | Zero | 0.0% | | 1inch | −0.4 bps | Low | 1.2% | | Odos | −0.6 bps | Medium | 2.1% |&lt;/p&gt;

&lt;p&gt;CoW Swap’s zero MEV toxicity is structural: its batch-auction settlement mechanism bypasses the public mempool entirely, making sandwich attacks impossible by design.&lt;/p&gt;

&lt;h4&gt;
  
  
  The L2 Finding: Structural Protection vs Coverage Gap
&lt;/h4&gt;

&lt;p&gt;Arbitrum and Optimism show near-zero sandwich counts compared to Ethereum. This is worth stating carefully — two very different things can produce near-zero counts: the detector runs and finds little (structural protection), or the detector has no data for the chain (a coverage gap that would be wrong to call protection).&lt;/p&gt;

&lt;p&gt;The verification checks active_days alongside sandwich_victims_30d. If the chain has ~30 active days but tiny victim counts, the detector is running and genuinely finding almost nothing — the Arbitrum case, consistent with its FCFS private-mempool sequencing that eliminates the pending mempool window bots need to frontrun.&lt;/p&gt;

&lt;h4&gt;
  
  
  What It Shows
&lt;/h4&gt;

&lt;p&gt;The ability to detect adversarial extraction in data that’s structured to hide it — and to distinguish a real signal from an absence of data. The v1 → v2 rewrite is the concrete example: identifying &lt;em&gt;why&lt;/em&gt; the wrong model was wrong (hash ≠ sequence) required understanding the underlying data structures deeply enough to know what to use instead.&lt;/p&gt;

&lt;h4&gt;
  
  
  What It Proves
&lt;/h4&gt;

&lt;p&gt;That you can build measurement infrastructure that holds up to scrutiny. ClearTrace’s MEV layer gives L2 foundations, DEX aggregators, and grant programs a neutral answer to a question their own analytics cannot answer honestly: how much of the slippage users pay is real execution cost, and how much is being extracted by bots?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Andrew Maury is the founder of&lt;/em&gt; &lt;a href="https://rantum.xyz" rel="noopener noreferrer"&gt;&lt;em&gt;Rantum&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, a senior data science &amp;amp; ML studio. He previously scaled data infrastructure at 0x Labs and contributed to Dune’s open-source Spellbook. ClearTrace is live at&lt;/em&gt; &lt;a href="https://cleartracedata.com" rel="noopener noreferrer"&gt;&lt;em&gt;cleartracedata.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>mev</category>
      <category>web3</category>
      <category>defi</category>
    </item>
    <item>
      <title>ClearTrace: On-Chain Execution Intelligence</title>
      <dc:creator>Andrew Maury</dc:creator>
      <pubDate>Tue, 30 Jun 2026 15:15:47 +0000</pubDate>
      <link>https://dev.to/andrewmaury/cleartrace-on-chain-execution-intelligence-4p4o</link>
      <guid>https://dev.to/andrewmaury/cleartrace-on-chain-execution-intelligence-4p4o</guid>
      <description>&lt;p&gt;By Andrew Maury, Founder of Rantum&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4eb3rnz3x2s3gnkwbgy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4eb3rnz3x2s3gnkwbgy9.png" alt="ClearTrace Data attribution" width="680" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The decentralized exchange ecosystem is flooded with fake volume. Wash trades, proxy routing, MEV-farm flow — they all look like “adoption” in standard dashboards.&lt;/p&gt;

&lt;p&gt;When L2 foundations and grant programs hand out incentives based on volume, they’re rewarding the wrong behavior because there’s no neutral way to attribute a trade back to the actual frontend that originated it. Was it Uniswap? A wallet-native swap? An aggregator? An institutional desk? On-chain, there’s no standard announcement.&lt;/p&gt;

&lt;p&gt;That gap is the problem &lt;a href="https://cleartracedata.com" rel="noopener noreferrer"&gt;ClearTrace&lt;/a&gt; solves.&lt;/p&gt;

&lt;h3&gt;
  
  
  What We Built
&lt;/h3&gt;

&lt;p&gt;ClearTrace is a live, neutral, third-party execution-intelligence engine built on Dune Analytics’ granular trace and call tables — building on our open-source contributions to Dune, including 67 contracts we submitted for decoding.&lt;/p&gt;

&lt;p&gt;It attributes trade origin, benchmarks execution quality, and measures MEV exposure across Ethereum, Base, Arbitrum, and Optimism using 172K+ attributed contracts — and serves it through a public dashboard and REST API at cleartracedata.com.&lt;/p&gt;

&lt;p&gt;The attribution uses four vectors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call-data suffix trapper — parses static hex suffixes appended to router calldata that standard decoders ignore, catching meta-frontends and wallet-native swap extensions.&lt;/li&gt;
&lt;li&gt;Proxy-router hunt — flags tx_to / pool-address mismatches to reveal custom enterprise frontends and institutional smart wallets.&lt;/li&gt;
&lt;li&gt;Multi-hop origin trace — uses window functions (LAG/LEAD) over per-wallet interaction sequences to map interface hops across chains.&lt;/li&gt;
&lt;li&gt;Fee-recipient vector — clusters anonymous frontends by the basis-point fees they route to on-chain identifiers during execution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Execution Quality, Measured Neutrally
&lt;/h3&gt;

&lt;p&gt;ClearTrace scores execution by comparing each trade’s realized price against a 1-minute VWAP oracle — the &lt;em&gt;true&lt;/em&gt; cost of a trade, not the quoted price an aggregator advertises. Across the four chains covered, the best-performing aggregators land around ~7.5 bps median effective slippage.&lt;/p&gt;

&lt;p&gt;It separately detects sandwich attacks (frontrun → victim → backrun) by scanning in-block transaction ordering, reporting both the attack count and total value sandwiched as a distinct MEV-exposure metric.&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Proves
&lt;/h3&gt;

&lt;p&gt;Foundations, grant programs, and protocol teams now have neutral proof of organic-versus-wash/proxy/bot volume for named recipients — the basis for spending incentives on real adoption. It runs today as a free dashboard and public API, with paid per-chain integrity reports and standing monthly monitoring engagements.&lt;/p&gt;

&lt;p&gt;Finding signal in deliberately adversarial data — data that is obfuscated, unlabeled, or actively trying not to be measured — and shipping it as live, defensible infrastructure is what Rantum does.&lt;/p&gt;

&lt;p&gt;If you have messy, fragmented data that needs to become a product, l&lt;a href="https://rantum.xyz" rel="noopener noreferrer"&gt;et’s build it together&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>ethereum</category>
      <category>datascience</category>
      <category>onchainanalysis</category>
    </item>
  </channel>
</rss>
