← PROTOTYPES

Sentiment · the public gauges

23 September 2026 · branch hub/sentiment-2-20260923 · built and checked on the MacBook · nothing deployed, nothing pushed

You asked three things. "The sentiment page… how exactly is this happening?" — that is the first section below, in plain words, before anything was changed. "Scoring by newest channel is not necessarily the right way. We need to blend the opinions of different channels." — that is now how the voices are read. "An internal sentiment meter when we don't have the entire market… same problem as the put to call." — that meter is gone, and the page says why. The headline is now the gauges other people publish, shown the way they publish them.

1 · How each voice is measured today

Four feeds, four different methods, none of them an AI reading the text. Here is exactly what happens to each one, and what makes each one wrong.

YouTube

A scheduled job on the Mac collects clips two ways: everything new from the channels you subscribe to, and the results of ticker searches. Both land in a table called youtube_videos — 11,262 clips stored, of which 6,085 carry a ticker. For the subscribed channels the job then downloads the English subtitles and, around each mention of a ticker, counts words from a fixed finance word list — "breakout", "squeeze", "dump", "overvalued" — flipping a word when a "not" or "never" sits just before it. That is all it is: a word list with a negation rule, not a model, and nothing reads the video or the picture. The counts for the last seven days are added up per ticker and written as one row into social_sentiment — 63 tickers, 231 mentions at the time of writing.

What makes it wrong. The row is pooled: every mention counts the same, so a channel that posts fifty clips a week carries the number and a careful channel that posts once does not register. The only channel named on the row is last_channel, the newest one to mention that ticker — that is the "scoring by newest channel" you spotted, and it is a label, not a measurement. A word list cannot hear a question or a joke: "is NVDA about to crash?" counts as bearish. And the two tables that would let anyone check a single video — youtube_transcripts and youtube_video_sentiment — are both empty (0 rows), so the pooled number cannot be taken apart.

X

A browser-side collector saves the posts on your Trading list and republishes them at /api/xfeed — 16,931 posts today. Every post's text goes through the same finance word list, so a post is bullish, bearish or neither, and the day's reading was the net share of the posts that leaned. What makes it wrong: the same word-list limits, plus the fact that the picture is never read — on X the chart in the image often is the call. Posts with no ticker still vote.

StockTwits

631 stored messages in social_posts, each carrying the poster's own Bullish or Bearish tag, so nothing is inferred at all. What makes it wrong: the ingester stopped months ago. The page shows it and never counts it.

News

news_sentiment holds 374 rows: one score per ticker over four days, weighted by how many headlines it came from. What makes it wrong: individual headlines are not scored anywhere, and the stored row carries no publisher — so there is nothing to blend across outlets, and the page now says that instead of implying an outlet-level reading it does not have.

2 · The headline is now the public gauges

Each card shows the value, the publisher's own word for it, the date it refers to, one line on what it measures, and a link to the source. Nothing is averaged with anything else. A gauge whose source cannot be read from a browser shows a dash, the real reason, and what would fix it — never a guess and never an old number without its date.

GaugePublisherWhat it measuresState today
Fear & GreedCNN BusinessSeven market readings, each measured as distance from its own averageLive · 35 "fear" at 19:32Z, with all seven parts on the card (52-week highs 0, breadth 0, momentum 32, put/call 49, volatility 50, safe haven 60, junk bonds 54)
Crypto Fear & Greedalternative.meBitcoin volatility, momentum, social posts, dominance, search interestLive · 71 "Greed", 23 Sep
VIXCboe, through our chart APIThe swing the options market expects in the S&P 500 over 30 daysLive · 14.21, 22 Sep session, below its 50-day average. The term structure line is not shown: VIX3M is not carried by the chart API, and Cboe's own file sends no cross-origin header, so a browser cannot read it directly.
Put / call ratioCboe, through our chart APIPuts traded for every call across all US optionsNot readable · the chart API answers 404 for PCC. Lane M13's branch adds that route; I folded M13's commit in, so this card fills itself in the moment the chart API is deployed.
Investor sentiment surveyAAII, weeklyMembers saying bullish / neutral / bearish for the next six monthsNot readable · aaii.com answered HTTP 403 to this machine on 23 Sep and publishes no free data file.
Exposure indexNAAIM, weeklyWhat active managers report actually holding, −200 to +200Not readable · no public data route — the number is printed inside the web page and the site's data endpoint answered 404 on 23 Sep.

The one thing that would fix three of these at once: a small reader on our own domain that fetches AAII's and NAAIM's weekly pages once a week and republishes the numbers with their dates, and the chart-API deploy that carries Cboe's put/call. That is one deploy and one tiny job, and it takes the headline from three live gauges to six.

3 · The internal "Scintilla fear & greed" is gone

You said it plainly: an internal meter when we do not see the whole market has the same problem as the put/call row did. Removed, and here is why that is the right call rather than moving it lower down. We hold 364 stocks out of some four thousand US listings, we have no options flow of our own, and we have no exchange count of 52-week highs and lows. A single number built from that was presented as a market reading while being a reading of our own shelf. The two runs I captured on production minutes apart read 54 and then 49, because a different set of inputs happened to be live — a headline that moves five points on which feed answered is not a measurement.

What stays: every input row — momentum, volatility, safe haven, junk bonds, how many of our stocks are up, put/call, 52-week highs — each on its own line with its own source, its own age and CNN's score for the same thing beside it. Nothing is averaged into a headline. The rows are useful; the average was the claim.

4 · The voices now blend across channels

One channel, one vote, whatever its volume. A channel's own lean is the average of its clips; a ticker's lean is the average of the channel leans; the reading is the average of the channels. Beside every reading the page prints how many channels and how many clips or posts are behind it, and when the channels split it says so on the row rather than averaging the disagreement away.

What that looked like when I captured it: YouTube 358 channels, 736 clips over seven days — 89 leaning positive, 68 negative, 201 neither, and the channels disagree (43% on the smaller side). Per ticker: NVDA neutral 52 from 122 channels across 179 clips, SPY neutral 46 from 87 channels, QQQ neutral 45 from 64, MU greed 64 from 55, GOOGL fear 37 from 32. X: 92 handles, 864 posts in 24 hours, greed 57. The old pooled YouTube number read 98 — near-maximum greed — over the same period, which is what happens when the loudest channel carries the count.

The honest limit. This blend reads the titles of the ticker-tagged clips, because the per-video and transcript tables in the database are empty — so it covers the nine tickers the search collector files (NVDA, SPY, QQQ, MU, IREN, NBIS, GOOGL, TSM, DRAM), not all 63 in the pooled roll-up. Both numbers are on the page, each named for what it is. When the collector starts writing per-video rows, the same blend covers everything without another change.

5 · Before and after

production sentiment tab at 1680
Before · 1680. Production today: the big Scintilla dial reading 54 NEUTRAL · THE MARKET, a second number for the voices, CNN's number small at the side, and the seven input rows below in 9px type.
new sentiment tab at 1680
After · 1680. The published gauges are the headline — CNN at 35 with its seven parts listed, crypto at 71, VIX at 14.21, and the three unreadable ones saying why. On the right, the voices blended across channels with the per-ticker table: channels, clips, and "channels split" where they disagree.
production sentiment tab at 390
Before · 390. The same dial on the phone, reading 49 a minute later.
new sentiment tab at 390
After · 390. One gauge card per row, the voices table underneath with the drawn split dropped so the counts fit.

How the shots were taken: the page was served from the branch on this MacBook and opened in a real Chromium at 1680 and 390. The chart API only answers https://scintillahub.ai, and CNN turns away anything that looks automated, so both were proxied through the capture script with the production origin and an ordinary browser header, and the X feed was proxied from production because a local static server has no serverless functions. Nothing else was changed, so what you see is what the deployed page renders. I opened both shots and read them.

6 · What could be wrong

7 · What I did not do