Collective Intelligence Protocol
HomeCrisisOne PriceObservatoryResearch
Hive β†’
Beta guide - under review. Describes NightWatch v1.0 beta; features marked v1.1 / v1.2 are planned.
draftlast updated 2026-09-29 (Step 6: WCI definition B3.1, fixed per audit R1 β€” the same-exchange exclusion now covers every warning type, not just one; a 24h lead floor; notice de-duplication keeps the date; stale-grade handling; notice-feed AND missing-aggregate-writer freshness paging. B3.1 became the headline on 2026-10-01. Step 7: cross-exchange flag signal, which flows through B3.1's same-exchange exclusion and 24h lead floor automatically)

The Crisis Bulletin and the Life of a Token

Why this is a chain, not a screen

The Crisis Bulletin looks like one page: red badges, a headline percentage, a scrolling strip of tickers. Underneath it is a chain of small workers that most people never see. One watches the whole pipeline every five minutes and writes warnings. Others clean up after it: they check whether a scheduled delisting actually happened, fix tokens that were wrongly marked dead, and correct warnings that were auto-closed by mistake. This chapter follows that whole chain, including the part where NightWatch found its own headline trust number was measuring the wrong thing and said so in public.

Step 1: the five-minute loop

Everything starts with the keeper worker, which runs on a five-minute loop watching the entire scanning pipeline. Every cycle it checks for anomalies (a grade suddenly dropping, order-book depth collapsing, a spread spiking, an exchange announcement about a delisting) and, when it finds one, writes a row to a table called nw_warnings. It also sends the Telegram alerts. Its ability to auto-restart a dead worker still exists, but the list of workers it can actually restart was cut down in July 2026 to just the two services that live on Render (the API and the frontend); every trading and scanning worker now runs on the Chuncheon server under systemd, which already restarts them on its own, so keeper's restart path is a deliberate no-op for those workers. This one loop is the single source both the Crisis Bulletin's warning cards and the whole "did we call it" tracking system depend on: if keeper goes quiet, both go quiet with it, silently.

Warning ideaWhat it means
grade_drop / grade_slipThe liquidity grade fell
depth_collapseOrder-book depth thinned out sharply
spread_spikeBid/ask spread widened sharply
zero_volumeNo trading activity for several scan cycles
exchange_notice_delist / _suspendAn exchange published its own removal or suspension notice
suspensionThe token's own record shows it currently suspended
st_taggedThe exchange applied a special-treatment (distress) tag

Step 2: three columns, one page

The Crisis Bulletin's main board is three columns that read left to right as a funnel: Detection (raw anomalies across the whole scanned SPOT universe), Tracking (the smaller Priority Watchlist getting closer live monitoring), and We Called It (confirmed outcomes: an ST tag, a suspension, a delisting, that a NightWatch warning came before). Below that sits a filterable Token Pulse Grid, which can be narrowed by verdict, exchange, or a search term, including a dedicated ST tab for distress-tagged tokens. A token doesn't have to move through all three columns to end up delisted; a lot of real events skip straight to "We Called It" with no prior Detection entry at all, which is exactly the gap the trust number below has to be honest about.

Since 2026-09-18 the bulletin also carries a separate Perps group: Hyperliquid main-dex and trade.xyz perpetuals, each with a Perp badge and its dex label (Hyperliquid or trade.xyz), plus a provisional marker on a grade with under 7 days of scan history. A perp is graded β€” the same NW Grade calculator as spot, chapter 2 β€” but it is not verdicted the Detection/Tracking/We-Called-It way spot rows are; it carries no crisis urgency scale, and it never counts toward the WCI or the grade-dropped warning universe below.

Step 3: the TOKEN LIFECYCLE ticker

Above the three columns runs a scrolling marquee called the Lifecycle Ticker. It is fed by one endpoint, GET /board/lifecycle_events, which independently pulls six kinds of event and fails soft: if one source query breaks, the other five still show up and the broken one just reports itself as failed rather than taking the ticker down.

Ticker kindWhat triggers it
delistA future-dated, still-scheduled delisting notice (shown as a D-N or D-DAY countdown)
listingA base ticker's very first appearance on any tracked exchange
promoted (subkind board)Confirmed entry into an exchange's main board from an emerging/innovation zone
promoted (subkind spread)An already-listed token appearing on a new venue
assessmentAn exchange placing a token into an assessment/monitoring zone
suspensionA deposit or withdrawal suspension

One design choice is worth knowing: the promotion signal does not come from the token's own change-history log. That log was investigated and rejected, because 2,657 of its roughly 2,660 entries all share the same reason code and near-identical timestamps from a single bulk migration in December 2025, not a live stream of real events. The ticker instead reads a separately maintained "entered main board" marker that keeper updates today.

Clicking a box, or the ticker's background, opens a panel of matching events. Navigation only happens from two links inside that panel (an external "Notice" link when a source URL exists, and "Full story" to the token's own page); the boxes themselves never navigate directly, which keeps an accidental tap on the moving strip from launching you somewhere you didn't mean to go.

Step 4: the number everyone actually reads: WCI

"We Called It" (WCI) is the headline percentage: of the spot tokens that had a real bad outcome, what share did a NightWatch warning predict in advance? It sounds simple. It has not been simple to compute honestly, and the story of getting it right is the most instructive thing in this chapter.

The timeline:

DateHeadline shownWhat was actually true
before 2026-09-0190%+Defective. A near-empty denominator was being forced to 1 by a coding shortcut, inflating the rate.
2026-09-0237.3%Honest fix landed: computed only from real warning outcomes, not from a broken table join.
2026-09-1038.4%Same honest definition (called "Definition A"), reproduced exactly for an audit.

At 38.4%, someone asked a harder question: why had the honest number fallen 27 percentage points since July? The answer, worked out in a full self-audit, is the platform's most detailed piece of self-auditing to date.

About 60% of the fall was not lost skill. It was what got counted. Two things had crept into the denominator that could never have been predicted in the first place:

  • Tokenized US equities on Bitget. In June 2026, 516 tickers like RAAPL and RTSLA (crypto wrappers around US stocks) were bulk-onboarded, and more arrive most weeks. They carry a different internal data shape than real crypto pairs, so the grade-based early-warning checks (grade_drop, depth_collapse, and the rest) read missing data and never fire on them. This affects specifically the roughly 83 of these tickers that were suspended with no 7-day liquidity grade ever computed for them; the rest of the tokenized-equity tickers do carry a normal grade and behave like any other token. For the affected 83, the one warning type they can still emit, zero_volume, takes two to three scan cycles to arm, so in practice it lands about one to two hours after the suspension it was supposed to warn about, not before, and so still counts as a miss. Removing this whole class of instrument from the count alone moved the rate from 38.4% to 46.9%.
  • Cross-exchange notice fan-out. When one exchange announces it is delisting a pair, the system was recording that as a delisting at every other exchange that happens to list the same ticker, even when those other exchanges said nothing at all. In one worked example, a single Binance announcement about removing a handful of trading pairs turned into about twenty recorded "delistings" spread across nine venues (Binance itself plus eight others that had published no notice at all), including entries claiming a token was being delisted from an exchange that had made no such announcement.

After removing both of those distortions, the real decline was about 11 percentage points, not 27, and it splits into two separate stories rather than one. The rate decline itself is concentrated on three exchanges: KuCoin, MEXC, and Gate.io. But the pattern behind it differs by venue: on KuCoin and Coinbase specifically, tokens that were already grade-A and had been listed for 50 to 320 days were flipping straight to suspended with no liquidity warning beforehand at all, a genuine gap worth investigating, not an artifact. On MEXC the gap is a different mechanism: newly listed tokens are dying before they accumulate the seven days of trading history a liquidity grade requires, so of 22 such under-14-day deaths in the audit window, only 2 were ever called.

What changed on 2026-09-10 ("Definition B2"): the fix was not to loosen the definition. One tempting shortcut was measured and rejected: counting a warning as a "call" even if it was issued up to six hours after the bad outcome (not just before it). That variant produced a rate of 78.8%, and it was rejected on the grounds that a warning issued in the very same detection cycle as the outcome is co-detection, not prediction, and a rate built that way is not meaningfully different in kind from the pre-09-02 90%+ defect. Instead:

  • suspension was removed from both ends of the calculation: it is self-referential as a denominator (grading yourself against your own detection) and too easy to co-detect as a numerator.
  • The numerator now counts only genuinely predictive warning types (liquidity/depth/volume advisories, on-chain exit signals), not every warning type NightWatch has ever issued.
  • Tokenized equities and cross-exchange fan-out notices are excluded from the population by name, not by guessing at a symbol pattern. From 2026-09-18, every Hyperliquid perpetual (asset class perp) is excluded the same way, by exchange name.

Measured the same day: before those pipeline repairs, B2 read 43.4% (389 of 896); after the repairs shipped, it read 51.9% (377 of 726), with an average lead time of about 30 days before the outcome (versus roughly 17 days under the old definition).

The 38.4% figure was never erased. Per NightWatch's own no-retroactive-restatement rule, a number already shown to readers stands as published; the change applied from its start date (2026-09-10) onward and nothing shown before it was rewritten. The same rule governs every later definition change, including B3.1 below.

Step 5: tightened again β€” definition B3, and a slower rollout this time

A follow-up self-audit (docs/ops/WCI_MISS_ANALYSIS_2026-09-28.md, then a second-round audit of the fix itself) found that with B2's repairs in place, most of what still looked like a "miss" was, again, an event that should never have been in the denominator at all β€” not a failure to predict anything:

  • Wallet and network maintenance mislabelled as distress. A deposit/withdrawal-pause notice β€” a Bithumb "temporary suspension" announcement, or a Binance network-upgrade/hard-fork/contract-swap notice β€” was being counted the same as a real suspend-for-distress notice. The audit also caught the reverse mistake: a caution or delisting designation worded around a deposit/withdrawal pause must never be waved through as "just maintenance," so the classifier checks for caution/delisting language first.
  • A margin-only delisting mistaken for a spot delisting. "Binance Margin And Loan Will Delist BTTC & POWR" describes a product, not the spot pair, being removed β€” but its wording slips past the margin-specific classifier and lands in the same bucket as a real spot delisting notice. KuCoin's "Convert Will Delist" wording, on the other hand, turned out NOT to reliably mean "still on spot" once the audit checked the actual bases β€” those are kept as real events, deliberately not excluded.
  • A quote-pair removal notice whose pair list got cut off. Binance's own announcement feed truncates the title of a long "Notice of Removal of Spot Trading Pairs" before it names every pair. B2 already excluded a verified quote-only removal (e.g. LTC/BNB); the fix for the truncated case doesn't just trust the label, either β€” it checks whether the named base is still actually trading on that exchange before excluding it. If the base looks gone, the notice is kept as a real event, since there is no proof it wasn't.
  • Special-treatment tags counted as a state, not a change. The keeper writes an ST tag warning every day a token stays tagged, not only the day it first got tagged. Requiring "no earlier tag" alone isn't enough, either β€” a pair we had simply never looked at before would also show "no earlier tag" without ever having been untagged. The fix additionally requires some earlier observation of the pair (an earlier warning, a rolled-up summary row, or a token record more than a day old) before treating "no earlier tag" as proof of a real transition.
  • Tokenised equities and stablecoins the registry hadn't caught yet (MEXC's Ondo-wrapped tokenised equities and a short list of stablecoins) β€” plus a first-round bug where the stablecoin exclusion was written into the registry but never actually wired into the query that reads it. Caught before shipping.

What changed in definition B3:

  • An ST tag counts as an outcome only when it is a genuine state change with a known prior state β€” no earlier ST tag for that pair (checked against both the live warning history and the rolled-up summary table), and some earlier sighting of the pair at all, so "we never looked" can't be mistaken for "it was untagged."
  • A notice is excluded from the outcome population when the full stored text (not a symbol pattern) identifies it as wallet/network maintenance or a margin-only action, or when a quote-pair-removal notice's named base is confirmed still trading on that exchange β€” recorded as a new field, kept separate from B2's own scope field so B2's own number never moves.
  • Two more warning types were promoted to predictive, but only once persisted for a real 24 hours: spread_spike and zero_volume count as a call only when the same condition also fired on BOTH of the two calendar days immediately before the event, not just one. (Requiring only the single day before turned out to let a row at 23:55 and another at 00:05 the next day qualify after ten minutes β€” the two-day check is the smallest one that actually guarantees a full day of continuity no matter where the day boundary falls.)
  • Composition is no longer hidden in one aggregate number: the payload reports events and calls separately for ST tags, delist notices, suspend notices and confirmed delistings, because β€” as the audit found β€” the vast majority of what this metric measures is ST-tag prediction, and that is worth knowing on its own.
  • The 90-day headline is shown with a 60-day figure alongside it, since a shorter window is naturally less exposed to how far back the retention floor reaches.
  • No minimum lead time is claimed anywhere β€” a warning that fires an hour before the event still counts as a call, same as one 60 days ahead of it. Measured read-only on production over the 90-day window: median lead time is about 29 days, and only 5.8% of calls come in under 24 hours before the event (0.4% over the 60-day window). A lead-time distribution like this is a description of how the detector behaves, not the headline rate, so it is stated directly rather than pointed at a live field.

How the switch was made. Tightening the definition this much moves the rate a long way in one step, so B3's own numbers computed from day one in a separate field and the headline changed only at a deliberate, dated release. The day of the switch is published (stats.wci_definition_since) and the change applies from that day; nothing earlier is restated, and the rate of the earlier definition is not shown next to the new one.

Step 6: a tighter definition, adopted 2026-10-01 β€” B3.1, and the audit that fixed it

B3 never actually became the headline: it shipped 2026-09-28 with the flag still pointing at B2. A same-day follow-up study (docs/ops/WCI_PREDICTION_GAPS_2026-09-29.md) asked a sharper question of the same numbers β€” under B3, what would have predicted the delist notices and special-treatment tags that were still missed, and what was actually just noise or double-counting in how the data itself was collected? A definition called B3.1 answers both, and it is the headline since 2026-10-01. A first cut of it was audited on 2026-09-29 and found to promise more than its code did; this section describes the fixed version. Whichever definition actually is the reader-visible stats.wci_rate right now is always named in stats.wci_definition_version β€” check it before quoting a number, the same rule as always.

  • An exchange repeating its own decision back to us is not a prediction β€” and removing one warning type wasn't enough to stop it. advisory_st_level, one of B3's counted predictive types, only fires once a special-treatment tag is already on β€” it is the exchange's own designation, read back through our pipeline, not something NightWatch worked out independently. The first attempt at B3.1 simply dropped that one type. The audit measured the result and found it changed nothing: on KuCoin, 10 of 12 "called" delist notices were actually called by a different warning type β€” depth_collapse, critical_liquidity or volume_anomaly β€” firing two to three days after KuCoin had already ST-tagged the pair. That is a thinning order book reacting to the exchange's own tag, not an independent prediction, and the old rule let it through. The fix is broader: a predictive warning issued at or after the pair's first special-treatment tag or first caution/monitoring designation on that SAME exchange never counts as a call for any outcome on that exchange, regardless of which warning type it is. Measured this way, only 2 of 44 delist notices in the 90-day window are called before any same-exchange ST/caution state existed (Bithumb RSS3 and KuCoin ACTSOL, both a spread streak). (A different exchange's flag on the same base token is a separate, real predictor β€” measured at 31% precision, median 35-day lead β€” but building that into the metric is its own, later piece of work, not part of this fix.)
  • A call now needs at least a day of lead. Neither B2 nor B3 claims a minimum lead time β€” a warning fired the same cycle as the outcome still counted. B3.1 requires at least 24 hours between the warning and the outcome, because the cross-venue signal this feeds into treats anything shorter as co-detection, not prediction, and it would be inconsistent to hold B3.1 to a looser standard than the signal built on top of it.
  • The same notice, counted twice. One of Binance's ninety-day "delist events" β€” COS, HIGH and MBOX, first published in June and delisted 06-19 β€” turned out to be the same notice text reappearing as what looked like a brand-new row on 07-07, three weeks later. The short 7-day duplicate check already in place only catches an immediate repeat; it has nothing to say about a repost a month later. B3.1 adds a second check, keyed to the notice's own stored text: a fingerprint of the title (case- and whitespace-normalized, but the date is kept β€” an earlier version stripped it and wrongly merged genuinely different notices, see below), checked against all of that exchange/token's history before a new row is written. A matching row is still written, not skipped β€” its own arrival and detail are real and belong in the record β€” but it is marked as a duplicate of the earlier row, and the WCI query excludes it from the outcome count. A one-off script applies the same marking to the handful of rows that predate this fix, without deleting anything. Measured effect on the 90-day delist-notice population: 47 events become 44 (COS, HIGH, MBOX resolve to one).
  • What "keep the date" fixed. The first version of the fingerprint stripped any date out of a notice's title before hashing, meant to catch a repost re-stamped with a new date. On real data that was wrong: Binance's own periodic network-upgrade suspend notices for POL, GLMR and MOVR each carry a near-identical template but a genuinely different upgrade date, and stripping the date merged them into false "duplicates." They're maintenance notices, so this never changed the WCI rate, but the rule itself was broken. The fix hashes the title as stored, date included β€” a true repost's text is unchanged on the repost, so it still collides; a template shared by genuinely different events does not.

What the We Called It block shows. The headline number is the B3.1 90-day rate and carries its definition and window next to it ("B3.1 Β· 90 days"), with one short note on what B3.1 upgraded: duplicate notices excluded, calls after same-exchange tags excluded, 1-day lead required. The line under it opens to the details and reads "since 2026-10-01 Β· 60 days, ST tags and delist notices" β€” the date the definition took effect, the 60-day rate, and the ST-tag and delist-notice rates, each shown on its own and never blended into the headline. The details add the split by type (ST tags, confirmed delistings and exchange delist notices), one sentence on risk (tokens graded F got a delist notice or were delisted within 30 days about 2Γ— as often as average, about 2–3 in 100 versus about 1 in 100), and the method link. The headline is what B3.1 measures from 2026-10-01 on: of spot tokens with a genuinely new exchange-declared bad outcome, the share that a NightWatch warning predicted at least a day earlier.

Two more integrity gaps, fixed the same day, that are not about the definition at all β€” they apply regardless of which WCI definition is the headline:

  • A stale number is not a healthy one, but a warning issued while it was still fresh stays a real call. Some MEXC pairs' 7-day liquidity grade had not actually been recomputed since January β€” not because nothing changed, but because the table it was computed from carries zero rows for five of the ten scanned exchanges (mexc, gateio, kucoin, coinbase, bitget), a gap traced to a data-processing worker that is not currently running as a deployed service (see the pager below). A pair sitting on an old, frozen "grade A" looks exactly like a genuinely healthy one, right up until it gets tagged. The fix does two things: an hourly refresh now recomputes the 7-day numbers straight from the raw per-cycle scan data for every pair that was actually scanned recently, not only the ones already flagged as risky; and separately, any grade older than 3 days is now treated as stale, never as healthy β€” Crisis Bulletin no longer issues a new warning off a number that old, and every grade a reader can see carries its own as-of date and a stale flag once it crosses that line. This is forward-only: a warning NightWatch already issued back when that same grade was still fresh is not un-counted or restated just because the underlying number has since gone stale β€” only new warnings are withheld once a grade is stale, per the no-retroactive-restatement rule.
  • A silent notice feed pages until someone looks β€” and so does a silent aggregate table. The MEXC Telegram channel this pipeline reads had posted nothing since 2025-11-18 β€” independently re-confirmed by fetching the channel directly. It is a real, reachable channel; the exchange itself simply stopped using it, and MEXC's own web announcement pages return an access-denied response from where NightWatch runs, so there is no working replacement source to switch to yet. Every notice source this pipeline reads has a freshness check: if 45 days pass with nothing new, it pages, and keeps paging every six hours for as long as the source stays quiet, not just once. The same discipline now covers the missing data-processing worker behind the stale-grade gap above: for each exchange the API still reads 7-day-grade history from, if that table has gone 6 hours without a fresh row, it pages every 6 hours until it doesn't β€” this does not restart or replace the missing worker, it only keeps the gap visible instead of letting a metric quietly degrade.

Step 7: cross-exchange flags β€” one exchange's own signal, passed to the others

The B3 self-audit found that the strongest single predictor of a delisting or ST tag NightWatch had never used was sitting in plain sight: another exchange's own state change on the same token. When Gate.io, KuCoin or MEXC newly ST-tags a base, or Bithumb designates it a caution listing, or Upbit designates it an investment-warning listing, or Binance applies its own Monitoring Tag, or Bithumb/KuCoin publish their own origin delist notice, that token dies or gets tagged somewhere else it's listed 31% of the time within 90 days β€” about 3.5Γ— the base rate, median lead 35 days. A follow-up study (docs/ops/WCI_PREDICTION_GAPS_2026-09-29.md) backtested adding exactly this as a new signal and found it would have called 12 more delist notices and 6 more ST tags on the same 90-day history B3 already measures, moving the delist-notice rate from 12/47 (25.5%) to 24/47 (51.1%).

Four small feed workers watch the source states, each hourly, each just storing what an exchange itself declares (idempotent upsert, first_seen/last_seen, in nw_exchange_flag_state): Bithumb's own caution-designation API, Upbit's own investment-warning API (its real warning flag only β€” a short-lived volatility alert alone doesn't count), Binance's own Monitoring Tag state, and β€” logged but not yet used as a signal β€” MEXC's own market-list metadata (st, the "Assessment" concept plate, firstOpenTime), because the doc found no way to test whether that plate comes before or after MEXC's own tag; it's watched for 30 days starting 2026-09-29 and the decision on using it lands 2026-11-01. Each feed's very first poll of a given state never counts as a fresh signal, no matter what it finds already flagged β€” the first read of an exchange's caution list on day one is a baseline, not 22 new events.

One signal worker, nw_xflag_signal.py, turns a NEW state on any of those feeds β€” or a genuinely new ST tag on Gate/KuCoin/MEXC, or a Bithumb/KuCoin origin delist notice β€” into a cross_exchange_flag warning on every OTHER exchange that also lists the same base token. It is never written onto the exchange that made the declaration itself; that exclusion is structural in the code, not a filter bolted on afterwards, for the same reason B3.1 already refuses to count an exchange's own declared state as a call toward its own outcome (Step 6 above): an exchange predicting its own decision is not a NightWatch call. Binance's own delist notices are deliberately excluded as a source too β€” the doc measured them propagating to other venues at 7.1%, indistinguishable from the base rate, and Β§6 of that doc says plainly: do not use them. A base symbol is only ever linked across exchanges through NightWatch's own contract-identity registry (nw_contract_identity) β€” a shared ticker alone is never enough, since a handful of tickers (GTC, FOLD) are known collisions between unrelated tokens on different chains, and this signal skips a base entirely rather than risk flagging the wrong one. The DECLARING exchange has to be identity-verified too, not only the targets: an audit found a base whose Korean listing was never actually confirmed as the same token as its other venues could still be the source of a flag, even though it could never receive one.

This can never backfill a published number. The signal worker keeps its own watermark; the first time it ever runs, that watermark is simply set to "now" and nothing is processed β€” not the roughly 22 tokens already on Bithumb's caution list that day, not any ST tag already sitting in the database. Every run after that only looks at states and notices newer than the watermark minus a 15-minute overlap; anything already emitted is skipped, so the overlap never repeats a warning. On its second run it can therefore pick up a tag or notice from the 15 minutes just before the first run, and nothing older. This means the 51.1%/+18-events figures above are expected, from a backtest over history that already happened β€” the live number only starts accruing forward from whenever this ships, and can never be quoted as something already achieved.

Where it shows up. cross_exchange_flag joins the predictive-type list both B3 and B3.1 read, so it counts toward "We Called It" the same way any other predictive warning does. Under B3, that means no minimum lead time (Step 5's "no minimum lead time is claimed anywhere" still applies there). Under B3.1, it goes through exactly the same two audit-R1 rules as every other predictive type (Step 6) with no xflag-specific carve-out: a call needs at least 24 hours of lead, and a cross_exchange_flag warning issued at or after the TARGET exchange's own first special-treatment tag, caution/monitoring designation, or exchange-declared flag-state (Bithumb caution, Upbit warning, Binance Monitoring Tag β€” an audit found the first cut of this rule only checked warning rows and missed all three of these, which live in a separate state table) never counts β€” if the target exchange had already shown its own distress signal before NightWatch forwarded another exchange's flag onto it, passing that flag along isn't an independent call. A follow-up audit caught a subtler version of the same mistake: for a feed's own FIRST-EVER poll of a base already under caution, the timestamp we store (first_seen) is only the moment WE noticed, not when the exchange's designation actually began β€” using it as the cutoff would have credited a warning that fired after the real flag but before our feed happened to catch it. The fix treats that first-poll case as "unknown, could have started any time" and never credits anything for it; for a designation the feed genuinely watched appear in real time, the cutoff is the feed's own previous successful poll (the last moment it confirmed the base was NOT yet flagged), not the poll that caught it. The payload also reports xflag_credit β€” how many of the calls in the current rate were credited by cross_exchange_flag, and the rate with and without them, both pooled and per outcome type β€” because a cross-exchange flag is another exchange's own call passed on across venues, and that composition is worth knowing on its own (same reasoning as B3's per-outcome-type split above). On a token's own timeline and in the Crisis Bulletin's Detection feed, a cross_exchange_flag card reads like any other warning card β€” the same generic trigger_data.message line every other warning type already uses β€” except its message names the source exchange directly (this is a market-data surface, docs/pm/VENUE_CODES.md "Public copy rule" category 2 β€” real venue names are the content here, not the anonymized VVΒ·III codes the /thusus fund-book tiles use), e.g. "caution designation on bithumb β†’ flagged here." No layout changed to add this; it rides the existing card renderer.

The workers nobody sees

Five more workers exist purely to keep the lifecycle data (and therefore the WCI) honest, and none of them ever appear on the page directly.

WorkerRunsJob
nw_delist_expirehourlyChecks every token with a scheduled delisting date that is more than 12 hours past due. If the exchange's live symbol list confirms it's gone, marks it DELISTED. If it's still trading, marks it stale (a likely mis-scoped notice, e.g. a margin-only notice mistaken for a spot delisting) instead of leaving it stuck forever. A notice whose own text marks it as margin or futures is resolved on the next hourly run without waiting for the date. Since 2026-10-03 the live arbitrage driver honours these verdicts: a token past its date by more than 24 hours and confirmed still trading, or a lock that came from a margin-only notice, no longer blocks a trade; a genuine spot delisting still does.
nw_delist_sweep_v1dailyCompares every token's recorded status against each exchange's own live active-symbol list and reconciles ghosts. Fixed a real incident: 5,700 stale rows (tokens delisted on the exchange but never updated in the database) were found this way. It has safety guards against a bad API response mass-mislabeling everything, and it deliberately skips any token with a pending scheduled delisting, on the principle that "a notice-based fact outranks an observation-based fact."
reverify_warningsone-shot, run as neededA correction tool. Several warning types (depth collapse, spread spikes, volume anomalies, on-chain and social signals) were being automatically marked "false alarm" after 72 hours regardless of whether the token had actually recovered. This resets those to pending so they get judged properly.
nw_warning_rollup_v1dailyWarnings are compressed into a summary row per (exchange, token, warning type), keeping the pattern and the confirmed/false-alarm/pending counts (about 93% storage compression) before the individual rows are deleted, in the same transaction so nothing is ever lost mid-operation. Since 2026-09-28 (definition B3) retention is type-aware: the predictive warning types that feed the WCI numerator are never rolled up before 180 days, so a WCI event never loses its own lookback history mid-measurement; every other type still follows the standard 90-day window. Any warning that cites an external announcement URL is never touched regardless of type: it's kept in full, forever, for its reference value.
nw_wci_stats_refreshevery 30 minutes (at :05 and :35)Computes the WCI headline and its breakdown in the background and stores the result in one row; the Crisis Bulletin reads that stored row instead of recomputing on every page load. The WCI you see is therefore at most about 30 minutes old, and the payload carries wci_computed_at with the exact time. Before 2026-10-02 the figure was recomputed inside the page request, and when several requests arrived together the copies piled up and slowed the whole site.

Where the Crisis Ribbon shows up

The Home page ("Command Deck") leads with a Crisis Ribbon summarizing active and confirmed delisting warnings before anything else on the page. It is one of six server-rendered sections, each fetched independently with an 8-second timeout and a safe fallback, specifically so one slow data source can never freeze the whole homepage.

How to read a warning card honestly

  • A badge count ("12 anomalies") mixes weak and strong signals. It does not tell you severity on its own; open the card.
  • A D-N countdown on the lifecycle ticker is a notice date, not a certainty. nw_delist_expire exists precisely because scheduled dates sometimes pass with the token still trading.
  • Treat the WCI percentage as two different questions blended into one number until you check the definition text under it: how good is NightWatch at predicting a liquidity-driven death, versus how often does it anticipate an exchange's own business decision (close to 0%, because that is not knowable from order-book data at all)?
  • A warning disappearing from view does not mean it is forgotten; the count and outcome survive in a summary row unless the row was tied to a cited announcement (kept in full indefinitely) or it is one of the predictive types the WCI numerator reads (kept at least 180 days before it can be rolled up).

What you can do now

  • Read the small print next to the WCI percentage before quoting it: it names its own definition version and effective date, because the definition has changed more than once.
  • Use the Detection β†’ Tracking β†’ We Called It layout as a funnel for a specific token, not just three unrelated boxes.
  • Click a lifecycle ticker box before treating a countdown as fact; the panel's "Notice" link shows the actual source.
  • Filter the Token Pulse Grid to the ST tab if you specifically want distress-tagged listings.
  • If you are an AI agent: call get_token_intel for a token to get its warning severity, convergence, and lifecycle status in one structured read, rather than parsing the page.