Open RadarPulse →
RadarPulse TOOLS & DEVELOPER · NEWS We were scoring a generated options tape against real congressional filings
Tools & Developer · August 2, 2026 · NEWS

We were scoring a generated options tape against real congressional filings

The congressional filings were real. The options flow sitting next to them was written by our own code, minutes earlier, by a function whose source comment calls it an "NVDA bull whale cluster".

On 2 August 2026 we found that the RadarPulse confluence board was scoring a generated options tape against real congressional filings, and presenting the pair as a current cross-domain signal. The filings were genuine. The options flow sitting next to them was invented by our own code. This is the account of what it did, why it did it, what changed, and how you can check the fix yourself without taking our word for any of it.

We are writing it up because a confluence score that looks like a live signal but is not is worse than not having the feature at all, and because a company that only publishes its wins is telling you something about the losses it is not publishing.

What the board claimed

The confluence board ranks tickers 0 to 100 by how many independent domains agree on them: unusual options flow, congressional disclosure, 13F institutional filings, and prediction-market odds. Only names with agreement across two or more domains surface. That cross-domain overlap is the thing RadarPulse is actually for, so the board is not a side panel. It renders on the Confluence tab, on the For-You home, in the Overview "Trending now" strip, and in the ticker quick-view.

The promise is specific: these domains independently point at the same name right now. Both halves of that sentence have to be true for the number to mean anything.

What it was doing

The options-flow half could be fabricated.

When the US market is closed, there are no live prints to stream. To avoid a blank flagship screen, the app falls back to a bundled sample session generated by a function called genSample(). That generator is not a random noise field. It writes a scripted narrative, including a cluster its own source comment describes as an "NVDA bull whale cluster". It exists to demonstrate the interface, and as a demo tape that is a perfectly reasonable thing to have.

The problem was what consumed it. The congressional leg of the confluence score had always been guarded: every consumer excluded rows tagged _sample, so a demo filing could never be scored. The flow leg had no equivalent guard. So the scoring function took real, dated, legally-required STOCK Act disclosures and paired them with prints our own generator had authored minutes earlier, then ranked the result and put a confidence number on it.

Two surfaces made it worse. renderXDomain() and renderTrending() did not merely consume a sample tape that happened to be loaded. Each one called loadSampleSession() itself when it found no flow. Opening the Confluence tab on a quiet market would generate a tape and then score it. The board was manufacturing its own evidence.

Why this was live and not theoretical

It would be convenient to describe this as an edge case that needed the market shut and the cache cold. It was not an edge case. It was the normal path.

RadarPulse runs on a free delayed market-data feed, which is capped at roughly 100 credits a day and scans in bursts rather than streaming. As of this writing the backend has no stored real session at all. You can see that yourself, and you do not need an account:

curl -s https://flowradar-backend-production.up.railway.app/api/flow/last-session

That returns {"replay":false,"trades":[]}. Zero real prints stored. Meanwhile the congressional feed is full:

curl -s https://flowradar-backend-production.up.railway.app/api/politician-trades

At the time of writing that returns 388 filings, none of them sample-tagged. So the exact conditions were: a real disclosure feed with hundreds of genuine rows, an empty flow feed, and a scoring function willing to fill the gap with fiction. The fallback was not the exception. It was what most users would have hit most of the time.

We cannot tell you how many people saw a fabricated score, and we are not going to estimate. RadarPulse ships with analytics switched off at the source: the shipped bundle contains ANALYTICS_ENABLED=false and collects nothing. That is a deliberate choice we stand behind, and one of its costs is that we genuinely do not know. Saying "very few users were affected" would be a guess dressed as a measurement, which is the same failure as the bug.

The fix

The rule we settled on is narrow: generated flow may exist, but it may never be scored. A demo tape is honest when it is labelled and inert. It stops being honest the moment a confidence number is computed from it.

One predicate now answers the question "is the flow on screen real?", and two compute choke points consult it before doing anything else. _confluenceRows() returns an empty list and _convictionFor() returns null when the tape is generated. Because every surface reads its numbers through one of those two functions, guarding two places covers 17 and 3 downstream call sites respectively, 20 in total. There is no surface left that can render a score the choke point refused to compute.

The two self-seeding calls were removed outright. A board with nothing to show now says so, instead of generating something to show.

One detail is worth stating because it is the part that nearly went wrong. The obvious implementation is to check whether the loaded session is flagged as a sample. That is incorrect here: the app deliberately keeps the previous session object in memory after it goes live, so an unconditional check would have reported "simulated" for users with genuinely streaming flow and silently deleted the feature for exactly the people it works for. The guard is scoped to the case where the sample session is actually the active source. We did not reason our way to that. The regression sweep caught it, which is the argument for running the sweep rather than trusting the diff.

What we did not fix

Three things remain true, and we would rather say them than have you find them.

The generated tape still exists. We did not delete genSample(). It is still the demo session, still loads when markets are closed, and is still labelled as a sample on screen. The rule is that it may not be scored, not that it may not exist.

The public scorecard is empty. Our /proof page grades every signal in public, and it is currently building rather than reporting. At the time of writing the API behind it returns tracked: 0, measured: 0, needed: 30. Not "a small sample". Zero. The tracker only records real prints scoring 70 or above, and with an empty flow feed nothing has qualified. A page that says "building" while showing nothing is unsatisfying, and it is the honest state.

The underlying cause is a data feed, not a bug. Real-time options flow costs money we do not currently spend. That is a business decision, described plainly on the Trust Center, and it will keep producing thin data until it changes. What we fixed is the product's willingness to paper over it.

How to check us

Two of these you can run right now.

The guard is in the code we actually ship. The fix is not a claim about a private branch. It is in the JavaScript bundle your browser downloads:

curl -s https://radarpulse.io/app.js | grep -c _flowIsSimulated

That returns 6, which is the number of lines in the bundle that mention it: the definition, one cross-reference in a comment, and four places where the guard actually runs. You can read the surrounding source in the same file. If that count ever drops to zero, the guard has been removed and this article has become false.

The bundle is byte-stable, so you can pin it yourself. Run curl -s https://radarpulse.io/app.js | sha256sum twice and you will get the same digest both times. It changes only when we deploy, so you can record it now and detect any change we make later. We are deliberately not printing a hash here: this article ships in the same release as an unrelated navigation change, so any value we quoted would be stale the moment you could read it. A digest you take yourself is worth more than one we hand you anyway.

One warning if you try the same trick on our homepage: it is not byte-stable. Cloudflare rewrites the obfuscated email links with a fresh key on every response, so the digest changes each fetch while the content does not. That is an edge feature rather than anything of ours. We mention it because it is the first check we tried and it failed, and an honesty page that hands you a broken verification step is worse than one that hands you none.

What you cannot check, and we will not pretend otherwise. The fix is commit baba92f, with the Trust Center and the scorecard fingerprint in 4c6266d. Our repository is private, so those references are for our own record. They are not something you can pull, and quoting them as if they were independently verifiable would be theatre. The bundle above is the real evidence.

What stops it coming back

A fix with no guard is a fix with a shelf life. Two things now hold this in place.

A permanent regression suite drives the exact incident state, real filings plus a generated tape plus the closed-market status, and asserts that every one of the affected surfaces renders nothing. It also asserts the opposite direction, that a real feed still produces a working board, because a guard that quietly deletes the feature is not a fix either. Both halves matter, and the second one is the one people forget to write.

The wider claim was corrected too. Our markets-terminal page had said the terminal "pairs each disclosed name with the live price and options tape". That sentence was true only when the tape was live, which is precisely the case that failed. It now states the condition explicitly, and a claims registry check fails the build if the old wording returns.

We would rather publish this than have it found. If you spot something like it, the Trust Center reads every feed live and tells you what is real, delayed, or simulated at that moment, and it is generated from system state rather than written by hand.