a discord bot for the tootsies server. ask, recap, discuss, ship features by typing.
First audit: 2026-09-18. Owner ask: “audit repo wide where we are using dictionary and string matching and regex for classification and decisions, enumerate exhaustively; we should go one by one and see possibly replace them all with Haiku.”
Refresh: 2026-10-18 (wave 19), at origin/main fba1952. Owner rule for the refresh: “regex should almost be exact closed set; model (Haiku or Jev) should do the rest for open sets and word lists; feed the lists to the model as input.”
This document has three parts:
The rule is in docs/ENGINEERING.md, “The deterministic / model-judged boundary”. In
short (stronger wording, owner 2026-10-19): code only for a CLOSED set checked by an
exact match; a model (Haiku, Sonnet or Jev) decides meaning, with the list as its input;
a safety floor may stay as code with a model on top, and the floor only blocks. The old list is not deleted. It becomes input to the model, as
reference examples, as candidate labels, or as the closed label set. The old rule stays
as the fallback when the model errors, and the surface keeps its fail direction.
| verdict | meaning |
|---|---|
| KEEP-CLOSED | Code. An exact match on a closed set: a fixed format (a number, a date, a URL, a ticker, a key), our own enum or payload field, an upstream field with a fixed vocabulary, a structural parse, or a parser of a model-output protocol (EMPTY, TRACK:, a closed label answer). A number check and an exact folded identity join are here too. |
| MODEL-HAIKU | Move the decision to Haiku (ClaudeClient.classify, or a field on a Haiku call that already runs). The old list goes into the prompt. |
| MODEL-SONNET | Move the decision to Sonnet. Use it only when Haiku was measured worse on the same real inputs; the reason cites that measurement. The old list goes into the prompt. |
| MODEL-JEV | Move the decision to Jev (utils/typesafe_client.py, a typed Noul, Choice or Score). The old list goes into the state. |
| KEEP-PROTECTED | Code until the owner signs off: settlement and money math, constitution.py and the memory fence, the permission allowlist, and the names / aliases privacy match. A safety floor is here too: a code check that only BLOCKS a banned or false post, never approves one alone, with a model reading what passes (owner, 2026-10-19). Its reason names the ban or false claim. A relevance or quality filter is not a floor. |
| MEASURED-KEEP | Code for an open set, in one of two cases. (1) A model was measured on real inputs and was worse; the reason states both results. (2) The site has no real traffic (the #4522 owner rule): the reason states the 30-day count of its decisions and the count it was taken from, for example 0 drops in 30 days (of 1,586 rows). Not debt. The registry reason starts #<issue or PR> measured:. Re-measure when a better model ships or the count grows. The exact contract is in tests/test_classifier_registry.py. |
| DONE | A model already decides every outcome. This includes a list that only NOMINATES: it widens the candidate set, and a model decides each candidate. A list that decides any outcome ALONE (a fast accept, a fast drop, an admission filter whose miss means no model sees the item) is not DONE for that branch. |
| OWNED | In-flight work owns the site. It is listed, and it is in no batch. |
Two old reasons to keep a word list are no longer enough on their own. “Hot path”: Jev answers in about 79 ms warm at about $0.042 per 1,000 calls. “A model judge runs after it”: a list that drops or ships before the judge still decides alone.
Haiku, Sonnet or Jev is a call on the merits, not a fixed rule. Haiku knows world facts
(acts, titles, chart names), can extract text through a JSON method, and has a durable
cache. Jev answers several typed questions about one text in one request and is fast,
but it writes no text, and it is weak at arithmetic, counting, dates, long state,
adversarial text, a bias toward the first Choice option, and recent music facts. The
refresh therefore puts Jev only where volume or latency earns it: per-post or
per-message labels, and small identity picks on a closed candidate list. Every other
MODEL site is Haiku, or Sonnet where Haiku was measured worse on the same inputs
(MODEL-SONNET). Contract and limits: docs/ARCHITECTURE.md lines 21-28 and
docs/INTEGRATIONS.md, “TypeSafe Jev”.
Semantic sites per partition, 2026-10-18. A site is a symbol, or a group of symbols that make one decision together. The partitions are the seven reports in Part 2.
| partition | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| P1 music, newsroom, identity, feeds | 158 | ~225 | 70 | 48 | 2 | 2 | 27 | 9 |
| P2 markets, betting, sports, media | 131 | ~191 | 76 | 13 | 4 | 8 | 8 | 22 |
| P3 conversation, X, gates, output checks | 94 | ~205 | 32 | 17 | 3 | 7 | 21 | 14 |
| P4 charts, cinema, ops, infra | 72 | ~150 | 38 | 11 | 0 | 5 | 11 | 7 |
| P5 the 16 remaining files | 57 | 54 | 37 | 9 | 0 | 0 | 9 | 2 |
| P6a files the first audit never read (charts, X tags) | 61 | 68 | 20 | 17 | 0 | 0 | 5 | 19 |
| P6b arcade, Jev callers, runtime scripts | 39 | ~100 | 13 | 12 | 5 | 1 | 3 | 5 |
| total | 612 | ~990 | 286 | 127 | 14 | 23 | 84 | 78 |
A few sites appear in two partitions, because a caller and its helper sit in different files (the games artist credit, the discourse sports gate, the YouTube leg check). The batch plan below merges them, so each site has ONE owner.
Comparison with 2026-09-18:
| measure | 2026-09-18 | 2026-10-18 |
|---|---|---|
| semantic sites | ~410 | 612 |
| sites to move to a model (old HAIKU + HYBRID / new MODEL) | ~107 | 141 |
| already model-decided or nominate-only (DONE) | (not counted) | 84 |
| kept as code | ~300 | 309 (286 closed, 23 protected) |
The count grew for three reasons. About 45 new runtime files landed (the arcade, the Jev
callers, x_artist_tags, billboard_stories, chart_history, the qualifier work).
utils/music_news.py grew from 4,680 to 7,752 lines and utils/output_checks.py from
about 1,400 to 2,658. And the rule changed: sites that were KEEP for “hot path”, “behind
a judge” or “tiny list” are now MODEL (16 of them in P1 alone).
Cost baseline. Axiom, 7 days to 2026-10-18, claude_api events: Haiku 24,902,
Sonnet 2,113, Opus 71. Jev (typesafe_api): 68 in 30 days, all engagement_labels.
The whole batch plan adds about 300 to 400 Haiku calls a day (cached), about 2,000 Haiku
calls a week, and 400 to 1,500 Jev calls a day for one batch (CB-09, about $0.02 to
$0.06 a day). It does not change the cost picture.
post_states_forecast turns the classifier’s is_projection=false into true,
_calls_title_a_song turns stream_shape=album into a song, figure_is_passed_threshold
swaps on judge OR regex, and _STREAM_SCOPED_RE vetoes before the stream fields read.
Each one was added after a measured classifier miss. Under the new rule the override
is a second model read (CB-01, CB-08), not a longer word list.take_names_leader_only ships a chart take with no model call when the leader’s name
is present, no rival leg is present, and none of about 18 negation words appears. The
leader judge ran 2 times in 7 days. “drops to No. 2” is not in the negation list. No
take was declined in 30 days, so this is a reasoned case, not an incident (CB-02).unnamed chart cuts lose real stories. 10 of 130 unnamed cuts in 30 days name a
chart the owner keeps (“Billboard Global Charts” 4 times, “Billboard’s R&B/Hip-Hop
chart” for an album record 3 times, “Spotify Global” or “Spotify US Weekly” 3 times).
That is about 8% (CB-01).post_states_forecast 0 recoveries, misstated_chart_frame 0 drops, _LATER_WEEK_RE
1 drop, and most desk shape fences 0 drops in 30 days. “0 fires” is not evidence that
a list is right. Each batch that converts such a list does a dry run on 30 days of
real text first.luminate_subject (B13), house_genre (C5), reference_film_pick (B15),
riaa_same_release, wiki_namesake, album_track_match, chimein_score,
pplx_found_answer, and the Jev guess_grade and mention_shadow paths.
kworb_act_check had 1 event. Most have a plain reason (no input of that shape, a
muted surface, a cache warmed by the dry run). luminate_subject is the one to check:
all 10 callers of fetch_desk_readings pass a client, but 968 market_subject events
ran while the B13 dry run sent 50 of 121 live events to the model. Not verified;
listed as a follow-up below./stats stores questions_labeled,
laugh_messages_labeled and hype_messages_labeled (#4318), but no code reads them.
utils/playercard.py still shows the shape-rule counts, so the shape rules still
decide every stat a member sees. Only the 2026-10-18 catch-up was labeled, so the
reader condition (labeled_messages == messages) is false for every member until one
full labeled rebuild runs (CB-14). Wave 20 shipped the reader (engagement.labeled_stat); the
rebuild is the owner’s to run.output_checks.memory_note_violations is described (here and in CLAUDE.md) as the code
half of the memory fence. Only tests call it. The fence today is the prompt and the
model choice. This is KEEP-PROTECTED, so a change needs the owner.
Wired by #4528 (owner merge): cogs/memory.py:_tag_and_store now calls
scrub_memory_note and re-checks with memory_note_violations before every store,
and drops a note that still fails.utils/release_age.py was listed with 0 semantic
sites; its iTunes row title check is a fuzzy identity join and the only date path
without a band confirm (81 refusals in 30 days, CB-04). The A13 note “every cert
carried a body in cert_id” is out of date: 31 of 52 cert_out_of_scope cuts had an
empty body and the prose regex decided them (all 31 were right). utils/sportsdata/
was not inventoried; it holds the settlement identity and is KEEP-PROTECTED.
market_subject_image.artist_subject_name is gone, and api_sports._team_logo_from_rows
and radio.standing are now exact (#3453, #3454).These are bugs or dead code in sites the refresh read. Each is a small deterministic change. The batch that owns the file does the fix first, or a separate PR does it.
| site | finding | fix |
|---|---|---|
utils/output_checks.py _ATTRIBUTION_TAG_RE (_HITS_PUBLISHER) |
All 8 attribution_tag desk rejects in 30 days were correct genre-board posts naming “HITS’ Top 50”. The module comment says that name must pass; the possessive arm matches it. |
Exclude “HITS’ Top 50” (a chart name) from the possessive arm. First commit of CB-03. Done (wave 20 Part A, #4526): the 8 real lines pass, the publisher credit still fails. |
utils/billboard.py chart_context |
The desk subject reads “Release – Artist”, so the containment test almost never matches a row. The Billboard standing line is probably missing from most market takes. No event measures it. | Pass the parsed artist and release; accept on credit_matches + exact title. First step of CB-18. Done (wave 20 Part A): 35 real compound subjects, old 0 / new 9 standing lines, 0 wrong on the live charts. |
cogs/market_drop.py _companion_names_artist |
Substring identity: “Future” matches “Future Islands”. | Parse the exact “BY |
utils/markets.py classify_intent, looks_like_sports, _looks_like_music |
Raw substring tests, reproduced: “general-chats”, “stats”, “conflict” (“nfl”), “nuclear” (“ucl”), “comma” (“mma”), “whats” (“ats”) read as sports; “Trap”, “Songs of Freedom”, “Grape” read as music. | Word boundaries. This becomes the fallback rule of CB-19. Done (CB-19, #4549): markets.has_cue_word; detect_league had the same bug and is fixed too. |
arcade fighter safety_reject (utils/arcade/fighter_models.py) |
A substring test on the provider error text sent 29 members to a final safety_reject in 30 days. The Grok word list (“reject”, “policy”) is wider than the OpenAI one. The event stores only “HTTP 400”, so the 29 cannot be checked. |
Read the provider’s JSON error code exactly; store the code on the event. Done (wave 20 Part A): is_refusal accepts on an OpenAI refusal code exactly, keeps the word test as the fallback (no stored body shows the other codes yet), the body cut is 2000 characters, and detail.error_code is on the event. |
image_gen._is_safety_reject |
Same shape on the OpenAI path. | Read the body’s code field (content_policy_violation). |
| dead code | BillboardClient.find(); the strict=False loose mode of kworb.find_chart_entry / _find_by_artist / find_song_entry; kalshi_channel_routing, derive_kind_tags, kalshi_player_props and the SGO tool’s league fast accept (0 /ask Kalshi or SGO tool calls in 30 days, the drop passes topic=None); output_checks.check_text, has_tool_narration, think_piece_hits, has_context_tag_leak, has_track_line; artist_roster.stale_entries. |
Delete, or leave and record. Do not convert dead code to a model. Wave 20 Part A: deleted BillboardClient.find(). Left and recorded: the output_checks dispatcher family (has_context_tag_leak is a guard that has no caller, so wiring it is a follow-up, not a deletion); the kworb strict=False mode (no production caller, but a parameter on 8 signatures); artist_roster.stale_entries (its docstring keeps it for a manual refresh); the Kalshi routing and SGO league paths (reachable code with 0 traffic, in utils/markets.py, which another executor owns). |
utils/cinema_news_stories.py story_signature |
A cinema story dropped as a duplicate emits no event, so a wrong merge cannot be counted. | Add a skip event (reason signature_dup). Part of CB-29. Done (wave 20): wire_collision (decision allow / drop, reason allowed / signature_dup / judge_error) on all three desks. |
tests/classifier_registry.txt, #4521)This document is the narrative register. The machine-checked register is
tests/classifier_registry.txt, and tests/test_classifier_registry.py enforces it in the
lint-typecheck job. The test finds every module-level re.compile(...) and every
module-level word list (3 or more string literals) in the runtime code, and it fails when a
site has no line in the registry. A line is path:NAME VERDICT reason:
| verdict | meaning |
|---|---|
| CLOSED-SET | a closed set: a format, a code, a ticker, our own keys. A reason that starts not a decision: marks a site that decides nothing (display text, a prompt, a tool schema, field names). |
| PROTECTED | a deliberate deterministic fence (constitution, safety, money, privacy) |
| MODEL-DONE | a model decides; this regex / list is only the model-error fallback or the model’s input. Not debt. The reason starts purpose=<name> or jev=<name>, and the test checks that <name> is a purpose="<name>" literal or a *PURPOSE = "<name>" constant in cogs/, utils/ or claude_client.py. |
| MEASURED-KEEP | an open set that stays code, in one of two cases: a model was measured on real production inputs and was worse, or the site has no real traffic (the #4522 owner rule). Not debt. The reason starts #<issue or PR> measured: and states the result (for example #4536 measured: Haiku 21 wrong of 719, Jev 11 wrong, code 0 wrong) or the 30-day count and its base (for example #4574 measured: 0 drops in 30 days (of 1,586 rows)); the test checks that shape. Re-measure when a better model ships or the count grows. |
| MODEL-FALLBACK | an open set that a batch here will move to a model; the code decides today. Debt. The reason names the batch (CB-xx), the owner (owned ...), MODEL:, or done: for a converted site not yet tied to one purpose. |
| UNCLASSIFIED | the 2026-10-18 baseline, not yet reviewed |
| OWNED-PENDING | an owner in _PENDING_OWNERS is converting it now (today: #4412) |
The guard sees module-level sites only, so its count (1468 at the baseline) differs from the semantic-site count of this document (612), which also counts inline patterns, substring tests and fuzzy ratios inside functions and leaves out the closed-set sites. The registry review (2026-10-18, this refresh). The seven partition passes gave each of the 1065 UNCLASSIFIED baseline lines a verdict. The registry now holds:
| verdict | lines | note |
|---|---|---|
| CLOSED-SET | 1122 | 228 of them decide nothing (not a decision:): 85 claude_client tool schemas, prompt text, display and label maps, canned replies |
| PROTECTED | 22 | settlement identity and status sets, the constitution, the permission allowlist, the identity-inference fence, the arcade likeness checks |
| MODEL-FALLBACK | 284 | 149 in a batch (CB-01 … CB-31), 64 done: (a model already decides; 62 of them later moved to MODEL-DONE, see below), 65 owned by in-flight work (W19-B1 22, #4412 21, W19-B3 8, #4422 7, W19-C1 4, #4428 3), 6 MODEL: with no batch (5 of them a dead path) |
| OWNED-PENDING | 40 | #4412, unchanged |
| UNCLASSIFIED | 0 |
So of the 1065 baseline lines, 228 were not classifiers at all, and 1065 - 228 = 837 were
real decision sites. _DEBT_CEILING is 284. Each batch that converts a site deletes its
line (or moves it to MODEL-DONE when the code stays as the fallback or the model’s
input), and lowers the ceiling.
MODEL-DONE (2026-10-18, later the same day). 62 of the 64 done: lines moved to
MODEL-DONE with the purpose that decides them, so _DEBT_CEILING went down by 62.
Two stay MODEL-FALLBACK: utils/apple_music.py:_EDITION_TAG_RE and
_PACKAGING_ZONE_RE. Their reason names “the vision media judge”, but no one purpose
could be tied to it.
The count of MODEL-FALLBACK plus UNCLASSIFIED lines is a ratchet (_DEBT_CEILING). The
count must equal the ceiling, and the ceiling may only go down. A conversion PR moves its
line from MODEL-FALLBACK to MODEL-DONE and lowers the ceiling by one in the same PR. A conversion PR passes without a registry edit: a line whose site is
gone prints a note and does not fail. Delete such a line and lower the ceiling in a later
PR.
| owner | sites |
|---|---|
| Qualifier epic #4412 (coordinator session_01QT9u9qKYuMvE23gt9Szz8j) | utils/qualifier_trim.py: every word list, including the #4516 detectors time_span, joins_as_only, states_most (fba1952), _RANK_RE / _RANK_ORDINAL (#4471) and the release noun / verb lists; utils/qualifier_check.py (4 sites) and check_claim_qualifier; utils/cinema_numbers.py (result-verb lists, PR #4513); output_checks has_career_claim, has_alltime_claim, every ungrounded_* claim check (old C8), unsupported_rank_claims; banger_subject (feeds check_source_qualifier, #4467); market_outcome.check_news_qualifier; qualifier_trim.restates_cut at market_alert. |
| bugs-classifier-review #4428 | market_cards.take_rank_conflict, swap_to_stated_alt (the card-vs-take regexes, #4383). |
| bugs-classifier-review #4422 / B4 | output_checks._SELF_CORRECTION_RE, has_self_correction, decline_narration_hits, _MARKET_DECLINE_RE, claude_client._SELF_CORRECTION_MARKERS, the wheel narration lists, and every drop_self_correction / has_self_correction call site (market_drop, market_alert, sports_boards, discourse icebreaker). |
| wave 19, B3 + A16 | utils/retrospective.py (_FRAMES, states_past_interval, frames_as_past, the interval arithmetic) and its callers in sports_desk and music_news._row_is_a_different_record; utils/chart_history.py _HEDGE_RE. |
| wave 19, C1 + A17 | artist_watch _ALIASES, _CREDIT_ONLY, canonical_credit, s_variants, lenient_tier; music_news wire_spelling, grounded_subject, named_by_mention, artist_grounded_in_wire, corrected_name, title_grounded_in_wire, the new ungrounded_quoted_titles; cog _artist_in_tier / _recover_bare_artist. |
| wave 19, B1 | The whole market_cards hero cluster: _OUTCOME_VERBS, outcome_split and its helpers (_field_split, outcome_subject, outcome_caption, prime_outcome_splits), named_rank, title_rank, winner_rank, award_slot, split_rank_authority, event_title_split, statement_title, how_much_title, subject_hero; market_drop._slot_figure / _kalshi_event_subject; market_alert._ending_soon_subject / _clean_authority; alert_triggers.outcome_label. The refresh read the B1 scope as this whole cluster (the old B1 row); the B1 executor should confirm. |
Owner ask, 2026-10-18: review the new regex and word-list classifiers again, and move each FUZZY one to a model check. A later owner rule the same day is stronger: a regex stays only for an exact closed set (a format such as “#N”, a key); an open word list goes to the model, with the list as the model’s input, and the old rule stays as the fallback on a model error. Every site below was measured on real production text, old rule against model, before any change.
The data:
post_preview values of the *_scored / *_posted
events, 30 days (Axiom);post_dedup_history rows, 30 days;kv_cache tweet cache (x:<id>,
source = x_text), 2026-09-18 to 2026-10-18;| site | decision | evidence |
|---|---|---|
utils/market_cards.py take_rank_conflict (_TAKE_RANK_RE, _FORMER_RANK_RE, _ORDINALS, the 4-word window, #4428) |
MODEL (Haiku take_rank_place), rule as fallback |
The “#N” hero stays an exact-format regex. The place words, the former-rank words and which song a place belongs to go to Haiku, which returns the place as a NUMBER; code compares it with the hero. 42 real “#N” market cards of 30 days with a take, 2 runs: the rule and the model both match the hand labels on all 42 (1 real conflict, Dai Dai), 0 flips. 7 hard cases from real takes: the rule is right on 2, the model on 6 (“X by Y is No. 2” past the 4-word window, “from No. 17 to No. 10” under “#17”, “debut at No. 2”, and “first” not given to the next song). The model miss is “with Britney Spears second at 8%”, a case I wrote from a real take that said “next”. About 1.4 calls a day, cached, under $0.01 a month. A reason-first answer measured worse (4 flips, 3 false conflicts) and was not shipped. |
utils/music_news.py release_windows (_RELEASE_WINDOW_RE) via cogs/music_news._first_week_window (#4428) |
MODEL (Haiku release_window), rule as fallback |
139 real texts (the 22 newsroom first-week takes of 30 days, 80 with a window phrase, 30 without, and the misses), 2 runs, 0 flips: 132 agree with the rule, all 22 first-week takes included. The 7 changes are all better: “first 10 days” and “nine days into its first month” name no window (the rule said “week” and “month”), “first chart day” and “release day” read “day”, and a week’s count “ten days into its first month” names none. 0 worse. About 1 call a day, cached. |
utils/output_checks.py _SELF_CORRECTION_RE / _CORRECTION_MARKER (#4422 added “let me correct” and “let me fix”) |
see the B4 PR | 0 hits in 11,294 composed takes and 1,317 shipped posts. A looser scan (39 texts with “wait”, “actually”, “let me”, “i need” and similar words) found 0 self-corrections it misses: all 39 are titles or plain words. A model check would add one call per composed post for 0 catches. A model is also the wrong tie-break here: the desk scorer read “Let me correct that: …” as a clean post on 39 of 48 calls (#4422). Known risk: the line-start arm would drop a post that opens with an unquoted title such as “Hold On, We’re Going Home” or “Wait for Me”. Both charted in the last 60 days. 0 such drops in 30 days. |
utils/music_markets.py release_card_subject (#4428) |
KEEP | An identity key (_album_key) on our own fields, not free text. |
utils/qualifier_trim.py has_qualifier (_QUALIFIER_RE, _RANK_RE) |
review only: KEEP recommended on #4412 (the qualifier-epic coordinator owns these files) | Sample of 609 agreed wire tweets: the gate passes 311 (194 real, 117 not) and blocks 298 (2 real). It is a recall-first gate in front of the Sonnet qualifier judge, and the judge keeps the false hits (“‘one of the best’ is a personal opinion”, 3 of 24 qualifier_check rows on 2026-10-18). A model pre-gate on the 311 was measured. Haiku (classify) skipped 18 and 14 real qualifiers of 194, with 8 flips between its runs and a p50 of 492 ms. Jev (Noul, cut 0.5) skipped 26 and 25, with 7 flips and a p50 of 786 ms. A skipped real qualifier ships unchecked, so both pre-gates are worse than the regex. |
utils/qualifier_trim.py _RANK_ORDINAL in _RANK_RE (#4471) |
review only: KEEP recommended on #4412 (the qualifier-epic coordinator owns these files) | 26 hits in 10,618 tweets; 24 of the 25 agreed are real rankings. The 1 false hit, “the sixth Her Loss song to hit the mark”, counts songs on one album. |
utils/qualifier_trim.py _RELEASE_NOUN_RE / _RELEASE_VERB_RE (#4471) |
review only: KEEP recommended on #4412 (the qualifier-epic coordinator owns these files) | 0 exclusions in 10,618 tweets. A closed phrase shape (“the second single to be released”). |
utils/qualifier_check.py _FIRST_RE + _SPOTIFY_GLOBAL_RE (#4502) |
review only: KEEP recommended on #4412 (the qualifier-epic coordinator owns these files) | 8 fires in 10,618 tweets, all Global Spotify first or only claims. It only adds kworb evidence for the judge and makes no verdict. |
utils/qualifier_trim.py cut checks from 6b6611c (is_cut, leaves_dangling, _INTENSIFIERS, _ABBREVIATIONS, _PRONOUNS) |
review only: KEEP recommended on #4412 (the qualifier-epic coordinator owns these files) | They check the structure of the judge’s own edit (a word subsequence of the claim). That is a fence on a model output, not a judgment. |
open PR #4516 qualifier_trim.states_most |
finding (#4412) | It fires on 352 of 1,843 qualifier tweets, and 85 of them are ranked claims (“the 2nd most-streamed R&B artist ever”). The rule it adds (“wrong only when the research names an act with MORE”) is false for a ranked “most”. Reported on #4412 before merge. time_span (153 fires) and joins_as_only (6 fires) read correctly on a sample. |
The other text sites merged in that window are our own enums (_QUALIFIER_TRIGGERS,
MARKET_ROOM_SURFACES, _DEBUT_LANES, _OCCASION_CHECKED_ART), number formats
(figure_value, swap_to_stated_alt) and length floors (too_short_to_ship on three
cogs, #4500). They are structural.
33 batches, ordered by user impact times brittleness (H = a miss ships a wrong public post, card or answer, or the list has a record of incidents and review rounds). Each batch is a set of sites that share a file or one code path. Each row gives the model shape, the input (with the old list), the expected calls a day, and the fail direction the change must keep.
Rules for every batch (from Part 1, still in force):
ClaudeClient.classify (label set, durable kv_cache cache), a
field on a Haiku call that already runs, or TypeSafe.ask for Jev. The old list goes
into the prompt or the state.purpose, and add a golden fixture that must keep failing.post_dedup_history, /debug/query),
2 runs, as the A13 and A14 items did. A field added to an existing classifier can move
other fields: add ONE field per PR and compare 2 runs.| batch | files | sites | count | shape | input (incl. old list) | calls/day | fail direction | impact x brittleness | from | notes |
|---|---|---|---|---|---|---|---|---|---|---|
| CB-01 newsroom chart-story read | utils/music_news.py, cogs/music_news.py, claude_client.py (new method) | chart_reportable KEPT / CUT tables, post_states_forecast (5 verb lists), post_states_later_week, names_edition, _FUTURE_RE, misstated_chart_frame._TRANSIENT_RE (retire into music_desk_score), _calls_title_a_song, mark_album, cog _is_tour_subject |
9 | One cached Haiku JSON per chart / milestone story: family (closed set: kept + cut family names + OTHER + NONE), tense (settled / forecast / later_week), edition (bool). Small Haiku labels ALBUM / SONG, MARKED / UNMARKED, TOUR / RECORD. |
post + claim + subject; the KEPT / CUT tables with the owner notes as the label list; the verb lists as examples | ~55 | chart scope: model error = regex (fail closed); a CUT regex hit still vetoes; tense: error = regex | H x H | P1-B3 | Dry run on the 130 unnamed claims and 30 days of chart stories, 2 runs. Shares files with CB-08 and CB-05: one executor, or CB-01 first. Done 2026-10-18: see “CB-01 result” below. |
| CB-02 chart-take fabrication gate (DONE, wave 20) | utils/market_subject_image.py, cogs/market_drop.py, cogs/market_alert.py, utils/youtube_grounding.py (reads market_cards.is_music_chart_market) |
is_youtube_daily_chart_market, is_netflix_rank_market, is_chart_slot_market (+ _MUSIC_SLOT_LEAD_RE), is_music_chart_market as gate input, take_names_leader_only (+ _NON_AFFIRMATIVE_RE), take_references_leg, take_names_a_leg, _chart_slot_gateable, _leader_check |
9 | (1) Haiku classify per event ticker: SLOT_TITLES / FIELD / BINARY / COUNT / OTHER, cached 30 days. (2) Every gated take goes to the existing market_take_names_leader (market_take_check); the phrase test becomes a logged agreement signal. (3) A leg no-match asks the same judge before the drop. |
event title, leg title, 3 leg labels, series tags, the regex verdicts as a hint; the take with leader and rival labels; the negation list as examples | ~10-20 cached + <=10 judge | (1) error = regex; (2), (3) judge error = drop (fail closed, today) | H x M | P2-A, P6a-4 | is_music_chart_market sits in the W19-B1 file (lines 161-189, outside the cluster): read it, or rebase it on MUSIC_SUBTAGS; do not edit the cluster. |
| CB-03 owner-ban prose fences | utils/output_checks.py, claude_client.py (rubric lines + one classify wrapper) |
_ATTRIBUTION_TAG_RE / attribution_tag_hits, confidence_hedge_hits, self_count_credit_hits, anonymous_credit_hits, has_cross_source_comparison (+ names_hits_source), has_stream_unit_comparison, has_row_arithmetic, _PRIOR_POSITION_RE phrase arms |
8 | Haiku classify on each regex HIT (per fence: CREDIT / CHART_NAME, DISCLAIMER / WRONG_CREDIT / OTHER, COMPARES / OK, SUM_OR_RATIO / OK, PRIOR / CURRENT_ONLY); one hard-fail line per ban in the desk scorer rubrics for the miss side (0 calls), as _IDENTITY_RULE did |
the line, the owner steer, the matched phrase; the regex lists as examples | ~1 | drop on model error (the regex verdict) | H x M | P3-B1 | First commit: the “HITS’ Top 50” code fix. prior_position is on the #4422 lanes: confirm with that owner first. The callers sit in other batches’ files; this batch changes only output_checks and the shared rubric. Done (wave 20, CB-03): ClaudeClient.owner_ban (purpose owner_ban) reads every regex hit at every runtime caller; no answer keeps the drop. 16 registry lines are MODEL-DONE; _HITS_SOURCE_RE stays MODEL-FALLBACK (the Perplexity context strip reads it alone). Measured on 30 days: hit side 748 distinct real hits, 0 true bans cleared in 4 runs; 21 false row-arithmetic hits cleared (the band TWICE, Tito Double P, “Don’t Think Twice”, chart names with “combined”). Miss side: a YES/NO probe on 860 shipped lines found 0 real misses and 59 false flags, so no scorer rubric line was added. |
| CB-04 release date iTunes row check | utils/release_age.py | _catalog_release_date iTunes row title check (deezer.album_title_matches) |
1 | Existing deezer.confirm_album_rows -> confirm_band_rows (catalog_title_match, durable cache); the exact pass stays the free accept CONVERTED (wave 20): release_age._band_confirmed. 94 real (title, artist) pairs: the iTunes rows gave 2 band passes, both wrong records (a 2010 “GTA IV” EP for “Grand Theft Auto VI: The Album”, a track for “Live at Carnegie Hall”); the judge refused both, 2 of 2 runs. |
requested title + row title; album_match_band picks the residue |
~1-3 | refuse = undated = no debut claim; model error removes the row | H x M | P5-A | Feeds the debut gates of music_alert, the music_desk called shot and the X gate. Check whether resolve_music_row already asked about the same row (then it is a cache hit). |
| CB-05 market and projection identity | utils/music_news.py (market block), utils/music_markets.py, utils/hits.py | market_leg_candidates / _event_conflicts / _topic_tokens / _MARKET_ROLES / _MARKET_ALIASES, poly_event_matches, threshold_metric, restate_market_claim, related_market_context, _subject_tier_hits, hits.projection_row |
7 | Haiku closed-set pick (pick_market_event shape): EVENT1..n / NONE over every non-empty candidate set, not only a tie; SAME / DIFFERENT for the act substring; ROW1..n / NONE for HITS rows |
candidates as the closed list (overlap order kept); the role and synonym tables as prompt text | ~3 | no pick = drop (absent) | H x M | P1-B4 | The N5 dry run found 0 ties in 59 claims; the value is a check on the top pick, which nothing checks today. Done (CB-05): the event pick runs on every candidate set with a year / role safety floor; a non-equal Luminate subject match gets Haiku SAME / DIFFERENT (reading_subject). threshold_metric, restate_market_claim, related_market_context and hits.projection_row stay code by measurement. 2 registry lines to MODEL-DONE, 5 to MEASURED-KEEP. See “CB-05 measurement”. |
| CB-06 Billboard story figures | utils/billboard_stories.py (+ callers cogs/chart_history.py _tick_story, music_markets reveal) |
_anchors (_MOVE_VERBS, _OTHER_CHART_RE, _LEADER_HINT_RE), verify_rows, leader_row_for, _artist_agrees / credit_parties, _QUESTION_RE |
5 | Haiku JSON extract per story (rank -> units + the quoted sentence); Haiku YES / NO / UNSURE for the headline leader; code checks that each figure appears verbatim | story paragraphs, the printed top-10 rows; the verb and chart-name lists as examples | <1 | fail closed: no figure; model error = regex parse | H x M | P6a-1 | In 30 days 399 of 510 backfill weeks parsed only part of the story (323 ok, 76 failed). Replay the 12-story fixture set and the 30-day backfill weeks. Converted 2026-10-18: billboard_story_figures (Haiku JSON per story; code checks the sentence, the number and the rank) and billboard_leader_check (YES / NO / UNSURE on the headline); the page road’s credit check reuses count_same_record. Replayed on all 107 stored weeks (1,070 top-10 rows, 2 runs): the regex fills 936, the model read about 1,035; 0 to 1 rows lost per run, both run-to-run flips; 2 rows where the figure changed, both corrections. About $0.085 per full replay. The 30-day “partial” count was retries of the same 67 incomplete weeks, not 399 distinct weeks. |
| CB-07 catalog identity residue | utils/apple_music.py (matcher block), utils/deezer.py (_artist_overlaps) |
_title_matches non-equal fast accept, _credit_similar / _artist_matches, release_tag_mismatch 55-word zone list, _is_compilation, _artist_is_billed |
5 | Widen C2’s match_catalog_title to every non-equal pass; new cached SAME / DIFFERENT on a ratio-only credit pass; reuse catalog_release_name for a zone the list does not classify; cached COMPILATION / OWN_RELEASE per collectionName |
both titles / credits + track; the zone and compilation lists as examples | ~15-50 (cached) | refuse the row (absent); compilation: error = regex | M-H x H | P1-B5 | Shares apple_music.py with CB-10 (other functions). Result 2026-10-18: the title band (every non-equal pass) and the credit check (catalog_credit_match, iTunes ratio-only + Deezer overlap-only) shipped; _is_compilation and the zone list stay code, measured (Haiku lost on compilation 1 better / 2 worse; the zone list made 0 wrong alone-decisions). |
| CB-08 classifier and verify field folds | claude_client.py (classify_music_news, verify_music_claim prompts), utils/music_news.py and cogs/music_news.py readers |
_RUNG_CLAIM_RE, figure_is_rank_word, figure_unit_phrase, the threshold_passed OR-branch, cert_claim_format, cert_reportable prose branch, cert_prose_names_other_body / cert_prose_is_riaa, _STREAM_SCOPED_RE, rank_list_tag (14 regexes), claim_chart_kind, cog _first_week_kicker |
11 | Fields on the existing Haiku calls: market_is_rung, figure_kind, figure_unit, cert_format, cert body as any authority + territory, stream_shape=subset, rank_list names the list; trust threshold_passed alone; claim_chart_kind from chart_key |
the claim and post the classifier reads; each list as prompt examples | 0 added | no field or error = regex | M x H | P1-B2 | One field per PR, 2 runs each (A14 measured drift). Cert fields last (31 of 31 cuts right). After CB-01. |
| CB-09 wire admission | utils/music_news.py (cue block), cogs/music_news.py _gather_candidates |
_NUMBER_CUES / looks_like_numbers_story, _CHART_CUES zero-strength drop |
2 | Jev Noul “this post reports a music number about an act” on each post the cues DROP; P >= 0.5 joins the bottom bucket, where the Haiku slate rank decides |
post text; the cue lists and 4 real non-stories (Gaza funeral, Gen Z stat, “A$AP”, a film gross) as reference | 400-1,500 Jev (cached per post id, ~$0.02-0.06 a day) | Jev error = drop (today) | M x M | P1-B1 | The one Jev batch in the newsroom: hundreds a day, one short text. Run one shadow week first (emit_shadow), because the miss side is not measured. SHADOW SHIPPED (r2c): Jev Noul on every cue-dropped post of the X pass, report-only (typesafe_shadow purpose=wire_admission with the post id). Measured on 1,635 real cue-dropped posts: 11 real music numbers; Jev 11/11, 16 false yes, 2 flips; Haiku 11/11, 19-20 false yes, 11 flips. The registry lines stay MODEL-FALLBACK until the shadow week is read and the switch ships. |
| CB-10 version tags on bulk rows | utils/release_type.py, utils/apple_music.py (version block), cogs/music_alert.py, cogs/music_desk.py, utils/song_pool.py, utils/deezer.py (pick_clip), cogs/games.py, cogs/x_game.py |
is_side_version* bulk consumers, _BAD_VERSION_RE / _is_guessable_title, _ALT_VERSION_RE / _is_clean_original |
3 | Nominate: a regex-flagged title goes to the cached release_version_kind; rendition_marker stays a hard RECUT (measured: the model lost on it, #4268) |
title + artist; the marker lists as examples | +30-100 (cached 30 days) | error = regex verdict | M x M | P1-B6 | Re-measure the music_alert debut lanes first: C3 found 0 better and 2 wrong there before #4268 fixed that shape. Touches cogs/games.py at the pool filter only (CB-15 owns the grader). Result 2026-10-18: NOT converted, measured. On 1,212 real flagged titles (2 runs, 12 flips) release_version_kind was worse on every bulk site: guess pool 27 wrong of 29 disagreements (tributes and karaoke called NEW, live cuts EDITION), side-version rows about 12 worse and 1 better of 803. The six measured lists are MEASURED-KEEP (#4575; only flagged titles were measured, so their misses are not, and the registry reasons say so); _RADIO_EDIT_RE (one exact phrase) is CLOSED-SET; a PLAIN / OTHER label for _ALT_VERSION_RE is #4571; the live + remaster = EDITION finding on the announce paths is #4570. |
| CB-11 desk caption and qualifier fences | utils/catalog_stats.py, utils/milestone_qualifier.py, cogs/music_desk.py (_RESERVED_OTHER_CHART) |
rank_claim_mismatch phrase half, is_unofficial_rank + source lists, _NO_QUALIFIER_MARKERS tail, _RELATIVE_SCOPE_MARKERS, _RESERVED_OTHER_CHART |
5 | Fold source_class + scope into qualifier_verify; one cached Haiku OK / NAMES_RIVAL / OTHER_METRIC on a catalog caption; pass the chart identity into topic_dedup |
the proved rank fact; the aggregator / official source lists; our own past post | ~2 | drop on error (captions, qualifiers); dedup: error = regex | M x M | P1-B7 | Agree with the #4412 coordinator first: verified_qualifier calls qualifier_check. Done 2026-10-19: see “CB-11 result” below. Caption: Haiku catalog_caption. Qualifier: Haiku qualifier_labels, NOT a field on qualifier_verify (measured worse). _NO_QUALIFIER_MARKERS and _RESERVED_OTHER_CHART are MEASURED-KEEP. qualifier_check is not touched. |
| CB-12 album metric and title read | utils/output_checks.py | _METRIC_FOREIGN_WORDS / metric_foreign_word, album_metric_named / same_album_metric_posts / _STREAMS_WORDS, missing_release_title / _title_forms |
3 | Haiku label cached per post text: PURE_SALES / UNITS / STREAMS / NONE / SEVERAL; YES / NO “does LINE name TITLE” only when the exact fold misses | the line; the word table as reference; the title with its edition forms | ~60 | today’s verdicts on error | M x M | P3-B2 | 0 ship-side drops in 30 days; the value is in the dedup read (the Popstar units settle that never posted). Same file as CB-03: run after it, or one executor. Done (wave 20, CB-12): ClaudeClient.album_metric (purpose album_metric, cached 7 days per text) reads the metric in the music desk and alert dedup reads (utils/album_metric.py, the ScheduledPoster._sched_dedup_history_read hook) and on a wrong-metric word at both ship gates; no answer uses the word table. Measured on 300 real posts, 2 runs: 17 disagreements, model right on 15, wrong on 1 (kept in the list, the safe side), 0 effective flips. The title read was NOT converted: all 4 fold misses in 2,959 real lines were a possessive (“Silver Sands Marina’s”), fixed in code (_POSSESSIVE_S_RE); after the fix a YES/NO read would make 0 calls. |
| CB-13 reissue check | cogs/music_releases.py | _reissue_keys: _REISSUE_RE fast yes, _REISSUE_ASK_RE miss branch |
2 | Existing release_is_reissue (REISSUE / NEW, cached) |
title + artist + release date + the release_version_kind label; the matched word as a hint |
~10-20 | error = regex (a regex word omits; no word = NEW) | M x M | P5-C | The list grew after C7 (“super deluxe”, “expanded edition”, 2026-10-06); “(2026 Mix)” has no word. Re-run the C7 set first: if wrong omits rise, convert only the fast-yes branch. Wave 20, measured, NOT converted: 110 real titles (72 album_total queries in 30 days + 69 fresh Apple Top Albums rows in US/GB/CA/AU, 2026-10-18), 2 Haiku runs. The current rule made 0 errors (2 of 2 reissues omitted, 0 new titles omitted). Asking release_is_reissue for every title added 3 wrong omits (Group Therapy, While The Flood Rages, The Shel Talmy Recordings, each in 1 of 2 runs) and fixed nothing. Both regexes re-verdicted CLOSED-SET with the count; _DEBT_CEILING 284 -> 282. |
| CB-14 engagement stats read the Jev labels | utils/playercard.py, utils/engagement.py (reader helper), cogs/stats.py (one full rebuild) | is_question, is_own_laugh, is_caps |
3 | Jev, already running (#4318). The work is the reader switch plus one full labeled rebuild. | cleaned message text; the shape rules stay as the stored keys and the fallback | 0 added; one rebuild ~15k requests (~$3.60); ~70 a day catch-up | per member: shape key unless labeled_messages == messages |
M x M | P6b-1 | is_caps -> “hype” changes a label members see: owner call. Reader shipped (wave 20): engagement.labeled_stat reads questions_labeled and laugh_messages_labeled for a fully labeled member; caps stays on the shape rule. Measured: the live eval (64 authored cases, 2 rounds) scored the shape rules 0.781 / 0.875 / 0.766 (question / laugh / hype) and Jev 0.984 on each; the 2026-10-18 production catch-up flipped 76 question, 13 laugh and 110 hype verdicts of 1,350 Jev-labeled messages. Real member text was not hand-labeled (a session may not read member messages). The full rebuild is NOT run yet: 709,777 messages, so about 35.5k requests, about $8.50 and about an hour at the limiter (the ~15k / $3.60 figure assumed 300k). Owner runs /stats rebuild:True. |
| CB-15 guess artist credit | cogs/games.py, utils/guess_grading.py | _artist_named (longest token + 0.82 ratio), _names_credit, _title_credit_artists / _NON_ARTIST_CREDIT_WORDS |
3 | Jev Noul names_artist in the request the title check already sends (0 added requests) |
the guess; the credited acts, features and remix credits as the closed candidate list | 0 added (29 rounds in 30 days, none since 2026-09-18) | Jev no answer = today’s rule | M x M | P6b-2, P3-B6 | Ask only when the rule nominates a credit hit. The X game scores no artist. Result 2026-10-18: shipped (names_artist / names_guest); 56 guesses x 2 runs: false credits 15 -> 1 HARD, 17 -> 1 EASY, 1 true credit lost. |
| CB-16 chart_history store reads | utils/chart_history.py, utils/artist_priors.py | _SUBJECT_HEAD_RE, _TITLE_BY_RE / _POSSESSIVE_RE / _subject_parts, the opener skip list, _chart_named, chart_history._credited, artist_priors._credited / same_act |
6 | Haiku JSON extract per Nora post (cached by tweet id); Haiku ONE / COLLAB (reuse K2 kworb_act_check) |
the post; the verb list and the two subject shapes as examples; the credit, the asked act, the ranked-act set | 10-20 + <5 | model error = regex parse / old split; a figure not verbatim is dropped | M x M | P6a-2 | After W19-B3 (parse_nora_text holds _HEDGE_RE). Bumping _NORA_SCAN_VERSION re-reads the 24-month backfill once (a few thousand cached calls). Do not edit the artist_watch alias table (W19-C1). Converted 2026-10-18: nora_extract (Haiku JSON per post, code checks every field word for word) and chart_credit_split (Haiku lists a credit’s artists, code matches the asked act exactly). The ONE / COLLAB reuse was dropped: a YES / NO label admitted “Ella” on 7 of 9 “Ella Langley” rows, and the list shape covers the duo case too. 553 real Nora posts: 45 better, 3 worse, 10 neither; 131 real credit pairs: 17 better, 1 worse. The real re-read is about 40 twitterio pages and 250 Haiku calls (their searchable history starts 2026-05). artist_priors stays code: no runtime caller. Fixes #4533. Follow-up #4591: a “#2.” list number that opens a line counts as a rank only on a line that names the read’s act or title (_quote_ranks), so a quote that runs over a numbered debuts list cannot store another row’s list number. Replayed on 138 figure posts x 2 runs: 0 ranks lost. |
| CB-17 album variant on every pair | utils/album_milestones.py | _relation (_VARIANT_WORDS_RE, _DISTINCT_RE) |
1 | Existing Haiku album_variant_relation on every pair (drop the fast paths in _group_releases) |
both titles; the word-list reading as a hint | 3-5 the first week, then <1 | error = word list; no verdict = withhold the count | M x M | P6a-3 | CONVERTED (r2c): every pair goes to album_variant (new wording, labels VARIANT / DISTINCT / UNSURE); album_milestones._combine joins it with the word list: the model decides a pair the list cannot place, a placed pair counts only when the model agrees, an error keeps the list. 311 labelled real pairs: before 275 right / 36 wrong, after 281 / 12 / 18 withheld. 2 registry lines to MODEL-DONE. Detail: “CB-17, CB-20, CB-24 measurement” below. |
| CB-18 Billboard chart context | utils/billboard.py (+ 2 callers in cogs/music_desk.py) | chart_context |
1 | Code fix first (see the table above), then Haiku SAME / DIFFERENT on containment-only hits | subject (artist, release); candidate row title, artist, chart name | <20 after exact accepts and a per-week cache | no chart line (absent) | M x M | P4-A | Replay one week of desk subjects first and count containment-only hits. Touches music_desk.py: sequence with CB-11 and CB-23. |
| CB-19 room and board cue lists | utils/markets.py, cogs/discourse.py, cogs/chimein.py (call sites) | _looks_like_music / _MUSIC_MARKET_CUES (fast keep), classify_intent as the discourse routing prefilter, looks_like_sports / _SPORTS_WORD_RE (icebreaker gate), arbitrated_match(catch=False) x4 |
4 | (a) music-cue hits go to the existing market_runner_up_check; (b) one cached Haiku SPORTS / PREDICTION_MARKET / OTHER per channel id + name + topic hash (7 days), shared by both discourse gates; (c) catch=True on the 4 dedup sites (existing topic_duplicate) |
event title + category, the cue list as music examples; channel name, parent, topic, _SPORTS_PATTERNS / _PM_PATTERNS as examples; post + history |
<2 + <5 + ~7 | (a) error = keep the event; (b) error = the keyword rule, repaired to word boundaries; (c) no verdict = ship | M x M | P2-B, P5-B, P3-B4 | Discourse is mostly muted (2 scored takes, 1 icebreaker in 30 days). classify_intent stays the _classify fallback (DONE). The catch=False reason was cost (#2083); measured volume is ~7 posts a day. Shipped (wave 20): (a) as planned, 31 live nominated titles, 0 errors old and new, 0 flips; (b) only the icebreaker gate (room_market_kind): the compose routing gate is on the retired path (#4119); (c) all 4 sites. See the CB-19 note below. |
| CB-20 Versuz manual card song match | scripts/versuz_card_manual.py | _similarity, _closest, option_song |
2 | Haiku classify SONG1..n / NONE over the played songs; the exact fold stays the free accept |
option text; the unused played songs as labels | manual, ~20-40 a night | NONE / error: the option keeps its own text | M x M | P6b-3 | A person reads the PNG before posting. MEASURED-KEEP (r2c): on the 44 real options of the 2 hand-made nights the title similarity is 44/44; Haiku 41-43/44, Sonnet 42/44. Not shipped. Detail below. |
| CB-21 kworb video match and functional audio | utils/kworb.py | find_video_match unique containment branch, _BASE_LABEL_RE qualifier drop; is_functional_audio regex drop branch |
3 | Haiku SAME / DIFFERENT cached 14 days per (label, video id); reuse functional_audio_check on each distinct name the regex drops |
leg label (with the dropped qualifier), video title, channel, event title; name + matched phrase | ~1 + ~0.1 | DIFFERENT / error: keep the row with unique=False, so the X vision gate decides; audio: error = drop (today) |
H x L | P4-B, P4-D | Do not drop the art on DIFFERENT; give it to the existing gate. Stay off the 1,000-row bulk path. Shipped (wave 20): the video match now asks kworb_video_same on every unique phrase or qualifier match whose title is not an exact fold (kworb.confirm_unique_video). Measured on 135 real Kalshi legs (30 days) against the live chart: 43 unique matches, 19 exact (no call), 24 asked, 2 runs, 0 flips; 2 downgraded to a pick (“Zid” in the Parvati title, the lyric-video leg on the music video), 0 hand-labelled SAME downgraded. The audio regex stays code, re-verdicted CLOSED-SET: 0 wrong drops in 30 days (2,694 artist_filter events, 2 names) and 3 names on today’s 3 pages, all functional; functional_audio_check agreed 6 of 6. Wiring a model into that bulk drop needs a client inside KworbClient, which bot.py builds. |
| CB-22 Perplexity answer reads and market outcome prose | utils/perplexity.py (+ one-line caller changes in music_desk, music_news, market_outcome), utils/market_outcome.py | is_hedged at the drop sites (music_desk, music_news x2, market_outcome.is_no_result), strip_industry_projection, _MARKET_TALK open words |
3 | Reuse _perplexity_grounded / perplexity_found_answer (Haiku FOUND / NONE) on a list hit; Haiku CUT / KEEP per HITS sentence; Jev Noul “talks about a betting market, odds or a probability” on the open words |
answer body + question, _HEDGE_MARKERS as NONE examples; the winner line with the word list as examples; %, percent, kalshi, polymarket stay exact |
~9 + <5 + ~2 Jev | the list verdict on error; market talk: re-ask, then drop | M x L-M | P3-B3, P2-C | Leave milestone_qualifier.is_no_qualifier’s is_hedged call to #4412. The market-talk ban is an owner steer (2026-09-06): the exact tokens stay the hard part. Wave 20: is_hedged at the 3 desk / newsroom drop sites CONVERTED (perplexity.hedged_checked: a list hit goes to perplexity_found_answer; on 35 real desk reads the list hit 5, all 5 real answers, all 5 kept, 3 goldens dropped). PROTECTED, not converted: market_outcome.is_no_result in resolve_outcome and resolve_winner (4 reads; they lead to the outcome post and its market_outcome_call ledger row). Its 2 prose reads (move_news_line, the news read) had 0 list hits in 30 days. Measured, kept as code (CLOSED-SET): strip_industry_projection cut 0 sentences in 35 real projection reads; _MARKET_TALK fired 0 times in 30 days, and the 14 shipped winner lines carry no market words. |
| CB-23 RIAA text and act-or-placeholder | utils/riaa_boards.py, utils/riaa.py, utils/chart_standings.py (+ its caller in cogs/music_desk.py) | _bare_title bracket keep list; _NOT_AN_ACT / own_credit; is_placeholder_credit as used on the census / catalog / debut boards |
3 | Bracket list folded into the existing riaa_recase call (0 added); one shared Haiku ACT / NOT_ACT (cached 90 days) for RIAA cells and board-leading credits |
titles with the keep / drop bracket lists; the cell or credit with _NOT_AN_ACT and _PLACEHOLDER_CREDITS as examples |
<1 (+ ~731 once for RIAA cells that reach a board) | today’s rule on error | M x L | P4-C, P5-D | artist_watch._PLACEHOLDER_CREDITS itself stays as the list (P1 kept the portrait skip exact); this batch asks the model only where a board would crown the credit. Done (CB-23): credit_act (Haiku ACT / NOT_ACT, cached 90 days, utils/credit_act.py) decides RIAA cells and Billboard census parties; riaa_bracket (Haiku KEEP / DROP per clause) decides _bare_title. Not folded into riaa_recase: that call may change only letter case (recase_valid), and the bracket choice is made when the board is built, before the recase. 2 registry lines to MODEL-DONE; _CREDIT_BRACKET_RE (a fixed credit opener, a certain drop before the model read) to CLOSED-SET; _DEBT_CEILING 84 -> 81. See “CB-23 measurement”. |
| CB-24 stream report loose join | utils/stream_report.py | _fold_loose loose-only residue in build_report |
1 | Existing release_version_kind; the exact _fold_track join stays the free accept |
row title + track title | <1 | error = old loose rule | M x L | P6a-6 |
| CB-23 RIAA text and act-or-placeholder | utils/riaa_boards.py, utils/riaa.py, utils/chart_standings.py (+ its caller in cogs/music_desk.py) | _bare_title bracket keep list; _NOT_AN_ACT / own_credit; is_placeholder_credit as used on the census / catalog / debut boards |
3 | Bracket list folded into the existing riaa_recase call (0 added); one shared Haiku ACT / NOT_ACT (cached 90 days) for RIAA cells and board-leading credits |
titles with the keep / drop bracket lists; the cell or credit with _NOT_AN_ACT and _PLACEHOLDER_CREDITS as examples |
<1 (+ ~731 once for RIAA cells that reach a board) | today’s rule on error | M x L | P4-C, P5-D | artist_watch._PLACEHOLDER_CREDITS itself stays as the list (P1 kept the portrait skip exact); this batch asks the model only where a board would crown the credit. |
|
| CB-24 stream report loose join | utils/stream_report.py | _fold_loose loose-only residue in build_report |
1 | Existing release_version_kind; the exact _fold_track join stays the free accept |
row title + track title | <1 | error = old loose rule | M x L | P6a-6 | CONVERTED (r2c) with a new read, not release_version_kind: track_version_join (row + track, SAME / DIFFERENT). The title-only read answered NEW once in 3 runs on a real row. 64 real album reports of 30 days: 3 loose rows, 3/3 SAME on 3 runs, the same as the loose rule. 1 registry line to MODEL-DONE. |
|
| CB-25 /ask reference router | utils/reference.py, utils/chart_data.py, utils/wikidata.py, utils/reference_movie.py, utils/genius.py, utils/musicbrainz.py, cogs/ask.py (tool schema, props join) | _CHART_INTENT, _TABULAR_CUE, sub-page pick (_SUBPAGE_HINT, _ASPECT_SYNONYMS, _aspect_weights), _title_names_subject residue, detect_chart, render_tables filter, _FACTOID_INTENT, want_founding, movie_matches miss branch, the genius intents + _best_annotation, _MUSIC_INTENT, the /ask player-prop name join |
13 | Make the tool aspect an enum the /ask model fills; one cached Haiku classify per lookup for the rest (chart, table, factoid kind); route non-music questions to the Movie source, where pick_reference_film decides; a candidate-name pick for props |
query + aspect; candidate titles / names; the regex lists as cue examples | ~0.2 (5 lookups in 30 days) | regex verdict on error | M x L | P3-B5, P4-E, P5-E, P1-B8 (router part), P3-B7 | B7 measured this router “not worth it” (#3430). Under the new rule it is MODEL, but it needs an owner yes; retiring the router is an acceptable outcome. CONVERTED (owner yes 2026-10-19): reference_route (one cached Haiku JSON read per lookup), reference_subpage, wiki_title_subject; song_credits takes a kind enum. 13 registry lines to MODEL-DONE. Measured on 72 questions (5 real, all that exist in 30 days; 67 hand-written, labelled before any model run): regex chain 49/72, Haiku 70/72 and 70/72, Jev 58/72. Sub-page: old weights 11/17, Haiku 15/17 x2. Title residue: 17/17 x2 with the subject kind (16/17 without). Not converted: the props join (0 player_props_lookup in 30 days) and the render_tables row filter (an exact match on the asker’s own words). Detail: “CB-25 measurement” below. |
|
| CB-26 manual music tools | scripts/music_drop_manual.py, scripts/riaa_credit_audit.py, scripts/artist_sweep.py | video_kind; _SAME_RECORDING / _recording_key, _NOT_AN_ACT_NAME; board_stream_totals called with no client |
4 | Haiku classify VISUALISER / LYRIC_VIDEO / MUSIC_VIDEO / AUDIO / LIVE / OTHER; SAME / DIFFERENT and ACT / NOT_ACT (share CB-23’s wrapper); wire the existing album-track match |
YouTube title + channel; titles and guest names with the lists as examples | manual, a few to tens per run | error = regex label / reject / blank | M x L | P6b-5, P6b-7, P6b-8 | video_kind labels “(Official Audio)” as video today, so the claim says “official video”. Done (CB-26): utils/video_kind.py (Haiku video_kind, the two regexes as the fallback) decides the report’s kind word; _NOT_AN_ACT_NAME stays as a block-only floor with the shared credit_act read on top; _SAME_RECORDING stays code (MEASURED-KEEP, the model was worse); artist_sweep passes a client, so the existing album-track match runs. _DEBT_CEILING -4. See “CB-26 measurement”. |
|
| CB-27 X tag scan drop branches | utils/x_artist_tags.py | _inside_longer_name (+ _CREDIT_WORDS), _is_title_position “by” branch, _FAN_BIO |
3 | Existing is_music_artist_mention; new OWN / FAN / UNSURE for bios |
the post + a position hint; the bio + the 12 phrases | 1-3 | no tag (absent) on NO or error | L x M | P6a-5 | _FAN_BIO refused 0 in 30 days and every tagged account is ID-pinned: it may wait. |
SHIPPED 2026-10-18 (wave 20): see the CB-27 result under the x_artist_tags inventory. |
| CB-28 competitor same-story judge | scripts/competitor_scoreboard.py | split_matchup no-separator branch, _work_kind, certs, same_story fallthrough, is_story cue admission |
5 | Haiku SAME / DIFFERENT per pair; STORY / OTHER per tweet | matchup, our preview, their tweet, chart keys, figures; the docstring rules as the definition | ~30-100 pairs + ~160 tweets | error = today’s rule ladder | L x H | P6b-4 | Blocked: the script runs in ops-monitor.yml, which has no model key. Adding one is a .github/ change, so the owner merges. Land after W19-C1 and W19-B3. CONVERTED (owner merges, .github/ change): competitor_same_story on SONNET (Haiku measured worse), competitor_story on Haiku; the rule ladder on no key / error. 30 days, 2 runs: pairs wrong 96 (rules) / 56-57 (Haiku) / 16-17 (Sonnet); posts wrong 56 (rules) / 6 (Haiku). No registry lines: the script is not in RUNTIME_SCRIPTS. Detail: “CB-28 measurement” below. |
|
| CB-29 wire signature collisions | utils/pop_stories.py, utils/sports_stories.py (+ cogs/sports_desk.py read), utils/cinema_news_stories.py (+ cogs/cinema_news.py) | story_signature / dedup_key collision drop, in three files |
3 | On a key collision whose texts differ, ask the existing topic_duplicate; same text stays a free drop; store the recorded headline beside the key |
both wire texts | ~1 | error = drop (today) | L x L | P1-B8, P2-D, P4-F | Add the cinema signature_dup skip event in the same PR. CONVERTED (wave 20): wire_lanes.collision_allowances, two topic_duplicate calls must agree; 226 real pairs, 23 allowed (all correct), 0 worse. |
|
| CB-30 side surfaces | utils/banger_lane.py, utils/ktt2.py, utils/versuz.py, utils/feeds.py | _SPAM_RE, match_score / match_threads, answer_order, room_is_quiet |
4 | Small cached Haiku labels: SPAM / REAL per tweet id, a thread pick from the newest N, A / B / UNSURE per poll answer, SUBSTANTIVE / CHATTER | each list as examples | ~5 | each keeps today’s rule on error | L x L | P1-B8 | Disjoint files; one executor. Wave 20: _SPAM_RE CONVERTED (Haiku banger_spam, regex on error; on 304 real Top-search results the model fixed 8 and was worse on 1). Not converted, each with 0 production inputs in the 30 days to 2026-10-18: ktt2.match_threads (0 search_ktt2 tool calls), versuz.answer_order (0 versuz events; a miss already falls to the host’s own pick), feeds.room_is_quiet (9 recaps; the message text is not stored, so it cannot be measured). |
|
| CB-31 small Jev identity picks and labels (DONE 2026-10-18: measured, every site stays code; see “CB-31 result” below) | utils/x_reply_draft.py (+ draft_x_reply), utils/starboard.py, utils/market_chart.py, cogs/playercard.py |
_TICS / tic_hits, looks_like_wall_channel, _order_two_up / _side_tokens, _resolve_target, _resolve_member_id |
5 | Jev: 7 Nouls (one per tic name); Choice over channel names + NONE; Choice “which label is side X” after the exact canonical_name fold; Choice over the members whose name contains the text |
tic names + example phrases; channel names; the two labels; display names | ~5 + <1 + <2 + <1 | the code rule on error | L x L | P3-B6, P2-D | _TICS was measured against a model once (showing drafts made tics worse, 9/35 to 19/36). A Jev label that names the tic is a different shape, but measure it against that baseline. |
|
| CB-32 arcade memory cities (DONE, wave 20) | utils/arcade/memory_cities.py, cogs/arcade.py _load_cities |
cities_in |
1 | Haiku PLACE / OTHER per nominated city (never Jev: the input is memory text) | the note sentences that name the city; the gazetteer as the closed candidate set | ~15-50 (1-day cache) | error = keep the regex hit | L x L | P6b-6 | ||
| CB-33 album-track recovery, zero-overlap branch | utils/chart_boards.py | recovery_candidates zero-overlap branch |
1 | Fold into the existing album_track_match call |
unmatched title + top unused rows by total | ~0 | absent (undercount) | L x L | P4-G | Only after the follow-up below confirms the recovery path runs (0 calls in 30 days). |
CB-02 result (wave 20). Haiku decides both reads; the regexes are input and fallback.
(1) claude.market_chart_family (purpose market_chart_family, labels SLOT_TITLES / FIELD /
BINARY / COUNT / OTHER, cached 30 days per event) decides which boards the gate checks. The
title rules are one input line and decide on a model error. (2) Every take on a SLOT_TITLES
board goes to market_take_names_leader (purpose market_take_check); the
take_names_leader_only fast accept is gone and rides the new chart_take_gate event as
matched. (3) The alert’s YouTube leg check ships only on a whole-phrase match. Any other take goes
to market_take_names_leg (purpose market_take_leg: is the take ABOUT a leg?) with the kworb
upload lines before a drop. The leader judge is the wrong question there: a take that says a
leg is out of the running crowns nothing (Codex, #4566). On 12 constructed takes (7 that name
a leg by its artist, 5 about another song), 2 runs: 12/12 with the uploads, 7/12 without them,
and every miss without them is a drop, as on main. Measured on real data, 2 runs each:
| read | set | old rule | Haiku | flips | Jev |
|---|---|---|---|---|---|
| board shape | 382 real Kalshi event series (196 with a chart word in the title + 186 random), hand-labelled (4 ambiguous left out) | 379 right (missed the 2 YouTube weekly song boards and the vinyl sales board) | 382 right on both runs (wording 3); wording 1 un-gated “Top Album on Spotify” (not shipped) | 0 that change the gate | 197 and 196 of 198: it gated 2 FIELD boards; p50 766 ms vs Haiku 590 ms |
| board shape, alert input | the 198 chart-word rows as the alert sends them: event title + ONE leg | (same rule) | 198 right on both runs (wording 3); wording 2 read the Billboard 200 #1 board as BINARY on both runs (Claude review, #4566) | 0 | |
| gated take | 34 real chart takes (30 days), leader as posted | ships 34 | ships 34 of 34 | 0 | not measured |
| gated take | the same 34 with a rival as leader | drops 30 of 34 | drops 30 of 34 (same 4 misses: the judge’s “unsure = true” line, #4271) | 0 | |
| gated take | 5 goldens (After You, My Brilliant Career, 3 falls) | ships 2 (“drops to No. 2”, “slides to No. 2”) | drops 5 of 5 | 0 | |
| live boards | 6 live SLOT boards, real regroup | (no take) | correct take ships 6/6, rival take drops 6/6, wrong-slot take drops 5/6 (the fast path ships 6/6) |
Regression table, old against new on the real takes: better 2 (the goldens), WORSE 0,
changed-neither 72 (per run: 34 real + 34 swapped + 4 ambiguous). Cost: shape reads about 5-15 a day (cached), judge reads about 4-10 a day
(was about 0.1 a day), together under $0.02 a day. The regression query after merge:
['tootsies'] | where event == 'chart_take_gate' and ok == false | project _time, surface,
matched, reason, ticker=parse_json(detail)['ticker'] joined to the market_drop_scored /
market_filtered drop rows for the take text; a correct take there is a WORSE.
is_music_chart_market (market_cards.py, not edited) is now only the fallback for the
gate; its branding, report-lock and catalog-hint uses still decide alone.
CB-19 measurement (wave 20, 2026-10-18).
catch=True. 0 chime-ins and 1 icebreaker posted in 30 days, so there is
no real input to replay. The cost is about one topic_dedup call per post.classify_intent as the market_intent fallback: 0 market_intent failures in 30
days, so the fallback did not run.CB-31 result (2026-10-18). Every site was measured on real production input, and
no model beat the code. One code bug was fixed. The registry line for _TICS is
now MEASURED-KEEP (a model measured worse), and _DEBT_CEILING went down by 1.
| site | input measured | old errors | Jev | Haiku | verdict |
|---|---|---|---|---|---|
_TICS / tic_hits |
88 real Sonnet drafts over real wire tweets, hand labels | 7 false-hit drafts, 1 miss | 35-42 false hits, 14 flips | 11-13 false hits, 5 flips | KEEP-CLOSED |
looks_like_wall_channel |
34 real text channels, 2 guilds | 0 | not run | not run | KEEP-CLOSED |
_order_two_up / _side_tokens |
88 real Kalshi two-leg game events | 0 | not run | not run | REMOVED 2026-10-19 (the two-number cover layout it served is gone) |
_resolve_target, _resolve_member_id |
517 queries from the real 279-member roster | 12 wrong picks that a start test fixes (1 tie goes the other way) | 10 of 11 decidable ties | 9-10 of 11, 5-7 refusals | code fix (best_name_match) |
The surface volumes are low: the X reply draft ran 1 time in 30 days (the experiment is
off), /card 3 times and the engagement_lookup tool 4 times. The /card typed text is
not logged, so the name queries were built from the real roster: each folded word and
each 4-letter prefix of each name.
CB-01 to CB-33 hold about 140 MODEL sites. The partition total of 141 counts a few shared sites twice. CB-14 and CB-15 include sites that already run Jev beside a code rule. The same file sits in more than one batch in these places; sequence them or give them to one executor:
| file | batches |
|---|---|
| utils/music_news.py, cogs/music_news.py | CB-01, CB-08, CB-05, CB-09 (CB-01 first) |
| utils/apple_music.py | CB-07, CB-10 (different functions) |
| utils/output_checks.py | CB-03, CB-12 |
| cogs/music_desk.py | CB-10, CB-11, CB-18, CB-23 (one function each) |
| cogs/games.py | CB-10 (pool filter), CB-15 (grader) |
| utils/market_cards.py | CB-02 reads is_music_chart_market; W19-B1 owns the cluster |
One cached Haiku JSON per story, ClaudeClient.chart_story_read (purpose=chart_story_read):
family, forecast, later_week, edition, title_is. One Haiku label on the take,
take_marks_album. Each field that the answer does not give uses its old rule. Design
change from the plan: a chart NAME in the KEPT or CUT list still decides with no read, and
the model reads only the residue. On 200 claims the rule keeps, the first model run
dropped 9 (6 daily stream counts, 3 bare “Hot 100” claims), so a model decision on the
kept side was worse than the rule.
The data, 2026-09-18 to 2026-10-18:
unnamed chart cuts (claim + subject, Axiom); 11 of them name a kept chart;classify_music_news; 201 are stories;album_unmarked
drops, and each one again with its first “album” removed.Every disagreement was read by hand. 2 runs per model call.
| site | inputs | better | WORSE | same | flips |
|---|---|---|---|---|---|
chart family, residue (chart_reportable unnamed) |
130 | 10 (the rule kept 0 of the 11 real kept charts) | 2: “US Pop & AC Radio” and a Spotify single-day record, both kept 2 of 2 runs; a daily stream count kept 1 of 2. The rule keeps that shape already when the post says “on Spotify”. | 117 | 1 |
forecast (post_states_forecast) |
201 | 11 rule misses (“is set to spent a 15th week”, “aiming for”, “challenging for”); none changes a shipped story in this sample, because the classifier flag was already set | 0 | 190 | 0 |
later week (post_states_later_week, take guard) |
201 | 11 (“third consecutive week”, “returns to its peak”, “another #1 week”; and another title’s later week in the same post) | 0 | 187 (3 neutral: artist-level weeks) | 1 |
edition (names_edition) |
201 | 11 (“re-issue” with a hyphen, the #4131 Rubber Soul case; a tour’s, a festival’s or a chart’s anniversary is not an edition) | 0 | 188 (2 neutral) | 2 |
| title is a song / album / tour | 32 | 2 (TWICE’s “This Is For” is a tour with no “tour” word) | 0 | 30 | 0 |
take says album (mark_album) |
262 | about 140 takes that already read as an album (“now 2016’s seventh most-streamed album”) stay unchanged; the rule added a second “album” | 0 (the model never said unmarked where the rule said marked) | 121 | 0 (1 error on a cut-off text: the rule decides) |
Cost: about 100 to 150 reads a day (one per composed story, plus about 4 residue reads at the scope gate), cached a day per story. About $0.1 to $0.3 a day on Haiku. The album label adds about 5 calls a day.
After merge, these Axiom queries show a regression:
['tootsies'] | where event == 'music_news_filtered' and reason == 'chart_cut' | extend via=tostring(parse_json(detail)['via']), fam=tostring(parse_json(detail)['family']) | summarize count() by via, fam
(via=rule on unnamed rows means the read is failing);['tootsies'] | where event == 'music_news_recover' and tostring(parse_json(detail)['via']) == 'chart_scope_model' | project _time, matchup, detail
(read each kept story; a non-chart there is a false keep);['tootsies'] | where event == 'claude_api' and purpose in ('chart_story_read', 'take_marks_album') | summarize count(), ok=countif(ok == true) by purpose, bin(_time, 1d);['tootsies'] | where event == 'music_news_scored' and reason in ('later_week', 'album_unmarked') | summarize count() by reason, bin(_time, 1d).Not changed, and why:
_TRANSIENT_RE (“briefly”): 0 chart_frame drops in 30 days. Moving it into the
music_desk_score rubric changes every desk score for a list that never fires._LATER_WEEK_RE in the classifier parse (_parse_music_news turns a later-week
first_week into chart): the read runs after the classifier, so it cannot decide
there. A field on classify_music_news is the fix (a CB-08 shape).title_grounded_in_wire: the read replaces it at the post_states_forecast
caller only. ungrounded_quoted_titles and _reads_exit still use the word match._KEPT_RE and
_CUT_RE stay MODEL-FALLBACK.Registry recheck in the same PR: FIRST_WEEK_PHRASE_RE and utils/dedup.py
_STREAM_COUNT_RE were CLOSED-SET, but both approximate a meaning (“launch week” and
“streamed 2B times” miss), and no model reads them, so both are MODEL-FALLBACK now.
_RELEASE_WINDOW_RE stays MODEL-DONE: its one runtime caller passes the
release_window read (_first_week_kicker(judged=True)).
The CB-01 read kept two unnamed residue claims that name no kept chart, on 2 of 2 runs:
“US Pop & AC Radio (Mediabase)” (read as pop radio) and “broke Spotify’s then-record for the
most-streamed song in a single day” (read as the Spotify chart).
What changed:
CUT_PATTERNS format_hot_ac also matches “AC radio”, the Mediabase panel name. A panel
that joins AC with a kept format is cut by its name, ahead of the read. On 30 days of
classifier claims the new words matched 4 AC panels and 0 kept stories.CHART_FAMILY_NOTES: the format_hot_ac note covers a joined panel, and the
spotify_daily note says a Spotify record is not a chart position.format_pop note.
It dropped “Back to No. 1 on Billboard Global Charts” to 1 of 8 keeps.Result on the same 131 residue claims, 4 runs on main and 4 on the branch:
| claim | main keeps | branch keeps |
|---|---|---|
| US Pop & AC Radio (Mediabase) | 4/4 | 0/4 (rule) |
| Spotify then-record, most-streamed in a single day | 4/4 | 0/4 |
| 43.0M Spotify streams a day (a count) | 1/4 | 0/4 |
| Back to No. 1 on Billboard Global Charts | 3/4 | 4/4 |
| Drake, most #1 albums on “Billboard Hip-Hop/R&B A…” | 4/4 | 3/4 (1 unreadable answer about the cut-off log text) |
| the other 126 | same | same |
Run-to-run flips: 2 on main, 1 on the branch. The chart_story_read eval passed 2 of 2
runs with a fourth golden (the Spotify record).
Coordinator call: measure every site first. Where the rule is not worse and a change touches under about 1 post a month, the site is MEASURED-KEEP with the number. A field PR ships only where the measurement shows real misses.
| site | measurement (real text, 30 days to 2026-10-18) | verdict |
|---|---|---|
quotes_ladder_rung (_RUNG_CLAIM_RE) |
The rule read a year as a threshold: “83% odds of being the top US artist in 2026” was dropped as ladder_rung 7 times. 29 real market claims, 2 runs: the model and the rule agree on 26; the model is better on 3 (the year case twice, “17+ passing TDs”); 0 worse; 0 flips. |
MODEL-DONE, ClaudeClient.market_claim_is_rung (purpose=market_rung), market kind only |
figure_is_passed_threshold OR-branch (_THRESHOLD_CUE_RE, _THRESHOLD_CUE_DURATION_RE, _DURATION_WORDS) |
55 real milestone stories with Perplexity research, 2 judge runs. The rule fires on 91 of 246 texts. On the verified stories, threshold_passed agreed with the rule on 4 of 4 rule hits, and it flipped between runs on 2 of 3 rule misses. “Trust the judge alone” changes 0 in the sample and adds flips. |
MEASURED-KEEP |
rank_list_tag (16 regexes) |
92 real ranked-list posts through the real classifier. The rank_list field and the rule differ on 1 post, where field-first would label a “top 10” tier as a rank. |
MEASURED-KEEP |
figure_is_rank_word (_RANK_WORDS) |
641 distinct real figures (1,610 events): 0 fires, 0 misses found. | MEASURED-KEEP |
_STREAM_SCOPED_RE |
0 fires on 310 real wire posts; the classifier’s stream_shape already refuses a scoped catalog count. |
MEASURED-KEEP |
figure_unit_phrase (_UNIT_PHRASE_STOP) |
A stop list of function words. | CLOSED-SET |
claim_chart_kind |
The count path ran 9 times, always on one chart: chart_keys_for already narrows by chart_key, so the songs / albums word never picks between two charts. Inline, no registry line. |
no change |
cert fields (cert_claim_format, cert_reportable prose, cert_prose_*) |
measured in #4590, see “CB-08 certification sites” below | MEASURED-KEEP |
A field on classify_music_news was tried first for the rung and NOT shipped: on 218 real
posts, 2 runs each, it moved a chart forecast (“expected to surpass Boyz II Men for the
sixth most weeks at #1”) to the market kind on 2 of 2 runs, where 3 runs of the old prompt
read it as a chart story. A one-word label on the market claim alone has no such reach.
About 1 call a day, cached.
Found on the way (#4583 shape, not fixed here): a career total scoped to “lead-credit
songs” (“BTS … 55 billion streams with lead-credit songs”) reads as an unscoped career
shape.
Measured on the 30 days to 2026-10-18 (Axiom music_news_filtered reason=cert_out_of_scope
and the 51 shipped music_news_posted phase=cert lines):
| site | measurement | verdict |
|---|---|---|
cert_reportable prose branch, cert_prose_names_other_body / cert_prose_is_riaa (_IN_SCOPE_CERT_PROSE_RE, _OUT_OF_SCOPE_CERT_PROSE_RE, _UK_CERT_PROSE_RE, _US_CERT_PROSE_RE, _FOREIGN_CERT_MODIFIER_RE) |
The prose branch (a cert id with no named body) cut 25 of 25 foreign certs correctly: New Zealand, Italy, Germany, Japan. 50 of the 51 shipped certs are US or UK. The one wrong ship was an Italian FIMI cert (Bad Bunny, 2026-10-06 16:50Z, artist-pull lane). It came through the OLD prose branch, 16 minutes before #3914 deployed: the classifier gave cert_id 5xplatinum| (no body), claim “5x Platinum (FIMI)” and source “FIMI”, and the old branch failed open, had no “fimi” word and did not read source. Every later copy of the story was cut. #4583 measured the remaining path, a kept body named on a foreign cert: 0 of 353 riaa / bpi ids in 30 days (the one prose hit was a real RIAA Latin cert), so no guard was added. |
MEASURED-KEEP |
cert_claim_format (_CERT_ALBUM_RE, _CERT_SINGLE_RE) |
Read only by the RIAA “Multi-Platinum” level lookup (_riaa_level_for). That figure appeared 2 times in 30 days. |
MEASURED-KEEP |
A model change here would move fewer than 1 decision a month. The 2026-10-06 ship came through
a body the classifier named itself; a named body decides alone in cert_reportable. It is
filed on #4583, not changed here.
luminate_subject (B13) still decides in production: 0 calls and 0 events
in 30 days against 968 market_subject events. The sweep passes a client at all 10
callers, so the cause is probably the cue rules or the cache, but it is not verified.memory_note_violations has no runtime caller (finding 7). KEEP-PROTECTED: owner call. Wired by #4528 at the memory write path.chart_fact misses 4 of 17 measured double posts (joint credits or an album spelled
two ways). That is an exact-key miss with fail-open, not a word list; 4 a month does not
earn a model join today.dedup.chart_claim / judge_evidence (#3912) skips the topic judge when no recent
post names the same folded title. If a repeat with a re-spelled title shows up, give
the judge a candidate list rather than a fuzzier fold.utils/release_board.py Spotify match (pick_spotify_release,
spotify_release_date_near), kworb.credit_members and apple_music.title_match_band
are fuzzy joins that the P5 pass saw but did not own. P1 and P4 covered their files;
confirm each is in their inventory on the next refresh.Five sites, three outcomes.
| site | outcome | real inputs | result |
|---|---|---|---|
catalog_stats _NAMED_COMPARISON_RE, _PLACE_ON_OTHER_METRIC_RE |
converted: Haiku catalog_caption (OK / NAMES_RIVAL / OTHER_METRIC), after the exact name and place checks; no answer drops |
the 51 catalog / daily-hits captions of 30 days (23 distinct), 2 runs; 16 goldens | real: 0 disagreements, 0 flips. Goldens: Haiku 16/16 both runs; the regexes missed 7 (“right behind Drake”, “level with Drake”, “fourth in monthly listeners”) and falsely hit 1 (“after only six years”) |
milestone_qualifier _AGGREGATOR_RE, _OFFICIAL_SOURCE_RE, _SCORE_RANKER_RE, _RELATIVE_SCOPE_MARKERS |
converted: Haiku qualifier_labels (source, scope) on each accepted qualifier; the lists decide with no label |
78 accepted qualifiers (25 from a live replay with their reads, 53 production clauses), 2 runs | drop decision: 0 worse; better on 2 both runs, 2 more on one run. Scope: 15 relative claims the list missed, 1 run worse (“this decade”). 7 label flips, 2 change a drop (each toward keeping a real official chart claim the lists drop) |
milestone_qualifier _NO_QUALIFIER_MARKERS (phrase tail) |
MEASURED-KEEP | 100 real lookup reads (50 subjects replayed) | 0 reads opened with a phrase other than NONE; the 52 no-qualifier reads were all NONE or a hedge |
music_desk _RESERVED_OTHER_CHART |
MEASURED-KEEP | 924 real Spotify desk lines of 30 days, 2 runs | regex 1 wrong (a Chartmetric “global artist rank” line, no effect); Haiku 3 wrong (“sixth highest globally” read as the Global chart twice, “Global Weekly” missed), 0 flips |
The first qualifier shape was measured worse and not shipped. The batch row said to fold
source and scope into qualifier_verify. A live replay of 50 real subjects (fresh
Perplexity + Grok reads, old and new prompt on the same reads, 2 runs each) showed the two
extra fields moved the Sonnet judge’s supported verdict on 14 of 43 judged subjects: about
7 better (Johnny Marr’s UK Top 5, Sheryl Crow’s 13th Billboard 200 entry) and 5 worse (a
“13th solo entry” whose citations were about Miranda Lambert, a stale Spotify chart position,
a blog’s “11th all-time”, an album rank given to a song, a lost real UK top 10). This is the
CB-08 lesson again: a field added to a judge moves its other fields. The labels moved to
their own Haiku read, which leaves the judge’s prompt unchanged.
The first label wording read a news site that reports a ranking (Yonhap, BroadwayWorld) as an aggregator and dropped two real superlatives on both runs; the shipped wording says a reporter is not the source.
Cost: catalog_caption about 2 Haiku calls a day (cached a week per caption);
qualifier_labels about 2 a day (one per fresh verified qualifier, cached a week). The
relative scope shortens the cache on about 1 in 5 qualifiers, so those re-verify after 12h.
The set: the 5 reference_lookup rows in Axiom for 2026-09-19 to 2026-10-19 (all that
exist; 132 /ask turns in the same days) and 67 hand-written /ask-shaped questions. Each was
labelled with a route, a chart key (CHART) and a tables flag (ARTICLE) BEFORE any model ran.
“Full” means all three are right. Two runs per model arm, with the classify cache cleared.
| arm | route right | full right | real 5 (full) | flips | p50 ms |
|---|---|---|---|---|---|
| regex chain (first source the chain selects) | 51/72 | 49/72 | 3/5 | 0 | 0 |
| Haiku, wording 1 | 71/72, 68/72 | 69/72, 66/72 | 5/5 | 4 | 667 |
| Haiku, wording 2 (shipped) | 72/72, 72/72 | 70/72, 70/72 | 5/5 | 2 (tables only) | 655 |
Jev (Choice route + chart, Noul tables) |
66/72, 66/72 | 58/72, 58/72 | - | 0 | 110 |
The regex chain’s misses include the two real ones: “New York Mets World Series titles”
went to the movie source first (series is in _FILM_WORDS), and “Best Rap Song winner
and nominees” got no tables. Others: “how many albums has she released” went to MusicBrainz
(released), which answered with one karaoke album; “who are her producers” and “production
credits” went to Genius; “when was it started” and “when did they form” were not seen as a
founding; “highest charting song” was not seen as a chart question (charting).
Wording 2 added three meaning statements (songs produced for others are ARTICLE; anything
about a person other than dates and names is ARTICLE; counts of number ones are CHART) and
one cost statement for tables (“an extra table costs little”). WORSE than the regex,
each listed: “Michael Jackson Thriller / how many copies sold” got no tables (both runs;
the prose holds the sales figure), and “Kendrick Lamar / Pulitzer Prize” got tables in one
run (one extra fetch). Jev lost on the same meaning cases the regex lost (“songs he
produced” -> CREDITS, “who is he dating” -> PERSON), so Haiku ships.
Sub-page pick, 17 real articles with a candidate link list (labels written after reading the lists, before the model ran): old word weights 11/17, Haiku 15/17 on both runs, 0 flips, 0 worse. New: Michael Jordan -> career achievements, Harry Potter -> the film series, The Bear -> the TV series, Tom Hanks -> performances and credits. Both arms miss the Yankees seasons list (MAIN) and Michael Jackson (no page lists songs he wrote for others).
Title residue, 17 (subject, title) pairs the token rule rejects: the rule is right on 7 (the NO pairs). Haiku with the subject alone: 16/17, and its one miss was the dangerous kind (“REPO” -> “Repossession”, YES; the subject is a video game). With the caller’s subject kind in the input: 17/17 on both runs, 0 flips.
Movie routing: sending every ARTICLE question to TMDB as well (the audit’s first shape) put the Eras Tour concert film on “The Eras Tour / total gross” (1 wrong of 29). The FILM route alone sends no ARTICLE question there, so only FILM reaches the movie source.
End to end, real sources, 18 questions old vs new: better on 4 (Interscope founding, Dune runtime from TMDB, Olivia Rodrigo chart peaks, Taylor Swift album count no longer a karaoke album), the same fact from another source on 1 (Doechii’s birth name, now Wikidata), fewer wrong sources tried on 3, same on 10, worse on 0. Cost: about 0.2 route reads a day at about 1,000 tokens each, plus at most one sub-page read per tabular lookup and one title read per rejected lead-image title.
The set: 30 days of real scoreboard inputs (our posts 2026-09-18 to 2026-10-18 plus the match window, read from Axiom: 3,495 posts; the four competitors’ posts from one paged twitterapi.io search: 1,360 posts). That gives 2,009 candidate pairs (inside the window, the subject words in their post) and 1,231 candidate story posts (not a reply, a repost or a look-back). Every arm ran twice on all of them.
Labels: an item where the rule ladder and every model run agree is taken as right. Every item where any run disagrees with the rules was read and labelled by hand: 181 pairs and 75 posts. 20 pairs are AMBIGUOUS and left out: a forecast against the final result, or our preview cut before its figure.
| read | arm | wrong (run 1, run 2) | worse than the rules | flips |
|---|---|---|---|---|
| pair, 1,989 scored | rule ladder | 96 | - | 0 |
| pair | Haiku, wording 1 | 72, 71 | 41, 39 | 20 |
| pair | Haiku, wording 2 | 57, 56 | 30, 27 | 17 |
| pair | Sonnet, wording 2 (shipped) | 17, 16 | 8, 7 | 8 |
| post, 1,231 | rule ladder | 56 | - | 0 |
| post | Haiku, wording 1 | 22, 21 | 15, 14 | 3 |
| post | Haiku, wording 2 (shipped) | 6, 6 | 4, 4 | 6 |
The rule ladder’s pair misses are mostly true pairs it refused: an emerging-artists #1, a prediction-market price, a ranked list that holds our figure, two posts that name the same event with no chart. Its false pairs are act-only matches across different facts (a crown race against a reaction post, an iTunes #1 against a different song’s return to #1). Its post misses are the chartmasters sales posts (“past 22 million equivalent album sales”), which carry no chart cue, and the polls and release posts it admitted.
Wording 1 told the pair read “DIFFERENT when you are not sure”, and Haiku refused true pairs that carried extra detail on one side. Wording 2 names the main fact and the details that do not change the story, with paraphrased examples, not the measured posts. Haiku still refused about 27 true pairs that the rules got right, so the owner rule’s second step applied: Sonnet, same prompt, same pairs. The posts stay on Haiku.
WORSE than the rules, Sonnet pairs (each listed): two Tinashe posts paired with her career history list (both runs); “The Art of Loving is No. 8” against the chart line (both runs); two release posts against a “will be released tonight” question post (both runs); three “Risk It All” most-streamed-of-2026 posts (one run each); a one-year-anniversary post (both runs). WORSE, Haiku posts: the year-end list prediction, the 2020s hitmakers ranking, the “most billion-stream songs” list and the VMAs most-wins list read as OTHER in one or both runs; the Grammy submission count and a recurrent-rule list read as STORY.
Golden: 10 known-DIFFERENT pairs from tests/test_competitor_scoreboard.py (a different
chart, a different position, a different count, a different work, a cert level, a figure
bound to another list entry) came back DIFFERENT on both runs of the shipped read.
Cost: about 70 pairs and 40 posts per scheduled run, two runs a day. The job installs
anthropic and Pillow (a clean venv with only those and aiohttp imports ClaudeClient;
config.py is not loaded) and gets ANTHROPIC_API_KEY on the step that runs the
scoreboard.
Every site was measured on its real 30-day traffic (Axiom, post_dedup_history,
chart_history_weeks, the cached HITS documents, and live Kalshi and Polymarket reads).
| site | 30-day decisions | result | verdict |
|---|---|---|---|
live market event pick (market_leg_candidates, _event_conflicts, _topic_tokens, _MARKET_ROLES, _MARKET_ALIASES) |
17 live-leg reads (11 picked, 6 dropped) | see below | MODEL (Haiku market_event_pick over every candidate set) + year / role safety floor |
Luminate subject tiers (_subject_tier_hits via reading_for_subject) |
7 X-mention matches; the newsroom forecast path matched 0 | 3 of about 280 real subjects reach a non-equal tier today; 2 of the 3 are wrong | MODEL (Haiku reading_subject on a non-equal tier hit) |
threshold_metric (+ poly_event_matches) |
13 parses, 2 distinct claims | none was a metric-threshold claim, so None was right 13 of 13; poly_event_matches ran 0 times |
MEASURED-KEEP |
restate_market_claim (4 _RESTATE_* regexes) |
11 restates (10 shipped, 1 refusal) | 0 wrong on the 7 real claim texts held | MEASURED-KEEP |
related_market_context substring match |
per desk units reading | 30 real reading subjects x 102 live field-market outcomes: 3 exact hits, 0 substring-only | MEASURED-KEEP (no registry line) |
hits.projection_row substring match |
2 market_drop subjects; the desk standing line | 200 real subjects x both HITS documents: 42 matches, all exact, 0 substring-only | MEASURED-KEEP (no registry line) |
Event pick, real claims. The 16 distinct real claims of 30 days (11 shipped picks,
the 5 drops) were replayed through the real _live_market_odds against live Kalshi and
Polymarket and the bot’s Kalshi search index, 2 runs, 0 flips.
| outcome | claims |
|---|---|
| model pick = the event that shipped | 10 (Coachella x2, Lana Del Rey, Bruno Mars, Rihanna, RAYE, Bruno Mars SOTY, Patient Zero, Octane nominee, Sienna Spiro) |
| no candidate today (event settled or gone) | 4 (Housewife, Iceman, one Octane claim, Taylor Swift Oscar) |
| changed, neither | 1: the 2026-10-13 Octane “market favorite for Best Rap Album” claim now picks the Best Rap Album WINNER event (right; the story was dropped later by the restate step that day) |
| WORSE without the floor | 1: JAY-Z “favorite to headline the Super Bowl halftime show” took “Who will perform at the 2027 Big Game halftime show?” in both runs. The code rule refused it (role). The floor (market_role_conflict) vetoes it, so the shipped result equals today’s. |
Three of the 10 were ties on today’s data (Lana Del Rey, Rihanna, Patient Zero), where main already asks the model. Hand cases built from real event titles with ONE candidate, labelled before any run: code rule wrong 5 of 10 (a “No. 2” claim took the Top artist event, a “week of Oct 24 #1” claim took the “#2 Song Week of October 31” event, an album claim took the new-song event, a “winning” claim took the nominees event, and a tie left a real nominee claim unread); model 0 of 10 in both runs.
Reading match. 12 cases (the 3 real non-equal hits and 9 hand cases in the real ticker shapes), 2 runs: the tier rule (keeps every hit) 7 of 12, Haiku 11 of 12 with the first prompt (it refused petal’s artist-named pure-sales ladder, the case the tier exists for) and 12 of 12 after one sentence that states the ticker format (the code after the dash starts with the title’s first letters; the example is GUTS, outside the set).
Calls. About 17 market_event_pick a month (cached 6 hours) and a few
reading_subject (cached 12 hours). Under $0.01 a month.
After merge. ['tootsies'] | where event == 'music_news_recover' and
tostring(parse_json(detail)['via']) == 'event_pick' | summarize count() by
v=tostring(parse_json(detail)['verdict']), a=tostring(parse_json(detail)['agree']) and
['tootsies'] | where event == 'claude_api' and purpose in ('market_event_pick',
'reading_subject') | summarize calls=count(), failed=countif(ok == false) by purpose. A
regression is an agree=false row whose picked title is a different question from the
claim, or a rise in verdict=error.
Two model reads replace three open lists. Each keeps its list as the prompt’s examples and as the fallback on a model error or a credit not yet read.
| site | model | decides |
|---|---|---|
riaa._NOT_AN_ACT (via own_credit) |
Haiku credit_act, ACT / NOT_ACT |
which unresolved RIAA artist cells a board may name |
artist_watch.is_placeholder_credit in chart_standings._entries_by_act |
the same credit_act |
which Billboard parties the census, catalog and leader boards may rank |
riaa_boards._IDENTITY_BRACKET_RE + _CREDIT_BRACKET_RE (via _bare_title) |
Haiku riaa_bracket, KEEP / DROP |
which bracket clauses a board row keeps |
The boards are pure, so the desk runs an async pre-pass before each build
(riaa.check_cells, st.check_board_credits, rib.check_titles, and each backfilled
record-ledger week). A cached verdict is read first (ClaudeClient.classify_cached) and
costs no model call; each pass sends at most 25 items to the model, most rows first, so
the items a board can crown are asked first. A bracket that opens with a credit or a
source (“feat.”, “with”, “from”) is a certain drop and is never asked: 0 of the 927 real
clauses with that opener read KEEP.
artist_watch._PLACEHOLDER_CREDITS stays the exact portrait skip (unchanged).
Data. The RIAA rows the bot holds in kv_cache (riaa_tallies, riaa_year_feed,
riaa_recent: 1,703 distinct artist cells, 7,790 titles, 927 distinct bracket clauses)
and every stored Billboard 200 and Hot 100 week (chart_history_weeks, 214 weeks,
2024-10-05 to 2026-10-17). Every input below is a real decision the old rule makes.
Act check, 2 runs, shipped prompt.
| input | n | agree | better | worse | flips |
|---|---|---|---|---|---|
| RIAA cells the rule names or drops | 954 | 952 | 1 | 0 | 1 |
| Billboard parties with 2+ entries in a week, and the 3 placeholder parties | 184 | 184 | 0 | 0 | 0 |
| hand-labelled hard credits (labelled before any run) | 20 | model 20 / 20 both runs | 0 |
Bracket check, 2 runs, shipped prompt, 927 clauses. 919 agree with the rule.
| change | clauses |
|---|---|
| better (the clause names a different recording; the rule cut it) | “(STRIPPED)”, “(EN VIVO)”, “(I’M GOD X DEMONS MASHUP)”, “(CHARLIE HEAT VERSION)” |
| worse (a kept subtitle or edition tag; the row is longer and names the same recording) | “(FOOT OR 2)”, “(RELOADED)”, “(DEATH OF AUTO-TUNE)” (1 of 2 runs) |
| changed, neither | “(FREESTYLE)” on “ALBUM OF THE YEAR (FREESTYLE)”, the song’s own title |
| flips | 1 (“(DEATH OF AUTO-TUNE)”) |
A first prompt that read the whole title was worse than the rule (about 20 wrong keeps, 13 flips): a title holding “REMIX” made it keep the feature credit after it. The shipped prompt reads the clause alone.
Effect on today’s boards. The top 20 of the Diamond singles, Diamond albums and 2026 year boards, and the census on every stored week since 2026-09-01: 0 rows change. The value is on the next placeholder or version clause the lists do not hold.
Cost. A cold cache asks at most 25 credits and 25 clauses a pass, each answer cached 90 days; the dry run (real rows, real Haiku, no recognition lists, so every cell counted as unresolved) stored 125 credit verdicts in 5 passes. After that, only a new credit or clause is asked. The measurement itself was about 4,600 Haiku calls.
After merge. ['tootsies'] | where event == 'claude_api' and purpose in
('credit_act', 'riaa_bracket') | summarize calls=count(), failed=countif(ok == false) by
purpose, bin(_time, 1d) and ['tootsies'] | where event == 'music_ranking' and reason ==
'credit_act' | project _time, count, detail. A regression shows as a credit_act row
whose detail.not_act names a real act.
CB-17, the album title pairs. The set: every pair of album titles where one title starts with the other, on the kworb album pages of 147 acts (the top streaming acts plus the acts the album lane has counted), 360 pairs. I labelled 311 of them by hand (V = the same record, D = a different album); 49 have no clear answer (a live album of a record, a remix EP, a tour edition) and are not scored. Each arm ran 2 times. The fail direction decides the metric: a wrong relation states a false album count, and a withheld one leaves the count out.
| arm | right | wrong | withheld | flips |
|---|---|---|---|---|
| word list alone | 230 | 13 | 68 | 0 |
| before CB-17: the list, then the old prompt on the ambiguous pairs | 275 | 36 | 0 | 0 |
| old prompt on every pair (with the list’s read as a hint / without) | 266-267 / 269-270 | 44-45 / 41-42 | 0 | 2 / 1 |
| new prompt on every pair, model alone | 289 | 18 | 4 | 8 of 360 |
new prompt + the list as a block (_combine, shipped) |
281 | 12 | 18 | 8 of 360 |
_own_albums_past with real pages, iTunes and Haiku: Taylor Swift 11,
Drake 7, Lil Uzi Vert 2, Queen 9, the same counts as before; Dua Lipa and Hozier stay
withheld. A crossing asks 3 to 24 pairs (Taylor Swift’s page has 24), cached 14 days.CB-24, the stream report’s loose join. The set: the 96 distinct per-track milestone
songs the qualifier events name in 30 days (295 events), rebuilt with the live kworb
songs pages and the iTunes tracklists. 64 had an album join; 2 had loose-only rows: 3
rows, all the same song as their track (“Cameras / Good Ones Go Interlude - Medley”, two
“Remastered 2009” Beatles rows). release_version_kind read the medley row NEW once in
3 runs, which would drop a true album track. track_version_join (row + track) read all
3 SAME in 3 of 3 runs, the same as the loose rule; on 9 constructed probes (a part 2, a
sped-up cut, a remaster) it was right 8 of 9 and the loose rule 6 of 9.
CB-20, the manual Versuz card. The set: the two hand-made nights in #main-stage (2026-09-03, 22 polls, 44 options, 58 played songs). The title similarity matched all 44 to the right played song (read by hand). With each option’s own song taken out of the played list (the truth is then NONE), the similarity matched a wrong song 16 times of 44.
| arm | real options right | leave-one-out NONE right | flips |
|---|---|---|---|
| title similarity (kept) | 44/44 | 28/44 | 0 |
| Haiku, wording 1, played list shrinking as the night goes | 43/44 | not run | 0 |
| Haiku, wording 2, a 20-song cap | 41/44 | 38/44 | 5 |
| Haiku, wording 2, the full played list | 42/44 | 24-27/44 | 15 |
| Sonnet, wording 2, a 20-song cap | 42/44 | 37-38/44 | 1 |
The model is worse on the real options, which is what the card shows, so the similarity stays (MEASURED-KEEP). Haiku with 43 labels picks the wrong song (“Fking Problems” to “Mo Money Mo Problems”) and misses a shortened title (“Diamonds remix”). A person reads the PNG before posting.
Three manual scripts. They run by hand, a few to tens of decisions a run, so each site was measured on real inputs the scripts would see.
| site | inputs | rule | model | verdict |
|---|---|---|---|---|
music_drop_manual.video_kind (_VISUALISER_RE, _LYRIC_RE) |
300 real YouTube titles off kworb’s music charts (2,798 held; every title with a kind word plus 60 at random), 2 runs | calls 9 “Official Audio” uploads and 20 live performances “official video” | 31 better, 1 changed-neither, 0 worse, 0 flips | MODEL-DONE video_kind |
riaa_credit_audit._SAME_RECORDING |
36 real title-key mismatches: 595 RIAA single rows (Diamond singles, Drake, Future, Taylor Swift) against Deezer | 36 of 36 right (karaoke, instrumentals, remixes, a parody, a Taylor’s Version) | Haiku SAME / DIFFERENT 31 of 36 on titles alone (5 covers read SAME), 35 of 36 with the hit’s artist; 0 better | MEASURED-KEEP |
riaa_credit_audit._NOT_AN_ACT_NAME |
the 54 guest names on those candidates, 2 runs | 2 rejects (two karaoke labels) | credit_act 3 rejects: the same 2 plus “HOT 100” (a karaoke label credit) |
PROTECTED floor + credit_act on top |
artist_sweep board_stream_totals with no client |
real sweeps of Zach Bryan and Olivia Rodrigo, with and without the client | identical output: no album fell to the tracklist sum | wired (the existing album_track_match) |
Two prompt rounds for video_kind. The first read unmarked titles as AUDIO or OTHER
(Avicii “Levels”, James Arthur “Say You Won’t Let Go” are music videos). The shipped
prompt says a title with no marker is MUSIC_VIDEO, and MUSIC_VIDEO and OTHER keep the
rule’s word, so the model changes the kind only where the title says so. Its language
examples (“Paroles”, “En Directo”) do not occur in the measured titles.
The Deezer replay used Deezer’s plain search: its advanced search (artist:"" track:"")
returns no rows from the session sandbox, while production’s advanced searches hit
(deezer_lookup albumtop 15 of 24 on 2026-10-19). Plain search returns the same kind of
fuzzy match the audit exists to reject, more often.
Not covered by any CB-26 site. Of the 9 candidates the rules ACCEPT, about 4 are a different version under the same title (the Phoebe Bridgers “The Night We Met”, the Kendrick Lamar remix of “Bad Blood”). Equal title keys are the free accept by design; the script’s docstring already says a person checks every candidate before writing.
This part is the first audit as it stood on 2026-09-18, with each worklist item’s outcome added as it shipped. Its verdicts (HAIKU / HYBRID / KEEP) follow the OLD rule. Part 0 gives the 2026-10-18 verdict for every site. “Part 2” in the text below means the 2026-09-18 inventory, which is in git at commit 4e1b6c0.
Scope. Every .py file under cogs/, utils/, the repo root, and the runtime
scripts (scripts/ops_monitor.py, scripts/axiom_setup.py, the manual mod tools). Tests
are excluded. Five audit passes each read one partition of the tree in full. The
partitions are the five inventory sections below.
What counts as a site. A regex, a keyword list / set / dict of terms, a substring or prefix / suffix test, or a dict lookup keyed on free text, that decides one of:
A site is SEMANTIC when the input is natural language and the rule approximates a judgment. A site is STRUCTURAL when the input is a URL, a payload key, a number, a date, a filename, a log line, or our own enum. Structural sites are listed but never candidates.
Verdicts.
| verdict | meaning |
|---|---|
| HAIKU | Replace the rule with a small-model call. The rule stays as the fallback when the model errors. |
| HYBRID | Keep the rule as the fast path or the fence. Add a model call only for the ambiguous residue. |
| KEEP | Leave as code. The reason column says why: structural, money path, safety fence, hot path, privacy, or already behind a model judge. |
The rule that decides the verdict is already in docs/ENGINEERING.md, “The
deterministic / model-judged boundary”: repeatable behavior lives in code, model judgment
is for taste and language, and “don’t hand-code brittle heuristics for a genuine judgment
call”. This audit applies that rule site by site.
Line numbers are anchors from the audit date. They drift. The stable reference is the symbol name in each row. Every symbol in the worklist was re-checked to exist on 2026-09-18.
Site counts per inventory section. The counts are the audit passes’ own tallies.
| section | semantic sites | structural sites | HAIKU | HYBRID | KEEP |
|---|---|---|---|---|---|
| Music, newsroom, identity, feeds | ~118 | ~110 | ~9 | ~25 | ~84 |
| Markets, betting, sports, media | 94 | 154 | 9 | 22 | 63 |
| Conversation, X, gates, output checks | ~80 | ~190 | ~6 | ~12 | ~62 |
| Charts, cinema, ops, infra | 76 | ~110 | 3 | 12 | 61 |
| The 16 remaining files | 41 | 39 | 1 | 8 | 32 |
| total | ~410 | ~600 | ~28 | ~79 | ~300 |
About three quarters of the semantic sites stay as code. That is the expected result: settlement math, dedup keys, identity joins with a documented incident, the constitutional fences, the permission allowlist, and the per-message hot paths are all deliberately deterministic.
Cost baseline. Axiom, 7 days to 2026-09-18, claude_api events:
| model family | calls / week |
|---|---|
| Haiku | 41,069 |
| Sonnet + Opus | 1,455 |
| total | 42,524 |
Haiku already carries 97% of the bot’s model calls. Tier A below adds zero calls. Tier B adds cached per-ticker or per-channel calls, in the low thousands per week at most. No item on the worklist changes the cost picture.
1. The biggest keyword surface sits on top of an existing Haiku classifier.
classify_music_news (Haiku) already returns kind / subject / claim / figure / cert_id /
milestone_id / outcome / source. About 20 regex parsers in utils/music_news.py and
cogs/music_news.py then re-parse its claim prose to recover facts the classifier could
have emitted as fields: chart key, debut vs re-entry, projection vs settled, threshold vs
count, stream-claim shape, market outcome / odds / venue / deadline / award, cert
territory, tour / live / non-audio. The same shape appears in markets
(market_subject_image re-derives what image_subjects already classified) and in X
mentions (asks_question runs beside scan_music_mention). The cheapest fix for these is
“add a field to the existing call”, not “add a call”. That is Tier A.
2. The model-output FENCES are the second-biggest class, and most of them stay.
utils/output_checks.py, claude_client.is_empty_response, ship_guard, the
ungrounded_* number checks and the retrospective arithmetic are deterministic on
purpose: each cites a measured judge miss (a career claim the judge scored 0.92, four
decline narrations that shipped at 0.72 to 0.78). The number and arithmetic checks stay.
The PROSE fences (decline narration, self-correction, cross-source comparison,
career / all-time claims) grow one phrase per incident and are the ones a model reads
better. Those are Tier B4 and Tier C8, with the regex kept as the free first pass.
3. Identity matching is deterministic by design, and the fix is a rescue rung, not a
swap. apple_music, deezer, artist_watch, chart_credits, catalog_art, steam_art,
market_art, espn.match_team_logo each carry a documented incident and Codex rounds. A
model here re-opens the wrong-face / wrong-cover class. The one measured gap is the
UNKNOWN band: 10 of 150 unknown-artist cuts in 30 days were watched acts lost to spelling
artifacts, and _title_matches at ratio 0.6 to 0.85 picked the wrong link three times.
The pattern that already works is claude.match_album_tracks: deterministic fold first,
cheap prefilter, Haiku closed-set confirm on the residue only. That is Tier C.
Do them in tier order. Within a tier, the order is brittleness times user impact. Each item names the site, the shape of the fix, the added call volume, and the fail direction the replacement must keep.
Every replacement PR carries the same five things. A new method on ClaudeClient
following classify_abuse (label) or topic_duplicate (JSON tri-state) with
skip_persona=True and the judge temperature; the old rule kept as the fallback when the
model errors; the surface’s fail direction preserved (gates fail closed, reads fail open);
an event with a purpose= so the ops monitor sees it; and a golden fixture that must keep
failing.
A new item adds its call through ClaudeClient.classify (#4199). It takes a
purpose, the task text, the input, a closed label set and an optional cache_key and
ttl. It fixes the parts a caller must not get wrong: Haiku, skip_persona, the judge
temperature, max_tokens of at least 16, and a prefix match on the upper-cased answer.
It returns the label, or None on an error or an answer outside the set; None is never
cached, and the caller maps None to its own fail direction. So a new item is a task
text, a thin wrapper that maps the label, and a golden. is_music_artist_mention is the
first wrapper. The methods shipped before it (same_screen_work, classify_abuse and
the rest) are not migrated.
The classify cache is durable (#4231). A label lives in the kv_cache table under
namespace classify for the caller’s ttl, so a deploy does not clear it. Before #4231
it was in memory only, and each deploy re-asked about 565 market_sport_check and 47
market_act_check verdicts. The cache key holds a hash of the model id, the task text
and the label set, so an edit to the prompt or the labels asks the model again. A caller
does not need to change its purpose or cache_key after a prompt edit.
| # | site | fix | fail direction |
|---|---|---|---|
| A1 (SHIPPED 2026-09-18, #3413) | cogs/music_news.py _TOUR_CLAIM_CUES, _TOUR_CLAIM_ANTI_CUES, _NONAUDIO_RELEASE_CUES, _LIVE_CLAIM_CUES, _LIVE_CLAIM_ANTI_CUES, _LIVE_VERB_RE, _played_at_subject, _TOUR_UPDATE_CUES, _is_tour_subject |
Add event_shape: release / tour / tour_update / live / nonaudio to classify_music_news. Retires five phrase lists, two anti-lists and a subject-anchored regex grown over four owner reports in two weeks. Each miss ships the wrong kicker, the wrong art and a listen link on a concert. |
Unknown shape reads as release (today’s default). |
| A2 (SHIPPED 2026-09-18, #3414) | utils/music_news.py charts_named, sole_weekly_chart, sole_chart_text, _forecast_near_chart, unsettled_chart_label, named_chart_label, _CHART_PATTERNS, _FORECAST_WORDING_RE |
Add chart_key (closed set from CHART_SOURCES) and is_projection to the classifier. The regex stays as the tiebreak. A wrong read today becomes absent and the stale gate drops a true story. |
No key: fall to the regex; still-no-key: web verify (today’s path). |
| A3 (SHIPPED 2026-09-18, #3415) | utils/music_news.py stream_claim (_STREAM_*_RE), entry_count_claim |
Add stream_shape / rung / count fields on the milestone kind. The regex already produced a false CONFIRM (Codex #2774). |
No fields: fall to the regex. |
| A4 (SHIPPED 2026-09-18, #3416) | utils/music_news.py figure_is_passed_threshold (_THRESHOLD_CUE_RE + duration / plus regexes) |
Add count and threshold_passed to verify_music_claim. Five Codex rounds to tell “100 entries” (a rung) from “107” (the count). |
Absent field: keep the wire figure (today). |
| A5 (SHIPPED 2026-09-18, #3417) | utils/music_news.py market_claim_parts, market_award, market_caption, _MARKET_ODDS_LEAD_RE, _MARKET_VENUE_TAIL_RE, _MARKET_DEADLINE_RE, _MARKET_AWARD_RE, _PROBABILITY_FIGURE_RE |
Ask the classifier for outcome / odds / venue / deadline / award on the market kind. Five regexes parse the classifier’s own prose today. |
Missing slot: blank caption (today). |
| A6 (SHIPPED 2026-09-18, #3418) | utils/music_news.py claims_debut, claims_reentry, _DEBUT_RE, _REENTRY_RE (has_debut_cue + its two cues retired: no production caller) |
Added chart_event: debut / reentry / move / hold / none on the chart kind; music_news.chart_event_of reads it ahead of the regexes at the debut dedup key, the deep-platform exemption, the repost gate and the unconfirmed-debut rewrite. Since #4131 the card’s era guard reads it too (mn.chart_story_is_same_record): hold / move / none / exit keep an old catalog row on a chart story; debut, reentry, “” and an edition word keep the guard. Bounded: a debut / re-entry needs the wording somewhere in the wire, a move / hold can only narrow. |
”” (no field): the regexes decide as before. |
| A7 (SHIPPED 2026-09-18, #3419) | utils/x_mentions.py asks_question, _QUESTION_STARTS, _REQUEST_CUES, _REQUEST_RE |
Added asks_question to scan_music_mention (the same Haiku read). x_mentions.mention_asks reads it ahead of the regex; a true on a wordless text (emoji, a bare link) is bounded back to the regex; a false on a text carrying a literal “?” is bounded back too (2026-09-20: a two-question-mark reply came back false and got no draft); no flag falls back to the regex. |
False: parent not fetched, no_facts (today). |
| A8 (SHIPPED 2026-09-18, #3420) | utils/market_outcome.py names_match, normalize_name, _in_field |
winner_extract already hands the model the leg labels and takes an INDEX back, so the 6-char prefix matcher was a second matcher that could only fire on a pick the extractor cannot produce. Retired names_match; _in_field is an exact re-check of the closed-slate contract. |
No index: no winner line (absent, today). |
| A9 (KEEP, decision on #3421, 2026-09-18) | utils/market_subject_image.py detect_media_brand, is_youtube_video_market, is_youtube_daily_chart_market, is_netflix_rank_market, artist_subject_name; utils/market_cards.py is_music_chart_market |
The premise was wrong: the card build does not call image_subjects before these gates (image_subject runs only at step 3 of the art resolver, for an un-hinted market), so the fix would add a call per card. The detectors read Kalshi’s own fixed series titles and scope a fail-CLOSED suppression gate: a structured source, kept deterministic per the ENGINEERING boundary. |
Unchanged. |
| A10 (SHIPPED 2026-09-18, #3422) | cogs/discourse.py drop_self_correction at four lanes |
Measured first: three drafting shapes the regex misses (“no wait, scratch that:”, an Option 1 / Option 2 list, “actually, let me try that again:”) scored 0.78-0.87 with the judge and would have shipped. The discourse_score rubric now carries a SHOWS ITS WORKING clause (0.0-0.2); the regex stays as the pre-judge backstop. Three eval goldens pin it. |
Low score: skip (today). |
| A11 (SHIPPED 2026-09-18, #3423) | cogs/music_news.py _songstats_verify ("stream" in claim.lower()) |
_songstats_verify reads mn.milestone_metric(milestone_id) (the classifier’s canonical id) ahead of the claim substring; the substring is the fallback for a story with no id. |
Same. |
| A12 (SHIPPED 2026-09-20, #3549 + #3544) | utils/x_mentions.py charts_named, _CHART_CUES, _kind_nearest, _ALBUM_WORD_RE, _SONG_WORD_RE |
Added charts ({platform, region, kind} on closed vocabularies) to scan_music_mention, the same Haiku read. x_mentions.charts_from_scan maps it to chart families and order_units_for_question takes them ahead of the cue regex, which stays as the fallback for a reply with no field. The regex grew through six Codex rounds on #3543, each a new phrasing (“Billboard says she’s #1 on Spotify”, “Spotify Global 200”, a track named by title); measured live, the classifier reads all fourteen fixture phrasings right at the platform level (scan_music_mention_charts, four goldens). The same prompt edit makes a pushback on the bot’s own number an ask (#3544, two fixtures on scan_music_mention_asks). |
None (no field): the regex decides; a platform outside the vocabulary is dropped at parse. |
| A13 (SHIPPED 2026-10-16, #4200; N2 + N3 of the 2026-10-15 refresh) | utils/music_news.py rank_list_tag (the 14 _RANKED_LIST_* patterns), claim_platform, count_label_on_platform, artist_ranking_label, _names_spotify_streams, cert_claim_format, the cert territory regexes |
Measured first, on 104 real wire posts (2 runs each, old and new prompt). ONE field earned its place: rank_list on milestone / chart, which VOUCHES for the list name the regex parsed: it lets a comparison tail the safe-end allow-list refuses (“moving past …”) through only when its words equal the parsed name. It never names a list on its own (two Codex rounds on #4212 showed that standalone bounds re-implement the regex’s guards badly). It agreed with the regex on 10 of 10 labels, recovered the 2 the allow-list refused (“moving past”), and the bounds refused both wrong values (0 wrong accepts). claim_platform now reads “YouTube Music” whole (it printed “YouTube”). NOT added, by measurement: platform / count_label (0 of 93 stories had a claim platform with an empty source, the only case those readers decide); cert_format (the post rarely says album or single, so a field bounded to the post adds nothing); cert_territory (every cert carried a body in cert_id, and the scope gate fails CLOSED by owner steer, so a model admission would widen it). _names_spotify_streams and artist_ranking_label stay: each is a bound on the classifier’s own output (Haiku shaped Apple Music as Spotify 3 of 3, #3854; five Codex rounds on #3816). |
No field, a refused field, or a model error: the regex decides, as before. |
| A14 (SHIPPED 2026-10-16, #4201; N4 of the 2026-10-15 refresh) | utils/music_news.py states_chart_exit, post_states_forecast, wire_is_next_week, post_states_later_week / first_week_figures |
Measured first, on 432 real wire posts (2 runs per prompt; 4 runs of the old prompt for the noise floor). ONE value earned its place: exit in the existing chart_event set, enum text only (an added example raised drift from 35 to 53 stable field changes and added kind changes). states_chart_exit reads the field first: exit cuts inside the regex’s own title-scoped bound plus “departs”, where a “from #N” or a peak position does not block; any other event is no exit; “” is the regex. It cut 13 of 13 real exits against the regex’s 5, refused all wrong exit labels (the TTPD “Only ‘Robin’ drops off” album, “departs the top 10”), and dropped the regex’s 1 false cut (“… After Festive Exit”, a #1 story). NOT added, by measurement: week (Haiku answered week=this on 3 of 3 HITS forecasts it also called is_projection=false, so narrowing post_states_forecast brings back #3874, and the rule forbids it to widen; wire_is_next_week compares the wire to the LIVE page, which the post cannot know); chart_event on first_week (Haiku read “aiming to re-peak at #2” as debut, the #3860 failure). Output tokens: no change (144.5 vs 146.8 mean). |
No field, or a reply with no event: the regex decides, as before. |
| A17 (2026-10-16, #4214 / #4216 / #4264, wave 8; title judge SHIPPED 2026-10-18, wave 19) | utils/music_news.py title_grounded_in_wire (the title_ungrounded drop); cogs/music_news.py chart card block; the ranked-list milestone dedup key |
Measured first, on 30 days of Axiom. #4264: NO Haiku rescue. Of the 152 title_ungrounded drops, real wire text (twitterapi.io) showed 8 real titles lost to a deterministic bug: _wire_words strips “‘s”, so the contraction “She’s” never matched (“She’s The Best”, “i think he’s got a girl”). Fixed exactly: a contraction word keeps its “‘s”. The model band had 0 confirmed correct restores and 1 wrong one: the issue’s own example, “DtMF”, is the SONG, while the classifier named the ALBUM “Debí Tirar Más Fotos”; “L.A.M.B.” reached the wire as a t.co link, so no checker can see it. The same stripped “‘s” dropped an artist such as “Destiny’s Child” in grounded_subject (class sweep, fixed). #4214: the unsettled chart card takes the rank_list_tag block, zero calls. #4216: NOT built – about 13 ranked-list milestone stories in 30 days and 0 repeats of the same act on the same list, so the key would have held nothing. Wave 19 (2026-10-18), owner rule “open sets go to a model”: the title judge shipped. A title_grounded_in_wire miss now asks Haiku (title_quote_in_post, purpose title_in_post) for the post’s OWN WORDS that name the title, and mn.quote_grounds_title keeps the story only when the quote is in the post AND shares a content word with the title. Measured on 47 real word-match misses (1,515 subject/post pairs, 2026-09-27..10-18, X wires; tweet text re-read by id), hand-labelled, 3 runs per arm: a YES/NO Haiku judge passed GUTS (lyric line) and L.A.M.B. (a t.co link); a reworded YES/NO judge was worse; Jev (Noul, 2 runs) was wrong on 5 at the 0.5 cut, GUTS at 0.77-0.82. The quote judge kept 11 real titles 3/3 (“The R&B Tour” x5, “The Writing’s On The Wall”, “Formula Of Love: O+T=<3” x2, “Bad and Boujee” glued to the next word, “House of R&B Concert” x2), “The Lucky Me Tour” 2/3, and 0 memory titles (GUTS, L.A.M.B., DtMF, the venue descriptions: 0/3 each). WORSE: 1, the “GOLF” jersey collab description, kept 2/3 (the post does state that collab). Flips: 2 of 47. About 6 calls a day, about 400 input tokens, p50 530 ms. The 135 artist-pull drops (Perplexity text, not stored) were not measurable; query: ['tootsies'] | where (event=='music_news_recover' and tostring(parse_json(detail)['via'])=='title_judge') or (event=='music_news_filtered' and reason=='title_ungrounded') | summarize count() by event, tostring(parse_json(detail)['rescue']). |
Title: a possessive word stays stripped (event names such as “Karol G’s Houston show” stay dropped). Chart block: no list name, or a settled live read, keeps the old block. Title judge: NONE, a quote that fails the check, or a model error drops (today). |
| A16 (2026-10-16, #4204 N10; wave 19 2026-10-18) | utils/chart_history.py _HEDGE_RE in parse_nora_text (projection vs hedge); utils/billboard_stories.py _LEADER_TITLE_RE |
Wave 19: Haiku reads EVERY rank sentence, not only the hedged ones (nora_records_checked -> claude.classify, purpose=nora_rank_check, CALL / CONTEST). The hedge words are now in the prompt, and the regex decides only when Haiku gives no verdict. The #4204 fast path (“no hedge word = a firm call”) stored wrong Billboard 200 #1 rows: “the #1 is too close to call”, “currently in the lead for the #1 debut with a 2k lead”, “has reached #1 on US iTunes”, “the longest-running #1 hit on the Global Spotify chart”, “It is 190k streams away from #1”. Measured 2026-10-18 on 552 real Nora posts and posts citing them (2026-06 to 2026-10): 60 rank sentences, 57 hand-labelled. Shipped behaviour (regex, plus the old prompt on the 15 hedged ones) was wrong on 9; the new path is wrong on 3. Better 6, WORSE 0, wrong both 3 (two “above #90” bounds, one “could spend a third week at #1”). 3 runs: 2 sentences flip. About 0.4 new calls a day (45-day cache), about $0.00004 each. _LEADER_TITLE_RE is KEEP: it only orders the story candidates, and the page parse decides. |
CONTEST drops the rank. No verdict, an error or no client: the hedge regex (a hedge word drops the rank, as before). |
| # | site | fix | volume | fail direction |
|---|---|---|---|---|
| B1 | utils/market_cards.py hero / outcome cluster: outcome_split and the 232-entry _OUTCOME_VERBS, _field_clause, outcome_subject, named_rank, title_rank, winner_rank, award_slot, split_rank_authority, event_title_split, statement_title, how_much_title, subject_hero; plus cogs/market_drop.py _slot_figure / _RANK_WINNER_TITLE_RE / _kalshi_event_subject, cogs/market_alert.py _ending_soon_subject / _clean_authority, utils/alert_triggers.py outcome_label |
One call per market ticker returning {hero, caption, subject, outcome, rank, authority}, durable-cached. The regex ladder stays as the fallback. Retires about 25 regexes across four files. A verb outside the registry ships a raw question as the hero today. |
one per new ticker | Model error: regex ladder (today). Shipped in part (#3424): the Haiku split runs on the regex RESIDUE only (prime_outcome_splits), feeds outcome_split and so every subject / caption / quantity-title / hero reader, and is grounded word for word. The regex stays the fast path. #4209 (2026-10-16): the FIELD shape now rides the same split with no second prompt (_field_split: “Who will headline X” goes in as “Will they headline X” and is kept only when the subject is the placeholder; “When will X |
| B2 (SHIPPED 2026-10-16, #3425) | utils/markets.py _is_cut_runner_up_event, _names_non_leader_slot, _looks_like_music |
The regex now only NOMINATES a cut; confirm_runner_up_cut asks a cached Haiku RUNNER_UP / OTHER label (claude.classify, purpose=market_runner_up_check, per event ticker) and cuts only on RUNNER_UP. The music cue list stays the fast path (kept, no call). Live 2026-10-16: the regex nominated 5 events (Netflix #2 x4, Google #2), Haiku confirmed 5 of 5; on 25 cue-less boards x3 runs the regex wrongly cut 7 of 8 music boards, Haiku 3 of 75 calls wrong. Event market_label_check. |
about five per week | Model error: keep the event (fail open) and emit reason=judge_failed. |
| B3 (SHIPPED 2026-10-18, wave 19) | utils/retrospective.py _FRAMES, is_retrospective, retrospective_frame, states_past_interval |
The anchored regex stays the fast path (a match costs no call). Every post it misses goes to Haiku once (prime_throwback -> ClaudeClient.throwback_frame, purpose=throwback_frame, event wire_throwback_check), which answers current or names the post’s own time-frame words. ground_frame keeps the words only when the post holds them, they name a time (a year, a time unit, “this day/date”, a tag) and no year is this year or later. Every reader (retrospective_frame label model, the note, retrospective_values, the grounding) then reads those words exactly as it reads a regex match, so the arithmetic is unchanged. states_past_interval stays code: it reads the CLAIM only when the desk’s retro flag (now fed by Haiku) is false. Measured on 3,526 real wire posts (music_news_seen ids, 2026-09-27 to 2026-10-18, text from twitterapi.io): the regex found 63 throwbacks; Haiku agreed on all 63 and added 57, all hand-checked real (most are @Kalshi_Music “… released X N years ago today.”, with the frame at the END). WORSE 0 (two Billboard all-time-list posts and one war-photo post are refused by the output check). Both miss about 7 (birthday posts that cite a year, “Remember when …”, year-trivia with no frame word Haiku reads). 2 runs: 2 of 3,463 flip. Haiku p50 0.52 s, p95 0.79 s. Jev (Choice) was measured on the same posts and NOT chosen: it cannot return the frame words the note and the number checks need, and it flagged unrelated posts (war photos, a tour gross, a pre-show clip) as throwbacks. End-to-end on the production compose model (gpt-cheap): 9 of 12 takes ship framed; 3 drop on a pre-existing retro_interval false positive (“since 1998” in the claim). At most about 170 calls a day (every wire post the desk sees), about $0.00007 each. |
per regex miss, cached 30 days | No client, an error, an unreadable reply or ungrounded words: the regex verdict (no throwback), as before. |
| B4 | utils/output_checks.py decline-narration battery (decline_narration_hits), _SELF_CORRECTION_RE / has_self_correction, claude_client._SELF_CORRECTION_MARKERS, utils/wheel.py is_narration / _NARRATION_PHRASES |
One “finished post, or the model’s working?” judge, purpose="decline_narration", over the composed text. Fail toward drop. Covers three phrase lists that each grow one incident at a time. |
one per compose | Model error: regex battery (today). Done in part, 2026-10-18 (owner rule: the lists are the trigger and the model’s input): ship_guard.drop_self_correction (17 lanes) asks Haiku ClaudeClient.shows_working when a list word touches the post, and the regex decides only on a model error. Measured: 4 of 11,294 real composed posts in 30 days trigger a call; 0 real drops before or after; correction goldens 12 of 21 caught by the regex, 17 of 21 by the model; finished goldens falsely dropped 2 of 18 (the real titles “Hold On, We’re Going Home”, “Wait for Me”) against 1 (the test line “let me fixate”). The direct has_self_correction sites (x_mentions, discourse icebreaker, sports_boards, music_desk, market_alert, cinema_desk, the wheel parser) and _strip_self_correction stay on the lists (follow-up). decline_narration_hits stays the decider: on all 1,874 real chart-lane posts Haiku caught the same 7 real declines, missed the same 6, and dropped 4-5 climbs the rule passes. |
| B5 (SHIPPED 2026-10-16, #3428) | utils/markets.py _kalshi_competition_to_sport (_KALSHI_SOCCER_CUES + substring ladder) |
The tag does not select a settlement feed: it only SCOPES a game’s Kalshi search (search_kalshi_events ... AND sport = $4). Every EPL row had no tag, so an “Arsenal vs Everton” search scoped to soccer found only the Champions League “Bayern Munich vs Arsenal” row. KalshiClient._apply_sport_checks now asks check_competition_sport (claude.classify, purpose=market_sport_check, SOCCER / GRIDIRON / BASKETBALL / BASEBALL / HOCKEY / TENNIS / MMA / NONE) once per competition per process, over the name and 3 event titles, before the hourly FTS rebuild. Dry run 2026-10-16 on all 564 live competitions, 2 runs: 138 tags change. The ladder was wrong on 6 competitions (119 events: EuroLeague and “Italy Serie A” basketball as soccer, eSoccer and eBasketball as real sports, the Czech soccer “National Football League” as NFL, the Rugby World Cup as soccer) and left about 130 real sport competitions untagged (EPL, Liga MX, KHL, the Grand Slams). The model was wrong on 2 to 3 per run, all non-team sports (table-tennis “TT Star Series” as tennis, darts “Modus Super Series” as MMA, and “Portugal LPB” basketball as soccer in 1 of 2 runs); 1 flip and 1 unreadable answer per run. About $0.02 a pass; the first refresh after a deploy pays it, later refreshes make no calls. A prompt that added darts and “a competition you do not recognize” made it worse (4 errors a run) and was reverted. |
about 560 per deploy, then 0 | Model error: substring ladder. |
| B6 (SHIPPED 2026-10-16, #3429) | utils/curator.py _IMAGE_TOPIC_TERMS, topic_is_image_room, prefers_media; cogs/curator.py mode decision; cogs/curate.py prefers_media call |
judged_image_mode: density first (no call at or over the ratio); below it a cached classify IMAGE / LINK (purpose curator_image_room, per channel + name + topic, one day, in memory) over name, parent, topic and six short samples. Measured 2026-10-16: the six live rooms all read IMAGE by density (0.88 to 1.00), so 0 calls and 0 mode changes in production today. On a labelled set of 16 low-density rooms the topic list got 6 right (7 picture rooms missed, 3 link rooms set to IMAGE), Haiku 15 (one no-topic room with chatter samples read LINK, which the list also missed), 0 wrong IMAGE. 3 runs: 48 of 48 and 45 of 45 answers identical run to run. |
per low-density room per day (0 today) | Model error: the old density + topic-list rule, exactly. |
| B7 (NOT BUILT 2026-10-16, #3430: measured not worth it) | The /ask reference router: utils/reference.py _SOURCES chain, _CHART_INTENT, _TABULAR_CUE; utils/genius.py _DETAIL_INTENT / _SAMPLE_INTENT / _MEANING_INTENT / _LYRIC_INTENT; utils/musicbrainz.py _MUSIC_INTENT; utils/reference_movie.py _FILM_WORDS / _STRONG_CUES; utils/wikidata.py _FACTOID_INTENT; utils/chart_data.py detect_chart |
One call per reference lookup returning {source, clean_title, year, aspect, chart}. Replaces six regex lists ordered by hand-tuned shadowing rules, and fixes the missing “is the TMDB hit the right title” check. The calling model already decided “this is a reference question”. |
per /ask tool turn |
Model error: regex chain. Outcome (#3430): the router was not built. Axiom held 5 reference_lookup calls in 30 days (2026-09-16 to 2026-10-16), and each one reached the right source, so a Haiku call per lookup had nothing to fix. The one real harm was B15’s TMDB title, now checked. |
| B8 (SHIPPED 2026-09-18, #3426) | utils/sports_stories.py classify_sport (_SPORT_KEYWORDS, about 250 words) |
Inverted: sports_desk._resolve_sports asks classify_sports_beats for EVERY story (cached 48h by signature, 72 new per pass in calls of 24); the handle map and the keyword table decide only a story the model did not place. Measured on 951 live stories: the table left 175 of 309 unknown vs the model’s 116, was wrong on all 6 disagreements, and the handle map was wrong 23 of 515 (WNBA on @nba). |
about 40 cached per slot | Model error: regex. #3431 (2026-10-15) added the shared-nickname goldens (Panthers, Rangers, Kings) and re-measured on 649 live stories from the last 2 days: the rules alone left 113 unknown, the model-first path 24; 102 tags changed; the rules were wrong on about 12 of the changed tags, the model on about 6, 4 of them combat used for a post that is not UFC, MMA or boxing. The combat guidance now says “and nothing else”, which cut those 4 to 2 in two re-runs. 28 Haiku calls, about $0.07 for the whole set uncached. |
| B9 (SHIPPED 2026-10-15, #3432) | utils/kworb.py is_functional_audio (_FUNCTIONAL_AUDIO_RE + stream-shape gate) |
Keep the regex as the bulk filter over 1000 rows; run Haiku only on rows that enter the rendered top-N of a daily-ranked board. A miss ships white noise at #1 to X. Shipped as kworb.screen_functional_top + ClaudeClient.functional_audio_check (purpose functional_audio), called from music_desk._artist_board_units on the artist streams, listeners, movers and songs boards. Dry run 2026-10-15 on the live pages: 0 of 32 rendered rows changed verdict; the judge caught 6 of 6 invented white-noise names and kept 10 of 10 real acts and sleepy-titled songs. |
about 30 per fresh fetch, then cached 30 days | Model error: regex. |
| B10 (MEASURED 2026-10-16, not built, #3433) | utils/markets.py kalshi_channel_routing (_MUSIC_CUES, _CINEMA_CUES, _TV_CUES, _POP_CUES) |
No Discord channel reaches this function now. Its channel caller, MarketsManager.kalshi_category_markets, has no caller outside the tests: the drop and alert rooms use the explicit /menu category since #480. Its one live input is the topic argument of the /ask kalshi_trending / kalshi_movers / kalshi_competitive tools, and Axiom shows 0 kalshi_trending reads in the last 30 days. A Haiku call here would have no traffic to improve. |
0 in 30 days | Cues (unchanged). |
| B11 (SHIPPED 2026-10-16, #3434) | utils/markets.py qualify_platform_metric (_PLATFORM_PATTERNS, nine platforms) |
The one-platform rule stays the fast path. When the rules name TWO or more platforms, confirm_event_platform asks Haiku for one from the closed list + NONE (purpose=market_platform_check, per event ticker), and the pick is used only if the rules name it. Rules that name no platform get no call: no text could ground the answer, so the MrBeast / PBD ‘subscribers’ titles (YouTube only in the SERIES settlement source) stayed unqualified; #4246 (2026-10-16) reads the series settlement_sources deterministically when the rules name none: one platform there is exact, two store nothing (no model call; 6 of 58,280 live snapshot titles change, all right). Live 2026-10-16: 0 events in the residue, 4 rewriting series unchanged; on 27 two-platform rules texts x2, 52 of 54 right, 2 arguable (an Apple Music primary with a Spotify fallback). |
per new ticker | Model error or NONE: no rewrite (today). |
| B12 | utils/banger_lane.py search_terms (_STOP, _QUOTED_RE, caps-run heuristic) |
Entity extraction from a headline: “which names should we search X for?”. | a few per day | Model error: regex. DONE (#3435): ClaudeClient.headline_search_names (Haiku, skip_persona) names the entities per headline; banger_lane.judged_terms keeps only names found word for word in that headline and uses the regex for a headline with no checked name, so a model error gives the old terms exactly. Measured on 72 live wire headlines: regex junk terms about 40 and 5 empty results, Haiku about 6 weak terms and 0 empty; 6/72 headlines changed between two Haiku runs. |
| B13 (SHIPPED 2026-10-16, #3436) | utils/luminate.py metric_from_text (ALBUM_METRICS), parse_subject (_SUBJECT_RE) |
The cue rules stay the fast path. metric_cues drops the timeframe cue (“first week”) and the sales-inside-pure-sales overlap, so one label settles the metric. subject_is_ambiguous sends the rest to one cached Haiku call (claude.luminate_subject, purpose=luminate_subject): no metric cue or two different ones, no leg that parses, or two acts in one comparison. ground_event_subject keeps a value only when it is in the text (metric only from the closed set), and a two-act comparison credits no act. Wired into the music sweep (music_markets._checked_subject). Dry run on 121 live events: 71 fast path, 50 model calls, 14 changed (1 two-act misattribution and its wrong metric fixed, 12 artist-total subjects cleaned), 0 new misattributions, about $0.02. |
per Kalshi event (cached 7 days) | Model error: cue list. |
| B14 (SHIPPED 2026-10-15, #3437) | utils/perplexity.py is_hedged (_HEDGE_MARKERS) as used by claude_client._has_perplexity_grounding |
The forced web-search retry in chimein_post / discourse now asks ClaudeClient._perplexity_grounded: an empty block is not grounding (no call); otherwise a cached Haiku FOUND/NONE (claude.perplexity_found_answer, purpose=pplx_found_answer) reads the answer prose without the header or SOURCES. is_hedged stays the hedged telemetry flag. Dry run 2026-10-15, 40 real Sonar answers to chime-in hooks and discourse categories: the phrase list accepted 33, Haiku 30-31 (two runs). Every one of the 8 answers about invented subjects is NONE (the phrase list accepted 5 of them); 3 real answers the phrase list refused are FOUND. One borderline real answer (“teased a new album, no date”) flipped between runs. About $0.0001 per call. Sibling: research_disputes (#4132) is now the fallback for the verify judge’s own web_disputes flag (same call, no extra cost). On 24 real confirmed stories the regex flagged 13 and the judge 14; the judge also caught a different-figure answer and a Spanish answer the regex missed. |
Model error: phrase list (as before). Disputes: no flag = regex. | |
| B15 (TMDB half SHIPPED 2026-10-16, #3430) | utils/reference.py _SUBPAGE_HINT, _ASPECT_SYNONYMS, _aspect_weights, _relevant_subpage |
A pick_*-style call over the subpage titles given the question. Untested today. Folds into B7. |
per /ask reference |
Model error: main page. Outcome (#3430): the movie source now checks the TMDB hit with one cached Haiku pick (ClaudeClient.pick_reference_film, purpose reference_film_pick); a live dry run on 30 film-routed questions: 28 and 29 right against 12 for the old top hit. The Wikipedia subpage half is not changed: it had no observed failure. |
| B16 | utils/riaa.py display_title recasing (_INITIALS_RE, _SMALL_WORDS, _ROMAN_RE, …) |
One recase call over a card’s rows. Rules print SZA as “Sza” and DNA. as “Dna.” on public cards. | per card | Model error: rules. DONE (this PR): riaa.recase_texts + riaa_boards.recase_board, Haiku purpose riaa_recase, one cached call per card, each row checked by recase_valid (only the case may change). |
| B17 (SHIPPED 2026-10-14, #3996) | cogs/music_news.py _news_x_facts: artist_from_subject split, is_daily_stream_count, _MONTHLY_LISTENERS_RE, _X_STREAM_SOURCES, the chart-unit read (chart_unit over claim_chart_keys) |
New call classify_x_post (topic / milestone / artist / title / unit / itunes), made by utils/x_gate.py only for a story whose X copy would ship (about 30-60 a day). A song or album unit is kept only when the unit_from words it quotes are in the story. The regexes were removed, not kept as a fallback (owner steer: replace). |
Fail-open: a failed read is OTHER, so the post goes to X ungated, as any gate error does. |
B4 shipped (#3427, 2026-10-16). The phrase lists stay as the free first pass. The
“finished post, or the model’s working?” judge rides the self-gate scorers as one more hard
fail, so it adds no call: claude_client._SHOWS_ITS_WORKING_RULE, placed by
_with_working_rule into every branch of music_desk_score, drop_score and
cinema_desk_score (discourse_score already had its #3422 form). A 0.0 score is under
every ship floor, so the fail direction is drop; the reason starts WORKING:. The newsroom’s
N7 hedge and unnamed-source regexes got a matching CONFIDENCE DISCLAIMER line in the
music-desk numbers rubric (reason HEDGE:). #4289: that line, together with the Haiku 5.5
move (#3939), dropped forecast posts (“forecast to open with ~32K”) at 0.0. The numbers
rubric’s UNGROUNDED line now says a forecast the ground truth gives, stated as a forecast,
is grounded; the HEDGE line also names “says it may change”. On 316 real tracking posts,
2 runs, drops under 0.6 went from 118-122 to 5-7; 100 of 100 hedge goldens still fail. N6 (misstated_chart_frame) needed no change:
the numbers rubric already fails “another chart period … or a hold it does not give
(‘briefly’)”. The wheel has no scorer, so it asks classify(purpose="decline_narration")
once per wheel and once per slice only when that first answer is WORKING; a model error
keeps the regex verdict. NOT moved: decline_narration_hits and _MARKET_DECLINE_RE. They
judge the DIRECTION of a rank or a figure (a rank pair compared as numbers, a decline verb
beside a figure), which is a deterministic fact, and they apply only on some lanes (a chart
EXIT narrates its fall on purpose), which the shared scorers cannot see.
Desk numbers rubric: the reason before the score (wave 15, 2026-10-17). With the
score first, Haiku 5.5 sometimes gave a correct post 0.0-0.12 and then wrote a reason that
ended “clean, grounded, score high” (4 of 119 hard-fail reasons in 14 days, and more on the
Ashe forecast). The numbers rubric of music_desk_score (the desk’s numbers lanes and the
newsroom) now asks for {"reason": ..., "score": ...}, with _DESK_SCORE_MAX_TOKENS = 400,
and the UNGROUNDED line says “Start the reason with ‘UNGROUNDED:’”. Zero added calls. On
332 real and real-derived posts, 4 runs a side: 0 verdicts worse, 9 posts better, and 0
flips between runs (old: 1-6). A re-score on a Haiku classify() read of the reason was
measured too and not shipped: the check said PASS on a WORKING: fail and a HEDGE: fail.
The release rubric keeps the score first (measured worse there). has_self_correction also
matches “let me correct” and “let me fix” now (#4331 shape 2).
Desk IDENTITY fence shipped (#4261, 2026-10-16); RECORD measured, not shipped (#2784).
has_identity_subset_claim misses slang (“carrying the ladies on this board”, “five guys
and SZA”). It stays as the free first pass. music_desk_score now carries
claude_client._IDENTITY_RULE in all three branches (reason IDENTITY:), plus one line
that keeps the reply to the JSON object. Zero added calls; the fail direction is drop.
IDENTITY fired on 0 of 260 verdicts over 130 real shipped posts, and the old rubric shipped
the slang goldens at 0.78-0.82.
The RECORD twin for ungrounded_ranking_claims (“the only artist alive with …”) was NOT
shipped. On 59 real chart-lane takes scored against the source production passes
(source=blob), it put 24-28 under the floor against 15-20 today: the judge read an
act’s own entry count (“her eleventh entry”) as an ungrounded record, because the career
fact the compose used is not in that source. The same PR passes that fact to the scorer
on the chart and called-shot lanes (music_desk._score_source), which alone lowered the
old rubric’s drops to 13-16. With that fix RECORD was only level with today, and other
callers (x_mentions, the newsroom) still pass a reduced source, so #2784 stays open.
#2784 closed deterministically instead (2026-10-17). ungrounded_ranking_claims now
reads the universal-scope words as a ranking context: “in the world”, “on the planet”,
“
Drop IDENTITY fence shipped (#4276, 2026-10-16). drop_score (254 calls in 7 days)
carries _IDENTITY_RULE, one pass line for sports event names (_EVENT_NAME_PASS) and
_FENCE_SILENT, through _with_drop_fences, in all five branches. Production gives this
scorer the market’s numbers without its title, so the pass line says an event name passes
even when the ground does not repeat it. The music desk’s rule text is unchanged.
Measured on 142 real-lane inputs: live Kalshi music and sports boards rendered by
market_drop._render_market_blob, and Kalshi game markets rendered by
betting_board._line_blob / betting_alert._move_blob. Each was composed on the live
guild’s model and scored against that same blob. SGO returned no games, so the game lines
fold Kalshi prices, as the live board does now. Two runs per arm, both arms fresh:
| measure | old | new |
|---|---|---|
| noise floor, run vs run (mean abs) | 0.098 | 0.037 |
| under 0.6 | 50, 47 | 33, 30 |
| ship to drop on both runs | 0 | |
| drop to ship on both runs | 10 |
The 10 drop-to-ship posts are correct takes the old judge docked for a market framing it
could not check (no title in its ground). IDENTITY fired on 4 of 284 verdicts, all on two
posts with no gender word that the old rubric also scored 0.0. Drift-run goldens (10
fixtures): 5 gender-sorting takes 0.00 on every new run (the old rubric shipped 2 at 0.82);
5 event-name takes (“the women’s final”, WNBA, “men’s singles”, “Women’s World Cup”) ship
on every new run. The live eval drop_score_fences keeps 7 of them (3 gender-sorting, 4
event-name). A first
wording without the “ground does not repeat it” clause failed two real event takes as
IDENTITY (“Chess.com Woman Player of the Year”, “WTA Singles Finals”). A third wording
with “a post with no gender word passes” failed a women’s-singles take, so it was cut.
Working rule on the result scorer (#4228, 2026-10-16). winner_line_score now carries
_SHOWS_ITS_WORKING_RULE. 3 calls in 7 days, so the drift run was the trivial-clean
check: 46 inputs (7 real shipped lines plus 39 real-lane composes, one per
market_outcome_calls row), scored against the production fact. Noise floor 0.015, mean
drift +0.002, 0 crossings either way. Goldens: 4 of 5 working lines score 0.0 on the new
rubric (the old one shipped 3 of those 4 on at least one run); a trailing EMPTY still scores 0.92-0.95, a known limit.
Skipped from #4228, with 7-day call counts (Axiom claude_api by purpose):
| scorer | calls 7d | why skipped |
|---|---|---|
pop_desk_score, sports_desk_score, cinema_news_score |
0 (0 in 30d) | No real post exists: their *_events tables are empty, so there is no drift run. |
chimein_score |
0 | It scores the chat buffer, not a composed post, so the rule does not apply. |
board_score |
0 | No production caller (only scripts/dryrun_betting_board.py). |
commentate_score |
0 (33 in 30d) | The production source is the live game feed at post time, which is not stored. A drift run would need a substitute source. |
| # | site | fix | fail direction | |
|---|---|---|---|---|
| C1 (wave 19 re-measured 2026-10-18: every site STAYS CODE) | utils/artist_watch.py lenient_tier, s_variants, _ALIASES / canonical_credit; utils/music_news.py wire_spelling, grounded_subject, artist_grounded_in_wire, corrected_name |
Haiku “is X one of [these candidates]” ONLY on an UNKNOWN verdict that is about to CUT a story (#3439, shipped). Wave 19 measured each remaining site on real data and converts none: (1) s_variants: 0 tier raises on 617 distinct credits in 21 days, so a model there has no traffic to judge. (2) The rescue label set: 37 of 45 rescue cuts (2026-10-15..18) had no near name, so the judge was never asked. Arm “near names + the whole watched list” on the 226 real cut credits, 5 runs: it mapped band members and relatives (Chris Martin -> Coldplay 1-4/5, RM -> BTS 4/5, YG Marley -> Bob Marley & The Wailers 2/5) and lost NBA YoungBoy (0/5 against 5/5). A reworded prompt fixed the members and lost KPop Demon Hunters. WORSE, not shipped. (3) _ALIASES: an exact table read before the gate; fed to the judge, it reached 0 of the 226 cuts. (4) wire_spelling: 1 change in 1,515 real pairs (Beyonce); 76 of its 77 near candidates were connector forms (&, “and”, “ft.”) it correctly refuses; no miss found. (5) grounded_subject: market stories only, 0 drops in 30 days. Pre-existing, not changed: the near-name judge maps “Ghost Town (Ghost)” to Ghost 5/5 in every arm (My Boo is Ghost Town DJ’s). |
Model error: cut (today). | |
| C2 (SHIPPED 2026-10-15, #3440) | utils/apple_music.py _title_matches; utils/deezer.py album_title_matches |
Both stay the prefilter. A pass that is not equal and scores under 0.85 (title_match_band; for an album, a new core word or overlap under 0.85, album_match_band) is the band. An equal row in the same result set drops the band rows with no call. Otherwise one cached closed-set Haiku pick (claude.match_catalog_title, purpose=catalog_title_match) keeps the picked title or none. The installment rule and the non-Latin rule run first, so Slime Language and Cinderella never reach the model. _artist_matches / _credit_similar are NOT changed: no band incident, and the 0.8 floor plus the partial-name guard already refuse the known shapes. Dry run (90 real chart rows): 1 changed link (Bad Bunny “Bokete” no longer links “Vete”), 3 Haiku calls. |
Model error: no link (absent). No judge attached: the old rule. | |
| C3 (SHIPPED 2026-10-16, #3441) | utils/release_type.py is_side_version (_SIDE_MARKERS, _BARE_TRAIL_MARKERS, _FEAT_RE, …); N11, the edition / variant tag readers album_milestones._relation, release_type._EDITION_MARKERS, _REMASTER_RE |
The regex stays on the bulk rows. The two announce paths ask the cached Haiku claude.release_version_kind (new / recut / edition, purpose=release_version): the release board over its first 20 in-window rows, and the new_entry lane on a regex-flagged title and on a regex-passed title it is about to keep. release_type.judged_side_version maps the label. N11: album_milestones._relation keeps its word list, and only an AMBIGUOUS pair goes to claude.album_variant_relation (purpose=album_variant). _EDITION_MARKERS and _REMASTER_RE are KEEP: they build persisted song keys and group a song’s uploads, so they must stay deterministic. No new title regex (utils/title_forms.py already owns the feature and radio-edit forms). Dry run: 80 calls on 14 days of real candidates, 2 decisions changed, both right, 0 wrong. #4230: every side_version drop now names its judge; the watch lane’s presence feed keys a side version on its own edition key, in its own <chart>:side record (_presence_key), so a model-cleared one is established after its window. The music_alert debut lanes stay regex-only: on 13 real regex-flagged titles Haiku changed 0 outcomes for the better and cleared 2 instrumental / a cappella album editions the lanes would post as debuts. #4268: a RENDITION marker in the version suffix (instrumental, a cappella / a capella / acapella, karaoke, sped up, slowed, reverb; release_type.rendition_marker) is RECUT with no model call, and judged_side_version treats it as a side version whatever the verdict. Haiku labelled the 4 real titles of that shape (“Popstar (Instrumental Edition)”, “Bass Persuades (A Cappella Edition)” and their pairs) EDITION on 2 runs of 2. In 399 real watch_new_entry / apple_debut titles (30 days) the marker matched those 4 and no other title. The bulk regex now also spells “A Capella” with one p. |
Model error: regex (the release check); withheld count (the album check). | |
| C4 (SHIPPED 2026-10-16, #3442) | utils/market_subject_image.py take_references_leg and cogs/market_drop.py fabrication-gate routing |
The gate now runs on every chart family: the YouTube daily-chart series plus every single-slot chart board with a clear leader (is_chart_slot_market: Netflix, Billboard, Spotify). The cheap pre-check is take_names_leader_only (the take names a leader by its whole phrase and no rival leg -> ship, no call). Everything else asks the existing Haiku claude.market_take_names_leader (purpose=market_take_check). No prompt change. take_references_leg stays for utils/youtube_grounding.take_names_a_leg. market_alert follow-up SHIPPED (#4239): the alert’s LEADER takes (lead change, confirmed ending-soon leader, swing on the leading leg) on every chart family now run the same two steps, fail closed; other takes on a YouTube daily-chart board keep take_names_a_leg. Dry run (2 runs, Haiku): 18 real alert takes from Axiom plus 15 inverted-overtake and 3 invented-song goldens. Old gate: 0 real drops, 14 of 15 inverted shipped. New gate: 1 real drop (a take that contradicted its own license), 0 to 1 of 15 inverted shipped, 0 invented shipped, 4 fast ships, 34 judged, 1 verdict flip across runs. No prompt change. Dry run (91 real takes, 2 runs per judged take): 55 fast ships, 21 judged, 2 decisions changed, 0 wrong ships, verdicts identical across runs, 42 calls for $0.0013. #4271 (2026-10-16): prompt left as is, measured. The prompt still says “If you are UNSURE, answer true”. Test set: 232 real chart takes from Axiom (market_drop_scored + market_alert, 30 days): 190 as posted and 42 with the leader swapped to a rival the take names. Two runs per arm. Old prompt: 0 verdicts moved between its two runs, 187/190 real passed, 2/42 swapped passed. Cut the UNSURE line: 3 to 7 moved vs old, 184-186/190, 1-2/42. Reword it to “answer false”: 3 to 7 moved, 185-186/190, 2-3/42. Cut only the stale last line: 2 to 3 moved, 187-188/190, 1-3/42. Every arm dropped 1 to 2 correct runner-up takes on both runs, and none stopped more swapped takes on both runs. The #4239 overtake goldens: 5/5 dropped on every arm. Also #4271: the chart_take_gate panel now counts the alert’s market_filtered drops, split by event. |
Model error: drop (fail closed). | |
| C5 (SHIPPED 2026-10-16, #3443) | utils/music_policy.py _IN_HOUSE_TAGS / in_house_genre, at cogs/music.py:_house_gate and cogs/music_news.py:_artist_new_release |
The exact allow list stays, and an on-list tag makes no call. An off-list tag goes to music_policy.judged_in_house_genre, which asks one cached Haiku label (claude.house_genre_check, purpose=house_genre, RAP / RNB / POP / NONE) with artist + title + tag. No call for a blank tag, a blank artist or title, or an owner-rejected tag (_NEVER_RESCUE: Indie Pop, K-Pop, Pop Latino, Pop/Rock). Dry run on 103 real off-list records (production drop history through iTunes, the 3 live off_genre refusals, 12 known hits): 3 Soundtrack-tagged classics rescued, 0 wrong accepts of 95 hand-labelled outs, 103 calls, 30.9k input + 0.5k output tokens. |
NONE or model error: refuse (today). | |
| C6 (SHIPPED 2026-10-16, #3444) | utils/chart_ages.py _matching_date (now _matching_pick), in resolve_week_ages (the oldest-songs board) and first_release_date (the RIAA plaques card) |
The containment match and the earliest-date pick stay. A pick whose folded title AND folded credit EQUAL the row makes no call. Any other pick goes to one cached Haiku SAME / DIFFERENT label (claude.classify, purpose=chart_age_check) that sees the group title, credit, primary type and first-release date. Measured on the live Hot 100 + Billboard 200 (top 40 each, 2026-10-16): 63 old picks, 61 exact (no call), 2 checked; the check refused Drake “Classic” dated 2015 off Bob Drake’s album. The debut gate (release_age, exact=True) passes no client and is unchanged. |
DIFFERENT: undated, cached as a miss. Model error: undated, nothing cached (retries next build). | |
| C7 (SHIPPED 2026-10-16, #3445) | cogs/music_releases.py _REISSUE_RE |
_REISSUE_RE stays the cheap yes. A title it passes that carries Deluxe / Edition / Version / Live / Expanded (_REISSUE_ASK_RE) goes to the cached Haiku claude.release_is_reissue (REISSUE / NEW, purpose=release_reissue), through MusicReleases._reissue_keys, at all three stat sites (the board’s first-night stat, the first-week card, the Songstats fill). Not release_version_kind: that check labels a re-recording and a new deluxe “edition” too, and both carry new plays. With no model client, the regex alone decides. Also #4230 item 3: the first-week roster now reads the release-version verdicts. Dry run, 58 real titles (46 asked), 2 runs: wrong-accepts 25 -> 2, wrong-omits 0 -> 4 to 6 (2026 records Haiku does not know). |
Model error: omit the stat. | |
| C8 | utils/output_checks.py has_career_claim, has_alltime_claim, ungrounded_career_ordinals, ungrounded_ranking_claims, has_cross_source_comparison, metric_foreign_word (+ N8, K5 from the 2026-10-15 refresh) |
Done for the two sites that drop posts (#3446). The regex stays the trigger. A flagged caption goes to ungrounded_flagged_ordinals (ordinal values, code) and then to Haiku claude.claim_grounded (a classify label, not qualifier_verify: that judge PICKS a qualifier from research; this one checks a written line against one source). Wired at the qualifier guard (_ranking_drop, 44 distinct drops in 30 days; since #2784 it also sends a fuzzy “alive” / “living” candidate from universal_scope_candidates to the Haiku label claude.universal_scope_claim, CLAIM or MOOD, claim_arbiter kind=scope; CLAIM or no verdict keeps the drop) and the bare-row career check when a career block exists (_drop_shaped, 3,484 drops in 30 days, all before #4083). The ranking regex also skips a duration (“its first month at 47.8K”). Not wired, measured 2026-10-16 over 30 days: has_alltime_claim (desk boards, cinema) 0 drops, ungrounded_career_ordinals (newsroom) 0, metric_foreign_word 0, has_cross_source_comparison 1, has_row_arithmetic (K5) 0, has_stream_unit_comparison 0. A judge there would only add false-ship risk. has_cross_source_comparison and metric_foreign_word also ask a different question (an owner ban, a metric name), not grounding. Revisit a site when its drops show on the panel. Re-measured 2026-10-18 for #4522 (30 days, Axiom), kept as regexes: has_alltime_claim 0 drops (music_desk board lanes, of 21,212 music_desk_scored rows; cinema_desk alltime_claim, of 46 rows), ungrounded_career_ordinals 0 (music_news career_ordinal, of 1,586 rows), has_cross_source_comparison 0 (music_desk and market_drop, of 21,212 and 1,377 rows), metric_foreign_word 0 (music_desk and music_alert, of 21,212 and 1,366 rows). The music_desk reason career_claim is shared: all 3,424 such rows have matchup chart or called_shot (_BARE_ROW_LANES), so they are has_ungrounded_career_claim (Haiku since #3446), not has_alltime_claim. Recall check: 1 of the 11,149 shipped music_desk / cinema_desk takes holds “ever”, “all-time”, “history” or “career” (a chart-lane career first, a different check). A model read here would add a call on every take to decide drops that do not happen. |
Model error: drop (kept). | |
| C9 (SHIPPED 2026-10-16, #3447) | utils/music_markets.py title_names_act |
The trigger is now title_act_hits: every watched act whose folded name is a whole-token run in the title, with no capitalisation rule. Each hit, in watchlist order (at most 3 a title), goes to one cached Haiku YES/NO (title_is_about_act through claude.classify, purpose=market_act_check, 7 days per act and title, in memory). The first YES is the act. judged_title_act replaces the old rule at the three artist-market call sites (listing, settle, and _artist_market_candidates for the move and leader lanes). A NO emits market_filtered reason=not_the_act; no verdict emits reason=act_check_failed and stops all checks for 10 minutes. The candidate list runs its checks 8 at a time. With no client, title_names_act (the old rule) still decides. Dry run 2026-10-16, 179 real titles (89 Kalshi + Polymarket act markets, 90 sport-filed Kalshi and Polymarket titles that name an act): wrong accepts 6 -> 0 (Derik / Patrick / Brenden Queen, three VP.Future esports titles); missed acts 9 -> 0 (two “Katseye” titles, seven “ |
Model error: skip (the market is not the act’s). | |
| C10 (SHIPPED 2026-10-16, #3448) | utils/music_news.py chart_cue_strength slate ordering, chart_reportable unnamed fallthrough, cert_reportable territory prose, _RUNG_CLAIM_RE / quotes_ladder_rung |
Slate: the cue order stays the shortlist and still drops a post with no cue. When it holds more than the 12 culture places, ONE Haiku call per slot (ClaudeClient.rank_music_news_slate, purpose=music_news_slate_rank) ranks its first 40 posts and returns indexes. mn.apply_slate_rank drops a bad index, caps one account at 3 places and fills the rest in cue order, so the model never adds a post and the classify budget stays 12. Replayed on 12 real slots (3 days of the 41 wires, 2 runs): real stories in the 12 places, cue order 118 of 144, Haiku 131 and 129 with the per-account cap (133 and 134 without it); 2 small-pool slots ranked below the cue order; about 3,450 input and 47 output tokens a call. unnamed: reads the classifier’s EXISTING chart_key (no prompt edit, so no drift): kept only when the key’s label maps to the kept Spotify daily family and “spotify” is in the text. 4 of 369 real chart stories changed, all “Spotify Global” / Spotify US wordings; Billboard keys on unnamed stories stay cut. Cert and rung: measured, not changed. 0 of 53 cert_out_of_scope cuts in 30 days were wrong. 0 of 41 real percentage claims were a missed rung, and every market story is re-read from the exchange on either branch. A new classifier field would move other outputs (#4212) for no measured gain. |
Model error: cues (the order on main). | |
| C11 (MEASURED 2026-10-16, no change, #3449) | utils/kworb.py find_video_match non-unique picks; utils/billboard.py find() with more than one match; utils/riaa.py _NOT_AN_ACT unresolved cells; utils/riaa_boards.py, utils/cinema_numbers.py _clean_news; cogs/discourse.py looks_like_sports; utils/retrospective.py frames_as_past |
No site changed. Each site was measured first, and none has an ambiguous case that is both frequent and wrong. Axiom covers the 30 days to 2026-10-16; RIAA was read from the prod riaa_tallies / riaa_year_feed caches. (1) kworb: 30 market_subject events with source=youtube_chart (unique), 0 with youtube_chart_pick. (2) BillboardClient.find() has no production caller (only tests/test_billboard.py). (3) RIAA: 2,931 rows (Diamond singles + albums + the 2026 feed), 731 cells own_credit names. One is filler: CAST OF HIGH SCHOOL MUSICAL, 1 Platinum single, which ranks on no board. A Haiku call per distinct cell (731 cold calls, cache in memory only) is not worth one cell. (4) _clean_news: the three news lanes produced 0 events; the cinema desk shipped 3 posts, all on 2026-09-19 and none from those lanes. (5) looks_like_sports: 1 discourse_icebreaker in 30 days, on a channel name that does not change. (6) frames_as_past: 0 retro_unframed drops on all four desks; the throwback takes that shipped state their frame (“35 years ago this week”, “in 2004”). Re-open a site only when its count above moves. |
Model error: today’s path (unchanged). | |
| C12 (SHIPPED 2026-10-16, #3450) | utils/wikidata.py _MUSIC_OCCUPATIONS / is_music_act unlisted classes; utils/artist_watch.py first_credit_party art-miss path, _PLACEHOLDER_CREDITS |
Measured first on 707 real chart credits (8 weeks of Billboard, 14 days of Spotify): 79 Deezer portrait misses. is_music_act rejected 2 Wikidata hits among them, both albums (right); _PLACEHOLDER_CREDITS matched 3 credits, all real placeholders. Neither gets a rescue: nothing to rescue, and a rescued placeholder is the worse error. The real miss side: 77 of the 79 were co-billings joined by “&”, “,” or “With”, which first_credit_party never splits. After the whole credit and the “+” retry miss, first_party_candidate cuts ONE name from the credit, and one cached Haiku YES/NO (artist_watch.haiku_first_party through claude.classify, purpose=credit_first_party) decides whether it is the full name of a music act. Code refuses a cut before an article (“Tyler, The Creator”: the real model said YES to “Tyler” on both golden runs) and a placeholder. The rescue keeps only an EXACT Deezer row (the whole name and _EXACT_MIN_FANS), because a YES on a fragment of one act’s name (“Sam” of “Sam & Dave”) reached a namesake whose name IS the fragment (“SAM”, 48.7K fans). It is still reported NON-exact, so the media gate also judges it. Dry run 2026-10-16 (real Haiku, real Deezer, 2 runs): portraits on the 79 misses 0 -> 46 on both runs, wrong rescues 0 (each YES read by hand), 1 Haiku flip with no portrait change, 72 calls a run (about 18.6k input, 0.3k output tokens). 22 YES answers get no portrait under the exact rule, mostly real acts under 50K fans (Carly Pearce, Aesop Rock, HARDY): absent, as before. Without the exact rule the count was 68. A first prompt with “or you are not sure” gave 55 to 57 YES and 16 flips. Goldens on the real model, both runs NO: Earth, Wind & Fire, Simon & Garfunkel, Hall & Oates, Pasek & Paul, Crosby, Stills & Nash, Brooks & Dunn, Big & Rich, Sam & Dave, Mumford & Sons, Helluva Boss, Original Broadway Cast Recording. |
Model error: absent. | |
| K2 (SHIPPED 2026-10-16, #4170) | utils/kworb.py _find_by_artist / find_chart_entry on an UNRANKED multi-act credit (the KworbClient.artist_standing, youtube_artist_standing, standings and resolve_chart_row callers) |
The strict matchers stay the hot path. A row that matched only a PART of an unranked multi-act credit (fragment_match) goes to one cached Haiku ONE / COLLAB label (claude.classify, purpose=kworb_act_check). COLLAB keeps the best-ranked part (the old rule); ONE gives no row. A first draft that asked Haiku to pick a candidate number answered NONE on real collabs and kept the namesake; the ONE / COLLAB question read 21 of 21 probe credits right. standings and resolve_chart_row now also pass the known ranked set (#2615). Dry run 2026-10-16 on live kworb (1,296 ranked acts, the 4 Spotify charts, the Apple albums chart; 577 requests): 31 multi-act credits, 12 Haiku calls, 1 pick changed (“Zezé Di Camargo & Luciano”: the rapper Luciano’s row to none), 0 wrong picks, about $0.002. Still on the old split rule: chart_history._credited, artist_priors, radio.standing (follow-up). Fast path added 2026-10-16 (#4277): a credit whose every part is a ranked act is COLLAB with no call. On 303 live credits that reach the check, it takes 168 (55%) off the model and fixes the one ONE flip (“George Michael & Wham!”, 1 of 2 runs); 0 verdicts get worse. No prompt edit: the other issue examples never reach the check. |
about 10 to 30 per day, cached 14 days per credit | Model error: no row (absent). |
| C13 (SHIPPED 2026-10-15, #4174) | utils/catalog_art.py screen_title_check (was screen_title_verified, #4118): the TMDB poster title check |
Folded-title equality stays the free accept. A bracketed request year (“Superman (2025)”) goes to TMDB’s year filter and must match TMDB’s year within one, so a same-title remake is refused with no call. On a title mismatch, a cached Haiku yes/no (claude.same_screen_work, purpose=screen_same_work) with both titles and both years. Dry run 2026-10-15: 45 real names, 37 accepted before and 41 after, 0 wrong accepts; 16 judge pairs, 13 right, the 3 misses all refusals. |
Model error: refuse (fail closed, as before). | |
| N1 (SHIPPED 2026-10-16, #4199) | utils/x_artist_tags.py _SCAN_SKIP, _inside_longer_name, _is_title_position (the scan that picks the public X @tag); K6, the utils/x_mentions.py scan_watched hit (“Queen”, #3567) |
The deterministic scan stays. x_artist_tags.scan_names now also scans the _SCAN_SKIP names, and sends every one-word or skip-list hit to a cached Haiku YES/NO (claude.is_music_artist_mention, purpose=x_artist_mention, through classify). A multi-word name, or a name the lane passed as its own artist (the newsroom story subject, which classify_x_post also reads), needs no call. In the mentions lane, x_mentions.confirm_scanned asks the same check for a one-word hit the mention classifier did not name. Dry run 2026-10-16 on 800 real @tootsiesbar posts (6 days): 579 scanned names before, 594 after; 0 removed; 15 added, all right (Ashe, Future as the artist); 168 Haiku calls, about $0.004 in total. Goldens on the real model: “Queen of the night”, “Queen behavior from Doechii”, “Future plans”, “Zendaya … Spider-Man premiere” all NO; “Drake dropped a surprise EP” and “Future’s Mask Off” YES. |
Model error: no tag (absent). Mentions: the check runs only when the mention classifier itself answered, so a Haiku outage keeps the lexical rule. | |
| N5 + K3 (SHIPPED 2026-10-16, #4202) | utils/music_news.py market_topic_overlap / pick_market_leg / restate_market_claim (N5); _fold / _artist_agrees / resolve_artist_count (K3, #3664) |
N5: code still scores the candidate events (market_leg_candidates); only a TIE (tied_market_legs) asks Haiku (pick_market_event, purpose market_event_pick, labels EVENT1..n + NONE over the tied events only). The restate keeps its own clause (the classifier fields carry no verb clause) but reads the odds or favourite phrase anywhere and drops the whole exchange tail: 8 of 59 real wire claims had read “according to Kalshi traders on Kalshi”. K3: the count still folds in code; artist_count_collisions finds same-title rows with different lead credits, and only those ask Haiku (same_record_listings, purpose count_same_record, YES/NO on the main artist). Dry run: 0 ties in 59 live market claims, 0 collisions over 321 acts on 5 live charts, so the steady-state volume is about 0 calls a day. Labelled sets: tie pick 0 wrong-accepts in 24, collision check 0 wrong in 28. |
No verdict: today’s rule (a tie drops the story; a collision folds to one record, an undercount). | |
| #4222 (SHIPPED 2026-10-16, no model) | utils/catalog_art.py cover_rung: the gate-exempt catalog_cover rung on a row whose COLLECTION belongs to another act |
Deterministic, no Haiku. cover_rung now also requires _collection_verified(row) (whole billed acts in either direction, no spelling ratio and no piece of a name): iTunes fills collectionArtistName only when the collection carries a different credit, so a filled credit that does not name the act (“Various Artists”, “Tom Howe”) reports catalog_cover_fuzzy and the vision judge decides. Replay 2026-10-16: of the 20 overruled flags, the 6 GTA VI covers move to the judge and the rest keep the rung (they are the song’s own album, an empty collection credit); of 93 judge-passed exempt rows, 2 move (the GTA VI row again, and a TV-soundtrack cut). No ambiguous band remains, so a Haiku call would add cost and no decisions. |
Absent collection credit: exempt as before (iTunes leaves it empty on the act’s own release). | |
| #4263 (SHIPPED 2026-10-16, no model, same PR) | utils/catalog_art.py cover_rung: a tagged REQUEST (Live, Acoustic, Remix, Taylor’s Version) verified the plain release |
Deterministic. The request’s recording tag (apple_music._edition_tagged) must be on the candidate too, else catalog_cover_fuzzy and the judge decides. Replay: 1 of 93 exempt requests carried a tag, and it resolves to its own tagged single, so it stays exempt. |
No tag on the request: unchanged. | |
| #4115 (2026-10-17, HYBRID) | utils/catalog_art.py _pick_artist_row / _row_title_matches: a bracketed release NAME on the request (“WEEZER (GOLD ALBUM)”) was dropped by _normalize_title, so another colour album or a remaster matched |
release_name_check keeps the exact cases in code: no bracket name on the request, or the candidate carries it, is “match”; a candidate with a DIFFERENT bracket name is “mismatch”, no call. Only a candidate with no bracket name of its own (“unsure”) asks Haiku (catalog_release_name, classify(), SAME / DIFFERENT, cached 30 days), at most 3 names per search page. No word list was added. Replay on the 54 bracket-named requests of 30 days (100 art + debut verdicts, live iTunes rows, 2 runs): 9 change, 7 better, 2 neither, 0 worse, 0 flips; about 1.3 calls a day. |
Model error or no judge: the old rule, so the name matches. The model can only refuse a name the fuzzy match took. The no-artist “several acts” guard reads the fuzzy matches first, so a refusal cannot leave one act’s row as a guess. | |
| #2016 (2026-10-16, new check, not an audit site) | utils/market_sibling_claims.py at market_alert._judge_and_ship and market_drop._compose: a market post against posts on OTHER Kalshi events about the same title |
Code picks the residue: same_subject_posts keeps the last 6h of market posts on another event (post_dedup_history.event_key) that share a quoted title or a “ |
Fail-OPEN (the claim gate’s direction): no event key, no sibling, a read error or no verdict ships the post. | |
| #3257 (2026-10-17, new check, not an audit site) | cogs/music_desk.py:_cut_flourish (every desk lane, through _detag_credit): a trailing clause that only judges the figure |
HAIKU from the start, with no word list (owner steer 2026-10-17: a filler-or-fact call is about meaning). output_checks.trailing_clause is structural only: it finds the last clause and skips one with a digit, because a cut must never remove a figure (that also covers a comma inside a name, “Tyler, The Creator”). Every such clause goes to the cached Haiku FACT / FLOURISH (claude.is_flourish_clause, purpose=flourish_check). FLOURISH cuts the clause; the post still ships. Measured 2026-10-17 on 30 days of shipped desk lines: 499 of 5,939 reach Haiku. Wording 1 cut 20 with 1 flip over 2 runs, and 2 of the cuts were trend facts (“a strong launch despite streaming cooling”, “a big opening even with her dailies cooling”). The shipped wording names a trend as a FACT with that example: 18 cut, all judgments, 0 flips, both trend clauses kept. A first version with a fact-word list in front (25 reach Haiku) was replaced on the steer; with no list, the split misread “Tyler, The Creator” and “Earth, Wind & Fire” as clauses until the digit rule went in. Coordinator review: a comma inside a closed quote span is not a break, and the task says a name or title cut at a comma is a FACT; 8 name-ending posts (“for Tyler, The Creator”, “Crosby, Stills & Nash”), 2 runs, FACT 16/16; on the 499, 18 cut as before, 1 flip. |
Model error: keep the clause (the rule before the check). | |
| #4350 (2026-10-17, new check, not an audit site) | cogs/music_releases.py _topic_verdict: the release board’s TEXT DEDUP drop (utils/dedup.duplicate_match, the shared spine gate) |
The text dedup stays the first pass and still decides every take it passes. A take it DROPS goes to the cached Haiku claude.release_take_adds_new (purpose=release_take_new, labels ADDS_NEW / SAME, through classify) with the recent posts, matched post first. ADDS_NEW ships it (the spine’s existing overturn path, dedup_overturned surface=music_releases); SAME keeps the drop. The board sets TOPIC_DEDUP = True and the new spine switch TOPIC_CATCH = False, so a take the text dedup passed is never asked about. Measured on every board and top-card drop 2026-10-02..17 (39 drops, real lines and real history): Haiku agreed with a hand label of “names an act no earlier post names” on 39 of 39, 0 run-to-run flips over 2 runs. Sequential replay of 2026-10-03..17: 4 dropped takes ship (DDG, Babyfxce E, Gucci Mane, Lucky Daye, each the first post to name that act), 0 real posts lost, 23 Haiku calls in 14 days (about $0.002). |
Model error or no verdict: the drop stands (today’s behavior). | |
| #3319 (2026-10-17, HYBRID) | utils/wikidata.py artist_portrait: the Wikidata portrait rung took the FIRST same-name music act with a photo (“Steve Lacy” -> the jazz musician Q504641 for the R&B singer’s card) |
wikidata.artist_portraits returns every same-name music act with a P18 photo (after the first act it reads only music-looking descriptions, inside _ARTIST_CLAIM_READS). One act: no call. Two or more: music_markets._pick_namesake asks Haiku (classify(), purpose wiki_namesake, ONE / TWO / THREE / UNCLEAR, cached 30 days) with the card credit, title and each Wikidata description. No word list. Measured 2026-10-17 on the 114 artist names the portrait rung saw in 30 days (Wikidata SPARQL with en and mul labels, then the live search order): 97 have a music act with a photo, 3 reach the call (Steve Lacy, Michael Jackson, Chris Brown). Haiku, 6 runs per case, 0 flips: Steve Lacy 3 of 3 contexts better (the R&B singer); Michael Jackson 3 of 3 unchanged; Chris Brown with a title unchanged, Chris Brown with NO title (an artist-only card) WORSE, UNCLEAR, so no photo where the old rule was right. A “current chart card” year line was measured and not shipped: it also turned Michael Jackson with no title to UNCLEAR. 2026-10-18: entity_image._credit_portrait_bytes (the newsroom and market art resolver) now calls the same rung under its Deezer candidates, so both ladders share this check (rung wiki_portrait, gated). |
about 0 per day: the Wikidata rung answered 0 cards in the 14 days to 2026-10-17 (it runs only when Deezer misses or, since #4134, is blurred) | Model error or no judge: the old first match. UNCLEAR: no photo (the card drops a rung). |
| #3259 (2026-10-18, new check, not an audit site) | utils/x_crosspost.py _media_gate on a found photo: the identity judge passed a right subject on the WRONG occasion (the Odell Beckham Jr. post of 2026-09-14, note “… during an ‘F2 vs Odell’ soccer trick shot video”) |
HAIKU from the start: a fuzzy occasion call, no rule to keep. _OCCASION_CHECKED_ART (found only, the owner’s 2026-10-15 decision) is the exact part. A passing identity verdict with a note goes to the cached Haiku DIFFERENT / SAME (claude.photo_occasion_mismatch, purpose=photo_occasion), which reads the vision judge’s own note, so no second vision call. Step 1 of the task makes a release / chart / tour-announcement / milestone post SAME whatever the photo shows (lenient, owner: “don’t be too strict”). A drop needs two agreeing votes (separate cache rows). Measured 2026-10-18: wording 1 put a chart post over a Super Bowl photo at DIFFERENT 2/5, so the post-type step went first; then 10/10 SAME, the Odell golden and two other wrong-occasion controls 10/10 DIFFERENT. Real data, 2 runs each: 150 shipped (take, note) pairs from 30 days, 1 single DIFFERENT per run on different items (2 flips), 0 two-vote drops; 82 real notes that name an event, 0 DIFFERENT, 0 flips. Exposure: 12 source=found verdicts in 30 days. |
Model error or a split vote: ship the photo (the rule before the check). | |
| #4522 pilot (2026-10-18, HAIKU, converted) | utils/qualifier_trim.py time_span, joins_as_only, states_most: the three shape gates that add the #4512 rules in claude.check_claim_qualifier |
Converted under the owner rule of 2026-10-18 (a regex keeps only an exact format). Code keeps the exact part: span_phrases lists the claim’s time phrases (the _SPAN_RE forms, titles blanked) and phrase_span computes their years. One cached Haiku read per claim (claude.qualifier_shape, purpose qualifier_shape, a JSON line on the classify cache and key) picks the ONE phrase that limits a qualifier and answers joins-as-only and maximum-“most”; the old patterns are in its task as examples. Two phrases give no span. Measured 2026-10-18 on 172 hand-labelled claims (the 33 harness claims, 63 detector probes, the 14 distinct qualifier_check matchups since 2026-10-17, 62 real newsroom claims of 30 days), 3 runs: all three gates right regex 138/172 (real claims 77/109), Jev 431/516 (300/327, 7 flips; it read every “biggest” as a “most”), Haiku 504/516 (324/327, 0 flips), p50 589 ms, p99 1174 ms, $0.15 per 1k. Haiku reads the 33 harness claims the same as the regex, so their judge prompts are unchanged (end to end on fresh research, real judge, n = 16 per claim: every one of the 528 judge prompts was byte-identical to main’s). About 30 calls a day (the judge’s own volume), cached a day per claim. Details: docs/PROMPT_OPTIMIZATION.md. |
Model error or an unreadable reply: the regex gates (the rule before). | |
| #4522 site 2 (2026-10-18, HAIKU, converted) | utils/qualifier_trim.py has_qualifier (the _QUALIFIER_RE word list and the _RANK_RE rankings): whether a claim pays for the qualifier research and the judge (qualifier_check.check_source_qualifier, the newsroom) |
Converted under the owner rule of 2026-10-18. The word list stays the fast path: qualifier_trim.qualifier_candidates lists the candidate words outside quoted titles, and a claim with none is False with no call. A claim with candidates gets one cached Haiku read (claude.claim_has_qualifier, a classify YES / NO, purpose qualifier_present) with the candidates in its input and the word list in its task. Measured 2026-10-18 on 1,000 distinct newsroom claims of 30 days (Axiom detail.claim): the word list fired on 168. Hand labels: 13 of the 168 hold no qualifier (“58-63k first week”, “Best Rap Album”, “from lead songs only”, “our most recent chart”), 25 are left out as unclear, and 3 of the 832 misses hold one. Plus 41 goldens (#4512, #4502, #4468, #4485) and 12 test cases. Per arm (3 runs): word list 130/143 on labelled hits, 0 false hits dropped; Jev (TypeSafe.ask, one Noul) 412/429, 22 of 39 false-hit reads dropped, 0 true qualifiers lost, 1 flip, p50 793 ms; Haiku (shipped wording, 6 runs) 850/858, 70 of 78 false-hit reads dropped, 0 of 1,092 true-qualifier reads lost, goldens 246/246, 2 flips, p50 about 560 ms, p99 about 2 s. Cost: at most about $0.55 per 1k reads (no prompt cache); about 36 reads a day (the judge’s own volume), so under $0.02 a day. Rejected, measured: a model on EVERY claim. With “none listed” as the candidates it found the 3 misses but read 504 of 894 misses wrong (plain chart figures sent to the judge), 61 flips. Details: docs/PROMPT_OPTIMIZATION.md. |
No verdict (an error, an answer outside YES / NO): True, the word list’s answer, so the judge runs (the rule before). | |
| #4522 site 3 (2026-10-18, MEASURED, regex kept) | utils/qualifier_trim.py _RANK_RE / _RANK_ORDINAL and the release noun / verb lists (#4471): _rank_matches, “does the claim rank its subject among other acts by the order they reached a feat?” It gates the ranking candidate, the #4485 ordinal rule in check_claim_qualifier, and the is_cut ranking spans |
Kept as code, measured. 6,534 tweets of 30 days from the 14 wire accounts #4471 measured; 1,262 hold an ordinal; the regex fires on 33. Set: the 293 tweets with an ordinal before “to” / “with” (hand labels: 35 yes, 258 no), plus 19 goldens (the #4485 ordinals and the _RANK_RE test shapes). Per arm: regex 289/293 (3 rankings missed: “the second Spanish-language song from the 1980s to reach”, “the second youngest player in WNBA history to win”, “the 4th ever among all artists”; 1 false fire: “the 16th Take Care track to pass”, an album’s own tracks), goldens 19/19. Haiku (classify-shaped YES / NO, the regex’s lead words, time units, release nouns and verbs in the task as examples) 814/879 over 3 runs, 61 counts read as rankings, 12 flips, p50 458 ms; a second wording that named the possessive count explicitly did not help (812/879 before the label fix). Jev (one Noul) 820/879, 56 counts read as rankings, 5 flips, p50 794 ms. Both models read a claim with a catalog count (“her 7th song to reach this mark”) or a tally standing (“the 3rd-highest tally among female rappers”) as a ranking. A false YES adds the #4485 rule to a claim that is not a ranking, which #4485 measured to change how the judge reads “first” claims. Re-measure when a better model ships. The list-position shape (“the 5th most-streamed album of 2016”, over 100 tweets) is not this rule’s shape and stays unmatched on purpose. Data: scripts/data/qualifier_rank_cases.json; harness: scripts/dryrun_qualifier_research.py --rank. |
Not converted, so no fallback. | |
| #4522 site 4 (2026-10-18, MEASURED, code kept) | utils/qualifier_trim.py leaves_dangling (with _DETERMINERS, _COPULAS) and the _INTENSIFIERS rule in is_cut (#4484, #4461, #4477): does a judge cut leave a broken phrase (“is his song to hit No. 1”), and does it remove only “ever” / “in history” / “of all time” while keeping the superlative they intensify? |
Kept as code, measured. Real traffic first: in 30 days, 2 cuts reached is_cut across every lane (pop_desk “for the first time”, music_desk “highest ever”); neither was an intensifier-only cut, and leaves_dangling (the music drop lane only) got no cut at all (0 broken_cut drops). So the set is the 28 cut cases in tests/test_qualifier_trim.py, which are real judge cuts from the #4452 / #4465 / #4477 dry runs and review cases (20 dangle: 8 broken, 12 fine; 8 intensifier: 3 blocked, 5 fine). Per arm: code 28/28 (these are its own tests). Haiku (YES / NO, the shapes as examples) 75/84 over 3 runs, 0 flips; it passed the real broken judge cut “‘Housewife’ is the track by Tate McRae to reach No. 1” in all 3 runs. Jev 74/84, 4 flips; it passed “Tate Is The Artist To Top The Chart”. Both flagged “the song to the top” as broken. A model miss ships a broken or still-false cut with no compose after it, the costly direction. With no production input and both models worse on the cases there are, a call would add latency to the cut path and buy nothing. Re-measure when cuts show up on the qualifier_check panel. Data: scripts/data/qualifier_cut_cases.json; harness: scripts/dryrun_qualifier_research.py --cuts. |
Not converted, so no fallback. | |
| #4522 site 5 (2026-10-18, MEASURED, regex kept) | utils/cinema_numbers.py tracking_items: the result-verb and projection lists (_RESULT_VERB, _RESULT_PAST_OPEN, _PROJECTION, the verb half of _TRK_PROSE) and the exact title match (_same_film) that decide whether a tracking pull is for an opened weekend (#4513) |
Kept as the rule: neither model beat it on real traffic. Traffic: about 22 tracking pulls a day since 2026-10-18 (pplx_cinema_desk 67 on 2026-10-18, 3 per sweep); every pull is a decision. Set: 36 real pulls of the production tracking_query made 2026-10-18 for 6 Fridays, 22 after dedup (tests/fixtures/cinema_tracking_pulls.json, hand labels per pull and per headline), run with the lane’s opened titles (production) and without them (a film open but not yet on the chart or TMDB); the 70 real SOURCES headlines as (film, headline) pairs; 54 probes (the 41 test_cinema_desk_tracking.py cases, the coordinator’s 10 #4513 cases among them, and 13 from real headline wording). Both model arms get the same films (_line_films, the pipe-form title) and answer the same evidence questions (a line, a headline or an opened title shows this film’s result). 3 runs (scripts/dryrun_cinema_desk_score.py --read 3): regex lane 22/22, bare 20/22, pairs 527/543, probes 46/54, 0 flips; Haiku (classify spine, one JSON call per pull, wording 4) lane 66/66 (130/132 over 6 runs), bare 62/66, pairs 1583/1629, probes 153/162, 1 flip, p50 607 ms, p99 2893 ms, $0.51 per 1k; Jev (TypeSafe.ask, one Noul per question) lane 63/66, bare 63/66, pairs 1614/1629, probes 157/162, 3 flips, 27 of 294 calls failed, p50 759 ms, p99 981 ms, $0.28 per 1k. The regex misses real result wording (“Rings Up No. 1 $51M+ WW Opening”, “Tanks With $5.5 Million Opening”, “Opens Small”, “Pulls Off a Box Office Shocker”), but in production the opened-title check catches every such pull (22/22). Each model adds false skips on real pulls, and a false skip loses a real post: Haiku read “‘Clayface’ Box Office Tracking Points to a Profitable Debut” and “Clayface Box Office Outlook Gets a Major Boost” as results (a Clayface pull skipped in 2 of 6 runs, another every bare run) and “Scream 7 Opens to $40M” as Scream’s result; Jev read “The Cat in the Hat | $40 million+ opening” (the only Nov 6 tracking film) as a result in every run. Re-measure with --read when the pulls change shape or a missed result ships (a cinema_desk_scored phase=tracking post for a film already open). Details: docs/PROMPT_OPTIMIZATION.md. |
Unchanged: the regex reading decides. | |
| #4522 close-out (2026-10-18, final verdicts) | The last 22 OWNED-PENDING #4412 lines in tests/classifier_registry.txt: 20 in utils/output_checks.py (old C8), qualifier_trim._FILLER, cinema_numbers._NOT_A_TITLE |
Every line has a final verdict, and #4412 left _PENDING_OWNERS. CLOSED-SET (13): the number and ordinal parsers _NUMBER_RE, _WORD_RE, _WORD_VALUES, _MAGNITUDES, _ORDINAL_RE, _ORDINAL_WORDS, _FLAGGED_ORDINAL_RE, _DURATION_AFTER_RE, _TALLY_WORDS, _ROW_TALLY_RE, plus _STANDING_RANK_BEFORE_RE, _STANDING_SCOPE_RE (two exact phrases) and _RANKING_NOUN_SYNONYMS (five song nouns). MODEL-DONE purpose=claim_grounded (3): _RANKING_CLAIM_RE, _RANKING_STOP, _POSSESSIVE_CLAIM_RE; they are the triggers whose flagged captions Haiku reads since #4237 (merged 2026-10-16). Axiom, 30 days: 52 qualifier ungrounded_ranking drops and 3,422 career_claim drops, all before #4237; 0 drops and 0 claim_arbiter events since. MEASURED-KEEP (6): _ALLTIME_CLAIM_RE (#4574: has_alltime_claim 0 drops; recount: 0 of the 3,422 career_claim drop previews match it, 3,419 are possessive entry ordinals), _CAREER_ORDINAL_RE (#4574: 0 of 1,586), _AGE_CLAIM_RE / _AGE_GROUNDED_RE (measured here: ungrounded_age 0 drops of 21,257 music_desk_scored and 1,376 music_alert_scored rows; 0 of 12,435 shipped post_preview texts hold an age phrase), _FILLER (#4585: 2 cuts reached is_cut in 30 days; its model read did not cover this list), _NOT_A_TITLE (#4573: 0 of 22 real pulls are prose; 0 fires on their 55 answer lines). |
Unchanged. |
These are bugs the audit found in KEEP sites. Each is a small code fix.
| site | fix |
|---|---|
utils/billboard.py _lead_credit + _history_slug |
“Earth, Wind & Fire” folds to “Earth”, so a solo act “Earth” can take EWF’s slug. Require a full party via artist_watch.credit_parties. |
cogs/cinema_desk.py budget lookup + utils/tmdb.py search_movie |
The first TMDB hit is used unverified. Pass the year and check title_matches, the guard omdb.by_title already has (the Moana incident). |
utils/api_sports.py _team_logo_from_rows |
“First row with a logo” ships a guessed crest. Return None on no exact match. |
utils/radio.py standing |
A second substring matcher beside the house identity (song_key / fold_tokens). Wire the home in. |
utils/riaa_boards.py _BRACKET_RE |
Drops “(Taylor’s Version)”. Allowlist identity-bearing parentheticals. DONE (#3455): _IDENTITY_BRACKET_RE + _bare_title keep “‘s Version”, remix/mix, live, acoustic, part, interlude, reprise, intro, outro; a feature, soundtrack or edition bracket is still dropped. |
utils/kworb.py find_chart_entry loose mode |
‘Future’ matches ‘Future Islands’. Callers stay on strict. Fixed (#3456): strict=True is now the default for find_chart_entry and standings(), so the four callers that took the loose default (radio-entry lane, /ask, the release lane, resolve_chart_row) run strict with no call-site edit. With a title, strict also accepts the request’s LEAD credit, because the radio chart lists more acts than Spotify (“KAROL G, Judeline & rusowsky” vs “KAROL G”). |
utils/markets.py detect_league direct use in sgo_snapshots |
Confirm every direct call sits behind the Haiku rung; else a “cowboys” query defaults to NBA (FIXED #3457). |
utils/kalshi_ladder.py companion pairing |
A Kalshi title-template change breaks the pairing silently. Add an event. DONE (#3458): companion_pair on every pairing (paired | tie | no_events | unparsed | no_partner, kalshi_ladder.companion_pair_reason); panel companion_pair (Markets board); ops-monitor finding kalshi_companion_template on unparsed only (60% over 5 or more pairings; no_events and no_partner are normal states). Live 30 days before the change: about 24 lone-leg attempts a day, 77 of 728 fell to the rank rung or dropped with no reason recorded. |
utils/chart_ages.py resolve_week_ages on an album chart (#4235) |
The album row matched its own title-track SINGLE and took the single’s earlier date. DONE (#4235): _matching_pick(album=True) keeps only Album groups (compilation and live albums stay, remix / DJ-mix / demo drop); album rows cache under album:<song_key>. Live Billboard 200, 2026-10-17: 28 of 200 rows change date, 8 change year (“One Thing At A Time” 2022 -> 2023, “Diamonds” 1974 -> 2017), 0 lose a date. No model call added. |
cogs/music_desk.py _plaque_facts on an ALBUM award (#4281) |
The RIAA plaques card read first_release_date with no album rule, so an album award took its title-track single’s date. DONE (#4281): first_release_date(album=True) reuses #4235’s _matching_pick(album=True); the in-process memo keys it album:. 189 real RIAA album awards, 2026-10-16, Haiku check on: 19 rows change, 7 change year (“Sweet Boy” 2023 -> 2024, “Thank U, Next” 2018 -> 2019), 3 undated rows gain the album date, 0 lose a date. No model call added. |
utils/chart_records.py _lead_act (#4265) |
Its own credit split keyed “Earth, Wind & Fire” as “earth”. DONE (#4265): the key is artist_watch.first_party over the ledger’s solo credits (_credit_corroboration_set). Live 2026 ledgers (Hot 100, Billboard 200, Global 200): every row and every board signature is unchanged; the two real merges (“Dracula”, “I Can’t Love You Anymore”) stay. Residual: a solo act named exactly like a band’s first fragment, with the same title in the same year, still merges. |
utils/music_markets.py resolve_art_url + cogs/music_desk.py _fetch_art (the Deezer portrait) |
DONE (#4134, 2026-10-17): both call catalog_art.portrait_blurred, the ONE sharpness floor entity_image already used (#2716). A blurred face falls to the next rung. Exact signal, no model. On the 23 ungated portrait picks of 14 days (19 distinct acts, live Deezer photos scored), 1 changes: DRAKE (0.0033) on 2026-10-12, now Drake’s Commons photo; 22 unchanged; 0 worse. |
utils/music_markets.py pick_album_art_row (the market row title match) |
DONE (#4349, 2026-10-17): a row whose title names a DIFFERENT bracket release (catalog_art.release_name_check == “mismatch”) is refused, so “Weezer (Green Album)” no longer covers “Weezer (Gold Album)”. Exact, no call; an “unsure” row keeps the old rule here. Replay 2026-10-17 on live iTunes rows: of the 55 real queries of 30 days whose bracket names a release, 34 could be replayed (21 had no rows, or no act name to split off). 68 album and song picks, 0 changed, 0 worse. It closes the Weezer case and changes nothing today. |
Checked and kept deterministic, with the reason:
db.bookie_bet_outcome, cogs/bookie.py _winning_team, every api_sports status set, every price threshold. A model must not decide a payout._MEMORY_FENCE, output_checks.memory_note_violations, roles.SAFE_PERMISSIONS, healthcheck._is_read_only, names / aliases (privacy). Never a model.ungrounded_numbers, ungrounded_row_tally, _AGE_CLAIM_RE, retrospective_values, strip_position_claims. The regex counts better than a model.is_empty_response, every _parse_* closed-set validator, track: / xpost: tags, <voice> / <gif> / <image> tags. They validate a model answer; the classification is already the model.x_reply_draft._TICS (naming the phrase works; showing drafts made tics worse, 9/35 to 19/36), slop_score (the independent lexicon signal is the point), /ask grounding pre-classifiers (tried and removed, see claude_client.py near classify_mention_intent), catalog_art.ad_banner_reject (docstring rejects a vision judge, measured).engagement.py (300k-message scan; the question / laugh / caps shape rules stay, and since #4318 an optional Jev labeling pass writes labeled counts beside them, see the rows below), games._grade_guess (every chat message during a round; the EASY near-miss band already escalates to judge_song_guess), versuz.is_play_command (per voice-chat message). Revised by #4311 for _grade_guess: the HARD containment win awarded ordinary chat (“my bad” won Bad). A model now judges the title on Jev (about 110 ms), not Haiku, whenever TYPESAFE_API_KEY is set; see the _grade_guess row below.market_art.norm_name (wrong politician), steam_art.pick_app (Uno), espn.match_team_logo (ambiguity refuses), deezer._credit_matches_contributors (media-gate exemption), _artist_named_in_strict (#2691), _IDENTITY_VERIFIED_ART.radio.COVERED_FORMATS, artist_socials._ARTIST_SOCIALS, music_news._TRUSTED, riaa._CURATED_OMITTED_CREDITS, music_policy allow list (fast path).utils/dedup.arbitrated_match + topic_duplicate, cogs/x_mentions._resolve_subject, chart_boards album-track recovery + match_album_tracks, watch_link rung above the Haiku pickers, sports_desk._resolve_unknown_sports.Seven read-only passes, one per partition. Each pass read every file in its partition as it stands at origin/main 4e1b6c0 (the qualifier files at fba1952). Each report has its counts, its per-file inventory (the old verdict and the new verdict for every semantic site, with structural sites in one line per file), the Axiom measurements behind its verdicts, and notes. Each report’s own batch proposals are merged into the Part 0 batch plan, whose “from” column names them (P1-B3, P2-A, …). The stable reference is the symbol name, not a line number.
Audit wave 19, 2026-10-18, against origin/main 4e1b6c0. Read-only. Old section:
docs/CLASSIFIER_AUDIT.md lines 372-688 (audit date 2026-09-18).
Abbreviations in the tables: KC = KEEP-CLOSED, MH = MODEL-HAIKU, MJ = MODEL-JEV, KP = KEEP-PROTECTED. “fold” = add a field or a rule to a model call that already runs (zero added calls). “NEW” = the site is not named anywhere in the old audit file (added after 2026-09-18, or missed by the old pass).
Semantic sites only. A row in the inventory is one site (a symbol, or a group of symbols that make ONE decision together).
| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| utils/music_news.py | 62 | ~30 | 22 | 22 | 2 | 0 | 11 | 5 |
| cogs/music_news.py | 11 | ~12 | 4 | 2 | 0 | 0 | 3 | 2 |
| utils/artist_watch.py | 9 | ~6 | 5 | 0 | 0 | 0 | 2 | 2 |
| utils/apple_music.py | 13 | ~5 | 6 | 6 | 0 | 0 | 1 | 0 |
| utils/deezer.py | 5 | ~4 | 2 | 1 | 0 | 0 | 2 | 0 |
| utils/chart_credits.py | 2 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| utils/catalog_art.py | 5 | ~8 | 2 | 0 | 0 | 0 | 3 | 0 |
| utils/names.py + utils/aliases.py | 3 | ~4 | 1 | 0 | 0 | 2 | 0 | 0 |
| utils/song_pool.py | 1 | ~3 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/hits.py | 2 | ~8 | 1 | 1 | 0 | 0 | 0 | 0 |
| utils/music_markets.py | 8 | ~7 | 3 | 2 | 0 | 0 | 3 | 0 |
| utils/release_type.py | 4 | ~4 | 2 | 1 | 0 | 0 | 1 | 0 |
| utils/release_board.py | 1 | ~2 | 1 | 0 | 0 | 0 | 0 | 0 |
| cogs/music_desk.py | 5 | ~25 | 4 | 1 | 0 | 0 | 0 | 0 |
| cogs/music_alert.py | 1 | ~8 | 1 | 0 | 0 | 0 | 0 | 0 |
| cogs/music.py, cogs/pop_desk.py | 0 | ~4 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/genius.py | 2 | ~2 | 0 | 2 | 0 | 0 | 0 | 0 |
| utils/musicbrainz.py | 2 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| utils/banger_lane.py | 2 | 1 | 0 | 1 | 0 | 0 | 1 | 0 |
| utils/ktt2.py + utils/ktt2_chatter.py | 2 | ~4 | 1 | 1 | 0 | 0 | 0 | 0 |
| utils/pop_stories.py | 1 | ~4 | 0 | 1 | 0 | 0 | 0 | 0 |
| utils/versuz.py | 4 | ~10 | 3 | 1 | 0 | 0 | 0 | 0 |
| utils/versuz_catalog.py, utils/versuz_card.py | 1 | 2 | 1 | 0 | 0 | 0 | 0 | 0 |
| cogs/versuz.py | 2 | ~5 | 2 | 0 | 0 | 0 | 0 | 0 |
| utils/milestone_qualifier.py | 5 | 1 | 2 | 3 | 0 | 0 | 0 | 0 |
| utils/catalog_stats.py | 2 | ~3 | 1 | 1 | 0 | 0 | 0 | 0 |
| utils/milestones.py, utils/stream_totals.py | 1 | ~4 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/feeds.py | 1 | ~6 | 0 | 1 | 0 | 0 | 0 | 0 |
| utils/artist_caption.py | 1 | ~4 | 1 | 0 | 0 | 0 | 0 | 0 |
| section H structural files (see below) | 0 | ~25 | 0 | 0 | 0 | 0 | 0 | 0 |
| total | 158 | ~225 | 70 | 48 | 2 | 2 | 27 | 9 |
Verdict changes against the old section: 48 MODEL-HAIKU and 2 MODEL-JEV. Of these 50, 16 were KEEP under the old rule (“hot path”, “behind a judge”, “identity”, “tiny list”), 16 are new or were missed by the old pass, and 18 were HYBRID / HAIKU items that a wave shipped only in part or measured and left as a regex. 27 sites are DONE: a shipped wave (A2-A17, B12, C2-C13, K3, N5, #4115, #3319) already puts a model on the decision.
Model nearby for every row: classify_music_news (Haiku, 361 calls/day), verify_music_claim
(Haiku, 117/day), music_desk_score (Haiku, 381/day), rank_music_news_slate (Haiku, about
2-3/day). Volumes below are 7-day Axiom counts divided by 7.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_TRUSTED, may_relay_number, is_trusted |
handle registry | wire handle | may an unverified number ship | KEEP | KC | our own registry | 0 | - | |
_NUMBER_CUES, looks_like_numbers_story (+ authority_watch_candidates) |
120 substrings | every polled wire post | admission to the paid classifier; a miss means no model ever reads the post | KEEP (it is the prefilter) | MJ (B1) | Jev Noul “this post reports a music number about an act” on each post the cues DROP; cue list + 4 real non-stories (Gaza funeral, Gen Z stat, “A$AP” $, film gross) in the state. Cue hit admits free, as today |
400-1,500 (code: 46 handles x 20 posts x ~22 slots, cached per post id) | Jev error: old rule (drop) | |
_CHART_CUES, chart_cue_strength, strength_buckets |
70 substrings, count | culture-tier post | ORDER is DONE (C10). A post with strength 0 is DROPPED before the slate rank sees it | HYBRID (C10 shipped for order) | MJ (B1) for the drop branch | same Jev question; a zero-strength post with P>=0.5 joins the bottom bucket, so the Haiku slate rank decides its place | same batch | Jev error: drop (today) | |
apply_slate_rank + cog _rank_culture |
index validation | Haiku slate order | which 12 culture posts classify | HYBRID | DONE | C10 | 2-3 | cue order | |
KEPT_PATTERNS, CUT_PATTERNS, chart_family, chart_reportable |
20 kept + 19 cut chart-name regexes, deny first | wire text + claim | may the newsroom report this chart story (fail closed, unnamed cut) |
HYBRID (C10 rescued Spotify only) | MH (B3) | one Haiku JSON read per chart story: family from the closed label set KEPT + CUT family names + OTHER + NONE (the two pattern tables fed as the label list with the owner notes); regex stays the veto when it names a CUT family |
~51 (music_news_chart_lookup 357/7d) | model error: regex (fail closed) | |
chart_key_family, _CHART_KEY_EVIDENCE |
key -> family | classifier chart_key |
rescue of unnamed Spotify stories |
- | DONE | C10 | 0 | - | NEW |
career facts: entry_ordinal_fact, peak_history_fact, chart_run_fact, chart_streak_fact, is_latest_entry, history_debut_confirmed, projected_entry_fact |
_fold exact |
Billboard page rows | grounded career clause | KEEP | KC | exact folded join | 0 | absent | |
corrected_name (_SPELLING_MIN_RATIO) |
SequenceMatcher 0.85 | wire vs model name | accept a spelling fix | KEEP | OWNED:W19-C1 | ||||
wire_spelling, _POSSESSIVES, _wire_words |
n-gram + ratio | artist vs wire | re-spell the artist | HYBRID | OWNED:W19-C1 | ||||
named_by_mention, artist_grounded_in_wire, grounded_subject, corrected_subject_from_wire |
whole-word grounding | artist vs wire | drop artist to bare title | HYBRID | OWNED:W19-C1 | ||||
title_grounded_in_wire, _TITLE_FILLER, _TITLE_TAIL_RE, _CONTRACTION_SUBJECTS |
token subset | title vs wire | title_ungrounded drop (177/30d) |
A17 | OWNED:W19-C1 | ||||
ungrounded_quoted_titles, _QUOTED_TITLE_RE |
quoted titles vs source | composed take | drop a take naming an unsourced title | - | OWNED:W19-C1 (same matcher) | NEW | |||
_RUNG_CLAIM_RE, quotes_ladder_rung |
% + 20 threshold verbs + number | classifier claim | ladder re-read vs leg re-read | HAIKU, then C10 measured 0/41 missed | MH (B2 fold) | add market_is_rung: bool to the market kind of classify_music_news; verb list goes in the prompt as examples |
0 | no field or error: regex | |
novelty_is_distribution, _RANGE_FIGURE_RE |
range shape, % count >= 3 |
figure + claim | drop a distribution novelty | KEEP | KC | number shape | 0 | drop | |
_RANK_WORDS, figure_is_rank_word |
30 superlative words | figure string | the card hero is dropped | KEEP | MH (B2 fold) | add figure_kind: count / rank / state to the classifier; word list in the prompt |
0 | error: list | |
collapse_rank_run, _RANK_LIST_RE, _RANK_RANGE_RE, top_block_rung, position_grounded, lead_figure, split_figure_block, _DURATION_BLOCK_FIGURE_RE |
position / number formats | figure | hero formatting | KEEP | KC | number format | 0 | as given | |
split_figure_unit, _FIGURE_UNITS, _MAGNITUDE_UNIT_FIGURE_RE |
16 unit nouns after a magnitude | figure | hero vs pill split | - | KC | our card unit vocabulary, display only, number anchored | 0 | as given | NEW |
figure_unit_phrase, _UNIT_PHRASE_STOP |
stopword cut after a number | claim | pill words (“YouTube subscribers”) | - | MH (B2 fold) | classifier returns figure_unit words, bounded to words in the claim |
0 | error: stopword cut | NEW |
figure_is_passed_threshold, _THRESHOLD_CUE_RE, _PLUS_FIGURE_RE, _DURATION_WORDS |
passing verbs before a number | wire text + figure | swap the wire rung for the research count | HYBRID (A4 shipped field) | MH (B2) | code reads vthreshold OR regex (cog _verify), so the regex alone still swaps when the judge said false. Trust threshold_passed; regex only on a judge error |
0 | error: regex | |
count_past_threshold, _FIGURE_SEGMENT_SEP_RE |
number > rung, unit words | judge figure | which researched count | KEEP | KC | number check on model output | 0 | ”” | |
market_claim_parts, _MARKET_ODDS_LEAD_RE, _MARKET_VENUE_TAIL_RE, _PROBABILITY_FIGURE_RE, is_probability_figure, probability_pct, market_venue |
percent format, two venue names | claim / figure | odds + venue slots | HYBRID (A5) | KC | fixed format: a percent and the closed venue set {Kalshi, Polymarket} | 0 | field fills a gap | |
market_deadline_phrase (_MARKET_DEADLINE_RE), market_award (_MARKET_AWARD_RE, _MARKET_AWARD_PARTICLES) |
preposition / win-verb tails | claim | caption window, award headline | HYBRID | DONE | A5 field first, bounded to the clause; regex only when the field is empty | 0 | blank caption | |
market_caption (_DANGLING_TAIL_WORDS), title_case_headline, sentence_case, _TITLE_SMALL_WORDS |
display casing / trim | caption text | display only | KEEP | KC | formatting | 0 | - | |
dedup keys: _CERT_CONJ_RE, _release_identity, _ARTIST_FEATURE_RE, _lead_party, _TITLE_FEATURE_RE, _cert_release_identity, cert_story_keys, milestone_story_key, chart_debut_story_key, chart_position_key |
credit syntax fold | subject + model ids | permanent dedup keys | KEEP | KC | exact folded keys | 0 | visible dup | |
_LATIN_PROGRAM_RE |
latin / oro / platino / diamante | claim | suppress units clause | KEEP | KC | RIAA Latin award names (fixed vocabulary) | 0 | - | |
cert_count_unstated (_UNCOUNTED_MULTI_RE), cert_batch_count (_BATCH_FIGURE_RE) |
exact figure shapes | figure | RIAA lookup / batch board | - | KC | fixed format | 0 | - | NEW |
cert_claim_format, _CERT_ALBUM_RE, _CERT_SINGLE_RE |
album/lp/ep/mixtape vs single/song/track | claim | RIAA format cell | A13: NOT added | MH (B2 fold) | cert_format: ALBUM / SINGLE / NONE; Haiku can use world knowledge of the title, which the regex cannot |
0 | error: regex | |
cert_reportable empty-body branch (_OUT_OF_SCOPE_CERT_PROSE_RE, _IN_SCOPE_CERT_PROSE_RE) |
17 bodies + 33 countries | claim + post + source | drop a non-US/UK cert (fail closed) | HYBRID; A13/C10: not changed | MH (B2 fold), lowest priority | widen cert_id body to any authority string + territory field; country list in the prompt. Measured 31 of 52 cuts in 30d took this branch, 31 of 31 right |
0 | error: regex (fail closed) | |
cert_prose_names_other_body, cert_prose_is_riaa (_US_CERT_PROSE_RE, _UK_CERT_PROSE_RE, _FOREIGN_CERT_MODIFIER_RE) |
27 demonyms + body names | cert prose | veto the RIAA level lookup | - | MH (B2 fold, same field) | same territory field |
0 | veto | NEW |
claim_platform, _CLAIM_PLATFORM_RE, milestone_platform, milestone_metric |
18 platform proper names; model id parse | claim / model id | block label | A13 kept | KC | closed set of platform names; model-id parse | 0 | ”” | |
threshold_metric, _THRESHOLD_METRIC_RE |
verb + number + metric words | claim | Polymarket metric + deadline | - | MH (B4) | returned by the B4 Polymarket pick call (metric, deadline), bounded to claim words |
in B4 | error: regex | NEW |
poly_event_matches |
artist substring + head noun in title | Polymarket titles | which event re-reads a wire rung | - | MH (B4) | Haiku pick EVENT1..n / NONE over the searched events (the existing pick_market_event shape) |
~0.5 | error: substring rule | NEW |
market_leg_candidates, _topic_tokens, _MARKET_TOPIC_STOP, _event_conflicts, _MARKET_ROLES, _NARROW_ROLES, _MARKET_ALIASES, _PROPER_WORD_RE, pick_market_leg |
token overlap >= 2, role stems, synonym table | Kalshi events vs claim | which live market answers a wire claim | HYBRID; N5 shipped TIES only | MH (B4) | send every non-empty candidate set (not only a tie) to pick_market_event; overlap stays the shortlist order |
~1 (ladder_rung 13 + live_leg 10 + market_unread 6 in 30d) | no pick: drop (absent) | |
restate_market_claim, _RESTATE_LEAD_RE, _RESTATE_NOT_ODDS_RE, _RESTATE_*_TAIL_RE, 18-verb lead list |
phrase surgery | claim | the restated market line | N5 kept | MH (B4) | build the clause from the classifier’s existing market_outcome field (A5), bounded to claim words |
0 | error: regex | |
claims_debut, claims_reentry, _DEBUT_RE, _REENTRY_RE, _DEBUT_BOUND_RE, _REENTRY_BOUND_RE, chart_event_of |
debut / re-entry verbs | claim + wire | debut key, repost gate | SHIPPED A6 | DONE | classifier chart_event first, regex bounds it |
0 | regex | |
names_edition, _EDITION_WORD_RE, chart_story_is_same_record |
9 edition words | claim + post | keep the era guard on a chart card (#4131) | - | MH (B3) | edition: bool in the B3 chart-story read; word list as examples |
in B3 | error: regex | NEW |
named_chart_label, _APPLE_SONGS_RE, _APPLE_ALBUMS_RE |
songs vs albums nouns | claim | Apple chart label | HYBRID | DONE | chart_key read first in unsettled_chart_label |
0 | regex | |
names_projection, _PROJECTION_CUES, _forecast_near_chart, _FORECAST_WORDING_RE |
forecast phrases | claim / wire | projection, no chart label | HYBRID | DONE | A2 is_projection first; cues only when the flag is absent |
0 | regex | |
post_states_forecast: _STRICT_FORECAST_RE, _SETTLED_CHART_VERB_RE, _HEADLINE_INFINITIVE_RE, _FACT_INFINITIVE_RE, _INFINITIVE_LEAD_RE, _CLAUSE_SPLIT_RE |
~60 verbs in 5 lists | post text | OVERRIDES a classifier is_projection=false to true (#3874) |
- (A14: week field measured worse) |
MH (B3) | tense: settled / forecast / later_week in the B3 read, asked of the post scoped to the subject; the 5 verb lists as examples. Measured: the override fired 0 times in 30d (music_news_recover via=forecast_wording) |
in B3 | error: regex | NEW |
states_chart_exit, _CHART_EXIT_RE, _EXIT_*_RE, _reads_exit |
exit verbs, blockers | claim + post | chart-exit lane | SHIPPED A14 | DONE | classifier exit first |
0 | regex | |
artist_ranking_label (_ARTIST_RANKING_RE, _RANKING_PLATFORMS, _TOP_ARTISTS_RE, _RANKING_POS_RE) |
“#N on |
claim | Top Artists label | A13 kept | KC | chart-name + position parse on a closed platform set | 0 | ”” | |
_FUTURE_RE (inside artist_ranking_label) |
will/would + 13 verbs | sentence | refuse a label for a future rank | - | MH (B3) | the B3 tense field |
in B3 | error: regex | NEW |
charts_named, sole_chart_text, chart_keys_for, names_unreadable_chart, _CHART_PATTERNS, _US_QUALIFIER_RE, _FLAGSHIP_PAIR_RE, _ON_BILLBOARD_RE, _AIRPLAY_RE |
chart-name table | claim | which live chart settles | HYBRID (A2) | DONE | classifier chart_key narrows / fills; regex vetoes |
0 | regex | |
deep_platform_cut |
chart keys + claims_debut |
position | depth floor | KEEP | DONE | reads chart_event_of |
0 | - | |
wire_is_next_week, wire_fall_position, wire_last_week, _WIRE_MOVE_RE, _BILLBOARD_MOVE_RE, _WIRE_STATES_NO1_RE, refute_is_last_week |
“#N(+3)”, “climbs 12-5” | wire text + live position | the wire is about last week | - | KC | position-number formats; the verb only anchors Billboard’s fixed headline form | 0 | False | NEW |
post_states_later_week, _LATER_WEEK_RE, later_week_first_week_claim |
re-peak / second week phrases | post | drop a “first-week” take on a later week | A14: not added | MH (B3) | B3 tense = later_week; measured 1 drop in 30d |
in B3 | error: regex | NEW |
FIRST_WEEK_PHRASE_RE, first_week_figures, release_windows, _RELEASE_WINDOW_RE |
“first week”, “day one” | take / claim | number anchor; block window word | - | KC; the block window is MODEL since #4538 | closed phrase set anchoring a number check; the first-week block window is read by Haiku release_window, and these phrases are its examples and the error fallback |
0 | no window | NEW |
wire_move_sizes, wrong_move_sizes, strip_wrong_moves, _MOVE_SIZE_RE, _FROM_TO_MOVE_RE, _WORD_NUMBER |
move-size numbers | take vs wire | drop / strip a wrong move size | - | KC | number check | 0 | strip | NEW |
scope_daily_streams, _DAILY_SENTENCE_RE, _BIGGEST_RISE_RE, is_daily_stream_count, _DAILY_CLAIM_RE |
one account’s fixed template | wire text | rewrite the date, daily-count shape | B17 removed the X use | KC | fixed bot template | 0 | as given | NEW |
misstated_chart_frame period half (_CHART_PERIOD_RE, _CHART_POSSESSIVE_RE) |
daily/weekly/… + chart noun | take vs ground | drop a wrong chart period | - | KC | closed period vocabulary compared to the ground | 0 | drop | NEW |
misstated_chart_frame hold half (_TRANSIENT_RE) |
briefly / momentarily / for a day | take vs ground | drop a take that adds “briefly” | - (B4 note: rubric covers it) | MH (B3) | retire to music_desk_score, whose numbers rubric already fails “a hold it does not give (‘briefly’)”; zero calls. Measured: chart_frame drops 0 in 30d |
0 | judge | NEW |
stream_claim, _STREAM_*_RE, _names_spotify_streams, _OTHER_STREAM_PLATFORM_RE, stream_shape_allowed |
stream shape | claim | settle off kworb | SHIPPED A3 / A13 bound | DONE | classifier stream_shape/rung/count first |
0 | regex | |
_STREAM_SCOPED_RE |
solo/different/separate/distinct/lead/credited + songs | claim + wire | refuse a subset count (veto before the fields) | - | MH (B2 fold) | add subset to stream_shape |
0 | error: regex | |
album_stream_story, _calls_title_a_song |
4 phrase patterns around the title | claim + wire | OVERRIDES the classifier album shape to a song |
- | MH (B3) | Haiku ALBUM / SONG with title + artist + post (world knowledge decides a title track); only when the shape says album | ~0.2 | error: regex | NEW |
mark_album, _album_next_to_title, _ALBUM_TOTAL_RE, _SELF_TITLED_RE |
does the take already call it an album | composed take | insert “album” or drop (album_unmarked 5 in 30d) |
- | MH (B3) | Haiku MARKED / UNMARKED on the take; the insertion stays code | ~0.2 | error: regex | NEW |
catalog_count_tag |
stream_claim catalog shape + figure equality |
claim + figure | catalog block | KEEP | KC | number match | 0 | ”” | |
rank_list_tag + 14 _RANKED_LIST_*_RE, _SPELLED_ORDINAL_RE, _RANK_HERO_RE |
list-name extraction + allow/deny lists | claim + figure | the block over a ranked-list hero | A13: field only vouches | MH (B2 fold) | let the existing rank_list field NAME the list, bounded to claim words; the authority / scope / comparison rules become prompt text; regex is the fallback. Five Codex rounds on #3778/#4212 |
0 (~13 stories/30d) | error: regex | |
claim_count_label, _COUNT_LABEL_RE, _COUNT_COORDINATED_RE, count_label_on_platform |
words before a unit noun after the hero number | claim | block label | A13 kept | KC | anchored to the figure’s exact value; unit nouns are the card unit set | 0 | ”” | NEW |
claim_top_n (_TOP_N_RE), entry_count_claim (_ENTRY_COUNT_RE) |
“top N”, “N … entries” | claim | count board | HYBRID | KC | number formats | 0 | refusal | |
claim_chart_kind |
songs vs albums nouns | claim | count chart disambiguation | HYBRID | MH (B2 fold) | derive from the classifier chart_key through _CHART_KIND; nouns only when no key |
0 | ambiguous |
|
exact chart joins: resolve_chart_position, resolve_entry_history, recover_chart_artist, strip_artist_prefix, lead_act, _credit_acts |
_fold equality |
chart rows | live settle | KEEP | KC | exact folded join | 0 | absent | |
_artist_agrees, artist_count_collisions, resolve_artist_count |
subset rule | rows vs subject | count | KEEP | DONE | K3 (count_same_record on collisions) |
~0 | fold to one |
Structural: _PULL_DATE_RE, _ISO_DATE_RE / humanize_iso_dates, _CLAIM_POS_RE, _NOTE_*_RE, _valid_cert_id, _valid_milestone_id, _CERT_LADDERS, CHART_SOURCES, _CHART_KIND, _CHART_PLATFORM, parse_chart_mark, format_threshold, leader_threshold, is_longshot_leg, _TIER_WEIGHTS, _NBSP, chart_text, market_forecast_context, poly_leader_context.
The A1 cue lists (_TOUR_CLAIM_CUES, _LIVE_CLAIM_CUES, _NONAUDIO_RELEASE_CUES) are gone (0 hits). The cog calls ~150 mn.* readers; they are counted under utils/music_news.py.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_is_tour_subject |
the word “tour” in the title | classifier subject | refuse a loose Deezer cover match | HAIKU (A1 family) | MH (B3) | nominate-only: the word sends the title to a cached Haiku TOUR / RECORD; the classifier’s event_shape stays primary |
~0.1 | error: refuse (today) | |
_first_week_kicker (\b(sold\|copies)\b) |
2 words | claim | block metric “sales” | - | MH (B2 fold) | classifier first-week metric field |
0 | error: regex | NEW |
_songstats_verify (“stream” in claim) |
substring | claim | spend a Songstats slot | SHIPPED A11 | DONE | milestone_metric first |
0 | - | |
pull answer NONE + is_hedged |
sentinel | Perplexity answer | drop the pull | KEEP | KC | model-output protocol | 0 | drop | |
_artistpull_desk_owns |
kind + metric id | classifier fields | drop desk-owned story | KEEP | KC | fixed keys | 0 | - | |
_names_the_collection, _listen_link |
normalize + equality | catalog row | song vs album link | KEEP | KC | exact | 0 | - | |
_row_is_a_different_record -> retrospective.states_past_interval |
throwback frame | claim | refuse old cover | KEEP | OWNED:W19-B3 | ||||
_rank_culture |
slate rank | cue order | culture places | HYBRID | DONE | C10 | 2-3 | cue order | |
_artist_in_tier -> aw.lenient_tier, _recover_bare_artist |
tier rescue | credit | unknown_artist cut (315/30d) |
HYBRID | OWNED:W19-C1 | ||||
_house_gate / _artist_new_release -> music_policy.judged_in_house_genre |
genre tag | Apple tag | in-house genre | HYBRID | DONE | C5 | ~1 | refuse | |
_recent_release, copyright_year lag |
dates | Apple rows | fresh drop | KEEP | KC | numeric | 0 | - |
Structural: _split_subject, _COLLECTION_TYPE_SUFFIX_RE, _MONEY_MARK_RE, _album_link URL strip, _KIND_ACCENT_KEYS, _KIND_NOUNS, _FIRST_WEEK_METRICS, _FEED_PLATFORMS, _RECORD_LANES, _EXISTING_RECORD_KINDS, _first_party_rank, _rotate_window, alnum edition keys (lines ~2053, ~2128), src != "riaa".
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
fold_tokens, _CONNECTORS, _POSSESSIVE_RE |
identity fold | credit | key | KEEP | KC | exact fold | 0 | - | |
_names_a_credit, Watchlist.contains, recognition_tier, recognized_for_store_chart |
whole-segment match | credit | WATCHED / KNOWN / UNKNOWN | KEEP | KC | exact segments | 0 | fail open on empty list | |
s_variants, lenient_tier |
trailing-s, raw vs corrected | credit spellings | rescue | HYBRID | OWNED:W19-C1 | ||||
_ALIASES, _CREDIT_ONLY, canonical_credit, credit_names, performing_names |
alias table | credit | alias -> canonical | HYBRID | OWNED:W19-C1 | ||||
rescue_candidates (ratio 0.75), rescue_unknown |
difflib nominate | UNKNOWN cut | closed-set rescue | DONE #3439 | DONE | Haiku watched_act_match (7/7d) |
~1 | cut | |
credit_parties, _PARTY_SPLIT_RE, _PARTY_SPLIT_AND_RE, _LIST_SHAPE_RE, is_solo_credit, lead_party, first_party, listed_parties, lead_run, _LIST_CUT_RE, _PARTY_JOIN_RE |
credit syntax + corroboration | credit | split joint credits | KEEP | KC | credit syntax, corroborated against the known list | 0 | whole credit | |
first_credit_party, _JOINT_CREDIT_RE, _ARTICLE_TAIL_RE, first_party_candidate, judged_first_party |
one cut name | credit | art-miss portrait party | DONE C12 | DONE | Haiku credit_first_party |
~2 | absent | |
_FEATURE_CLAUSE_RE, featured_credit, _FEATURE_MARKER_RE, _TITLE_WITH_RE, _TRAILING_GROUP_RE, title_feature, row_credit, row_is_theirs, credit_matches |
feat syntax | credit / title | feature parse | KEEP | KC | credit syntax | 0 | - | |
_PLACEHOLDER_CREDITS, is_placeholder_credit |
15 exact folded stand-ins | credit | skip portrait lookup | KEEP (C12 measured 3/3 right) | KC | exact folded equality on catalog stand-in strings | 0 | absent |
Structural: daily_share_ok, daily_is_plausible, check_daily_drop(s), _TOP_RUNG_RE, TOP_MOVE_KINDS, _STORY_WHAT, _STORY_EYEBROW, _POSITION_ONLY_EYEBROW, rotate.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_EDITION_NOISE |
edition parentheticals | search term | strip noise from the query | KEEP | KC | query normalization only | 0 | - | |
sequence_mismatch, _sequence_marker, _TITLE_TAIL_NOISE, _NUMBER_WORDS, _roman_installment |
installment number | title pair | refuse a different installment | KEEP | KC | number parse | 0 | refuse | |
_title_matches (substring >= 3 or ratio >= 0.6) |
difflib | title vs trackName | which link / cover | HYBRID; C2 band (< 0.85) shipped | MH (B5) | a NON-EQUAL pass at ratio >= 0.85 (or a substring pass) still accepts alone. Send every non-equal pass to match_catalog_title (C2, 12/7d); equality stays the free accept |
+5-20 (code estimate, cached 30d) | no pick: refuse | |
_credit_similar (ratio >= 0.8, word-sorted), _artist_matches, _primary_artist_matches, _partial_name |
difflib on credits | requested vs artistName | homonym guard for links and art | HYBRID | MH (B5) | _credit_exact stays the free accept; a ratio-only pass goes to a cached Haiku SAME / DIFFERENT (both credits + track) |
+5-20 (cached) | error / DIFFERENT: refuse | |
credit_verified, _credit_exact, _acts_within, _same_act_words, title_verified, core_title |
whole-word, Counter equality | credit / title | exempt a cover from the vision judge | - | KC | exact; a False sends the cover to the vision judge | 0 | judge | NEW |
release_tag_mismatch, _release_name_tag, _NOT_A_NAME_ZONE_RE (55 words), _ZONE_STOPWORDS |
which bracket zone NAMES the release | raw titles | refuse a row (Weezer colours) | - | MH (B5) | the zone word list decides “is this bracket a name”; reuse catalog_release_name (#4115) for a zone the list does not classify as packaging |
~1 | error: list | NEW |
_edition_tagged, _EDITION_TAG_RE, _PACKAGING_ZONE_RE |
recording tags | title | a tagged request needs a tagged row (#4263) | - | DONE | a mismatch only drops the gate exemption; the vision judge decides | 0 | judge | NEW |
pick_apple_music_url fallback order |
logic | results | link choice | KEEP | KC | logic over the matchers | 0 | - | |
_is_single_or_short |
”- single” suffix, <= 2 tracks | collection | album vs single | KEEP | KC | upstream suffix + count | 0 | - | |
_exact_artist_row, _pick_album |
exact name, fold containment | rows | discography row | KEEP | KC | exact | 0 | no row | |
_BAD_VERSION_RE, _is_guessable_title, _version_tag_text |
27 version words in tag zones | track title | drop from the /guess and X-game pools, Deezer pick | KEEP (bulk) | MH (B6) | nominate: a flagged title goes to the cached release_version_kind (exists, 28/day); RECUT keeps the drop, NEW clears it |
+10-40 (cached 30d per title) | error: drop (today) | |
_ALT_VERSION_RE, _is_clean_original, targets_alt_version |
11 alt-version words | title | prefer the clean original row (clip, art rank) | KEEP | MH (B6) | same label (recut / edition vs new) |
in B6 | error: regex order | |
_COMPILATION_RE, _is_compilation |
30 compilation phrases + “various” | collectionName | prefer the act’s own album cover | KEEP | MH (B5) | cached Haiku COMPILATION / OWN_RELEASE per collectionName (90 days); only when two collections compete | ~2-10 (cached) | error: regex |
Structural: copyright_year (_PHONOGRAM_MARK_RE, _COPYRIGHT_YEAR_RE), apple_music_id, _FORMAT_SUFFIX_RE, _CREDIT_TAG_RE, _FEAT_CREDIT_RE, _PAREN_ZONE_RE, _BILLING_SEPARATOR_RE, breaker / retry constants.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
album_title_matches, album_match_band, _TITLE_STOPWORDS, _core_title, _fold_stylized |
60% token overlap | album row vs request | release date / genres | HYBRID | DONE | C2: every non-equal core goes to the Haiku pick | ~1 | refuse | |
_credit_matches_contributors, _initialism, _split_billing, _names_whole_acts |
subset / initialism | contributors | FOUND cover, gate exemption only for a one-act exact credit (#4203) | KEEP | KC | exact; non-exempt covers go to the vision judge | 0 | judge | |
album_cover, _cover_from_rows, _cover_from_artist_albums, _one_act |
core-title equality | rows | which cover | KEEP | KC | exact | 0 | - | |
artist_picture_match (any token overlap, top fans) |
token overlap | artist rows | portrait + exact flag |
KEEP | DONE | a non-exact pick is flagged and the media gate (vision judge) decides it; verify each consumer reads exact |
0 | judge | |
_artist_overlaps, _artist_is_billed (60% token overlap) |
token overlap | credit vs Deezer artist | which track row gives date / genres / top track | KEEP | MH (B5) | exact fold free accept; overlap-only pass to the B5 SAME / DIFFERENT credit check | ~2 | refuse |
Structural: _is_real_deezer_image (md5 sentinel), _SEARCH_CONNECTOR, _GLUED_CONNECTOR_RE, connector_glued, credit_key, _is_varied.
| file: symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
chart_credits: _artist_matches |
_names_a_credit both ways |
chart credit vs Genius | attach Genius credits | KEEP | KC | exact whole segments (Miguel Newberry fix) | 0 | absent | |
chart_credits: credit_matches filter |
segments | credit | drop self-credit rows | KEEP | KC | exact | 0 | - | |
catalog_art: screen_title_check |
equality + Haiku | TMDB title | poster | DONE C13 | DONE | screen_same_work |
~0.5 | refuse | |
catalog_art: release_name_check, _judge_release_names |
bracket name | rows | match / mismatch / unsure | DONE #4115 | DONE | catalog_release_name on unsure |
~1 | refuse | |
catalog_art: cover_rung, _collection_verified, _edition_tags |
exact credit + tags | row | gate-exempt rung | #4222 / #4263 | KC | exact; any miss goes to the vision judge | 0 | judge | |
catalog_art: _SELF_TITLE_TAG_RE, _only_self_title_tags, _names_the_act |
packaging-tag allow-list | title zones | self-titled ranking boost | - | KC | allow-list on catalog packaging tags; a miss only removes a ranking boost | 0 | no boost | NEW |
catalog_art: _pick_artist_row, _row_title_matches, _rank_rows |
apple matchers | rows | cover row | KEEP | DONE | C2 via apple_music (and B5 widens it) | - | - | |
names: name_pattern, name_in_text, match_forms |
whole-word name match | Discord prose | which member is named (/forget, attribution) | KEEP | KP | privacy matching | 0 | - | |
aliases: AliasIndex.users_in, _text_fold_keys |
alias fold | Discord prose | member resolution | KEEP | KP | privacy matching | 0 | - | |
names: strip_ep_marker (_EP_MARKER_RE) |
“(EP)” | title | identity join | KEEP | KC | catalog suffix | 0 | - | |
song_pool: song_key, recognizable |
apple normalizers, fans | rows | song identity, pool floor | KEEP | KC | exact / numeric | 0 | - | |
hits: projection_row (_norm_name substring both fields) |
substring | HITS rows vs title + artist | which projection row a debut card / market answer reads | KEEP | MH (B4) | exact fold free accept; a substring-only row goes to a Haiku pick ROW1..n / NONE | ~0.5 | NONE: no projection | |
hits: find_upcoming |
exact | rows | upcoming release | KEEP | KC | exact | 0 | - |
Structural (song_pool, hits): song_pool genre dicts (DEEZER_GENRE_CHART, RSS_GENRE_IDS, GENRE_BUNDLES); _to_int, _COLUMN_FIELDS, _spins_agree, _slash_date, TSV parsers, decap_title, benchmark_key, _COUNT_CELL.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
pick_album_art_row, _credits_artist, _rank_art_rows |
apple fuzzy matchers + release_name_check mismatch (#4349) |
iTunes rows | market cover | KEEP | DONE | delegates; fixed at the source in B5; media gate downstream | - | - | |
_is_full_album |
”- single” / “- ep” + track count | row | album vs single | KEEP | KC | upstream suffix | 0 | - | |
_is_soundtrack, _SOUNDTRACK_NAME |
genre field + 3 words | row | art preference | - | KC | upstream genre field; release-name words are catalog naming | 0 | - | NEW |
_subject_tier_hits |
token-set equal / superset / subset tiers | Kalshi subjects vs text | which ladder answers a question | KEEP | MH (B4) | equal tier is the free accept; superset / subset tiers go to a Haiku pick over the tier’s readings | ~0.5 | NONE: no ladder | |
_FIELD_LABELS |
7 title regexes | Kalshi market title | label in the related-markets line | KEEP | KC | Kalshi’s fixed title templates; the fallback prints the title itself | 0 | title | |
related_market_context (_artist_key substring >= 5) |
substring | subject vs outcome names | which act’s odds join the compose context | KEEP | MH (B4) | exact fold free accept; substring-only hit to a cached Haiku SAME / DIFFERENT act | ~0.5 | DIFFERENT: no line | |
title_names_act, title_act_hits, judged_title_act |
token run | event title | artist market | DONE C9 | DONE | market_act_check (67/day) |
67 | skip | |
_pick_namesake, _wiki_portrait |
Wikidata namesakes | descriptions | portrait | DONE #3319 | DONE | wiki_namesake |
~0 | UNCLEAR: none |
Structural: _TICKER_DATE_RE, _DEBUT_TICKER_DATE_RE, _RELIST_SUFFIX_RE, "::" subtitle split, "PUREALBUM" in ticker, "stream" in metric, ARTIST_MARKET_SKIP_SERIES, _SALES_PAIR_METRICS.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
is_side_version, side_version_marker, is_side_version_beyond_radio_edit on BULK paths: music_alert debut lanes (2259, 2279, 2674, 2986, 3095, 3121), music_desk presence / sort / new_entry rows (1834, 3940, 6568, 6575, 10070, 10079), music_news row filter (6172) |
_SIDE_MARKERS, _BARE_TRAIL_MARKERS, _FEAT_RE, _TRAILING_DASH_RE, _FORMAT_TAG_RE, _RADIO_EDIT_RE |
track title | suppress a debut, hold out of presence memory, down-rank | HYBRID; C3 shipped on 2 announce paths only | MH (B6) | nominate: a regex-FLAGGED title goes to the cached release_version_kind; rendition_marker stays a hard RECUT. C3 measured the music_alert debut lanes: 0 better, 2 wrong (instrumental editions) before #4268 fixed that shape; re-measure first |
+20-60 (cached 30d) | error: regex | |
judged_side_version (release board, new_entry) |
label map | title + verdict | announce paths | DONE C3 | DONE | release_version 28/day |
28 | regex | |
rendition_marker, _RENDITION_RE |
instrumental / a cappella / karaoke / sped up / slowed / reverb | version suffix | RECUT with no call | - | KC | closed catalog rendition-tag set; the model measurably lost on it (#4268: EDITION 2 of 2 runs) | 0 | side version | NEW |
_EDITION_MARKERS, edition_marker, without_edition, _REMASTER_RE, version_base |
edition words | title | persisted song keys | KEEP (C3) | KC | builds persisted keys | 0 | - | |
release_board: dedup (artist.lower(), title.lower()) |
exact | rows | dedup | KEEP | KC | exact | 0 | - |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
music_desk: _RESERVED_OTHER_CHART |
“US”/”U.S.” vs “global” | our own recent posts | exclude a line from the Spotify board’s dedup comparison (#3894) | - | MH (B7 fold) | pass the board’s chart identity into the existing topic_dedup judge (Haiku, 247/day); the regex only pre-sorts |
0 | error: regex | NEW |
music_desk: wl.contains / recognition_tier / _is_recognized / aw.lead_party / credited_names delegations |
exact segments | credits | floors, caps, grouping | KEEP | KC | exact | 0 | fail open | |
music_desk: "streams a day" in qual_source |
substring of our own template | card_qualifier text |
drop the live line | - | KC | our own template string | 0 | - | NEW |
music_desk: _kworb_career_row (kworb_fold) |
exact | board rows | career rung | KEEP | KC | exact | 0 | - | |
music_desk: _genre_debut_groups |
Apple genre + Deezer genres | upstream tags | genre board | KEEP | KC | upstream fixed vocabulary, two-source confirm | 0 | - | |
music_alert: _ARTIST_MARKET_NOT_ACTS |
3 exact folded names | watchlist name | exclude from the act candidates | KEEP | KC | exact folded keys; market_act_check decides every other title |
0 | - |
Delegations counted elsewhere: is_side_version* (B6), output_checks / ship_guard / qualifier_* (other partitions, #4422 / #4412), mq.on_chart (milestone_qualifier), match_album_tracks (Haiku). Structural: music_desk _ORDINAL_RE, _CHART_ENTRY_KINDS, lane sets, slug keys, " -- " splits; music_alert _RANK_FIGURE_RE, _CROWN_LANES, lane-name startswith, "stream" in metric, "album" in lane; music _MUSIC_LINK_HOSTS, drop_song_key; pop_desk _VISION_HOSTS.
| file: symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
genius: _DETAIL_INTENT, _SAMPLE_INTENT, _MEANING_INTENT, _LYRIC_INTENT, matches, lookup render branch |
4 intent regexes | query + aspect (the /ask model’s own words) | which source, which render | HYBRID; B7 not built (5 lookups/30d) | MH (B8 fold) | make the song_credits tool’s aspect an enum (credits / samples / meaning / identify) in the /ask tool schema, so the /ask model picks it; regex only for a free-text aspect |
0 (5 reference_lookup in 30d) |
regex | |
genius: _best_annotation |
word overlap | question vs annotations | which ONE annotation reaches the model | KEEP | MH (B8 fold) | hand the top 3 annotations to the /ask model, which already answers | 0 | top 1 | |
musicbrainz: _MUSIC_INTENT, matches |
release / drop / label words | /ask intent | route to MusicBrainz | HYBRID | MH (B8 fold) | same tool-argument enum | 0 | regex | |
musicbrainz: "feat" in joinphrase |
upstream field | artist-credit | main vs featured | KEEP | KC | upstream fixed field | 0 | - | |
banger_lane: search_terms, judged_terms |
stopwords / caps runs | headline | X search names | DONE B12 | DONE | headline_search_names |
~2 | regex | |
banger_lane: _SPAM_RE |
15 spam phrases | candidate tweet | drop a reply target | HYBRID | MH (B8) | cached Haiku SPAM / REAL per tweet id, phrase list as examples (Jev not used: low volume, owner direction 2026-10-17) | ~2 (banger_lane 14 events/7d) | error: regex | |
ktt2: match_score, _STOPWORDS, match_threads |
title-word overlap > 0 | forum threads vs topic | which threads reach /ask context (a 0 score is never seen) | KEEP | MH (B8) | Haiku pick of the relevant threads from the newest N (indexes); overlap stays the order | ~1 (ktt2_fetch 20/day) | error: overlap | |
ktt2 _is_watched, ktt2_chatter is_watched |
watchlist fold | thread | watched first | KEEP | KC | exact | 0 | - | |
pop_stories: story_signature, dedup_key, _STOPWORDS |
first 5 content tokens | wire text | durable moment dedup; a key collision drops alone | KEEP | MH (B8) | on a key collision whose texts differ, ask the existing topic_duplicate (Haiku); same text stays a free drop |
~1 | error: drop (today) | |
versuz: is_play_command, PLAY_COMMAND_RE, STRICT_PLAY_COMMAND_RE |
command syntax | chat message | play attribution | KEEP | KC | bot command syntax (closed) | 0 | - | |
versuz: parse_shorthand, SHORTHAND_RE, _LETTER_DASH_RE, slot_for_name |
“name: song” | host text | slot | KEEP | KC | our input syntax | 0 | - | |
versuz: _title_key, base_title (_EDITION_WORDS, _FEAT_RE) |
normalize | Jockie title | queue identity, display | KEEP | KC | exact after fold; display | 0 | - | |
versuz: answer_order |
name / handle / title substring | hand-made poll answers | which slot each answer scores for | KEEP | MH (B8) | Haiku A / B / UNSURE per answer with both names, handles and titles; UNSURE keeps today’s fallback (play order, said aloud) | <1 | UNSURE: fallback | |
versuz_catalog: _YT_NOISE_RE |
official / lyric / audio | YouTube title | cleanup | KEEP | KC | upload-title tags, display | 0 | - | |
cogs/versuz: _handles, _member_id_named, _pop_pre_queued |
lowercase equality | “Requested by” | attribution | KEEP | KC | exact | 0 | unattributed | |
cogs/versuz: by_name and open_rnd and not (url or artist) |
shape | message | chat vs correction | KEEP | KC | input shape | 0 | - |
| file: symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
milestone_qualifier: is_no_qualifier NONE lead |
sentinel | Perplexity read | skip the judge | KEEP | KC | protocol sentinel | 0 | absent | |
milestone_qualifier: _NO_QUALIFIER_MARKERS tail (12 phrases) |
“no notable”, “not a first” | read lead | skip the judge (decides alone) | KEEP | MH (B7) | send a phrase hit to qualifier_verify (Haiku, 3/day) instead of skipping |
+~1 | absent | |
milestone_qualifier: is_unofficial_rank, _AGGREGATOR_RE, _OFFICIAL_SOURCE_RE, rank_from_score_ranker, _SCORE_RANKER_RE |
source-name lists | qualifier + reads | drop an aggregator rank (TV Girl / Chartmetric to X) | - | MH (B7 fold) | qualifier_verify returns source_class: official / aggregator / none; the lists go in its prompt. Coordinate with #4412 (it owns qualifier_check) |
0 | error: list (drop) | NEW |
milestone_qualifier: _RELATIVE_SCOPE_MARKERS |
this year / ytd / today | qualifier | cache TTL | KEEP | MH (B7 fold) | same call returns scope: relative / standing |
0 | short TTL | |
milestone_qualifier: on_chart, nth_release_qualifier |
label containment, fold | qualifier | scope gate, nth release | KEEP | KC | exact chart label / fold | 0 | drop | |
catalog_stats: rank_claim_mismatch names_act phrase half (_NAMED_COMPARISON_RE) + _PLACE_ON_OTHER_METRIC_RE / _OTHER_METRIC |
“trailing only”, “second only to”; streamed/played/… | composed catalog caption | drop the caption | - | MH (B7) | cached Haiku OK / NAMES_RIVAL / OTHER_METRIC with the proved rank fact; the exact-name and place-number checks stay code | ~1 | error / no verdict: drop | NEW |
catalog_stats: stated_places, _COUNT_PLACE_RE, exact rank.ahead names |
ordinal numbers | caption | wrong place | - | KC | number check + exact names | 0 | drop | NEW |
milestones: _REMASTER_TAIL_RE; stream_totals: _CREDIT_SPLIT_RE |
key fold, credit split | title / credit | keys, act list | KEEP | KC | persisted key / credit syntax | 0 | - | |
feeds: room_is_quiet |
>= 4 words or media | room buffer | skip the forced web search in recap (#880) | KEEP | MH (B8) | Haiku SUBSTANTIVE / CHATTER on the human lines (Jev not used: about 1 recap a day) | <1 | error: word count | |
artist_caption: _HAS_WORD_RE |
any letter | caption | decoration-only caption | KEEP | KC | structural | 0 | - |
Section H structural files, one line each:
attachment_is_image MIME + extension, _HTML_TAG_RE, mention regexes, _SOURCE_PATTERNS / _classify_url host table._VERDICT_RE parses the Grok verdict (protocol)._TAG_RE, _ATTR_RE, _CLOCK_RE, _FALSEY parse the model’s media tag (protocol).wire_identity 15/day)._KIND_PHRASES (our media enum)._STATUS_ID_RE), industry_feeds.py (HTML / meta regexes), songstats.py, spotify.py, apple_releases.py, alt_merge.py, music_links.py, utils/music.py (exact dedup), versuz_card.py, streaming_stats.py (_DEFAULT_EXCLUDE_MARKETS = {“US”}), lifetime_boards.py, chart_presence.py: registries, numeric decay, URL / RSS parsing, fixed keys. 0 semantic.All Axiom, dataset tootsies.
| # | query (short) | window | result | what it decides |
|---|---|---|---|---|
| 1 | claude_api count by purpose |
7d | music_news_classify 2,529; music_desk_score 2,666; music_news_verify 817; topic_dedup 1,726; market_act_check 470; release_version 195; music_news_slate_rank 18; catalog_title_match 12; watched_act_match 7; chart_age_check 6; screen_same_work 4 | the fold batches (B2, B7) add 0 calls to calls that already run |
| 2 | music_news_filtered count by reason |
30d | not_a_story 2,184; shortlist_full 477; chart_cut 337; unknown_artist 315; title_ungrounded 177; cert_out_of_scope 52; ladder_rung 13; market_unread 6 | ranks B3 (chart_cut) above B2 cert work |
| 3 | chart_cut by detail.family |
30d | unnamed 130; genre_country 57; format_hot_ac 29; uk_official 28; genre_rock 27; billboard_japan 17; aria 12; others 37 | |
| 4 | the 130 unnamed claims, read by hand |
30d | 10 name a KEPT chart and were cut: “Billboard Global Charts” x4 (Global 200), “most No. 1 albums on Billboard’s R&B/Hip-Hop chart” x3 (genre_albums), “Spotify Global chart/top 10” x2, “Spotify US Weekly Top 10” x1. 4 more imply the Billboard 200 (“No. 1 on the US albums chart, 88K”). The uk_official and aria cuts read correct | B3 impact H: about 8% of the unnamed cuts lose a true story |
| 5 | cert_out_of_scope by empty body (cert_id ends in |) |
30d | 31 empty body, 21 named body; the 31 claims are all foreign (New Zealand x16, Italy/FIMI x11, Germany x3) | the prose branch is live, and 31 of 31 cuts are right, so B2 cert work is lowest priority. It contradicts the A13 note “every cert carried a body” |
| 6 | music_news_slate by detail.rank, culture pool sums |
7d | rank model 18 slots, skip 35, blank 102 (pre-#3448 rows); culture pool 13,033 rows in 172 slots (about 1,860 rows a day after the number cue) | B1 volume: the Jev check runs on the posts the cues drop, cached per post id |
| 7 | music_news_recover by detail.via |
30d | live_chart 423; mention_name 83; stale_refute 24; live_leg 10; tracker_lag 8; wire_spelling 3; forecast_wording 0 | post_states_forecast override fired 0 times; its miss side is not measured |
| 8 | music_news_scored shipped=false by reason |
30d | unsupported_rank 14; prior_position 5; album_unmarked 5; later_week 1; chart_frame 0 | _TRANSIENT_RE (0) can move to the scorer; mark_album and _LATER_WEEK_RE are low volume |
| 9 | reference_fetch / reference_lookup by source, surface |
30d | reference_lookup 5 (ask); genius fetches 3,560 and musicbrainz 6,805 come from the boards, not the intent router | the genius / musicbrainz intent regexes route about 5 questions a month: fold, do not add a call |
| 10 | music_desk_trim by reason |
7d | streams_tier 3,376; light_milestone 254; tenure_floor 1 | numeric trims, no word list (not a candidate) |
Merged into the Part 0 batch plan.
utils/music_news.py grew from 4,680 to 7,752 lines and holds 140 compiled regexes; about 100 symbols are named nowhere in the old audit file. Most of the new ones are number checks (move sizes, refutes, wire units, daily templates) and stay KEEP-CLOSED. The new SEMANTIC ones are the forecast / later-week / edition / album verb and phrase lists (post_states_forecast, _LATER_WEEK_RE, names_edition, _calls_title_a_song, mark_album, _FUTURE_RE, _TRANSIENT_RE) and the cert territory modifiers. They are grouped in B3 and B2.post_states_forecast turns is_projection=false into true, _calls_title_a_song turns stream_shape=album into a song, figure_is_passed_threshold swaps on vthreshold OR regex, _STREAM_SCOPED_RE vetoes before the stream fields. Each was added after a measured classifier miss. Under the new rule the override is a second model read (B3), not a word list.cert_id. In 30 days, 31 of 52 cert_out_of_scope cuts had an empty body and were decided by the prose regex. All 31 were right.unnamed chart residue loses real stories. 10 of 130 cuts name a kept chart in a form the patterns do not read (“Billboard Global Charts”, “Billboard’s R&B/Hip-Hop chart” for an album record, “Spotify US Weekly”). Some predate C10 (2026-10-16); the Spotify rescue covers 2 of the 10 only when the classifier key is set.post_states_forecast (0 recoveries), misstated_chart_frame (0 drops) and _LATER_WEEK_RE (1 drop) fired almost never in 30 days. Their MISS side is not measured, so “0 fires” is not evidence they are right. B3 should dry-run them on the 30-day chart stories.release_type debut lanes. C3 kept the music_alert debut lanes regex-only on a measurement (Haiku 0 better, 2 wrong). #4268 then fixed that exact shape (rendition marker), so the measurement no longer holds. B6 must re-run it.classify, cached in kv_cache) is the owner’s stated default (Jev is not a Haiku replacement, docs/ARCHITECTURE.md lines 21-28). versuz.is_play_command stays KEEP-CLOSED on its merits: it parses a bot command syntax, not prose.cert_prose_is_riaa and the RIAA-lookup veto, threshold_metric, poly_event_matches, release_tag_mismatch and its 55-word zone list, catalog_stats.rank_claim_mismatch, milestone_qualifier.is_unofficial_rank and its source lists, music_desk._RESERVED_OTHER_CHART.reference_lookup); the Genius and MusicBrainz fetch volume comes from the boards, which pass a fixed aspect. music_markets._FIELD_LABELS only labels a context line and falls back to the raw title.ungrounded_quoted_titles (new) reuses title_grounded_in_wire, so it is OWNED:W19-C1. milestone_qualifier is not #4412 code, but it calls qualifier_check (#4412); B7 should be agreed with that coordinator before it starts.Audit date 2026-10-18. Repo at 4e1b6c0 (branch claude/classifier-audit-wave19). Read-only
pass. Scope: the 51 files of the old section (docs/CLASSIFIER_AUDIT.md lines 692-1172),
plus utils/sportsdata/*.py (11 files) and the new utils/market_sibling_claims.py.
Every file was grepped for re.compile, word-list literals, substring tests, fuzzy
ratios and free-text dict lookups, and the code around each hit was read.
The git history in this checkout is shallow (50 commits), so “NEW” means “not in the old section’s inventory”, checked symbol by symbol.
Semantic sites only. KEEP-PROTECTED sites are listed as semantic rows so that the protected set is visible.
| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| utils/markets.py | 22 | 16 | 15 | 3 | 0 | 0 | 4 | 0 |
| utils/market_cards.py | 18 | 7 | 8 | 1 | 0 | 0 | 0 | 9 |
| utils/market_subject_image.py | 13 | 3 | 8 | 5 | 0 | 0 | 0 | 0 |
| utils/market_outcome.py | 10 | 4 | 7 | 1 | 1 | 0 | 0 | 1 |
| utils/market_chart.py | 3 | 3 | 2 | 0 | 1 | 0 | 0 | 0 |
| utils/alert_triggers.py | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
| utils/market_triggers.py | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/market_siblings.py | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/kalshi_price.py | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
| utils/market_sibling_claims.py (NEW file) | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
| utils/kalshi_ladder.py | 6 | 2 | 5 | 0 | 0 | 1 | 0 | 0 |
| cogs/market_drop.py | 12 | 6 | 8 | 1 | 0 | 0 | 1 | 2 |
| cogs/market_alert.py | 12 | 7 | 7 | 1 | 0 | 0 | 0 | 4 |
| cogs/bookie.py | 2 | 6 | 0 | 0 | 0 | 2 | 0 | 0 |
| cogs/betting_board.py, betting_alert.py, betting_value.py | 0 | 11 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/bet_corrections, odds_adapt, odds_compare, called_shot, leaderboard, table_card, ranking_strip | 0 | 8 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/sports_stories.py | 4 | 2 | 1 | 1 | 0 | 0 | 2 | 0 |
| cogs/sports_desk.py | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 1 |
| utils/api_sports.py | 2 | 6 | 1 | 0 | 0 | 1 | 0 | 0 |
| utils/espn.py | 1 | 7 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/highlightly.py | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
| cogs/sports_boards.py, utils/sports_boards.py | 0 | 14 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/sportsdata/*.py (11 files) | 6 | 22 | 3 | 0 | 0 | 3 | 0 | 0 |
| utils/playercard.py | 2 | 5 | 2 | 0 | 0 | 0 | 0 | 0 |
| cogs/playercard.py | 4 | 1 | 2 | 0 | 2 | 0 | 0 | 0 |
| utils/retrospective.py | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
| utils/scrapecreators.py | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/steam_art.py | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/entity_image.py | 0 | 7 | 0 | 0 | 0 | 0 | 0 | 0 |
| image utils (vision_image, xai_image, image_gen, image_inspect, grid_vision, image_hash, image_codec) | 1 | 14 | 1 | 0 | 0 | 0 | 0 | 0 |
| media utils (media_edit, video_trim, clip_pick, video_fetch, video_ingest, audio, audio_tags) | 1 | 22 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/radio.py | 2 | 4 | 2 | 0 | 0 | 0 | 0 | 0 |
| utils/artist_socials.py | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| total | 131 | ~191 | 76 | 13 | 4 | 8 | 8 | 22 |
OWNED split: W19-B1 = 12 (market_cards 7, market_drop 2, market_alert 2, alert_triggers 1), #4428 = 2, #4412 = 2, #4422 = 1, W19-B3 = 5 (retrospective 4, sports_desk 1).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
qualify_platform_metric + _PLATFORM_PATTERNS |
9 platform names, one-platform rule | Kalshi settlement rules | weave the platform into the title | HYBRID (B11 shipped) | DONE | Haiku market_platform_check already decides the 2+ platform case; the 1-platform case is an exact name match |
0 (0 events in 30d) | no rewrite | |
_UNQUALIFIED_METRIC_RE |
views / streams / subscribers nouns | Kalshi title | whether a title needs a platform | (part of above) | KEEP-CLOSED | Kalshi’s own metric nouns; the rewrite also needs a grounded platform | 0 | no rewrite | |
series_source_platform |
platform name in settlement_sources[].name |
Kalshi series payload | series platform | – | KEEP-CLOSED | upstream source name, exact | 0 | no rewrite | NEW (#4246) |
_AFTER_ISSUANCE_RE / strip_issuance_clause |
“after issuance” | Kalshi title | cut a rules phrase | – | KEEP-CLOSED | fixed upstream phrase | 0 | title unchanged | NEW |
_DOUBLED_ARTICLE_RE / tidy_kalshi_title |
“a a” | Kalshi title | collapse a typo | – | KEEP-CLOSED | exact lowercase article pair | 0 | title unchanged | NEW |
_names_non_leader_slot (_RUNNER_UP_RE, _RANK_HASH_RE, _SEED_RANK_RE, _AUCTION_RANK_RE) |
runner-up / #N>=2 | Kalshi event title | NOMINATE the runner-up cut | HAIKU (B2 shipped) | DONE | nominate-only: confirm_runner_up_cut (Haiku RUNNER_UP/OTHER) decides every cut; a regex miss keeps the event |
~0.5 new tickets/day (15 calls/7d) | keep event (open) | |
_MUSIC_MARKET_CUES / _looks_like_music |
– | – | REMOVED 2026-10-27 | – | REMOVED | owner steer: music #2 boards are cut too, so no music exemption exists and the cue list is gone. The Haiku task names music as RUNNER_UP | 0 | – | |
_is_cut_runner_up_event |
category == entertainment + _names_non_leader_slot |
Kalshi category + title | drop at discovery | HAIKU | DONE (via the two rows above) | – | – | – | |
_is_cut_netflix_views_event |
ticker cue NETFLIXTOPVIEWS + title backup |
Kalshi ticker + title | drop the view-count board | KEEP | KEEP-CLOSED | ticker prefix | 0 | drop (276 in 30d) | |
classify_intent (_SPORTS_PATTERNS, _PM_PATTERNS, _WILL_X_BY_RE) as the _classify fallback |
substring word lists | user query | intent when the Haiku market_intent call errors |
KEEP | DONE | fallback only; 0 markets_classifier errors in 30d, so it never ran |
0 | None | |
classify_intent as the discourse routing prefilter (cogs/discourse.py sportsy_channel) |
same lists, RAW SUBSTRING | channel name + topic | whether a quiet slot asks the market classifier at all | KEEP | MODEL-HAIKU | branch: the admission miss (no convo, no category, no cue = no call). One cached classify SPORTS / OTHER per channel id + name + topic hash, 7d TTL; feed _SPORTS_PATTERNS as examples |
<5 after warm-up (one per channel per topic edit) | model error: today’s regex | |
looks_like_sports + _SPORTS_WORD_RE (icebreaker _market_line in cogs/discourse.py) |
classify_intent(...) == "sports" or \bsport |
channel name + topic | whether the icebreaker fetches market odds at all | KEEP | MODEL-HAIKU | same call as the row above (shared cache). Substring bug reproduced: “general-chats”, “stats-and-facts”, “conflict zone” (“nfl”), “nuclear takes” (“ucl”), “comma club” (“mma”), “whats good” (“ats”), “beats and bars” all read SPORTS | shared with above | model error: today’s regex (fix it to word boundaries as the fallback) | |
detect_league + _LEAGUE_KEYWORDS in sgo_snapshots |
league words, fast accept before Haiku | /ask SGO tool query | league for the SGO fetch | HYBRID (fixed #3457) | KEEP-CLOSED (dead) | fast accept (“football” -> NFL) decides alone, but the /ask SGO tool had 0 calls in 30d; revisit if it gets traffic | 0 | Haiku on miss | |
_LEAGUE_SENTINELS |
“none” / “unknown” | model output | sentinel | KEEP | KEEP-CLOSED | protocol sentinel | – | NBA default | |
_KALSHI_SPORT_TAGS / kalshi_sport_label |
tag map | Kalshi series tags | sport label | KEEP | KEEP-CLOSED | upstream enum | – | unclassified = kept | |
_TAG_KIND_CUES / derive_kind_tags |
cue substrings | Kalshi taxonomy tag names | kind tags | KEEP | KEEP-CLOSED | upstream taxonomy; reached only from the dead routing path below | 0 | whole category | |
kalshi_channel_routing (_MUSIC_CUES, _CINEMA_CUES, _TV_CUES, _POP_CUES) |
cue substrings | /ask topic arg |
which Kalshi category a topic pulls | HYBRID (B10 measured dead) | KEEP-CLOSED (dead) | the drop passes topic=None; the /ask kalshi tools had 0 calls in 30d (tool_call). Dead-code candidate |
0 | global pool | |
_kalshi_competition_to_sport + _KALSHI_SOCCER_CUES |
substring ladder | competition name | sport tag | HAIKU (B5 shipped) | DONE | fallback under check_competition_sport (Haiku, 13,165 “changed” of 55,172 checks in 30d) |
~575 calls/day in 7d (re-asked per process, cache 7d) | ladder on error | |
"kalshi" in lower (source order) |
substring | /ask query | source order | KEEP | KEEP-CLOSED (dead) | venue name; same 0-call path | 0 | default order | |
_norm_game_tokens + token guard in kalshi_player_props |
any >=3-char team token inside the folded title | /ask game query vs Kalshi titles | which events count as the matchup | KEEP | KEEP-CLOSED (dead) | a fuzzy join by the new rule, but the tool had 0 calls in 30d. If revived: Haiku pick among the <=6 FTS candidates | 0 | prop dropped | |
_kalshi_player_from_label |
split “:” | Kalshi label | player name | KEEP | KEEP-CLOSED | template | – | whole label | |
_clean_kalshi_label |
rsplit “: “ | Kalshi label | draw detection | KEEP | KEEP-CLOSED | template | – | 2-way fold | |
_POLY_QUERY_STRIP |
quote strip | query | search text | KEEP | KEEP-CLOSED | cleanup | – | – |
Structural: _PARSER_SPORTS, _SGO_SPORT_LABEL, league constants, _classify_fetch_error,
bookmaker preference, _PROP_STAT_* labels, bet in (ou, yn), _BLOCKED_TICKER_PREFIXES,
SHOW_CATALOG, KXMVE prefix, yes/no formatting, _SGO_LEAGUE_ALIASES, _UNOPENED_STATUSES,
_KALSHI_QUERY_TOKEN / _or_expand_query, kalshi_ticker_start / _KALSHI_TICKER_START_RE
(NEW, #3560 date parse), DROP_CATEGORIES / parse_drop_category, MUSIC_SUBTAGS.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
figure_is_number |
digit + <=8 letters | figure string | number vs text card | KEEP | KEEP-CLOSED | format | – | text card | |
_MUSIC_CHART_RE / is_music_chart_market |
billboard / hot 100 / first week … / spotify | Kalshi title | music branding, report-lock branch, catalog-hint rung, AND admission to the take fabrication gate (via is_chart_slot_market) |
HYBRID, then A9 KEEP | MODEL-HAIKU | a regex that approximates “is this a music chart market”. Cheaper closed option first: read the series tags (MUSIC_SUBTAGS, an upstream enum) if the snapshot carries them. Else fold into the batch P2-A family call (per event ticker). Keep the regex as the fallback |
shared with P2-A | model error: regex (today) | |
is_music_lane / _MUSIC_SURFACES |
own surface names | surface | branding | KEEP | KEEP-CLOSED | own enum | – | – | |
_snapshot_is_sports / _is_sports_card |
category / tag / bet prefix |
meta | sports layout | KEEP | KEEP-CLOSED | upstream category + own surface | – | not sports | |
_fold_cardtext / redundant label |
yes/no or title prefix | labels | hide a label row | KEEP | KEEP-CLOSED | closed vocab | – | shown | |
proposition_clause |
label in question | labels + title | clause text | KEEP | KEEP-CLOSED | substring of an upstream leg label in its own question | – | title | |
named_rank, title_rank, winner_rank (_RANK_RE, _RUNNER_UP_RE, _TOP_SLOT_RE, _THRESHOLD_*, _TOP_BOARD_RE) |
rank words | title | hero rank | HAIKU (cluster) | OWNED:W19-B1 | old-B1 row (measured: regex does not miss on 42,708 live strings, #3424 note) | – | – | |
award_slot / _AWARD_HEAD_RE |
winners / awards | title | award hero | HAIKU (cluster) | OWNED:W19-B1 | old-B1 row | – | – | |
split_rank_authority / _RANK_AUTHORITIES |
authority prefix | title | authority split | HAIKU (cluster) | OWNED:W19-B1 | old-B1 row | – | – | |
market_chart_tag (_YT_CHART_TAG_RE, _BILLBOARD_TAG_RE, _SPOTIFY_TAG_RE, _NETFLIX_TAG_RE) |
per-family template | event title | eyebrow tag | HYBRID | KEEP-CLOSED | one exact pattern per Kalshi series template; a miss gives the category block (absent) | – | category block | |
split_metric_title (_METRIC_WORDS, _METRIC_TITLE_RE, _METRIC_TAGS) |
Luminate / view-count metric | event title | metric / subject split | HYBRID | KEEP-CLOSED | anchored Kalshi metric template; a miss keeps the whole title | – | whole title | |
event_title_split (_EVENT_HEAD_RE, _EVENT_TAIL_RE, _EVENT_HEAD_BAD_RE, _TOP_LIST_HEAD_RE) |
event-word list | event title | event block | HAIKU (cluster) | OWNED:W19-B1 | old-B1 row (_EVENT_HEAD_RE is an open word list) |
– | – | |
_OUTCOME_VERBS cluster: outcome_split, _regex_split, _field_clause, _field_candidate, _field_split, outcome_subject, existential_question, _outcome_plural, outcome_caption, prime_outcome_splits |
232 verbs + anchors | title | hero + caption | HAIKU (B1 part-shipped #3424, #4209) | OWNED:W19-B1 | – | – | – | _field_split NEW (#4209) |
statement_title, how_much_title (_INTERROGATIVE_WORD, _HOW_QUESTION) |
question words | title | statement rewrite | HAIKU (cluster) | OWNED:W19-B1 | – | – | – | |
subject_hero ladder |
rung order | title | hero rung | HAIKU (cluster) | OWNED:W19-B1 | – | – | – | |
take_rank_conflict (_ORDINALS, _TAKE_RANK_RE, _FORMER_RANK_RE, _TAKE_RANK_WINDOW_WORDS) |
position near the subject | composed take + card hero | drop the “#N” hero | – | MODEL (#4538) | Haiku take_rank_place reads the place; the “#N” hero stays an exact regex; this rule is the error fallback |
– | hero dropped | NEW (#4383) |
swap_to_stated_alt |
figure stated in take | take + figure | swap the hero figure | – | OWNED:#4428 | number check | – | figure kept | NEW (#4383) |
_RANK_HERO_RE / _region_word |
“#N”, region words | title | hero region word | KEEP | KEEP-CLOSED | small closed set | – | none |
Structural: card_block / number_card_tag_rung ladder, emit_card_hero rung names,
_CONTAIN_SOURCES, _valid_http_url, _BARS_ONLY_SURFACES / _SURFACE_LABELS,
_SINGLE_LEG_HERO_MIN_PCT, SETTLED_LEADER_PCT / market_settled.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_is_generic_outcome (_GENERIC_OUTCOME_WORDS, _GENERIC_OUTCOME_RE) |
yes/no/month/number | leg label | skip as image subject | KEEP | KEEP-CLOSED | closed vocab | – | skip | |
_top_charted_leg, _featured_label |
label in title | labels | image leg | KEEP | KEEP-CLOSED | structural | – | first leg | |
_subject_query, _extraction_text |
prefix before “:” | title | text sent to image_subject |
KEEP | KEEP-CLOSED | feeds the model | – | whole title | |
detect_media_brand (_MEDIA_BRANDS, _BRAND_PATTERNS) |
16 platform aliases | title | org-logo rung 3b | HYBRID, then A9 KEEP | KEEP-CLOSED | runs only after image_subject named NOTHING (no_subject); the output set is closed to brands with a verified P154 logo; exact alias match |
– | branded floor | |
subtitle_catalog_hint |
”::” prefix | Kalshi subtitle | catalog rung | KEEP | KEEP-CLOSED | own encoding | – | none | |
is_youtube_video_market |
“music video” and “youtube” | title + event title | YouTube chart art rung (fail OPEN) | HYBRID | KEEP-CLOSED | Kalshi series wording; only selects an art lookup that verifies its own match (find_video_entry) |
– | next rung | |
youtube_chart_day / _CHART_DAY_RE |
date | title | chart-day window | KEEP | KEEP-CLOSED | date parse | – | not current (gated) | |
is_youtube_daily_chart_market (_YT_DAILY_CHART_RE) |
“daily … music video” | title | ADMITS a take to the fail-closed fabrication gate | HYBRID | MODEL-HAIKU | P2-A family call: one cached Haiku classify per event ticker, labels SLOT_TITLES / FIELD / BINARY / COUNT / OTHER; input = event title, leg title, 3 leg labels, series tags, and the current regex verdicts as a hint |
P2-A | model error: regex (today) | |
is_netflix_rank_market (_NETFLIX_RANK_LEAD_RE, “view” / “how many” excludes) |
netflix + show/movie + rank lead | title | admits to the gate | HYBRID | MODEL-HAIKU | P2-A family call | P2-A | regex | |
is_chart_slot_market (_MUSIC_SLOT_LEAD_RE, uses is_music_chart_market) |
rank lead + music chart | title | admits to the gate (every chart family, #3442) | – | MODEL-HAIKU | P2-A family call. A miss means the judge never reads the take, and the take ships unchecked | P2-A | regex | NEW (#3442, #4238) |
take_names_leader_only (_leg_phrase_in_take, _NON_AFFIRMATIVE_RE) |
leader phrase present, no rival phrase, no negation word | composed take + leg labels | FAST-PATH SHIP with no model call | – | MODEL-HAIKU | branch: the fast accept. Send every gated take to the existing market_take_names_leader (purpose market_take_check). Keep the phrase test as a logged agreement signal. _NON_AFFIRMATIVE_RE is an open negation list (“drops to”, “couldn’t hold on” are not in it) |
<=10 (bounded by gated takes; 303 drops shipped in 30d across all families) | judge error: drop (fail closed, today) | NEW (#3442, #4238) |
take_references_leg (_LEG_NOISE_WORDS, _LEG_QUALIFIER_RE, _PHRASE_MATCH_MAX_TOKENS, _POSSESSIVE_RE, fold helpers) via utils/youtube_grounding.take_names_a_leg |
phrase / token-bag identity | composed take + leg labels | DROPS a YouTube take that names no leg (market_alert non-leader YouTube lanes) |
HYBRID (C4 partial) | MODEL-HAIKU | branch: the no-match drop. Keep the phrase match as the fast accept; ask the same market_take_check judge (“does the take name one of these legs”) before a drop; feed the leg list |
<1 | judge error: drop (today) | |
resolve_market_image rung ladder |
routing | classifier output | image source | KEEP | KEEP-CLOSED | routing on image_subject |
– | branded floor |
Structural: _market_key, _subject_key / _cache_key, _download_raster checks.
Removed since the old audit: artist_subject_name, _ARTIST_COUNT_METRIC_RE,
_ARTIST_QUESTION_RE (no longer in the file).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
is_no_result lead word “none” |
NONE token | Sonar / Grok read | no result | KEEP | KEEP-CLOSED | protocol sentinel the query asks for | – | no result | |
is_no_result -> perplexity.is_hedged |
hedge phrase list | Sonar / Grok prose | treats a read as NO result, alone | KEEP | MODEL-HAIKU | branch: the hedge drop. Reuse claude.perplexity_found_answer (FOUND / NONE, purpose pplx_found_answer, B14) on the lead before the SOURCES block; feed _HEDGE_MARKERS as examples of NONE |
~2 (outcome_extract 3 + winner_extract 9 in 7d; move_news reads also pass here) | model error: hedge list (today) | |
cited_hosts / cited_host (_SOURCE_URL_RE, _X_HOSTS, _MARKET_HOSTS) |
URL hosts | read text | independent source | KEEP | KEEP-CLOSED | URL | – | not counted | |
_GENERIC_LABELS, DECIDED_LOCK_PRICE |
yes/no, price | labels / price | decided entity | KEEP | KEEP-CLOSED | closed / numeric | – | undecided | |
normalize_name / _in_field |
exact fold | winner index vs labels | winner leg | SHIPPED (A8) | KEEP-CLOSED | exact | – | no winner line | |
_MARKET_TALK / has_market_talk / market_talk_phrase |
%, kalshi, polymarket, market, odds, favourite, underdog, tracking, priced, betting | composed winner line | one re-ask, then drop | KEEP | MODEL-JEV | branch: the open words only (“market”, “odds”, “favourite”, “tracking”, “priced”, “bettors”). Keep %, percent, kalshi, polymarket exact. Jev Noul: “Does this line talk about a betting market, odds or a probability?” with the word list in the state as examples |
~2 | model error: today’s regex (re-ask, then drop) | |
_NONE_VERDICT |
NONE / “answer is none” | Sonar lead | move_news_line = None |
– | KEEP-CLOSED | protocol sentinel plus its two prose forms | – | no news line | NEW (#3783) |
lead_publisher (_SOURCE_LINE) |
[n] -> SOURCES line | Sonar read | publisher stamp | – | KEEP-CLOSED | structural | – | no line | NEW |
move_news_date, news_dates (_EVENT_DATE, _ISO_DATE, _WORD_DATE) |
dates | Sonar lead | date window | – | KEEP-CLOSED | date parse | – | None | NEW (#3760) |
check_news_qualifier |
qualifier check | news lead | cut a qualifier | – | OWNED:#4412 | – | – | – | NEW |
Structural: _SETTLED_STATUSES, encode_retry / hold_state state strings,
_CITATION_MARK, _MARKDOWN_EMPHASIS.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
stamp_is_redundant |
source word in eyebrow | own labels | hide a stamp | KEEP | KEEP-CLOSED | own strings | – | shown | |
_order_two_up / _side_tokens |
shared >=3-char token overlap | outcome labels vs matchup sides | which number sits under which crest | KEEP | REMOVED 2026-10-19 with the two-number cover layout (owner: “go back to lines”) | Measured 2026-10-18: 88 of 88 real Kalshi two-leg game events seat each number under its own crest; 0 errors. A same-city pair (“Los Angeles C” / “Los Angeles L”) never reaches it, because kalshi_game_teams returns no sides, and a no-match keeps the ranked order (safe). Old plan: a fuzzy identity join. First try the exact sportsdata.names.canonical_name fold (KEEP-CLOSED fast accept); on the residue, Jev Choice “which label is side X” over the two labels |
<2 | input order (today) | |
_lower_medium / _chart_medium |
plural rules | own tag | caption noun | KEEP | KEEP-CLOSED | cosmetic | – | tag |
Structural: _mark_is_dark, size / aspect math, font fit.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
alert_triggers.outcome_label (_TITLE_OUTCOME) |
“will X win” | Kalshi title | claim dedup key | HYBRID (cluster) | OWNED:W19-B1 | old-B1 row (0 of 28,116 legs lack yes_sub_title, so the title path never runs) |
– | yes_label | |
kalshi_price trusted-price rules (WIDE_SPREAD, LAST_TRADE_TOL, bid_supported, book_backs_move) |
price thresholds | order book | trusted price | KEEP | KEEP-PROTECTED | price threshold | – | dropped rung | |
market_sibling_claims.same_subject_posts (_QUOTED, _TITLE_BY) |
quoted title, “ |
our own market posts | NOMINATE siblings for market_sibling_claim (Haiku SAME / CONTRADICTS / DIFFERENT) |
– | DONE | nominate-only; the extractors parse our own post shapes | ~0.4 | no match = ships | NEW (#2016) |
Structural: market_triggers.classify_market_event bands, charted_move; market_siblings
group-by; alert_triggers.claim_key.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
is_ladder_rung (_NUMERIC_STRIKE_TYPES, _THRESHOLD_LABEL_RE) |
strike_type + above/below words | Kalshi meta + label | rung vs leg | KEEP | KEEP-CLOSED | upstream enum + fixed strike phrase | – | outcome | |
_rung_subject / rungs_share_subject (_STRIKE_PHRASE_RE, _STRIKE_NUMBER_RE) |
strike words + numbers | rung labels | same ladder | KEEP | KEEP-CLOSED | number strip | – | separate cards | |
ladder_unit, is_bucket_leg |
%, $ | label | unit | KEEP | KEEP-CLOSED | format | – | none | |
date_rung_deadline, is_date_ladder, is_threshold_ladder, is_threshold_family |
dates | labels | ladder shape | KEEP | KEEP-CLOSED | date parse | – | threshold | |
_COMPANION_LADDERS, companion_event_matches, companion_outcome_matches, companion_outcome_period_end |
ticker registry; subject+period substring; equality | Kalshi subtitles | companion pairing | KEEP | KEEP-CLOSED | one Kalshi template; companion_pair event watches template drift (#3458) |
– | no pair | |
ladder_is_decided, bucket_is_decided |
price thresholds | prices | decided | KEEP | KEEP-PROTECTED | price threshold | – | none |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_POLY_TAG, _GAME_RISK_CATEGORIES, _REPORT_CATEGORIES / _is_report_lock, _POLY_GAME_TAG |
category / tag | upstream category | drop family | KEEP | KEEP-CLOSED | upstream enum (_is_music_chart part is in market_cards) |
– | default | |
_take_catalog_hint |
image_subject kind |
model output | catalog rung | KEEP | DONE | model already decides | – | none | |
_slot_figure / _RANK_WINNER_TITLE_RE |
rank words | title | rank-winner figure | HAIKU (cluster) | OWNED:W19-B1 | – | – | – | |
titled_leg yes/no |
closed set | labels | named leg | KEEP | KEEP-CLOSED | – | – | – | |
_source_artist |
split “::” | Kalshi subtitle | crediting artist | KEEP | KEEP-CLOSED | own encoding | – | ”” | |
_companion_names_artist |
artist substring in leg title | Kalshi leg titles | companion pairing (number on card) | KEEP | KEEP-CLOSED (fix) | substring today (“Future” in “Future Islands”). Closed fix, no model: parse the “BY |
– | no pair | |
_is_single_game / _DRAW_LABEL_RE |
draw/tie | labels | single game | KEEP | KEEP-CLOSED | closed set | – | field | |
_clean_side, _matchup_sides, _slate_pairs, _matchup_covered (_MATCHUP_RE, _SIDE_*) |
canonical team names | game titles | one drop per game | KEEP | KEEP-CLOSED | exact canonical_name keys |
– | both post | |
_norm_topic |
strip “the “ | topic | dedup key | KEEP | KEEP-CLOSED | fold | – | raw | |
_kalshi_event_subject / _KALSHI_TITLE_SUBJECT |
“win (the) X” | title | topic subject | HYBRID | OWNED:W19-B1 | – | – | – | |
_chart_slot_gateable + the gate call (yt_chart or _chart_slot_gateable) |
family detectors + fast accept | snapshot + take | whether the take is judged / ships | HYBRID (DONE #3442) | MODEL-HAIKU | P2-A (caller side of the family call and the fast-accept removal) | P2-A | fail closed | |
_FIGURE_RE / _withhold_figures |
number formats | own prior posts | mask figures in the history block | – | KEEP-CLOSED | number format | – | – | NEW (2026-09-18 steer) |
Structural: price-shape helpers (_is_competing_field, _is_threshold_leg,
_is_priced_threshold_ladder, _is_flat_wall, _is_unpriced_board, _frontrunner…),
_alert_already_said (exact claim compare), CHILL / YAPS times. Calls into
output_checks (drop_self_correction = OWNED:#4422, has_cross_source_comparison,
ungrounded_numbers) belong to the output-checks partition.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_GENERIC_LABELS, _PULSE_SUBTAGS / _is_pulse_market |
closed sets | labels / tags | pulse lane | KEEP | KEEP-CLOSED | – | – | – | |
_clean_authority |
authority prefix | title | prose subject | HYBRID | OWNED:W19-B1 | – | – | – | |
_headtohead_favorite (_VS_SPLIT) |
label in “A vs B” side | event title + label | favorite side | KEEP | KEEP-CLOSED | Kalshi “A vs B” template; the label is that side’s own name | – | no favorite | |
_forecast_figure (_LABEL_UNIT, _UNIT_SUFFIX) |
million/billion | rung label | unit | KEEP | KEEP-CLOSED | format | – | – | |
_quotes_range |
numbers in line | take | drop on wrong range | KEEP | KEEP-CLOSED | number check | – | drop | |
_race_label, _named_leg_event |
labels | labels | race framing | KEEP | KEEP-CLOSED | – | – | – | |
_non_leader_reason, ending-soon leader compare |
exact label | labels | leader identity | KEEP | KEEP-CLOSED | exact | – | – | |
_ending_soon_subject |
title | title | subject | HYBRID | OWNED:W19-B1 | – | – | – | |
has_self_correction |
output_checks | take | drop | KEEP | OWNED:#4422 | – | – | – | |
_CAUSE_BANS / _news_context |
exact prompt strings | our own blob | lift a ban | – | KEEP-CLOSED | own prompt text | – | – | NEW (#3363 follow-up) |
_leader_check (is_youtube_daily_chart_market or is_chart_slot_market, take_names_leader_only) |
family + fast accept | snapshot + take | ship / drop | – | MODEL-HAIKU | P2-A (alert caller) | P2-A | fail closed | NEW (#4239, #4272) |
qualifier_trim.restates_cut + check_news_qualifier |
qualifier words | take | drop | – | OWNED:#4412 | – | – | – | NEW |
Structural: _PUBLIC_DELIVERIES, _settled_out, _soft_priced, _headline_license
thresholds, context prompt constants, retry:hunting: state prefix.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
bookie._winning_team / _split_matchup (+ is_single_leg_knockout, knockout_advancer) |
scores + “ @ “ | feed scores | who won -> payout | KEEP | KEEP-PROTECTED | settlement | – | void / push | |
bookie._WORLD_CUP_FOOTBALL_LEAGUES, _KNOCKOUT_NATIONAL_LEAGUES, _THREE_WAY_SPORTS, _ODDS_API_* |
league ids | own enums | knockout + 3-way settlement, odds feed | KEEP | KEEP-PROTECTED | settlement / pricing | – | – |
Structural: bookie stake presets, _line_is_known_stale, _is_degenerate_side,
_needs_pricing, legacy key split; betting_board _SPORT_SUBJECT_WORD,
_BOOK_LINE_NON_SPORTSBOOK, _PREDICTION_VENUE_LABELS, is_effectively_decided;
betting_alert _favorite, _classify_move, _has_started; betting_value coherence /
edge math; called_shot verdict_for, pct_error, SCORECARD_COLUMNS (no name
matching); bet_corrections.STRANDED_BETS data; odds_adapt source routing;
odds_compare, leaderboard, table_card, ranking_strip math / rendering.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
story_signature / dedup_key (_STOPWORDS, _TOKEN_RE, _SIGNATURE_TOKENS=5) |
first 5 non-stopword tokens | wire post | SKIP a story whose key matches a recent post (recent_sports_desk_events), and within a slot |
KEEP | MODEL-HAIKU | branch: the key-collision drop only. On a key hit against a recorded moment, ask the existing topic_duplicate (Haiku) with both texts; the stopword list stays the key builder. Needs the recorded headline stored beside the key |
<1 (18 desk posts in 30d) | model error: skip (today) | |
is_postable_moment |
not reply, >=24 chars | wire post | postable | KEEP | KEEP-CLOSED | length | – | skip | |
SPORT_BY_HANDLE |
handle map | author handle | sport tag | KEEP | DONE | B8: the model tags every story; the map decides only a story the model did not place | – | – | |
classify_sport (_SPORT_KEYWORDS) |
~250 words | headline | sport tag | SHIPPED (B8) | DONE | fallback under classify_sports_beats (sports_beat 83 calls / 7d) |
~12 | regex |
Structural: sport_penalty, apply_sport_diversity.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
sports_desk retrospective_note / retrospective_frame / frames_as_past calls |
retrospective.py | wire text / take | throwback framing + drop | see retrospective | OWNED:W19-B3 | – | – | – | |
api_sports._team_logo_from_rows |
exact casefold name | /teams rows |
crest | KEEP, flag | KEEP-CLOSED | fixed #3453: no exact match -> None | – | absent | |
api_sports status-code sets (_FOOTBALL_*, _BASKETBALL_*, … _TEAM_STATUS_SETS) |
status.short enum | API-Sports | live / done -> settlement | KEEP | KEEP-PROTECTED | settlement | – | – | |
espn.match_team_logo |
canonical_team or exact short; 2+ hits -> “” |
side name vs ESPN teams | crest | KEEP | KEEP-CLOSED | exact folded keys; ambiguity refuses | – | ”” |
Structural: sports_desk._VISION_HOSTS; api_sports _count_goal_events, _event_kind,
WNBA “ W” suffix, stat labels / leader thresholds, _response_error, _TEAM_IMAGE_HOSTS;
espn _ENDPOINTS, _SINGLES_SLUGS, _competitor_name, TEAM_LEAGUES, stat names,
_leader_display, odds math; highlightly _HOSTS, type == VERIFIED;
cogs/sports_boards _ODDS_KINDS, _CHANGE_GATED_KINDS, dedup key format,
_ODDS_PROP_MARKETS, _SGO_BOARD_LEAGUE, date filters, side == “Over” (its
has_self_correction call is OWNED:#4422, counted in output_checks);
utils/sports_boards floors, short_stat, join keys, _game_line_figure,
league_is_live, streak / record parsing, _with_implied_pct, upcoming_board hero rules.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
names.canonical_team / canonical_name / canonical_fighter / canonical_soccer_club (+ _SOCCER_CLUB_TOKENSET token-set index, espn_team_name) |
alias tables, exact fold, token-set equality with an ambiguity guard, initial+surname | provider team / fighter names | match_key -> bet settlement, hub dedup |
– | KEEP-PROTECTED | settlement identity; a miss voids (never mis-pays) | – | void | NEW to audit (#4327 token-set) |
names.kalshi_game_teams / _league_team / _MATCHUP_SPLIT_RE |
ticker league + unique roster resolve; a soccer series (_KALSHI_SOCCER_SERIES) passes the two club names through |
Kalshi ticker + title | crest pair on a market card | – | KEEP-CLOSED | exact roster resolve; both sides must resolve uniquely (soccer: both must match inside one ESPN league) | – | None (branded floor) | NEW to audit |
format.is_knockout_round, _is_final_round, _KNOCKOUT_ROUND_KEYWORDS, _TWO_LEGGED_NAME_HINTS, _is_two_legged_competition |
round-label and league-name substrings | API-Sports league.round / league name |
draw suppression -> 2-way vs 3-way settlement and pricing | – | KEEP-PROTECTED | settlement | – | keep the draw | NEW to audit |
format.fold_prediction_as_line, fold_prediction_match_winner, prediction_line_odds |
canonical_team mapping |
prediction outcomes vs game sides | the bettable line | – | KEEP-PROTECTED | money path (pricing) | – | no write | NEW to audit |
format “own goal” in e.detail |
upstream detail text | API-Sports event | own-goal label | – | KEEP-CLOSED | upstream field | – | – | NEW to audit |
providers._espn_event_kind |
goal / card / substitution in type.type |
ESPN keyEvent type | event kind | – | KEEP-CLOSED | upstream enum | – | drop incident | NEW to audit |
Structural: board stat / period labels, _ODDS_BOARD_MARKETS; cadence
_BASKETBALL_PERIODS; competitions registry; format _SPORT_LABEL, _DAY_WORDS,
_STAT_ORDER, _EXCHANGE_LABELS, _LINE_KEYS, _MONEYLINE_KEYS, _DRAW_SPORTS, draw / tie
label checks, “player “ prefix; hub _SGO_SIDED_SWAP, _SGO_UNSIDED_KEYS; models
status code sets, match_key_parts; names rosters / aliases / _QUIRK_OVERLAY /
_CODE_SYNONYMS; odds_health key checks; providers _EXTRA_SPORT_FETCH,
_ODDS_SPORT_TAG, _ESPN_PERIOD_PREFIX, _ESPN_TEAM_STAT_LABELS, _ESPN_LEADER_ABBR, clock
regex; sources capability sets, _SETTLEMENT_PRIORITY; sports watch keys and league
id sets.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
utils.playercard.about_member_text (_SENT_SPLIT, names.name_pattern / match_forms) |
exact alias forms | memory notes + aliases | sentences fed to the Opus blurb | KEEP | KEEP-CLOSED | exact alias match; the model judges after | – | ”” | |
utils.playercard.board_ranking / format_card_pages aliases |
closed alias sets | model tool argument | board / page | KEEP | KEEP-CLOSED | closed-label parser with a self-describing miss | – | hint | |
cogs.playercard._who_autocomplete |
fold contains | keystrokes | autocomplete list | KEEP | KEEP-CLOSED | search fold; the user picks | – | [] | |
cogs.playercard._resolve_target |
fold exact, then FIRST contains-hit | /playercard text | whose card renders | KEEP | KEEP-CLOSED (CB-31) | Measured 2026-10-18 and FIXED in code: best_name_match adds two exact start steps (whole name, then a word) before contains. 517 queries from the real roster: 12 better, 1 tie changed, 0 other worse. Jev Choice 10 of 11 and Haiku 9-10 of 11 on the decidable ties, the start steps 11 of 11. Old plan: fuzzy identity join. Exact fold stays the fast accept; when 2+ members contain the text, Jev Choice over those display names (closed list) |
<1 | not_found / first hit (today) | |
cogs.playercard._resolve_member_id |
exact name, else FIRST substring | /ask engagement tool target |
whose stats the tool reads | KEEP | KEEP-CLOSED (CB-31) | Same best_name_match as _resolve_target (CB-31). Old plan: same shape as above (“sam” -> “samantha” before “sam”) |
<1 (engagement tool: 4 calls in 30d) | first hit (today) | |
cogs.playercard scope / board aliases |
closed sets | model tool argument | scope / board | KEEP | KEEP-CLOSED | – | – | hint |
Structural: _STATS weights, archetype_for, _BADGE_RULES, top_public_channel,
_SUPERLATIVES; cog aspect in (member, card).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_FRAMES / is_retrospective / retrospective_frame / retrospective_note / _TAG_RE |
anchored throwback leads | wire text | throwback instruction | HAIKU (B3) | OWNED:W19-B3 | – | – | – | |
states_past_interval / _PAST_INTERVAL_RE |
“N years ago” | wire text | cover vs photo | HYBRID | OWNED:W19-B3 | – | – | – | |
frames_as_past / _PAST_MARKERS / _FUNCTION_WORD / _ANNIV_COUNT |
past markers | take | drop | HYBRID | OWNED:W19-B3 | – | – | – | |
retrospective_values, look_back_values, _interval_count, _COUNT_WORDS |
numbers | phrase / take | number grounding | KEEP | OWNED:W19-B3 | the brief keeps the arithmetic (number check) | – | – |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
steam_art.pick_app / _fold |
exact alphanumeric fold, 2+ hits -> None | leg name vs Steam names | appid art | KEEP | KEEP-CLOSED | exact identity; image_subject kind=video_game gates the rung (Uno incident) |
– | None |
Structural: steam_art.first_screenshot, _LIBRARY_URL; entity_image _SPORT_SEARCH_WORD,
subject_search_query (artist-in-name query build), _deterministic_art kind ladder,
_artist_rung, _BRAND_SUFFIXES, _card_bare_logo, _team_fallback_card,
_resolve_primary order (all routing on image_subjects output); scrapecreators
tweet / TikTok / IG shape maps, _IG_MEDIA_TYPES, short-link host rewrite,
FailoverProvider._active, credits_remaining key.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
image_gen._is_safety_reject / _SAFETY_SIGNATURES |
“safety”, “moderation”, “content policy” substrings | OpenAI 400 body | fail over to Grok | KEEP | KEEP-CLOSED | upstream error text. Better closed key: the error body’s code field (content_policy_violation) |
– | no failover | |
audio_tags.filter_to_allowlist / ALLOWED_TAGS / _TAG_RE |
11-tag allowlist | model output | which [tag] reaches ElevenLabs | KEEP | KEEP-CLOSED | closed allowlist on a model-output protocol | – | drop tag |
Structural: vision_image (magic bytes, SUPPORTED_MEDIA_TYPES, pbs host bound,
redirect codes), xai_image._ASPECT_RATIOS, image_gen _ASPECT_SIZES / _FAILOVER_KINDS,
image_inspect colour anchors and grid thresholds, grid_vision thresholds,
image_hash threshold, image_codec limits; media_edit (_OP_SPECS, HEIC brands,
extensions, _COPY_CONTAINERS, clamps), video_trim._PTS_RE, clip_pick (_PTS_RE,
_LOUD_RE, marker keys), video_fetch (host lists, _YOUTUBE_ID_RE, caption language
order, VTT parsing, X length limit), video_ingest (_enabled, _needs_summary),
audio ffmpeg args.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
radio.COVERED_FORMATS (+ CUT_FORMATS) |
3 Mediabase formats | upstream format name | which charts make stories | KEEP | KEEP-CLOSED | upstream format enum, owner-curated | – | out (absent) | |
radio.standing |
song_key equality + artist_watch.credit_matches |
Mediabase rows | radio context block | KEEP, flag | KEEP-CLOSED | fixed #3454: exact house identity | – | ”” | |
artist_socials._ARTIST_SOCIALS / socials_for / name_for_handle |
curated map, exact fold | artist name / handle | official accounts | KEEP | KEEP-CLOSED | curated on purpose (a guessed handle seeds an impersonator) | – | skip |
Structural: radio spin / add thresholds, _KIND_EYEBROW, card_fields, board_groups
(shared identity home).
All Axiom queries are on dataset tootsies. “30d” = now-30d to now (2026-10-18).
claude_api | summarize count() by purpose, 7d. In scope: market_sport_check 4027,
image_subject 276, market_act_check 470, sports_beat 83, market_intent 59,
market_runner_up_check 15, winner_extract 9, outcome_extract 3,
market_take_check 2, drop_score 169, sports_desk_score 30. Decides: the take judge
runs about twice a week, so removing the fast-path accept (P2-A) adds calls bounded by
the gated takes, not by all posts.market_label_check | summarize count() by purpose, reason, 30d:
market_runner_up_check cut 893, kept 0; market_sport_check same 42,006, changed
13,165, judge_failed 1; market_platform_check 0. Decides: the runner-up judge has
never overruled a nomination, so sending the music-cue hits to it (P2-B) is cheap and
only adds cuts on false cue hits. The platform check has had no input in 30 days.tool_call | summarize count() by tool, 30d: chart_history 71, search_messages 29,
look_at_image 8, engagement 4, spotify_chart 1, box_score 1, game_plays 1. No
kalshi_* or SGO tool call. Decides: kalshi_channel_routing, derive_kind_tags,
the detect_league fast accept in sgo_snapshots, the “kalshi” source-order test and
the kalshi_player_props token guard are DEAD paths (KEEP, revisit on traffic). The
two playercard resolvers see under 1 call a day.market_drop_scored | summarize total, shipped, leader-gate declines, 30d: 1,375 rows,
303 shipped, 0 leader_fabrication / leader_check_unavailable. Decides: the volume
bound for P2-A (at most about 10 gated takes a day), and that the gate never fired in 30
days (every gated take went through the regex fast path or the judge passed it).market_filtered | summarize count() by reason, 30d: non_leader_chart 3,290,
netflix_views 276 (plus price and horizon reasons). Decides: the runner-up cut is
active; the music exemption decides before the judge on every ranked music board.error | where source in (markets_classifier, markets_manager), 30d: 0. Decides: the
classify_intent regex fallback inside _classify never ran (DONE, fallback only).claude_api 30d, market_intent 135, image_subject 497, sports_beat 83,
topic_dedup 13,611. Decides: per-call volumes used in the batch table.surface == 'sports_desk' or event startswith 'sports_desk', 30d: 18
sports_desk_posted, 531 slot_muted. Decides: the sports-story signature dedup
(P2-D) is low impact.classify_intent and
looks_like_sports return sports for “general-chats”, “stats-and-facts”, “conflict
zone”, “nuclear takes”, “comma club”, “gamma rays”, “whats good”, “beats and bars”;
_looks_like_music returns True for “#2 Most Streamed Show: Trap”, “Runner-Up Netflix
Show: Songs of Freedom”, “#2 Google search: Grape”. Decides: P2-B brittleness = M (raw
substring tests, not word boundaries).Merged into the Part 0 batch plan.
take_names_leader_only ships a take with no model call when the leader’s phrase is
present, no rival phrase is present, and none of about 18 negation words (_NON_AFFIRMATIVE_RE) appears. The judge
then ran only 2 times in 7 days. A sentence such as “Dai Dai drops to No. 2 as a
non-leg video takes the top spot” names the leader, names no rival leg, and carries no
listed negation word (“drops” is not in _NON_AFFIRMATIVE_RE), so it ships unchecked.
This is a reasoned case, not a production incident: 0 gate declines in 30 days.is_chart_slot_market and its siblings
decide whether the judge sees a take at all. They were widened four times by Codex
review (#2525, #2538, #3442, #4238). A Kalshi chart family whose title does not lead
with the expected rank framing is not gated.classify_intent
("ats" in q, "nfl" in q, "ucl" in q, "mma" in q) and _looks_like_music
("rap", "song") match inside other words. classify_intent is safe where it is the
model fallback (it never ran in 30 days), but it also gates two discourse paths alone.kalshi_channel_routing, derive_kind_tags, tags_for’s
routing caller, and MarketsManager.kalshi_category_markets serve only the /ask
topic argument; the /ask kalshi tools had 0 calls in 30 days, and the drop passes
topic=None. Same for kalshi_player_props and the SGO tool’s league fast accept.utils/sportsdata/. It holds the settlement identity
(canonical_team, the #4327 club token-set index, canonical_fighter) and the
knockout-round substring lists that switch a soccer line between 2-way and 3-way. All
are KEEP-PROTECTED (money path). is_knockout_round reads API-Sports round labels with
substrings (“round of”, “semi final”); a new label spelling keeps the draw (safe
direction for settlement).market_subject_image.artist_subject_name and its two
regexes are gone. api_sports._team_logo_from_rows and radio.standing were fixed to
exact matches (#3453, #3454), as the old audit asked.utils/market_sibling_claims.py (#2016). It is
nominate-only (quoted title / “Title by Artist” opening from our own posts, Haiku
decides). A sibling post that quotes no title is never compared (fail open).market_drop._companion_names_artist is a substring identity (“Future” inside
“Future Islands”). It does not need a model: Kalshi’s leg template states the credit
(“BY ROD WAVE have above”), so an exact parse of that slot closes it.market_cards.is_music_chart_market sits in W19-B1’s file. P2-A reads it but should
not edit the outcome cluster; a tag-based rewrite of lines 161-189 is the cleanest split.utils/media_signal.py (the <media> tag parser) is a model-output protocol parser
(KEEP-CLOSED). It was not in this partition’s old list and is likely covered with the
other *_signal parsers.output_checks.has_cross_source_comparison,
ungrounded_numbers, has_row_tally, has_row_arithmetic from market_drop and
sports_boards; rt_reconcile from market_alert; music_markets art helpers from
market_drop.Repo state: branch claude/classifier-audit-wave19 = origin/main 4e1b6c0. Read-only pass. Old audit section: docs/CLASSIFIER_AUDIT.md lines 1174-1506. Axiom window: 30 days to 2026-10-18 unless a row says 7 days.
Ownership applied:
_SELF_CORRECTION_RE,
has_self_correction, decline_narration_hits, _MARKET_DECLINE_RE,
claude_client._SELF_CORRECTION_MARKERS, wheel narration).has_career_claim, has_alltime_claim and every
ungrounded_* claim check (old row C8), plus unsupported_rank_claims (#4471) and the
qualifier-feeding banger_subject. These are in no batch.| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| claude_client.py | 16 | ~30 | 10 | 0 | 0 | 2 | 2 | 2 |
| utils/output_checks.py | 30 | 8 | 7 | 10 | 0 | 2 | 1 | 10 |
| utils/slop_score.py | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/x_reply_draft.py | 1 | 3 | 0 | 0 | 1 | 0 | 0 | 0 |
| cogs/x_reply_draft.py | 1 | 3 | 0 | 0 | 0 | 0 | 0 | 1 |
| utils/perplexity.py | 4 | 3 | 0 | 2 | 0 | 0 | 2 | 0 |
| utils/dedup.py | 4 | 4 | 1 | 1 | 0 | 0 | 2 | 0 |
| utils/engagement.py (+ engagement_labels) | 3 | 3 | 0 | 0 | 0 | 0 | 3 | 0 |
| utils/curator.py, cogs/curator.py, cogs/curate.py | 1 | 4 | 0 | 0 | 0 | 0 | 1 | 0 |
| utils/curate.py | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/x_mentions.py | 3 | 5 | 0 | 0 | 0 | 0 | 3 | 0 |
| cogs/x_mentions.py | 2 | 5 | 2 | 0 | 0 | 0 | 0 | 0 |
| utils/x_crosspost.py | 1 | 6 | 0 | 0 | 0 | 0 | 1 | 0 |
| utils/x_game.py, cogs/x_game.py | 2 | 4 | 1 | 0 | 0 | 0 | 1 | 0 |
| utils/reference.py | 3 | 4 | 0 | 3 | 0 | 0 | 0 | 0 |
| cogs/games.py | 4 | 4 | 2 | 0 | 1 | 0 | 1 | 0 |
| utils/wheel.py | 1 | 2 | 0 | 0 | 0 | 0 | 0 | 1 |
| cogs/awards.py | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/starboard.py, cogs/starboard.py | 2 | 6 | 1 | 0 | 1 | 0 | 0 | 0 |
| utils/roles.py, cogs/roles.py | 2 | 4 | 1 | 0 | 0 | 1 | 0 | 0 |
| cogs/chimein.py | 1 | 3 | 1 | 0 | 0 | 0 | 0 | 0 |
| cogs/memory.py + memory utils | 1 | 4 | 0 | 0 | 0 | 1 | 0 | 0 |
| cogs/ask.py | 4 | 8 | 2 | 1 | 0 | 0 | 1 | 0 |
| cogs/commentator.py | 1 | 6 | 0 | 0 | 0 | 0 | 1 | 0 |
| cogs/scheduled_poster.py, utils/abuse_tracker.py | 2 | 2 | 0 | 0 | 0 | 0 | 2 | 0 |
| cogs/order.py | 1 | 2 | 0 | 0 | 0 | 1 | 0 | 0 |
| utils/image_signal.py (+ voice/gif/emoji tag files) | 1 | 9 | 1 | 0 | 0 | 0 | 0 | 0 |
| the other ~40 files (structural only, see Inventory) | 0 | ~60 | 0 | 0 | 0 | 0 | 0 | 0 |
| total | 94 | ~205 | 32 | 17 | 3 | 7 | 21 | 14 |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
is_empty_response |
EMPTY exact / prefix / last sentence |
model output | skip slot | KEEP | KEEP-CLOSED | sentinel protocol | - | skip | |
_SELF_CORRECTION_MARKERS, _strip_self_correction, _after_correction_clause |
16 lowercase phrases | model output | keep last paragraph | HYBRID | OWNED:#4422 | - | - | ship | |
_parse_wheel_items + _WHEEL_*_WORKING_TASK |
has_self_correction + is_narration, then classify(decline_narration) |
wheel lines | drop slice | HYBRID | OWNED:#4422 | already a Haiku label behind the lists | - | keep slice | |
_final_card_line, _extract_track_line, _extract_xpost_directive |
EMPTY, TRACK:, XPOST: tags |
model output | split / link / crosspost mode | KEEP | KEEP-CLOSED | protocol tags | - | no link | |
_TRENDING_LABEL_LEAK, _clip_for_reaction |
[A] / clip A leak; link in text |
react output | retry | KEEP | KEEP-CLOSED | scaffolding leak, structural | - | ship | |
_parse_* closed-set validators (market_intent, mention_intent, music_mention, music_news, image_subject, video_subject, sport_beats, gif_pick, picked_tickers, album_track_matches, keyword_terms, song_pool, scored-JSON spine, topic_duplicate, qualifier_verify, names_leader, outcome_value, winner_pick, match_verdict) |
enum / JSON literal checks | model output | route / drop | KEEP | KEEP-CLOSED | model-output protocol | - | per method | |
_parse_x_post unit_from |
model-quoted words must be a substring of the story and not of the title/artist | Haiku classify_x_post reply + story |
keep song/album unit | - | KEEP-CLOSED | grounding of a model quote in its source (exact containment) | - | unit “” | NEW |
_artist_named_in, _artist_named_in_strict, _mark_grounded_artists |
folded whole-word containment | model artist vs source | artist_grounded stamp |
KEEP | KEEP-CLOSED | exact folded grounding check outside the model (#2691) | - | ungrounded | |
_has_perplexity_grounding (forced retry) |
is_hedged |
Perplexity block | skip forced web_search | HYBRID | DONE (B14 #3437) | _perplexity_grounded -> Haiku perplexity_found_answer first, list on None |
0 in 30d (pplx_found_answer purpose absent) |
retry | |
draft EMPTY / len > 400 |
prefix + length | X reply drafts | drop draft | KEEP | KEEP-CLOSED | protocol + length | - | drop | |
preflight_order verdict parse |
ALLOW/PLUMBING/REJECT prefix |
Sonnet output | /order gate | KEEP | KEEP-PROTECTED | protected path | - | reject | |
label parses (classify_abuse ABUSE, wire_subject_named NO, media/clip/admat/identity YES/NO/DIFFERENT, classify() prefix match) |
prefix on upper-cased label | model output | label | KEEP | KEEP-CLOSED | closed-label parser | - | per method | |
_IMAGE_FAILURE_PHRASES, _GENERIC_FAILURE_PHRASES, _IMAGE_BLOCK_RE, _is_image_error |
API error substrings | Anthropic 400 text | drop one image | KEEP | KEEP-CLOSED | upstream error vocabulary | - | not image error | |
_MEMORY_FENCE |
prompt text | - | - | KEEP | KEEP-PROTECTED | constitutional | - | - | |
_WORKING_LABEL_RE |
^WORKING: on scorer reason |
Haiku scorer reason | tag a WORKING fail | - | KEEP-CLOSED | model-output protocol | - | - | NEW |
model judges added since 09-18 (claim_grounded, universal_scope_claim, is_flourish_clause, is_music_artist_mention, perplexity_found_answer, _SHOWS_ITS_WORKING_RULE, _IDENTITY_RULE) |
- | - | - | - | DONE | these ARE the model side | see Measurements | - | NEW |
Structural: fence-strip / first-{...} regexes in every _parse_*, _BARE_INT_KEY, _MARKET_PCT_RE, capability sets (_SAMPLING_MODELS, _THINKING_OFF_PARAM, _NO_FORCED_TOOL, _ALWAYS_THINKING, _OPENAI_TRUNCATED_STOPS, _OPENAI_MODEL_IDS, _RETRYABLE_STATUS), tool type.startswith("web_search"), robots.txt/disallowed exception text, URL strip in tool messages, memory_rollup stop reason, _format_kalshi_candidate substring, all *_TOOL schemas. Cross-partition note: _parse_music_news calls music_news.later_week_first_week_claim and FIRST_WEEK_PHRASE_RE (music partition owns them).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_TOOL_NARRATION_RE, has_tool_narration |
first-person tool verbs | model output | check_text flag |
KEEP | KEEP-CLOSED (DEAD) | no production caller; only tests | 0 | - | |
_THINK_PIECE_WORDS, think_piece_hits, check_text |
9 critic words; dispatcher | model output | flag | KEEP | KEEP-CLOSED (DEAD) | no production caller; delete or wire | 0 | - | |
_SELF_CORRECTION_RE, _DRAFT_SEPARATOR_RE, has_self_correction |
correction markers | model output | drop | HYBRID | OWNED:#4422 | - | - | drop | |
_ALLTIME_CLAIM_RE, _POSSESSIVE_*, has_career_claim, career_claim_hits, career_claim_ungroundable, has_alltime_claim, has_ungrounded_career_claim |
superlative / ordinal regex | model output | drop | HYBRID (C8) | OWNED:#4412 | - | 3,428 drops / 30d (career_claim) |
drop | |
_DECLINE_NARRATION_RE, _POS_PAIR_RE, decline_narration_hits, has_decline_narration |
decline verbs + objects | model output | drop | HAIKU (B4) | OWNED:#4422 | - | 6 drops / 30d (newsroom) | drop | |
_MARKET_DECLINE_RE, market_decline_hits, has_market_decline |
decline verb + figure | model output | drop | - | OWNED:#4422 | - | - | drop | NEW |
_PRIOR_POSITION_RE, prior_position_hits (phrase arms), has_prior_position |
“last week”, “was #9”, “after ranking”, “previously” | fall take | drop (fall lanes) | - | MODEL-HAIKU | classify on a regex HIT only: “does LINE state the title’s earlier chart position or an earlier week?” labels PRIOR / CURRENT_ONLY; the phrase list fed as examples. Miss branch: one rubric line in music_desk_score (0 calls). Coordinate with #4422 (same lanes, same ship_guard). |
5 drops / 30d -> ~0.2 | drop on error | NEW |
_ANY_POS_RE arm of prior_position_hits (current=) |
any other #N than the take’s rank |
fall take | drop | - | KEEP-CLOSED | number compare | - | drop | NEW |
_ROW_ARITHMETIC_RE, has_row_arithmetic |
combined / double / 3x / half | board take | drop | (KEEP) | MODEL-HAIKU | classify on HIT: “does LINE add rows up or state one row as a multiple of another?” SUM_OR_RATIO / OK; exemption list (cert levels, “double album”, HITS Daily Double) fed. Miss branch: rubric line. |
0 desk drops / 30d -> ~0 | drop on error | |
_HITS_SOURCE_RE, names_hits_source, _MARKET_SOURCE_RE, _CROSS_SOURCE_COMPARATIVE_RE, _SETTLED_COUNT_RE, has_cross_source_comparison |
three regexes must all hit; settle exemption | desk take | drop (owner ban) | HYBRID (C8, not wired) | MODEL-HAIKU | classify on HIT: “does LINE weigh a prediction-market figure against HITS Daily Double’s figure?” COMPARES / OK. Miss branch: rubric line. |
0 drops / 30d (music_desk), market_drop also calls it | drop on error | |
_STREAM_FIGURE_RE, _UNITS_FIGURE_RE, _STREAM_UNIT_RANKING_RE, has_stream_unit_comparison |
units fig + stream fig + ranking word | desk take | drop | - | MODEL-HAIKU | same shape: “does LINE rank a units/sales figure against a stream count?” | 0 / 30d | drop on error | NEW |
_ROW_TALLY_RE, row_tallies, ungrounded_row_tally |
“N of the top 10” vs source | board take | drop | KEEP | OWNED:#4412 | (number check; KEEP-CLOSED in substance) | 0 / 30d | drop | |
has_row_tally (sports_boards, cinema_desk) |
“N of the top M” | board take | drop | KEEP | KEEP-CLOSED | fixed count format | - | drop | |
_IDENTITY_FAMILIES, _IDENTITY_SUBSET_RE, identity_subset_hits, has_identity_subset_claim |
rank word + lowercase gender word, source grounding | take | drop | - | KEEP-PROTECTED | constitution-adjacent hard fail; the model _IDENTITY_RULE already decides every desk/drop post beside it (#4261/#4276) |
0 / 30d | drop | NEW |
_HITS_VERBS, _HITS_PUBLISHER, _ATTRIBUTION_TAG_RE, attribution_tag_hits, has_attribution_tag |
source names + reporting verbs + possessive | numbers take | re-ask then drop | KEEP | MODEL-HAIKU | classify on HIT: “does LINE credit a data source (per X / X says / X’s count), or only name a chart or product?” CREDIT / CHART_NAME; the source list fed. Measured false positive: all 8 drops in 30d were “HITS’ Top 50” (a chart name the code comment says must pass). |
8 drops / 30d -> ~0.3 | drop on error | |
_CONFIDENCE_HEDGE_RE, _HEDGE_* allowlists, confidence_hedge_hits |
“unverified”, “reportedly”, “is reported to” | newsroom take | drop | - | MODEL-HAIKU | classify on HIT: “does LINE disclaim confidence in its own figure?” DISCLAIMER / OTHER; _HEDGE_NON_FIGURE_NOUNS fed as examples. Measured: 1 of 6 drops hedges a non-figure fact (“negotiations reportedly fell through”). Miss branch: the existing CONFIDENCE DISCLAIMER rubric line. |
6 / 30d | drop on error | NEW |
_SELF_COUNT_CREDIT_RE, _ANONYMOUS_CREDIT_RE, self_count_credit_hits, anonymous_credit_hits |
“per X’s own count”, “a third-party tracker” | newsroom take | drop | - | MODEL-HAIKU | same call as the hedge row (label WRONG_CREDIT added) | 0 / 30d | drop on error | NEW |
_CLAUSE_SPLIT_RE, trailing_clause, strip_trailing_clause |
last clause finder | desk take | nominate clause | - | DONE | Haiku is_flourish_clause decides every clause (#3257) |
14 / 7d | keep clause | NEW |
_METRIC_FOREIGN_WORDS, metric_foreign_word |
wrong-metric word table | settle / alert take | drop | HYBRID (C8, not wired) | MODEL-HAIKU | one cached classify per line: “which album metric does LINE state its figure in?” PURE_SALES / UNITS / STREAMS / NONE / SEVERAL; the word table fed as reference |
shared with next row | drop on error | |
_STREAMS_WORDS, ALBUM_METRIC_KEYS, album_metric_named, same_album_metric_posts |
inverse of the word table | recent posts | which posts the topic judge may compare | - | MODEL-HAIKU | same label, cached per post text (history posts are re-read each slot) | ~60 new texts/day (music_alert_scored 414 / 7d) | keep post comparable | NEW |
_FIGURE_TOKEN_RE, states_figure, figure_value, settled_figures |
number at printed precision | take | settle repeat test | - | KEEP-CLOSED | number check | - | - | NEW |
_TITLE_EDITION_RE, _title_forms (lead 3 words of a long title), missing_release_title |
folded containment, edition strip, prefix | settle take vs subject | drop / dedup filter | - | MODEL-HAIKU | exact fold stays the free accept; on a miss, classify “does LINE name the release TITLE (an edition or short form counts)?” YES / NO |
few / day | drop on error (today) | NEW |
_WORD_VALUES, _NUMBER_RE, ungrounded_numbers, numeric_grounding |
number set difference | take vs source | drop | KEEP | OWNED:#4412 | (number check) | - | drop | |
_AGE_CLAIM_RE, ungrounded_age_claim |
age figure | take vs source | drop | KEEP | OWNED:#4412 | - | - | drop | |
_CAREER_ORDINAL_RE, _FLAGGED_ORDINAL_RE, ungrounded_career_ordinals, ungrounded_flagged_ordinals |
ordinal vs source | take | drop | HYBRID | OWNED:#4412 | - | - | drop | |
_RANKING_CLAIM_RE, _RANKING_STOP, _UNIVERSAL_SCOPE, ungrounded_ranking_claims, universal_scope_candidates |
ranking regex + stopwords | take | drop / nominate | HYBRID | OWNED:#4412 | - | - | drop | |
_RANK_SUPERLATIVE_RE, _SOURCE_RECORD_RE, unsupported_rank_claims |
rank superlative vs evidence | newsroom take | drop | - | OWNED:#4412 (#4471) | - | 14 / 30d (unsupported_rank) |
drop | NEW |
memory_note_violations |
mention / snowflake / URL regex | memory note | reject note | KEEP | KEEP-PROTECTED | fence | cogs/memory.py:_tag_and_store via scrub_memory_note (#4528) |
- | |
has_context_tag_leak, has_track_line |
own tags | model output | flag | KEEP | KEEP-CLOSED (DEAD) | no production caller | 0 | - | |
too_short_to_ship |
length < 15 | model output | skip | KEEP | KEEP-CLOSED | length | - | skip |
Structural: has_em_dash / strip_em_dashes / strip_markdown_emphasis / strip_citation_tags (formatting), emoji_ok, visible_len / length_ok / count_sentences / link_count, _MENTION_RE, _DISCORD_ID_RE, _TRAILING_URL_LINE_RE, _TRACK_LINE_RE, _CONTEXT_TAG_RE, _LINK_CEILING_SURFACES / _POST_SURFACES / _RUNDOWN_SURFACES.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _NOT_X_BUT_Y, _lexicon_re, slop_hits, slop_score | vendored EQ-Bench lexicon | post_preview | telemetry field only (emit auto-stamp, x_audience) | KEEP | KEEP-CLOSED | decides nothing; the independent lexicon signal is the point | - | - | |
Structural: _WORD_RE.
| symbol | pattern | input | decision | old | new | shape + input | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _TICS, tic_hits | 7 named tic regexes | Sonnet X reply draft | one re-ask naming the phrase | KEEP | KEEP-CLOSED (CB-31) | Measured 2026-10-18 on 88 real Sonnet drafts (hand labels): regex 7 false-hit drafts + 1 miss; Jev 7 Nouls 35-42 false hits, 14 drafts flipped run to run; Haiku 11-13 false hits. The models lose; the regex stays. Old plan: 7 Nouls in one Jev request, one per tic NAME (“does draft lean on the phrase
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| banger_subject | first search term name_in_text the post | banger post | subject for check_source_qualifier | - | OWNED:#4412 | feeds the qualifier check (#4467) | - | author fallback | NEW |
Structural: _QUALIFIER_TRIGGERS, _OWN_HANDLES, "tootsiesbar" in author, author_name label strip, _CHANNEL_SOURCES.
| symbol | pattern | input | decision | old | new | shape + input | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| is_hedged at the forced-retry gate | _HEDGE_MARKERS (11 phrases) | Sonar answer | skip retry | HYBRID | DONE (B14) | Haiku first | - | retry | |
| is_hedged at its OTHER callers: cogs/music_desk.py (pplx research), cogs/music_news.py x2 (artist pull, figure research), utils/market_outcome.is_no_result, utils/milestone_qualifier.is_no_qualifier | same 11 phrases | Sonar answer | DROP the research (fast-path drop, decides alone) | (telemetry) | MODEL-HAIKU | on a list HIT only, call the existing ClaudeClient._perplexity_grounded / perplexity_found_answer (FOUND / NONE, cached by body hash); a miss needs no call because the compose and verify judges read the research. The milestone_qualifier caller is qualifier-epic territory: hand that one to #4412. | ~9 (59 hedged of ~4.8k Sonar answers / 7d) | list verdict on error | |
| _DISPUTE_RE, research_disputes | dispute words in the opening paragraph | Sonar verify answer | dispute flag | - | DONE | the verify judge’s web_disputes decides first; the regex only on no flag | - | no dispute | NEW |
| _MAGNITUDE_RE, _NOT_UNITS_RE, strip_industry_projection (+ names_hits_source) | HITS named + units magnitude per sentence | Sonar text (model INPUT) | cut the sentence | KEEP | MODEL-HAIKU | per candidate sentence that names HITS (names_hits_source), classify “does this sentence give HITS Daily Double’s projected first-week units?” CUT / KEEP; the regex verdict on error | <5 (music_desk projection lane, pplx_music_desk 389 / 7d, few name HITS) | cut on error (today) | |
Structural: _SEARCH_CONFIG, _CATEGORY_QUERIES, build_search_query, answer_body, _SENTENCE_SPLIT_RE, _extract_sources.
| symbol | pattern | input | decision | old | new | shape + input | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| duplicate_match signals (SequenceMatcher 0.6, 40-char run, _STOPWORDS content overlap) + arbitrated_match(catch=True) | mechanical + Haiku topic_duplicate both directions | composed post vs history | drop / ship | KEEP (hybrid) | DONE | judge decides hits and misses | topic_dedup 13,618 / 30d | mechanical on None | |
| arbitrated_match(catch=False) miss branch (cogs/discourse.py x2, cogs/chimein.py x2) | the fuzzy ratio alone says “fresh” | room post | ship without the judge | KEEP | MODEL-HAIKU | pass catch=True (the existing judge); this is the only branch where a fuzzy text ratio decides alone | ~7 (discourse_score 195 / 30d; chime-in 0 calls in 30d) | ship on None | |
| _POSITION_RE, _PAST_RANK_RE, _post_ranks, _same_rank (same_chart_position signal) | current vs past rank per clause | chart line vs history | mechanical hit | - | DONE | a hit goes to the judge (overturn); dedup_overturned 1,774 / 30d shows it works | - | judge | NEW |
| chart_claim, _titles (quoted / “X by Y”), _fold_title, same_chart_claim, comparable_topics, judge_evidence | exact folded title + chart key join | chart line vs history | which posts are comparable; empty -> no judge call | - | KEEP-CLOSED | identity join on exact folded keys (charts_named itself belongs to the music partition) | - | ship (no comparable) | NEW |
Structural: canonical_url, _urls, _MENTION_RE, _URL_RE, _CHART_WEEK_RE, _FEATURE_RE / _EDITION_RE title strip, summary_for_dedup, FORMAT_SIGNALS.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| is_own_laugh (_LAUGH_RE, _OWN_LAUGH_EMOJI) | laugh tokens | message | laugh stat | KEEP + JEV | DONE | Jev Noul per message (#4318), shape rule = stored key + fallback | typesafe_api engagement_labels 68 / 30d (rebuild only) | shape rule | |
| is_question (endswith("?")) | shape | message | question stat | KEEP + JEV | DONE | same | same | shape rule | |
| is_caps | caps ratio | message | hype stat | KEEP + JEV | DONE | same | same | shape rule | |
Structural: _MEE6_TRIGGER_DOMAINS, LAUGH_EMOJI / BANGER_EMOJI reaction sets, attachment_kind ext lists, _URL_RE, _ALL_COUNTERS; engagement_labels mention/emoji/URL scrubbers.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _IMAGE_TOPIC_TERMS, topic_is_image_room, prefers_media, called through judged_image_mode (cogs/curator, cogs/curate) | topic word list | channel name + topic | image vs text judge | HAIKU (B6) | DONE (#3429) | density first; Haiku IMAGE / LINK below it; list only on no verdict | curator_image_room 2 / 30d | density | |
| is_curate_post (🔁 / via @), ENDORSING_EMOJIS | own marker | message | seed eligibility | KEEP | KEEP-CLOSED | own repost marker | - | not curate | |
Structural: handle / id / shortcode regexes, _RESERVED, _PLATFORM_ALIASES, _VISION_UNFETCHABLE_HOSTS, _human_endorsed, handle caps (.lower() sets), clipboard autocomplete cur not in name.lower(), route_caption slug.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| asks_question, _QUESTION_STARTS, _REQUEST_CUES, mention_asks | first word / cue phrases / ? | mention | fetch parent | SHIPPED A7 | DONE | scan flag first, regex on None and inside the two mechanical bounds | music_mention_scan 450 / 30d | not a question | |
| charts_named, _CHART_CUES, _kind_nearest, _ALBUM_WORD_RE, _SONG_WORD_RE | chart cue words | mention | which charts get fact slots | SHIPPED A12 | DONE | charts_from_scan first | same | whole family | |
| scan_watched (name_in_text) + confirm_scanned | whole-word watchlist names | mention | subject | KEEP / N1 | DONE | Haiku x_artist_mention on one-word hits; classifier drops lexical hits on a clean empty read | x_artist_mention 35 / 7d | no hit | |
| cogs _resolve_subject name_in_text(text, ex_artist) | literal-name grounding of the classifier’s artist | tweet | accept off-watchlist act | KEEP | KEEP-CLOSED | grounding check on a model answer | - | absent | |
| cogs is_bare_name, title_in_text (fold_tokens equality) | exact folded tokens | mention vs name / title | reaction vs new subject; song ownership | - | KEEP-CLOSED | exact folded join | - | - | NEW |
Structural: _URL_RE, _LEADING_MENTIONS_RE, _RETWEET_*, _BOT_AUTHOR_FLAGS, _REPLY_TO_* keys, _STREAMS_METRIC_RE / _UNITS_METRIC_RE (our own format_reading output), _PLATFORM_KEYS, _GLOBAL_KEYS / _US_KEYS, _is_stale, dedup keys.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _media_gate / _clip_gate with _IDENTITY_VERIFIED_ART, _DROP_VERDICTS, _OCCASION_CHECKED_ART | own rung names / model labels | art rung + vision verdict | attach or drop image | KEEP | DONE | the gate is the vision model (media_coherence 1,017 / 7d) | - | drop image | |
Structural: OPT_IN_SURFACES, _DEDUP_SURFACES, _MARKET_LINK_HOSTS, _BARE_SOCIAL_RE, markdown strip, _dedup_key, URL path canon, MARKET_ROOM_SURFACES.
utils/x_audience.py (_LEADING_HANDLES_RE, _CANON_RE, telemetry), cogs/x_audience.py, utils/x_followers.py (numeric floors), utils/x_poster.py (_URL_RE, x_len), utils/x_fetch.py (_STATUS_RE, _RES_RE, media type), utils/twitterio.py (_credits_exhausted_message, payload keys), utils/x_filter_rules.py, utils/social_search.py (_REL_RE, _PHRASE_STRIP, "verif" in an API field, parse_trending_phrases validates a model list), utils/social_graph.py, utils/social_profile.py, utils/grok_search.py (_X_URL_RE, _X_HOST_RE, exact handle set).
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _artist_matches (_norm_artist equality) | exact fold | seed vs iTunes row | round pick | KEEP | KEEP-CLOSED | exact folded join | - | skip seed | |
| reply grading (grade_guess HARD + jev_grade_and_log) | containment + Jev | X reply | award round | KEEP / #4311 | DONE | Jev decides; code only grants a bare title + artist on no answer | 0 in 30d (no rounds) | no win | |
Structural: _ART_TAG, reply_order_key, reply_targets_round, slot math.
| symbol | pattern | input | decision | old | new | shape + input | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _CHART_INTENT (extractor predicate), _TABULAR_CUE | intent regex on query + aspect | /ask tool args | run chart extractor / render tables | HYBRID (B7 not built) | MODEL-HAIKU | one cached classify per lookup: CHART / TABLE / PROSE, both regexes fed as cue examples; regex on None | 0.17 (5 reference_lookup / 30d) | prose page | |
| _SUBPAGE_HINT, _ASPECT_SYNONYMS, _aspect_weights, _relevant_subpage | synonym weights over sub-article titles | question vs link titles | which sub-page to fetch | HAIKU (B15 wiki half not changed) | MODEL-HAIKU | classify with the candidate sub-page titles as the closed label set (+ MAIN); synonym table fed | same | main page | |
| _TITLE_STOPWORDS, _title_tokens, _title_names_subject | stopword-dropped token overlap | resolved title vs subject | reject page / lead image | KEEP | MODEL-HAIKU | exact fold stays the fast accept; on a REJECT, classify “is TITLE a page about SUBJECT?” YES / NO | same | reject on error | |
Structural: _EXTRACTORS, _SOURCES, must_contain in title search pick, _wiki_url, size caps. Owner decision needed: B7 measured these “not worth it” at 5 lookups in 30 days; under the 2026-10-18 rule they are still MODEL. Lowest priority.
Structural only: link platform / host / extension tables, _TWITTER_STATUS_RE, _BLUESKY_POST_RE, [deleted]/[removed], verify_url_alive; watch_link host predicates, _AGE_RE date freshness (fail closed) above the Haiku pickers; url_guardrail URL_RE, _BARE_WWW_RE, _MD_LINK_RE, _MEDIA_PREFIX_RE, allowlist; comments / reddit host routing and over_18; message_search DSL (HAS_KINDS, AUTHOR_TYPES, parse_has, parse_order, parse_match_reply ANSWER protocol), cog mention / snowflake / CDN regexes and exact-then-substring member resolvers; embeddings similarity floor.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _NARRATION_PHRASES, _NARRATION_OPENERS, is_narration | phrase lists | wheel lines | drop slice | HAIKU (B4) | OWNED:#4422 | - | - | keep slice | |
Structural: _SPLIT_RE, _MARKER_RE, normalize_items, slice caps; cog _CUSTOM_ID_RE, result strings.
| symbol | pattern | input | decision | old | new | shape + input | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| _grade_guess TITLE win (containment, _WIN_RATIO, _CLOSE_RATIO) | tight containment + char ratio | chat message | win / close | HYBRID (#4311) | DONE | Jev names_title + several_titles decide; code on no answer; Haiku judge_song_guess on EASY close | 0 Jev guess calls in 30d (1 game started) | grader | |
| _artist_named, _mentions, _ARTIST_FUZZY_RATIO 0.82, _credit_acts, _names_credit, _win_components (+ _NON_ARTIST_CREDIT_WORDS, _title_credit_artists) | whole word, longest token, fuzzy ratio | chat message vs credited acts | artist / feature points; artist-only consolation | KEEP | MODEL-JEV | add a Noul names_act to the SAME Jev request (“does guess name one of the acts in acts, including a nickname or a small misspelling?”); acts = primary credit parts + features + remix credits; the non-artist words fed as “not an act”. 0 added requests. Code rule on no answer. | 0 added | code rule | |
| _FEAT_RE, _REMIX_CREDIT_RE, _extract_features | feat / remix credit format | catalog title | candidate guests | KEEP | KEEP-CLOSED | fixed upstream title format; the list of candidates now goes to Jev | - | no credit | |
| _DECADE_TITLE_MARKERS, _decade_title_ok | decade tokens | playlist title | accept a fuzzy playlist hit | KEEP | KEEP-CLOSED | closed date-token format | - | reject | |
Structural: _MUSIC_HOSTS, is_rap genre enum, _hint_mask, difficulty enums.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| awards _quotable | strip emoji / URL / mentions, need one word | highlight | quote or skip | KEEP | KEEP-CLOSED | “has a word” is mechanical | - | skip | |
Structural: game_lookup.ASPECTS, _BALANCE_EXCLUDED_SURFACES, _SINGLETON_CHANNEL_KEYS, tune unit labels. settings.py has no text decision site.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| looks_like_wall_channel | “fame” and (“wall” or “hall”) | channel names | auto-detect the MEE6 wall | KEEP | KEEP-CLOSED (CB-31) | Measured 2026-10-18: 34 real text channels in the 2 guilds, 1 true hit (#wall-of-fame), 0 false hits, 0 misses. The stored channel id wins first anyway. Old plan: Jev Choice over the guild’s readable channel names + NONE (“which channel is the members’ hall-of-fame / wall-of-fame board?”); substring rule on error; a /star channel: pin still wins | <1 (auto-detect only when unpinned) | None | |
| cog _find_member_by_name | exact casefold, ambiguous -> None | repost author name | fold repost | KEEP | KEEP-CLOSED | exact join | - | drop | |
Structural: STAR_EMOJIS, _FIXER_RE, _DISCRIM_RE, _AVATAR_ID_RE, _JUMP_RE, classify_message, _member_roster.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| SAFE_PERMISSIONS, parse_permissions | allowlist | mod args | grant / refuse | KEEP | KEEP-PROTECTED | permission allowlist | - | refuse | |
| _EVERYONE_TOKENS, _BOTS_TOKENS, cog _SELF_TOKENS | own command tokens | args | resolve target | KEEP | KEEP-CLOSED | closed command vocabulary | - | - | |
Structural: _NAMED_COLOURS, mention / snowflake / jump regexes, _DURATION_RE, _CUSTOM_EMOJI_RE, discord_info.ASPECTS, role / event substring resolvers, calendar firehose sets.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| SKIP_VIBES | vibe label in set | Haiku chimein_score label | skip slot | KEEP | KEEP-CLOSED | policy over a closed model label | 0 (chimein_score 0 calls / 30d) | skip | |
Structural: thresholds, voice_present, react emoji pick. No per-message word list exists here, so the “per-message chime-in” hot path has no list to move.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| memory pipeline (forgotten_names, memory_note / memory_rollup, tag_memory_note) | names / aliases privacy + Sonnet fence | notes | store / skip | KEEP | KEEP-PROTECTED | fence + /forget privacy matching | - | skip | |
Structural: ACTIVITY_THRESHOLD, _prepend_legend, context_beat framing, nickname_seed policy sets, users.mention_or_name.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| classify_mention_intent label routing (intent in ("discourse","icebreaker")) | model label | mention | route | KEEP | DONE | Sonnet + Jev shadow | mention_intent 44 / 30d | ask | |
| player-props filter any(n in p.player.lower() or p.player.lower() in n ...) | substring both ways | model tool arg vs odds-api rows | which props to show | KEEP | MODEL-HAIKU | exact folded name stays the fast accept; for the non-exact residue, classify with the candidate player names as the closed label set (+ NONE) per asked name | <1 (ask 177 / 30d, props a small share) | include on error (today) | |
| "us" in query.lower() (spotify_chart top_songs) | tool arg documented as ‘us’ / ‘global’ | model tool arg | US vs global | - | KEEP-CLOSED | model-output protocol (tidy to equality) | - | global | |
| game_lookup aspect alias sets, find_image match enum, "stream" in wanted (canonical metric key) | enum aliasing | model tool args | tool routing | KEEP | KEEP-CLOSED | validating model tool args | - | help text | |
Structural: _TOOLSIDE_WEB_MODELS, _strip_html, self-mention strip, URL / content-type prefixes.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| commentator _passes_quality | commentate_score floor | model score | ship / skip | KEEP | DONE | model | commentate_score 33 / 30d | exception ships | |
| scheduled_poster arbitrated_match + too_short_to_ship | dedup + length | composed post | ship / skip | KEEP | DONE | hybrid (see dedup) | - | - | |
| abuse_tracker | Haiku classify_abuse labels | - | mute | KEEP | DONE | model + Jev shadow (#4406) | classify_abuse 134 / 30d | open | |
Structural: commentator trigger enums (_MILESTONE_TRIGGERS, _RETRY_TRIGGERS, _ODDS_OPENING_TRIGGERS, _ODDS_SUPPRESSED_TRIGGERS, _CONTEXT_TRIGGERS) and sport maps; recap size guards; tunables / experiments GRADUATED_* / permissions MASTER_USER_IDS / gates / kill_switch enums; mention_shadow is a Jev shadow (model).
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| order preflight_order verdict mapping | Sonnet label | /order | state | KEEP | KEEP-PROTECTED | protected path | - | reject | |
Structural: _FIX_ISSUE_LABELS / _FIX_INTERNAL_LABELS (GitHub labels), order search substring filters, _resolve_member_mention, config _flag, _RETRY_STATUSES. persona / constitution / help / models / menu_style / wheel_card / engagement_window: no sites.
| symbol | pattern | input | decision | old | new | shape | calls/day | fail | NEW? |
|—|—|—|—|—|—|—|—|—|—|
| image_signal _ASPECT_SYNONYMS | aspect words in the model’s <image aspect=> tag | model output | image aspect | KEEP | KEEP-CLOSED | model-output tag vocabulary | - | default aspect | |
Structural: <voice>/<sing>, <gif: q>, <image>/<remix> tag regexes, emoji regexes, tts [ sing tag, voice / sing char caps, gif rendition ladders, stt diarize. voice_cues.py synthesises tones only (no text decision), so the “voice cues” hot path has no list to move.
All Axiom APL, dataset tootsies.
claude_api | summarize count() by purpose, 7 days: 27,078 calls. In this partition: topic_dedup 1,726, curate_route 400, curator_pick 331, music_desk_score 2,666, discourse_score 63, music_mention_scan 61, classify_abuse 59, x_artist_mention 35, flourish_check 14, mention_intent 10. Absent: chimein_score, quiet_room_score, song_guess_judge, pplx_found_answer, decline_narration. Decides: the conversation surfaces are near idle, so a per-message Jev move there buys little today.typesafe_api | summarize by purpose, 30 days: only engagement_labels 68 (all ok). guess_grade 0, mention_shadow 0 recorded. guess_game_started 1 in 30 days. Decides: the games hot path has no live traffic; the Jev artist-credit Noul adds zero requests.music_desk_scored phase=shape_reject | summarize by reason, 30 days: career_claim 3,428 (291 distinct previews); attribution_tag 8; every other shape guard 0 (cross_source_comparison, stream_unit_comparison, self_correction, identity_subset, decline_narration, prior_position, row_arithmetic, row_tally). Decides: the owner-ban fences fire about never on the desk, so a Haiku confirm on a hit costs about 0 calls.music_desk_scored reason=attribution_tag | project post_preview, 30 days: 8 of 8 are genre_board lines naming “HITS’ Top 50” (for example “Iceman by Drake leads hip-hop albums on HITS’ Top 50 …”). The code comment says “HITS Top 50 names a chart and is not in this list”, but _HITS_PUBLISHER matches the possessive HITS’. Decides: _ATTRIBUTION_TAG_RE has a measured false-positive class; it is the top item in batch P3-B1.music_news_scored shipped=false | summarize by reason, 30 days: unsupported_rank 14, confidence_hedge 6, decline_narration 6, prior_position 5, album_unmarked 5, ungrounded_number 4; wrong_credit 0. Samples: one confidence_hedge drop hedges a non-figure fact (“U2’s 2027 world tour skips Chile after Santiago negotiations reportedly fell through”); the 5 prior_position drops all name a peak run (“after three weeks at No. 1”), which the owner steer covers.music_alert_scored / music_desk_scored reason metric_word:* or release_title, 30 days: 0. Decides: metric_foreign_word and missing_release_title never dropped a post in 30 days; their value is now in the dedup read (album_metric_named), where the Popstar case (2026-10-04) lost a units settle.pplx_* | countif(hedged), 7 days: about 4,800 Sonar answers, 59 hedged (music_desk 49 of 389, pop_desk 4, music_news 3 of 3,866, others 3). Decides: a Haiku read on is_hedged HITS only is about 9 calls a day.x_mentions | summarize by kind, reason, 30 days: scan no_artist 340, scan hit 101, boards shipped 80, reply shipped 71, reply no_facts 6. Decides: the mention lane is low volume and already model-first.Merged into the Part 0 batch plan.
_ATTRIBUTION_TAG_RE rejected 8 genre_board takes in 30 days, all for “HITS’ Top 50”. The comment above _HITS_PUBLISHER says “HITS Top 50 names a chart and is not in this list”, but the possessive arm \bHITS['’](?:s\b)? matches it. These were real, correct posts. This is worth a code fix before any model work.output_checks.check_text, has_tool_narration / _TOOL_NARRATION_RE, think_piece_hits / _THINK_PIECE_WORDS, has_context_tag_leak, has_track_line (an eval script names it in a docstring only), and memory_note_violations. The last one matters: the old audit and CLAUDE.md describe memory_note_violations as the CODE half of the memory fence, but no runtime path calls it. The fence today is prompt-only plus the Sonnet model choice. That is a KEEP-PROTECTED item, so it needs owner sign-off; #4528 wires it at the memory write path._MARKET_DECLINE_RE, prior_position_hits, has_stream_unit_comparison, identity_subset_hits, the attribution / hedge / credit batteries, trailing_clause, album_metric_named, states_figure, missing_release_title, universal_scope_candidates, unsupported_rank_claims. Each one cites an owner steer and a judge that scored the banned line 0.82-0.95, which is why they were built as fences. The batch keeps that: the model confirms a hit and the rubric covers the miss, and the regex stays the fallback.chimein_score had 0 calls in 30 days); voice_cues.py only synthesises tones; engagement already runs Jev (#4318); _grade_guess title already runs Jev (#4311). The remaining hot-path list is the games artist credit (P3-B6), with 1 game in 30 days.chimein_score, quiet_room_score, song_guess_judge or pplx_found_answer calls in 30 days; 2 discourse_scored events. Volume estimates for those surfaces come from code, not traffic.dedup.chart_claim / judge_evidence (#3912, new) skips the topic judge when no recent post names the same folded title. That is an exact join, so it is KEEP-CLOSED, but a re-spelled title in an earlier post means the judge never sees the repeat. If a repeat incident shows up, the fix is a candidate list to the judge, not a fuzzier fold.cogs/ask.py "us" in query.lower(): the tool schema documents query as ‘us’ or ‘global’, so this is protocol; an equality test would be tidier (“status”, “music” also contain “us”).claude_client._parse_music_news calls music_news.later_week_first_week_claim / FIRST_WEEK_PHRASE_RE; dedup._charts calls music_news.charts_named; is_hedged callers in music_desk / music_news / market_outcome / milestone_qualifier. The music partition owns those files; P3-B3 changes only the is_hedged decision.career_claim drops (OWNED:#4412) were not sampled; cogs/settings.py and cogs/ask.py were grep-swept, not read line by line; Jev latency and accuracy for the proposed tic and wall-channel questions are not measured.Read-only pass, 2026-10-18, branch claude/classifier-audit-wave19 = origin/main 4e1b6c0.
Old section: docs/CLASSIFIER_AUDIT.md lines 1508-1809. Git history in this checkout is
shallow (50 commits), so “NEW” means “not in the 2026-09-18 inventory”, found by reading
the code. Most files grew a lot since then (kworb 2517 to 3616 lines, chart_boards 4191 to
4815, luminate 762 to 1142, ops_monitor about 5000 to 6879). Most of the growth is
structural or already model-backed.
| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| utils/kworb.py | 10 | 14 | 5 | 2 | 0 | 0 | 3 | 0 |
| utils/riaa.py | 7 | 8 | 4 | 1 | 0 | 0 | 2 | 0 |
| utils/riaa_boards.py | 1 | 5 | 0 | 1 | 0 | 0 | 0 | 0 |
| utils/billboard.py | 4 | 10 | 3 | 1 | 0 | 0 | 0 | 0 |
| utils/luminate.py | 6 | 6 | 3 | 0 | 0 | 0 | 3 | 0 |
| utils/chart_boards.py | 7 | 8 | 5 | 1 | 0 | 0 | 1 | 0 |
| utils/chart_data.py | 2 | 3 | 0 | 2 | 0 | 0 | 0 | 0 |
| utils/chart_records.py | 3 | 1 | 3 | 0 | 0 | 0 | 0 | 0 |
| utils/wikidata.py | 6 | 3 | 2 | 2 | 0 | 0 | 2 | 0 |
| utils/cinema_boards.py | 3 | 2 | 3 | 0 | 0 | 0 | 0 | 0 |
| utils/cinema_numbers.py | 4 | 2 | 2 | 0 | 0 | 0 | 0 | 2 |
| utils/cinema_news_stories.py | 1 | 2 | 0 | 1 | 0 | 0 | 0 | 0 |
| cogs/cinema_desk.py | 4 | 6 | 2 | 0 | 0 | 0 | 0 | 2 |
| cogs/cinema_news.py | 3 | 2 | 0 | 0 | 0 | 0 | 0 | 3 |
| utils/rotten_tomatoes.py | 1 | 5 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/rt_reconcile.py | 2 | 3 | 1 | 0 | 0 | 1 | 0 | 0 |
| utils/healthcheck.py | 1 | 3 | 0 | 0 | 0 | 1 | 0 | 0 |
| db.py | 4 | 5 | 1 | 0 | 0 | 3 | 0 | 0 |
| manual scripts (riaa_credit_audit, music_drop_manual, versuz_card_manual) | 3 | 2 | 3 | 0 | 0 | 0 | 0 | 0 |
| structural-only files (17, listed below) | 0 | ~60 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 72 | ~150 | 38 | 11 | 0 | 5 | 11 | 7 |
No MODEL-JEV site in this partition. Every MODEL site here either needs world knowledge
(is this a music act, is this the same recording) or runs at under ~50 calls a day, so
Haiku classify with the durable cache is the better shape. No site is a per-message hot
path.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
find_video_match (unique branch) |
_fold_phrase whole-phrase containment of the leg label in a YouTube title; exactly one distinct video = unique=True |
Kalshi YouTube leg label vs kworb video titles | which video’s thumbnail + credit a market card uses; unique=True makes the X vision gate treat it as verified identity (_IDENTITY_VERIFIED_ART) |
HYBRID, then C11 no change | MODEL-HAIKU on the non-equal residue | Keep fold-EQUAL (label == title fold) and the video-id suffix (#4127) as exact accepts. A containment-only unique hit asks classify SAME / DIFFERENT with the leg label, the video title, the channel, and the event title. Cache 14 days per (label fold, video_id). |
~1 (35 market_subject source=youtube_chart in 30d, all unique; a share are fold-equal) |
DIFFERENT or error: return the row with unique=False, so the vision gate keeps authority (not a silent drop) |
no |
find_video_match qualifier drop (_BASE_LABEL_RE) |
drop a trailing (...) then require one distinct video |
same | same, unique=True |
HYBRID | MODEL-HAIKU (same call as above) | Same SAME / DIFFERENT question; the dropped qualifier (“Remix”) is part of the input. | <1 | same | no |
find_video_match (non-unique pick) |
most-viewed of several containment hits, unique=False |
same | thumbnail pick | HYBRID | DONE | The vision media gate decides (nominate-only). 0 picks in 30d. | 0 | gate keeps authority | no |
_artist_credits / _ARTIST_CREDIT_SPLIT / strict find_chart_entry, _find_by_artist, find_song_entry |
separator split (&, feat, ft, with, vs) + exact fold equality | artist credit vs ranking rows | which row is the act | KEEP | KEEP-CLOSED | Separator parse of a credit format + exact folded key. | - | no row | no |
fragment_match / confirm_act / all_parts_ranked (K2) |
part-of-credit match goes to Haiku ONE / COLLAB | unranked multi-act credit | keep or refuse the row | - | DONE | classify purpose kworb_act_check. 1 event in 30d. |
~0 | no row | NEW since 09-18 (#4170/#4277) |
_REQUEST_LEAD_SPLIT lead widening |
cut the request credit at its first , & ` x ` feat |
request credit | the lead may match a row credit | - | KEEP-CLOSED | Separator parse; the row must ALSO carry the exact same title. | - | no row | NEW |
loose mode (strict=False) of find_chart_entry, _find_by_artist |
either-way folded containment | artist | row | KEEP (Tier D) | KEEP-CLOSED (DEAD) | No production caller passes strict=False (grep of cogs/, utils/, bot.py). Delete the branch. |
0 | - | no |
_strip_feature |
[(\[](w/|feat|ft|with)...$ + title_forms.bare_title |
title | identity fold | KEEP | KEEP-CLOSED | Feature-marker format. | - | - | changed (#4172) |
is_functional_audio regex branch (_FUNCTIONAL_AUDIO_RE) |
~80-word functional-audio phrase list | artist name on the streams / listeners ranking (~1000 rows a fetch) | DROP the row alone, with no model check | HYBRID | MODEL-HAIKU on the drop branch only | Send each DISTINCT regex-positive name to the existing functional_audio_check (cached 30d), with the matched phrase. The regex stays the bulk filter. |
~0.1 (2 distinct names in 30d: “White Noise Radiance”, “Rain Sounds”; 2685 artist_filter reason=functional_audio events re-drop the same two) |
model says MUSIC: keep the row; error: drop (today’s rule) | no |
screen_functional_top (B9) |
Haiku on the regex-negative rendered top-N | rendered rows | drop | - | DONE | functional_audio, 51 calls in 30d, 0 model drops. |
~2 | regex verdict | no |
_UPLOAD_TAG_RE + trending_credit |
(official|lyric|letra|audio|video|visualizer|mv|hd|4k...) bracket strip; " - Topic" channel; first " - " split |
YouTube upload title + channel | display title and credit on the US trending board | - | KEEP-CLOSED | YouTube upload-tag convention + Topic-channel naming; a miss leaves a tag on the card, empty artist when unsure. | - | absent artist | NEW (#3768) |
Structural: HTML row/cell/link regexes, _PEAK_DAYS_RE, _PAGE_DATE_RE, _VIDEO_ID_SUFFIX_RE +
label_video_id / display_leg(s) (NEW #4127/#4342), _one_track track-id anchor (NEW
#4451), find_artist_song track id then song_key (NEW), */^ feature marks,
_US_VIDEO_CHART_SIZES, _BLOCKED_STATUSES, "anglo" in path, _PER_ENTITY_QUERIES,
“total”/”global” header rows, stream-shape gate (numbers).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_NOT_AN_ACT in own_credit |
11 filler cells (soundtrack, various, cast, original broadway cast …) | RIAA artist cell that names one act | is the cell an act that can be named on a board | HYBRID, C11 measured no change | MODEL-HAIKU | classify ACT / NOT_ACT on cells NOT in the list and that would rank on a board; the 11 entries go in the prompt as examples of NOT_ACT. Durable cache 90 days per cell. The exact list stays the fast NOT_ACT. |
~731 cells once (C11 count), then ~1 a day (new feed cells) | error: today’s rule (named as an act) | no |
_TITLE_FEATURE_RE, _FEATURE_AND_RE / _feature_guests |
feature markers; bare “and” split only when every piece resolves | award title | guest credits | KEEP | KEEP-CLOSED | Marker format; each piece must exactly resolve to a listed act. | - | uncredited | no |
_PERSONA_AS_RE |
\s+as\s+ in the artist cell |
artist cell | credit both halves | KEEP | KEEP-CLOSED | RIAA cell convention (“X AS Y”); halves go through credit_matches. |
- | - | no |
_CURATED_OMITTED_CREDITS + generated JSON |
exact (artist, title_identity) keys | award row | add guests | KEEP | KEEP-CLOSED | Owner-curated exact keys, built by a manual audit. | - | - | no |
title_identity + resolve_title_collisions |
feature-strip fold; Haiku on base-equal / whole-different groups | titles | dedupe key | KEEP | DONE | riaa_same_release. 0 calls in 30d. |
~0 | merge (old rule) | NEW since 09-18 (#3959) |
display_title recasing |
_INITIALS_RE, _SMALL_WORDS, _ROMAN_RE … |
ALL-CAPS cell | card text | HYBRID | DONE | riaa_recase per card (B16). 1 call in 30d. |
<1 | rules | no |
display_credit joins |
_CREDIT_JOIN_RE, _CREDIT_SLASH_RE |
credit | joiner text | KEEP | KEEP-CLOSED | Separator format, cosmetic. | - | - | no |
Structural: _ROW_RE, _BADGE_RE, _TD_RE, _TALLY_ROW_RE, _ARTIST_ROW_RE,
_TIMELINE_BLOCK_RE, _LEVEL_LABEL_RE, _LATIN_LABEL_RE, page-shape guards.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_bare_title (_BRACKET_RE, _IDENTITY_BRACKET_RE, _CREDIT_BRACKET_RE) |
keep a bracket only if it holds ‘s Version / remix / mix / live / acoustic / part / interlude / reprise / intro / outro | title on a public RIAA card | drop or keep the bracket; a miss prints “Love Story” for “Love Story (Taylor’s Version)” | KEEP, fixed #3455 | MODEL-HAIKU (fold, 0 added calls) | Fold into the existing riaa_recase call in recase_board: return the display title with the identity brackets kept. The word list goes in the prompt as the examples of KEEP; feature / soundtrack / edition brackets as examples of DROP. Validate: output must be the input with whole brackets removed. |
same as riaa_recase (<1) |
invalid answer or error: _bare_title rule |
changed (#3455) |
Structural: _fold, chart-key prefixes, _CERT_PREFIX, fmt == "ALBUM", _MONTHS,
_WHOLE_RANKING_PREFIXES.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
chart_context |
needle in _norm(title) or needle in _norm(artist), best rank wins |
the desk subject vs every row of every held chart | which chart line (“#N on Hot 100, up 3”) goes into a market / prediction / music-desk compose blob | KEEP | MODEL-HAIKU on the containment residue | Step 1 (deterministic, first): pass the structured artist + release (the luminate subject reads “Release – Artist”, which _norm never contains, so most market calls get no line today) and use credit_matches + exact title fold as the accept. Step 2: a containment-only hit asks classify SAME / DIFFERENT with the subject, the row title + artist. Cache per (subject, chart, week). |
upper bound ~380 (music_desk_score 2666 in 7d is the compose volume); after exact accepts and the weekly cache, est. under 20 | error or DIFFERENT: no chart line (absent) | no |
_lead_credit + _slug_is_the_lead / _history_slug |
head segment + slug-word compare | credit vs artist slug | history slug | KEEP + fix | KEEP-CLOSED | Fixed by #3451 (slug must be the cut lead’s own page). | - | no slug | changed |
find() |
title containment, best rank | wire title | chart row | HYBRID, C11 | KEEP-CLOSED (DEAD) | No production caller (C11 and today’s grep). Delete. | 0 | - | no |
rank_of |
exact _norm title + artist |
title | rank | KEEP | KEEP-CLOSED | Exact fold. | - | None | no |
Structural: HTML regexes, _STAT_LABELS, _REENTRY_FRAGMENTS badge parse, _KIND_WEIGHT,
TOP_MOVE_KINDS, _FALL_KINDS, _KIND_EYEBROW, _slug_key, _BLOCKED_STATUSES.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
ALBUM_METRICS / metric_cues / metric_from_text |
Kalshi metric words in registry order | Kalshi event title | metric label | HYBRID | DONE | B13: one clear cue = fast path (Kalshi’s fixed metric vocabulary); none or two cues go to luminate_subject. |
see Notes | cue result | no |
_SUBJECT_RE, _METRIC_TAIL_RE, enrich_event_title |
Kalshi title template “Will X by Y have …” | leg title | release / artist | HYBRID | DONE | Template parse; no parse or two acts go to luminate_subject. |
see Notes | cue result | no |
_LEG_TWO_ACT_RE, _TITLE_VS_RE |
“have … than … by”, “vs” | leg / event title | send to the model; credit no act | - | DONE | Nominates the residue; the outcome (no act credited) is the absent direction. Kalshi’s own template words. | - | no credit | NEW (#4211) |
_KALSHI_CATEGORY_LABELS |
exact “music, fashion, film” | release slot | collapse to artist | KEEP | KEEP-CLOSED | Exact upstream category. | - | - | no |
release_stage ticker substrings, _WORLDWIDE_STREAM_SERIES, stream_scope |
ticker family names | series ticker | stage; “worldwide” word | KEEP | KEEP-CLOSED | Ticker schema. | - | ”” (no word) | partly NEW |
"stream" in reading.metric |
our own label | metric | streams reading | KEEP | KEEP-CLOSED | Our enum. | - | - | no |
Structural: _NUM_RE, _SUFFIX, _PERIOD_RE + date parses, "lumin" settlement source.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
recovery_candidates zero-overlap branch |
a tracklist title that shares no 3+ char token with any unused kworb row gets no candidates | album track title | the track is left out of the album’s stream total; the model never sees it | KEEP | MODEL-HAIKU (low) | Fold into the existing album_track_match call: a zero-overlap title gets the top unused rows by total as candidates. Same recovered_total ceiling. |
~0 (album_track_match had 0 calls in 30d) |
absent (undercount) | no |
_album_track_fold + album_track_match recovery |
fold, prefilter, Haiku pick | album tracks | which rows are the album’s | KEEP | DONE | Reference HYBRID. | 0 in 30d | fail closed | no |
APPLE_GENRE_GROUPS, DEEZER_GENRE_GROUPS, confirmed_genre_group |
exact upstream genre names | published genre tags | genre board membership | KEEP | KEEP-CLOSED | Upstream API fields with a fixed vocabulary; two sources must agree. | - | absent | no |
_VERSION_SUFFIX_RE / _version_stripped_fold |
” - From …”, “ - Remastered” | Spotify title | same recording | - | KEEP-CLOSED | Spotify’s fixed suffix format. | - | - | NEW |
_release_identity / _act_leads_credit |
fold_tokens prefix ending on a connector |
credit | lead act key | - | KEEP-CLOSED | Exact token prefix with a boundary. | - | - | NEW (#3657) |
_match_hits, song_total_streams etc. |
exact keys + credit_matches |
rows | join | KEEP | KEEP-CLOSED | Exact fold (credit_matches is artist_watch’s, OWNED:W19-C1 for its aliases). |
- | - | no |
_label_case |
<=4-char caps kept | label | casing | KEEP | KEEP-CLOSED | Cosmetic. | - | - | no |
Structural: _RANK_NOTABILITY, _SECONDARY_CHARTS, _GENRE_LABELS, GENRE_MEMBERSHIP,
kind frozensets, _CREDIT_EXAMPLES / _PRINTED_STEERS / _PLATFORM_STEERS /
_PROJ_STEERS / _WATCH_COLUMN_FENCE (prompt text, not decisions), _PERIOD_END_RE.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
detect_chart |
“billboard 200”, \buk\b, “canad”, “hot 100”, “album” |
/ask reference query + aspect | which Wikipedia chart table is fetched | HAIKU, B7 not built | MODEL-HAIKU | One classify over the closed key set (hot100 / billboard200 / uk_singles / uk_albums / canada), the cue words in the prompt as examples. Shares the call with the wikidata intent below (batch P4-E). |
~0 (4 reference_lookup in 30d, all source=Wikipedia, 0 reached the chart or Wikidata source) |
error: cue rule | no |
render_tables keyword row filter |
any(k in row.lower()) relevance |
table rows vs query words | which rows the /ask model sees | KEEP (structural) | MODEL-HAIKU (or remove) | Simplest: hand the /ask model the capped table and drop the filter, so the calling model decides. | ~0 | full table | no |
Structural: wikitable parser, _clean_title, _is_chart_col, _MAX_PEAK.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
RECORDS |
curated all-time table | - | record claims | KEEP | KEEP-CLOSED | Curated facts, exact keys. | - | - | no |
_same_song, _credit_corroboration_set, _lead_act |
exact fold; artist_watch.first_party |
title / credit | record identity | KEEP | KEEP-CLOSED | Exact folds; _lead_act fixed #4265. |
- | - | changed |
_record_phrase / _CLOSE_MARGINS |
number margins | numbers | phrasing | KEEP | KEEP-CLOSED | Numbers. | - | - | no |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_FACTOID_INTENT / matches |
born, birth, how old, age, died, founded, inception, what year … | /ask reference query + aspect | route to the Wikidata factoid source | HYBRID, B7 not built | MODEL-HAIKU | Same call as detect_chart: add the label set FACTOID_BIRTH / FACTOID_DEATH / FACTOID_FOUNDING / NONE; the regex words go in as examples. |
~0 (see detect_chart) |
error: regex | no |
want_founding (in lookup) |
founded / founding / inception / established | aspect | founding vs birth render | KEEP | MODEL-HAIKU | Same call (FACTOID_FOUNDING label). | ~0 | regex | no |
_MUSIC_DESCRIPTION / _WORK_DESCRIPTION |
musician / band … ; album / film / tour … | Wikidata hit description | ORDER of claims reads; after the first act, read only a music-looking second candidate | KEEP | DONE | Ordering only; is_music_act (Q-ids) decides and _pick_namesake (Haiku wiki_namesake) picks among acts. The second-act admission is a request-budget gate on 0 cards / 14d (#3319). |
0 | first act | changed (#3319) |
artist_portraits + _pick_namesake |
Haiku ONE / TWO / THREE / UNCLEAR | same-name acts | which portrait | - | DONE | wiki_namesake, 0 calls in 30d. |
0 | no photo | NEW (#3319) |
_MUSIC_OCCUPATIONS, _MUSIC_GROUP_CLASSES, is_music_act |
Wikidata Q-ids | claims | is a music act | KEEP | KEEP-CLOSED | Structured ids (C12 measured). | - | not an act | no |
_norm_act_name / _hit_name_candidates |
exact fold | label vs name | candidate | KEEP | KEEP-CLOSED | Exact. | - | - | no |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_POSITION_CLAIM_RE / strip_position_claims, _ROW_POSITION_RE, _PACKED_SCORE_RE |
“#N”, “number N”, “ranks N” | model output | strip rank figures for the number check | KEEP | KEEP-CLOSED | Number check. | - | - | no |
_debut_lead |
weeks / gross thresholds | BOM numbers | debut framing | KEEP | KEEP-CLOSED | Numbers. | - | - | no |
short_studio / short_director (_STUDIO_SUFFIXES, _NAME_PARTICLES, _NAME_SUFFIXES) |
suffix / particle lists | studio / director name | display shortening | KEEP | KEEP-CLOSED | Display only; never decides inclusion. | - | full name | no |
| symbol | new verdict | note |
|---|---|---|
_clean_news (“no notable” / “no major” / “nothing “ on a short Perplexity answer) |
OWNED:#4412 | C11: 0 events from the three news lanes. Not batched. |
| result-verb lists (PR #4513, not yet on main) | OWNED:#4412 | Not batched. |
_is_new_opener / _notable_holdover |
KEEP-CLOSED | Numbers. |
norm_subject |
KEEP-CLOSED | Exact fold. |
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
story_signature / dedup_key (_STOPWORDS, first 5 content tokens) |
stopword-dropped token prefix | wire post text | same moment: a match DROPS the story (durable cinema_news_events key, and the per-slot used set) |
KEEP | MODEL-HAIKU | Keep exact signature equality as the trigger; a hit against a RECORDED key asks the existing dedup arbiter (dedup.topic_duplicate / arbitrated_match, Haiku) with both wire texts, the stopword list is not needed as input. Also emit an event on a signature drop (none today, so a wrong merge is silent). |
<1 (19 cinema_news_posted in 30d; collisions are a fraction of candidates) |
error: drop (today’s rule) | no |
Structural: _URL_RE, _HANDLE_RE, _TOKEN_RE, _MIN_HEADLINE_CHARS.
| symbol | new verdict | note |
|---|---|---|
_board_unshippable, ungrounded_numbers |
KEEP-CLOSED | Number checks behind cinema_desk_score (40 calls / 30d). |
budget lookup tmdb.search_movies(title, year) + title_matches + year |
KEEP-CLOSED | Tier D fix landed (exact title + year). |
has_self_correction (L1417) |
OWNED:#4422 | |
check_source_qualifier, qualifier_trim.restates_cut |
OWNED:#4412 |
Structural: _SUBJECT_DEDUP_KINDS, _NEWS_KINDS, _POSTER_CARD_KINDS, _CARDED_KINDS,
_QUALIFIER_CHECKED_KINDS, _CINEMA_CARD_SOURCE, _SOURCE_LABEL.
| symbol | new verdict | note |
|---|---|---|
drop_self_correction |
OWNED:#4422 | |
retrospective_note / frames_as_past / retrospective_frame |
OWNED:W19-B3 | |
check_source_qualifier / restates_cut |
OWNED:#4412 |
Structural: _VISION_HOSTS, is_source_photo. news_age.is_stale_recap and wire_lanes
are called here but live outside this partition.
| symbol | pattern | decision | old verdict | new verdict | note |
|---|---|---|---|---|---|
normalize_title + title_matches + year_matches |
exact alnum fold, year slack 1 | same film | KEEP | KEEP-CLOSED | Exact identity with year. |
rt_reconcile.threshold_from_label, RTCall.verdict / cleared |
“above / over / more than / at least N”; distance bands | Kalshi strike and the hit / miss verdict | KEEP | KEEP-PROTECTED | Price threshold math (settlement class). |
rt_reconcile.is_rt_event, film_from_event |
KXRT prefix; “rotten tomatoes score” tail | series membership, film name | KEEP | KEEP-CLOSED | Ticker + Kalshi template. |
| symbol | new verdict | note |
|---|---|---|
_is_read_only |
KEEP-PROTECTED | Permission allowlist. |
Structural: Bearer strip, X webhook auth, debug routes (NEW /debug/clip, /debug/usage).
| symbol | new verdict | note |
|---|---|---|
bookie_bet_outcome + _canonical_name |
KEEP-PROTECTED | Bookie payout. |
side_label void-to-won correction |
KEEP-PROTECTED | Settlement. |
alias_index(exclude_nicks) / aliases_for_text |
KEEP-PROTECTED | names / aliases matching. |
_MEMORY_QUERY_TOKEN / _or_search_terms |
KEEP-CLOSED | Query syntax rewrite for websearch_to_tsquery. |
Structural: _FACT_CLAIM_SURFACES, POST_HISTORY_RETENTION_HOURS, sql_op labels, jsonb
codec, FTS SQL.
| symbol | new verdict | note |
|---|---|---|
scripts/riaa_credit_audit.py _SAME_RECORDING, _NOT_AN_ACT_NAME, accept() |
KEEP-CLOSED (manual) | A human reads every output before it enters the curated JSON. |
scripts/music_drop_manual.py _VISUALISER_RE, _LYRIC_RE |
KEEP-CLOSED (manual) | The music-drop skill; the owner reads the result. |
scripts/versuz_card_manual.py _SCORE_RE, _LOOSE_FEAT_RE, _SUFFIX_RE, token overlap |
KEEP-CLOSED (manual) | The versuz-card skill; the owner reads the card. |
scripts/artist_sweep.py (NEW, 271 lines) and scripts/called_shot_scorecard.py: no
semantic site (they call riaa_boards / called_shot).
_ACCENT_PREFIXES, _CUT_NOTE_RE, unicode font buckets._DETAIL_COLUMNS, _MEDIABASE ids, issue-date compare._TITLE_HEADERS, “artist” / “discography” header detection._COLUMNS header map, money / pct / rank regexes.Source names, “N/A”, is_usable_year.type / site / official fields for the trailer pick, WATCH_PROVIDERS, search_movies(year=)._VENDOR_BY_KIND, _VENDOR_FROM_SOURCE_MAP, _TOOL_PROMOTED, detail fold; the slop_score stamp is telemetry only (lives in utils/slop_score, other partition)._FAILED_STATUSES, log substring filter, 400-body “column limit” read.WATCHES numeric rules, period != "minute"._LOGIN_RETRY_STATUSES, ARCADE_ONLY_COMMANDS._DEBUT_GATE_*, _INTEGRATION_BENIGN_ERRORS, _MEDIA_EDIT_BENIGN_ERRORS, NON_SCORE_REASONS, _COVER_RUNGS, _MISC_INTEGRATIONS, _SETTLE_EMIT_RANK, _COMMENTARY_DEPTH_FLAGS, _MODEL_PRICING, _PER_SOURCE_MISC, _OPAQUE_QUERY_PREFIXES, _LOG_SIG_DIGITS_RE log grouping, _PCT_HERO_RE). Every input is our own emitted field or a log line.All Axiom, dataset tootsies.
| # | query (short) | window | result | what it decides |
|---|---|---|---|---|
| 1 | claude_api count by purpose, purposes of this partition |
30d | functional_audio 51, cinema_desk_score 40, cinema_news_score 34, riaa_recase 1; kworb_act_check, riaa_same_release, luminate_subject, wiki_namesake, album_track_match: 0 | Volume of the shipped model rungs. No MODEL-JEV case: nothing here is high-volume. See Notes on the zero rows. |
| 2 | artist_filter by reason, make_set(detail.dropped) |
30d | reason functional_audio: 2685 events, distinct names {“White Noise Radiance, Rain Sounds”}; reason functional_audio_model: 0 | The regex drop branch fired on 2 distinct names, both right. A model confirm costs ~2 cached calls. Low priority (P4-D). |
| 3 | market_subject by source, source startswith 'youtube' |
30d | youtube_chart 35, youtube_chart_pick 0 | find_video_match: 0 non-unique picks; ~1 unique leg a day reaches the card (P4-B). |
| 4 | reference_lookup by source |
30d | 4, all Wikipedia | detect_chart, _FACTOID_INTENT, render_tables route ~0 traffic (P4-E). |
| 5 | cinema_news_posted / cinema_desk_posted |
30d | 19 / 22 | Volume ceiling for story_signature (P4-F). |
| 6 | kworb_act_check / luminate_subject events |
30d | 1 / 0 | Confirms #1: the K2 and B13 rungs barely run in production. |
| 7 | claude_api music_desk_score (and related) |
7d | music_desk_score 2666, market_drop_history 244 | Upper bound for chart_context callers (P4-A). |
Merged into the Part 0 batch plan.
luminate_subject (B13, #3436): 0 claude_api calls and 0 luminate_subject events,
while 968 market_subject events ran and the B13 dry run sent 50 of 121 live events to
the model. kworb_act_check (K2): 0 calls, 1 event. riaa_same_release,
wiki_namesake, album_track_match: 0 calls. Some may be idle for a real reason
(durable caches warmed by the dry run, the trigger shape did not occur, #3319 measured
~0/day). But luminate_subject at 0 against the dry-run rate is a candidate silent
failure: check that music_markets._checked_subject (L2083) is reached in production
and that bind_subject_cache ran. NOT verified in this pass; worth a follow-up issue.billboard.BillboardClient.find() (no
production caller) and the strict=False loose mode of kworb.find_chart_entry /
_find_by_artist / find_song_entry (no caller passes it).billboard.chart_context likely misses most market subjects. The luminate desk
subject is “Release – Artist” (luminate._subject), and _norm keeps the two
spaces, so the needle is almost never a substring of one row title or artist. The
context line the #1981 steer asked for may be absent on most market reads. Not
measured (no event). This is a deterministic bug before it is a model question (P4-A
step 1). The old audit missed this site’s fuzzy shape (it listed it as KEEP).story_signature drops are silent. No event records a cinema story dropped as a
duplicate, so a wrong merge cannot be counted. The fix is an event (P4-F)._lead_credit (#3451), TMDB budget lookup
(title + year check in cinema_desk), _BRACKET_RE (#3455), find_chart_entry
strict default (#3456), chart_records._lead_act (#4265).cinema_boards.short_studio /
short_director, kworb._UPLOAD_TAG_RE, riaa.display_credit. They change how a
name prints, never whether a row ships. riaa_boards._bare_title is the exception
(it can remove a recording’s identity), so it is in P4-C.cinema_numbers.py: whole file OWNED:#4412 per the coordinator update (result-verb
lists, PR #4513, not yet on main). Listed, not batched.ops_monitor classifies only our own emitted
enums and log lines; its model judging runs in the GitHub workflow, not here.Repo state: 4e1b6c0 (origin/main). Read-only pass. Old audit section: docs/CLASSIFIER_AUDIT.md
lines 1811-2067. Worklist items that already shipped in this scope: A10 (#3422, discourse rubric
“shows its working”), B6 (#3429, curator image room), B15 (#3430, TMDB film pick), C5 (#3443, house
genre), C6 (#3444, chart_ages confirm), C7 (#3445, reissue check), #4235 (album-chart match), C11
(#3449, measured looks_like_sports: no change). B7 (reference router) was NOT built.
The clone is shallow (50 commits), so “NEW” is decided by comparing each site to the old audit text,
not by git log.
| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| cogs/artist_curator.py | 1 | 3 | 0 | 0 | 0 | 0 | 1 | 0 |
| cogs/curate.py | 5 | 4 | 3 | 0 | 0 | 0 | 2 | 0 |
| cogs/discourse.py | 13 | 5 | 6 | 4 | 0 | 0 | 1 | 2 |
| cogs/music_releases.py | 7 | 4 | 4 | 2 | 0 | 0 | 1 | 0 |
| utils/awards.py | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/chart_ages.py | 7 | 5 | 6 | 0 | 0 | 0 | 1 | 0 |
| utils/chart_standings.py | 7 | 2 | 6 | 1 | 0 | 0 | 0 | 0 |
| utils/feed_status.py | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/filler_solver.py | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/market_art.py | 1 | 2 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/music_policy.py | 5 | 2 | 4 | 0 | 0 | 0 | 1 | 0 |
| utils/openai_chat.py | 5 | 1 | 5 | 0 | 0 | 0 | 0 | 0 |
| utils/reference_movie.py | 2 | 3 | 0 | 1 | 0 | 0 | 1 | 0 |
| utils/release_age.py | 2 | 4 | 1 | 1 | 0 | 0 | 0 | 0 |
| utils/subject_image.py | 2 | 4 | 1 | 0 | 0 | 0 | 1 | 0 |
| utils/the_odds_api.py | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
| total | 57 | 54 | 37 | 9 | 0 | 0 | 9 | 2 |
No KEEP-PROTECTED site is in this partition. No settlement math, constitution, fence, permission
allowlist, /forget matching or preflight path lives in these 16 files.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
claude.pick_curator |
Haiku vision pick | candidate frames + captions + room topic | which post ships, or none | KEEP (model) | DONE | already a model judge | curator_pick 5,914 / 30d (shared with curate) |
none_fit / pick_error: skip | no |
Structural: filter_candidates(require_media=True) + is_fresh (timestamp window), channel.topic or parent.topic (attribute fallback to _DEFAULT_TOPIC), _PLATFORMS (own provider table).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_compose_caption: artist.lower() == source.lower() |
exact handle fold | upstream X handles | caption a repost of a distinct act, or bare link | KEEP | KEEP-CLOSED | exact identity join on a handle (closed format) | - | equal: bare link | no |
_compose_caption: "\n" in cap or link_count or visible_len > _CAPTION_MAX |
shape gate | model caption | drop caption | KEEP | KEEP-CLOSED | count / length on model output | - | drop caption | no |
judged_image_mode(...) (was prefers_media + _IMAGE_TOPIC_TERMS) |
density, then cached Haiku IMAGE/LINK | room name, parent, topic, 6 samples | image vs text judge + prompt | HYBRID | DONE (B6 #3429) | classify, purpose curator_image_room; the topic list is the model-error fallback |
2 / 30d (all six live rooms decided by density) | model error: old density + topic list | yes (#3429) |
home.get(p.external_id) == channel_id |
routed-home equality | map built by claude.route_curator |
which room gets the post | KEEP | DONE | model decides (curate_route 13,460 / 30d) |
~450 | route error: fail open | no |
is_empty_response (L324, L754) |
EMPTY sentinel | model output | skip vs ship | KEEP | KEEP-CLOSED | protocol sentinel | - | sentinel: skip | no |
Structural: _fetchable (host allow-list _VISION_HOSTS), _platform_label (host substrings over canonical_host), parse_external_id tweet-id dedup, reason not in ("none_fit","no_candidates") (own reason enum).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_market_routing_query: sportsy_channel = classify_intent(name + topic) (markets._SPORTS_PATTERNS, _PM_PATTERNS, _WILL_X_BY_RE) |
substring list + regex | channel name + topic | on a quiet slot (no category, no convo): fetch markets at all | KEEP (prefilter) | MODEL-HAIKU (miss branch only) | classify labels SPORTS / PREDICTION_MARKET / OTHER on name + topic; _SPORTS_PATTERNS and _PM_PATTERNS fed as examples; cache key = name+topic, ttl 7d |
<1 (one per channel per name/topic change; discourse is mostly muted, see Measurements) | model error: today’s keyword rule | no |
icebreaker _market_line: looks_like_sports(name + topic) (classify_intent == "sports" or \bsport) |
substring list + regex | channel name + topic | whether a betting line may feed the icebreaker | HYBRID; C11 measured, no change | MODEL-HAIKU (miss branch; hit branch is nominate: markets.get_context runs the Haiku market_intent) |
the SAME cached label as the row above (SPORTS -> allow) | <1 (1 icebreaker in 30d) | model error: today’s rule | no |
drop_self_correction at news lane (L593), retry (L720), trending lane (L1192) |
_SELF_CORRECTION_RE |
model take | drop take -> fallback | KEEP; A10 moved the judgment into discourse_score |
OWNED:#4422 | - | - | drop | no |
icebreaker has_self_correction(line) (L1743) |
_SELF_CORRECTION_RE |
model opener | drop opener (no score judge on this lane) | (not listed) | OWNED:#4422 | - | - | drop | yes (missed by old audit; #2755 sweep) |
icebreaker arbitrated_match(..., catch=False) (L1773) |
text ratio / shared run / same link; Haiku only overturns a hit | opener vs 30 days of own openers | drop a repeat opener | HYBRID (already) | MODEL-HAIKU (miss branch) | set catch=True: claude.topic_duplicate (purpose topic_dedup) reads the opener vs the recent openers; the mechanical signals stay as the hit path |
<1 | catch: fail open (no verdict = ship, as today) | no |
scheduled take arbitrated_match(..., catch=False) (L1940) |
same | take vs last 20 discourse posts | drop a repeat take | HYBRID (already) | MODEL-HAIKU (miss branch) | same, catch=True |
<1 | same | no |
trending canonical_url(c[3]) not in posted_links |
canonical URL fold | clip links vs 21d of own posts | drop already-posted clips | KEEP | KEEP-CLOSED | exact URL identity | - | DB error: no dedup (fail open) | no |
picked = next(c[3] for c in clips if c[3] in line) |
URL substring | model take | telemetry only | KEEP | KEEP-CLOSED | exact URL in text | - | - | no |
_perplexity_phrases -> parse_trending_phrases |
line-shape regex | Perplexity output | which phrases get searched | KEEP | KEEP-CLOSED | protocol parse of a line-per-phrase answer | - | junk line: wasted search | no |
_native_x_phrases -> claude.filter_trending_topics |
Haiku match of X trends to room | X trends + name + topic | which trends fit | (noted) | DONE | model decides (trending_filter 1 / 30d) |
<1 | Haiku error: top trends unfiltered | no |
_trending_search_phrases._add: p.lower() dedup |
exact fold | phrases | drop a repeat phrase | KEEP | KEEP-CLOSED | exact fold | - | - | no |
t != "(no caption)" |
own sentinel | own placeholder | exclude from Grok prompt | KEEP | KEEP-CLOSED | own enum | - | - | no |
is_empty_response (L593, L713, L1182, L1732, L1922) |
EMPTY sentinel | model output | decline | KEEP | KEEP-CLOSED | protocol sentinel | - | skip | no |
Structural: _trending_clip_url (host allow-lists + YouTube id regex), x_fetch.x_tweet_id (_STATUS_RE), _parse_retry_after_seconds (header parse), filter_recent(keep_undated=False) (date parse), u.startswith("data:") (URL scheme).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_REISSUE_RE in _reissue_keys (\d+ year, anniversary, reissue, remaster, super deluxe, expanded edition) |
regex word list | Apple album title | fast YES: omit the first-night stat, drop from the first-week card | HYBRID -> C7 kept it as the cheap yes | MODEL-HAIKU (fast-yes branch) | send the hit to the existing claude.release_is_reissue (REISSUE / NEW, purpose release_reissue, cached per title); feed the matched word as a hint (“title carries ‘anniversary’”) |
~2 (10 album_total reason=reissue in 30d) |
model error / no verdict: omit the stat (today’s direction) | yes: “super deluxe” and “expanded edition” were added after C7 (Rubber Soul, 2026-10-06) |
_REISSUE_ASK_RE (deluxe, edition, version, live, expanded) |
regex word list | Apple album title | hit: ask Haiku; miss: NEW, no call | (C7) | hit DONE; MODEL-HAIKU for the MISS branch | ask release_is_reissue for every roster title the stat / first-week card reads (_STAT_SCAN 4 + first-week roster up to FIRST_WEEK_SCAN 20); pass the release date and the release_version_kind label already fetched for that title |
~10-20 new titles/day, then cached (est. from code: roster size x 1-2 slots, release_reissue 22 calls in 3 days) |
model error on a title with no regex word: NEW (today); on a regex word: omit | yes (#3445) |
_standout_stats: song_date != rel.released |
date equality | iTunes date vs feed date | credit a charting track to this drop | KEEP | KEEP-CLOSED | exact date | - | no stat | no |
_standout_stats: entry.title.casefold() == rel.title.casefold() |
exact fold | kworb vs Apple title | show song name or blank | KEEP | KEEP-CLOSED | exact fold | - | name shown | no |
kworb.album_chart_entry(..., known=known) |
strict credit + exact folded title | kworb vs Apple | Top Drops rank | KEEP | KEEP-CLOSED | exact join (helper in utils/kworb.py) |
- | left off | no |
_version_verdicts -> claude.release_version_kind |
Haiku new / recut / edition | (artist, title) | board roster | (not present) | DONE | model decides (release_version 195 calls in 3 days); the regex in utils/release_board.py decides only a None row |
~65 | None: regex decides that row | yes (#3441) |
label == "new music friday" |
own label | own plan label | caption text | KEEP | KEEP-CLOSED | own enum | - | - | no |
Structural: _CHART_DEBUT_DAYS days window, rb._roster_key(rel) in reissues (own key set), f"first:{mark}" in self._delivered_keys() (own key), rb.outside_first_week (Spotify date window).
No semantic site. Structural: metric.split("+") on own metric keys, "{month}" in t (own template), _FIELD_LABEL / _BY_KEY lookups (own keys), recent winner frozenset (own ids).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_matching_pick containment (non-exact) + confirm_pick |
fold + containment either way | MB release-group title + credit vs Billboard row | the row’s original date (oldest-songs board, RIAA plaques card) | HYBRID | DONE (C6 #3444) | an exact title+credit pick makes no call; any other pick goes to Haiku SAME / DIFFERENT (purpose chart_age_check) |
<1 (6 in 30d) | DIFFERENT: undated + cached miss; error: undated, not cached | no |
_matching_pick(exact=True): _bare_title equality + artist_watch.credit_matches |
exact fold after bracket strip | same | debut-gate date (release_age MusicBrainz rung, no model client) | (not present) | KEEP-CLOSED (exact fold). The alias half of credit_matches is OWNED:W19-C1 |
- | - | no match: next rung | yes (#2958) |
_NOT_THE_RECORD / _NOT_THE_ALBUM on secondary-types |
set of MB type names | MB secondary-types |
drop compilation / live / remix / DJ-mix / demo groups | (not present) | KEEP-CLOSED (upstream fixed vocabulary) | - | - | group skipped | yes (#3483, #4235) |
_self_titled |
title fold == artist fold | row | use exact match + official filter | (not present) | KEEP-CLOSED (exact fold) | - | - | - | yes (#4295) |
_self_titled_pick |
official status, no secondary type, one year per primary type | MB JSON fields | candidate set for a self-titled row | (not present) | KEEP-CLOSED (structural fields + year compare) | - | - | conflict: undated | yes (#4295) |
_bare_search_title |
bracket strip | row title | second MB search | (not present) | KEEP-CLOSED (structural) | - | - | - | yes (#4371) |
confirm_pick answer parse label == "SAME" |
closed-label parser | Haiku answer | keep date | - | KEEP-CLOSED (protocol) | - | - | not SAME: undated | yes (#3444) |
Structural: _lucene_escape, _year_of, _credit_name (joinphrase rebuild), _BRACKET_RE, earliest-year / most-precise-date pick.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
credit_parties(row.artist, known) (artist_watch._CONNECTORS) |
connector split, corroborated by exact known keys |
Billboard credit | which acts an entry counts for | KEEP | KEEP-CLOSED (a split stands only on an exact folded key in known) |
- | - | under-split: collab partner loses an entry | no |
is_placeholder_credit(party) (artist_watch._PLACEHOLDER_CREDITS: soundtrack, various artists, original cast, karaoke, …) |
exact folded word list | Billboard credit party | drop a non-act from the census / catalog / debut boards | KEEP | MODEL-HAIKU (the miss branch: an unlisted stand-in, e.g. “Cast of Wicked”, counts as an act alone) | classify ACT / PLACEHOLDER on the credit, _PLACEHOLDER_CREDITS fed as examples; scope it to the credit that would LEAD a board (the public claim), cached 30d per credit |
<1 (boards per week, est. from code) | model error: today’s list | no (the list grows by incident, #2739) |
_match_key |
[^a-z0-9] strip + fold_tokens(lead_artist(...)) |
Billboard vs kworb vs sales rows | attach a figure to a row | KEEP | KEEP-CLOSED | exact fold | - | blank cell | no |
genre_entries: fold_tokens(board.subject) not in notable |
exact set | kworb top-artist keys | suppress an unknown genre leader | KEEP | KEEP-CLOSED | exact fold | - | empty set: fail open | no |
lead-act tally (lead_artist, fold_tokens) |
feature-clause strip | Billboard credit | “from N different acts” | KEEP | KEEP-CLOSED (fixed credit format) | - | - | - | no |
lead_party(row.artist, known) grouping |
connector split + exact known |
Billboard credit | group entries per lead act | (folded into lead tally) | KEEP-CLOSED | - | - | - | no |
row_key lower-case identity |
exact fold | rows | cluster fold | KEEP | KEEP-CLOSED | - | - | - | no |
Structural: _KIND_TITLE / _KIND_COLUMN_NOTE dict lookups on own kind.
No semantic site. Structural: _PROVIDERS / _FAILOVER keyed on own source ids; pct >= LOW_PCT numeric.
No semantic site. Structural: _OPPOSITE / corner_cell on own corner names, AREA_PALETTE / COLOR_NAMES (RGB table), _NEIGHBORS.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
norm_name(label) == key in leg_image_in / find_leg_image |
NFKD + punctuation strip + casefold, exact | Polymarket groupItemTitle vs subject name |
use that leg’s portrait | KEEP | KEEP-CLOSED (exact folded identity join) | - | - | next art rung | no |
Structural: img == event_img (URL identity), big_enough (image dims).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
in_house_genre / _IN_HOUSE_TAGS (fast accept) |
exact tag allow list | iTunes primaryGenreName |
rap / R&B / pop: post | HYBRID | KEEP-CLOSED (upstream field with a fixed vocabulary; owner-curated fast path) | - | - | - | no |
judged_in_house_genre (off-list tag) |
cached Haiku RAP / RNB / POP / NONE | artist + title + tag | rescue an off-list record | (C5) | DONE (#3443) | house_genre_check, purpose house_genre |
0 in 30d (no off-list tag reached the gate) | NONE / error: refuse | yes (#3443) |
_NEVER_RESCUE (indie pop, k-pop, pop latino, pop/rock) |
exact tag set | iTunes tag | fast drop, no model call | (not present) | KEEP-CLOSED (closed upstream vocabulary; each tag rejected by the owner by name) | - | - | refuse | yes (#3443) |
APPLE_GENRE_IDS in in_house_genre_ids |
integer id set | Apple feed genres ids |
filter the “just dropped” pool | KEEP | KEEP-CLOSED | - | - | row refused | no |
drop_verdict order (genre, new, watched, certified) |
ordered boolean gate | bools + date | post / skip + reason | KEEP | KEEP-CLOSED (own enum; watched membership is resolved in cogs/music.py) |
- | - | unknown_artist |
no |
Structural: normalize_tag (spelling folds), is_new_release (ISO date window).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_classify_failure ("insufficient_quota" + status sets) |
documented error code + status | OpenAI error body | fail over vs surface | KEEP | KEEP-CLOSED (API error code) | - | - | provider: fail over |
no |
_read_api_response "insufficient_quota" |
same | same | do not retry | KEEP | KEEP-CLOSED | - | - | retried | no |
is_reasoning_model prefixes, _NO_EFFORT_NONE, min_effort |
prefix + set | own model id | effort param + token reserve | KEEP | KEEP-CLOSED (own config id) | - | - | non-reasoning | no |
finish == "length" / status == "incomplete" (reasoning_exhausted, responses_exhausted) |
enum literals | OpenAI body | retry once | KEEP | KEEP-CLOSED (protocol) | - | - | ship fragment | no |
_content_to_text None on empty |
shape | OpenAI body | refusal = failed call | KEEP | KEEP-CLOSED | - | - | canned line | no |
Structural: parse_responses_body (item["type"], url_citation tags).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
movie_matches (_FILM_WORDS, _STRONG_CUES) |
substring lists | /ask reference query + aspect | route to TMDB+OMDb or fall through to Wikipedia | HAIKU (B7, not built) | hit branch DONE (nominate: _pick_film judges every TMDB hit and NONE falls to Wikipedia via reference.lookup); MODEL-HAIKU for the MISS branch |
cheapest form: make movie_matches true whenever TMDB is provisioned, so the existing pick_reference_film judge decides every non-music question (it already answers NONE for a non-film question). The two lists move into the judge prompt as cues |
<1 (5 reference_lookup in 30d) |
judge NONE / error: Wikipedia (today) | no |
_pick_film -> pick_reference_film |
cached Haiku pick over TMDB hits | question + up to 5 “title (year)” lines | which film, or none | (B15) | DONE (#3430) | purpose reference_film_pick |
0 in 30d | NONE / no verdict: Wikipedia | yes (#3430) |
Structural: top.release_date[:4], len(lines) == 1, the provisioned gates.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_catalog_release_date: deezer.album_title_matches(title, row["title"]) on the iTunes row |
token overlap >= 60% + sequel / bracket-tag rules | requested title vs the resolve_music_row row title |
accept or refuse the iTunes date | (old audit: 0 semantic sites) | MODEL-HAIKU (the pass band only) | replace the bare check with deezer.confirm_album_rows(title, [row], kind=...): the exact pass stays the fast accept; a pass inside album_match_band goes to the existing cached Haiku pick (match_catalog_title, purpose catalog_title_match); the requested title + the candidate are the closed input |
~1-3 (est.: iTunes answered 797 of 5,096 resolves in 30d; the band is a fraction; results are cached per pair) | refuse = undated = no debut claim (today’s refuse direction); model error removes the row | yes (#3176, #3998) |
MusicBrainz rung chart_ages.first_release_date(exact=True) |
exact fold | MB groups | first-release date | (not present) | KEEP-CLOSED | - | - | timeout: catalogs answer | yes (#2958) |
Structural: _MISS_PREFIX cache sentinel, date.fromisoformat, max(rd, it) later-date rule for an album, partial-date _PARTIAL_MIN_AGE_DAYS rule.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
pick_subject_image -> confirm_subject_image |
Haiku rank + Sonnet confirm | downloaded candidates + host + caption | which photo ships | KEEP (model) | DONE | subject_image_pick 202, subject_image_confirm 34 in 30d |
~8 | none: no photo | no |
is_source_photo |
own enum | rung string | delivery trust | KEEP | KEEP-CLOSED | - | - | - | no |
Structural: URL scheme check, image/ content type, _MAX_IMAGE_DIM, _host.
No semantic site. Structural: market-key literals (h2h, player_ prefix, outrights), _clean_link ({/} placeholder + scheme), _is_permanent_4xx / _request_ok status classes, x-requests-* header parse, score keyed by exact home_team / away_team, counts.most_common(1) consensus line.
| helper | owner | verdict here |
|---|---|---|
utils/markets.py _SPORTS_PATTERNS, _PM_PATTERNS, _WILL_X_BY_RE, _LEAGUE_KEYWORDS, classify_intent, detect_league, looks_like_sports |
P2 (markets) | Not planned here. Batch P5-B wraps only the two discourse CALL SITES and leaves markets.py unchanged, so it cannot collide with P2. |
utils/curator.py _IMAGE_TOPIC_TERMS, topic_is_image_room |
(none named) | DONE (B6 #3429): the list is now the model-error fallback only. |
utils/artist_watch.py _CONNECTORS, _PLACEHOLDER_CREDITS, lead_artist, credit_parties, fold_tokens, credit_matches aliases |
P1; aliases OWNED:W19-C1 | _CONNECTORS split is KEEP-CLOSED (corroborated by exact keys). _PLACEHOLDER_CREDITS is the MODEL-HAIKU site in batch P5-D; if P1 plans is_placeholder_credit itself, drop P5-D. |
utils/output_checks.py _SELF_CORRECTION_RE, ship_guard.drop_self_correction |
OWNED:#4422 | DONE in part (B4): Haiku shows_working decides at drop_self_correction; the lists are the trigger, the examples and the error fallback. The direct has_self_correction sites are a follow-up. See the B4 row. |
claude_client.is_empty_response |
P3 | KEEP-CLOSED (protocol sentinel). |
utils/social_search.py parse_trending_phrases, filter_recent |
(none named) | KEEP-CLOSED: a line-shape parse of a model answer, and a date parse. |
utils/reference.py _SOURCES chain (genius_matches, wikidata_matches, musicbrainz_matches) |
(none named; /ask) | MODEL-HAIKU in principle (B7 router), but 5 reference_lookup calls in 30d, each to the right source (#3430). Each matcher’s hit is nominate-only (a None result falls to the next source); the miss branch decides alone. Lowest rank; only movie_matches is in a batch (P5-E) because its judge already exists. |
All queries on Axiom ['tootsies'], window now-30d (to 2026-10-18), unless noted.
where event == 'claude_api' | summarize count() by purpose: the model calls already in this scope: curate_route 13,460, curator_pick 5,914, curate_caption 1,471, topic_dedup 13,611 (all surfaces), subject_image_pick 202, release_version 195 (since 2026-10-15), discourse_score 195 (shared with music, music_desk, chimein), release_reissue 22, chart_age_check 6, curator_image_room 2, trending_filter 1, discourse_icebreaker 1, house_genre 0, reference_film_pick 0. Decides: which sites are DONE and live; C5 and B15 have not fired yet.event in (discourse_scored, discourse_icebreaker, discourse_dedup, dedup_overturned, reference_lookup, music_house_gate, release_date_resolve) | summarize count() by event: discourse_scored 2, discourse_icebreaker 1, discourse_dedup 0, reference_lookup 5, music_house_gate 9, release_date_resolve 5,096. Decides: the discourse batch and the movie gate are LOW volume (rank L); release_age is the high-volume site in this partition.event == 'slot_muted' | summarize count() by surface: discourse 500 (music 1,091, curator 673). Decides: discourse is mostly muted, so its batch is low impact today.event == 'dedup_overturned' | summarize count() by surface: discourse 0 (music_desk 1,214, music_news 518). Decides: the discourse mechanical gate had no hit to arbitrate in 30d; only the catch direction can add value there.event == 'release_date_resolve' | summarize count() by reason, source: itunes_title_mismatch 81 (called_shot_age 47, debut_release_age 30, x_gate 4), no_date 248, musicbrainz_timeout 8. Decides: the 60% overlap rule fires about 3 times a day, so the ambiguous region is populated.event == 'release_date_resolve' | summarize count() by provider, mode: deezer/song 1,752, musicbrainz/album 1,371, musicbrainz/song 813, itunes/song 463, deezer+itunes/album 253, itunes/album 81, none 268. Decides: 797 resolves (about 27/day before the per-process cache) took an iTunes date that passed only the bare overlap rule, with no band confirm.event == 'music_house_gate' | summarize count() by reason: watched 5, new_release 3, certified 1, off_genre 0. Decides: the music_policy allow list refused nothing in 30d; KEEP-CLOSED needs no measurement beyond this.event == 'album_total' and reason in (reissue, outside_window): reissue 10, outside_window 4. Decides: the reissue omit path is live (about 2 a week).claude_api purpose in (release_reissue, release_version, ...) by bin 7d: all of release_reissue (22) and release_version (195) fall in the week from 2026-10-15. Decides the calls/day estimate for P5-A.Merged into the Part 0 batch plan.
utils/release_age.py had 0 semantic sites. It has
the iTunes row title check (album_title_matches, a fuzzy token-overlap identity join, #3176 /
#3998). It is the highest-impact site in this partition, and it is the only path in the
release-date chain whose band does not go to confirm_band_rows. The icebreaker
has_self_correction site (L1743) was also not listed; it is OWNED:#4422.slot_muted and 2 discourse_scored in 30 days. The
discourse_score purpose (195 calls) comes mostly from music.py, music_desk.py and
chimein.py, which share that rubric. Batch P5-B is correct under the rule but does little
until the surface is unmuted._REISSUE_RE grew after C7. “super deluxe” and “expanded edition” were added on or after
2026-10-06 (Rubber Soul). That is the “list grows by incident” signal the rule targets. A
title such as “Rubber Soul (2026 Mix)” carries no regex word, so neither regex sends it to the
model; the _CHART_DEBUT_DAYS age check and the date-equality check are the only guards on
the first-night stat, and _inside_window (Spotify date) on the first-week card.house_genre (C5) and reference_film_pick
(B15) have 0 calls in 30 days, because no off-list tag and no film question reached them.
curator_image_room (B6) has 2. These are live but unexercised; they cannot be judged by
production data yet.rb.pick_spotify_release and
rb.spotify_release_date_near (utils/release_board.py, the Spotify tracklist match for the
Songstats fill), kworb.credit_members (joint-credit split on “&”), and
apple_music.title_match_band (SequenceMatcher ratio). Each is a fuzzy title or name join;
the partition that owns those files should check them._matching_year and _matching_date in
chart_ages.py are thin wrappers kept for tests.Checkout: claude/classifier-audit-wave19 at 4e1b6c0. utils/qualifier_trim.py was also read at
origin/main (fba1952, which adds the #4516 detectors). The old audit has no inventory section for
these files, so every site counts as NEW unless the worklist (lines 1-360) names it. The worklist
names these items: B17 (x_gate / classify_x_post), N1 (x_artist_tags scan), A16
(chart_history._HEDGE_RE, billboard_stories._LEADER_TITLE_RE), C3/N11
(album_milestones._relation ambiguous residue), K2 (it lists chart_history._credited and
artist_priors as follow-ups that still use the old split rule), and #2016
(market_sibling_claims).
| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| utils/x_artist_handles.py | 1 | 2 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/x_artist_tags.py | 9 | 6 | 5 | 3 | 0 | 0 | 1 | 0 |
| utils/x_gate.py | 1 | 5 | 0 | 0 | 0 | 0 | 1 | 0 |
| utils/chart_fact.py | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/chart_peak.py | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/chart_priors.py | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/itunes_charts.py | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/stream_report.py | 3 | 3 | 2 | 1 | 0 | 0 | 0 | 0 |
| utils/forecast_backtest.py | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| utils/source_watch.py | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/youtube_oembed.py | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/youtube_grounding.py | 1 | 2 | 0 | 1 | 0 | 0 | 0 | 0 |
| utils/qualifier_trim.py | 14 | 3 | 0 | 0 | 0 | 0 | 0 | 14 |
| utils/qualifier_check.py | 4 | 1 | 0 | 0 | 0 | 0 | 0 | 4 |
| cogs/chart_history.py | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/chart_history.py | 10 | 9 | 3 | 5 | 0 | 0 | 1 | 1 |
| utils/album_milestones.py | 3 | 2 | 2 | 1 | 0 | 0 | 0 | 0 |
| utils/artist_priors.py | 2 | 2 | 1 | 1 | 0 | 0 | 0 | 0 |
| utils/billboard_stories.py | 8 | 6 | 2 | 5 | 0 | 0 | 1 | 0 |
| utils/market_sibling_claims.py | 2 | 1 | 1 | 0 | 0 | 0 | 1 | 0 |
| utils/title_forms.py | 2 | 1 | 2 | 0 | 0 | 0 | 0 | 0 |
| total | 61 | 68 | 20 | 17 | 0 | 0 | 5 | 19 |
MODEL-JEV is 0 on purpose. Every MODEL site here needs one of these, and Jev is weak at all of them: music world knowledge (is “Drake” the rapper, is “Scary Hours Edition” a version), a recent act’s identity, or text extraction (Nora subjects, Billboard figures). Volume is also low (under about 25 calls a day per batch), so Haiku’s cost and latency do not matter.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
REVIEWED_NAMES |
124 catalog spellings | a finished post (read by x_artist_tags.names_in_text) |
which reviewed acts a post names | – | KEEP-CLOSED | An exact, case-sensitive match on a closed, owner-reviewed list. The meaning check for the risky one-word and everyday-word hits is scan_names (DONE, N1). |
0 | – | NEW |
Structural: VERIFIED_HANDLES, REVIEWED_ACCOUNT_IDS are exact folded-key / handle-to-ID lookups (data only; no logic in the file).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_FAN_BIO in verify_profile |
12 bio phrases (“fan account”, “parody”, “unofficial”) | live X profile bio | refuse the handle (fan_bio) alone |
– | MODEL-HAIKU | classify OWN / FAN / UNSURE. Input: the display name, the handle, the bio, and the 12 phrases as reference examples. Cache per handle for 30 days, beside the handle cache. The phrase hit stays the fallback on a model error. |
under 1 (Axiom: 0 fan_bio refusals in 30d; about 7 uncached profile checks a day) |
Refuse the tag (absent). FAN or UNSURE = refuse. | NEW |
_inside_longer_name + _CAP_BEFORE_RE / _CAP_AFTER_RE / _CREDIT_WORDS |
one-word name next to a capitalized word, except credit words | finished post | drop the scanned name alone, before the Haiku check | worklist N1 (scan stays) | MODEL-HAIKU (drop branch) | Send the hit to the existing claude.is_music_artist_mention(name, text) instead of dropping it. Add the neighbour word as a hint (“next to: ‘Maye’”). The _CREDIT_WORDS list goes in the task as the credit connectors. |
1-3 (the whole scan made 35 x_artist_mention calls in 7d) |
Model error or NO: no tag (absent), as now. | NEW branch |
_is_title_position + _BY_AFTER_RE |
inside double quotes, or before “by |
finished post, and the tag_text path for lane-passed names |
drop the name alone (title, not artist) | worklist N1 | MODEL-HAIKU (the “by” branch only) | Same Haiku call, with the hint “the name sits before ‘by X’”. The quote-count branch is a structural parse of the quote marks and stays KEEP-CLOSED. | under 1 | No tag (absent). | NEW branch |
_SCAN_SKIP, needs_artist_check, scan_names |
60 everyday-word names; one-word names | finished post | tag or not | N1 SHIPPED | DONE | Every one-word or skip-list hit goes to Haiku; a multi-word reviewed name is an exact closed-list hit. | – | – | no |
_spellings, _SMALL_WORDS, _MC_DJ_RE, _EDGE_SYMBOLS_RE |
case / accent / small-word variants | the reviewed names | which exact spellings the scan looks for | – | KEEP-CLOSED | It only widens the exact spellings of a closed list. | 0 | – | NEW |
spelling_ok, _DOTTED_KEYS |
“B.o.B” needs its dots | a lane name | refuse a dotted key spelled without dots | – | KEEP-CLOSED | An exact form rule on a closed list. | 0 | – | NEW |
verify_profile name check |
normalize_name(artist) equals display name or handle |
profile | name_mismatch |
– | KEEP-CLOSED | An exact folded-key identity join. The ID check (REVIEWED_ACCOUNT_IDS) is also exact. |
0 | – | NEW |
_name_pattern |
case-sensitive whole-word name | post text | where to put the tag | – | KEEP-CLOSED | An exact match of a closed name. | 0 | – | NEW |
artist_from_subject |
split on “ – “ / “ - “ | the desk’s own Title - Artist subject |
which name a desk lane tags | – | KEEP-CLOSED | It parses our own subject format. A bare subject gives “” (absent). | 0 | – | NEW |
CB-27 result (2026-10-18). Measured on 30 days of real text: 2,192 unique posts
(1,200 @tootsiesbar tweets from twitterapi.io plus 1,000 post_dedup_history rows,
tags stripped) and the live bios of the 223 handles that tagged in 30 days (191 with a
bio). Two runs of the real Haiku model on each set.
| site | old | new | old errors | new errors | runs agree |
|---|---|---|---|---|---|
_inside_longer_name drop |
drops alone | held_names -> is_music_artist_mention(hint=...), purpose=x_artist_position |
2 wrong of 3 (“Four Drake songs”, “BTS World Tour”; “Luis Miguel” right) | 0 of 3 | 3 of 3 |
_before_by (“by” branch of _is_title_position) |
drops alone | same call, the “by” hint; a YES is recorded so tag_text tags there |
2 wrong of 2 (“f/Don Toliver by Drake”, “f/Ava Max by BIGXTHAPLUG”) | 0 of 2 | 2 of 2 |
_FAN_BIO |
refuses alone | bio_refused -> Haiku x_bio_owner OWN / FAN / UNSURE, purpose=x_bio_owner; UNSURE or error = the phrases |
0 refusals of 191 real bios (0 wrong) | 0 refusals of 191 (0 wrong) | outcome 191 of 191; label 185 of 191 (6 OWN / UNSURE flips, same outcome) |
quote branch of _is_title_position |
KEEP-CLOSED | unchanged (a parse of quote marks) | – | – | – |
Goldens on the real model, both runs: “Madonna by Drake”, “Drake Maye”, “Luis Miguel”,
“The Eminem Show” stay NO; a fan, an updates and a parody bio read FAN (the updates bio
has none of the 12 phrases, so the phrase rule passed it). Two earlier prompt arms were
measured and not shipped: the first position hint said YES on “The Eminem Show”; the
first two bio prompts read 1 and then 2-3 real accounts as FAN (Gunna’s “BRING DRIP
SEASON BACK !”, “Official Ed Sheeran HQ account”, Jack Johnson’s management bio). The
batch row said UNSURE should refuse: measured, 34-42 of 191 real bios read UNSURE (a
link, a symbol, one word), so UNSURE uses the phrase rule instead. Calls: about 0.2 a
day for the position check (6 held names in 30 days); the bio check runs once per
handle and bio per 7 days (durable cache), at most about 30 a day. Cost under $0.01 a
day. Median latency 0.52 s per call. After merge: ['tootsies'] | where event ==
'claude_api' and purpose in ('x_artist_position', 'x_bio_owner') | summarize n=count(),
ok=countif(ok==true) by purpose and ['tootsies'] | where event == 'x_artist_tag' and
reason in ('fan_bio', 'by_not_artist', 'longer_not_artist', 'by_check_failed',
'longer_check_failed') | project _time, reason, artist=parse_json(detail)['artist']. A
fan_bio row on a reviewed artist is a regression.
Structural: _HANDLE_RE (X handle format), _GROK_LINE_RE / parse_grok_handle (the Grok HANDLE: protocol), _POSSESSIVE_TAIL_RE / _BARE_POSSESSIVE_RE (where the tag is inserted), the "://" URL test, mode() / _MODES, SCAN_SURFACES (our own surface enum).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
classified -> claude.classify_x_post |
Haiku topic / unit / artist / title | newsroom story text | STREAMS / CHART / OTHER for the X gate | B17 SHIPPED | DONE | Already a model call (purpose=x_gate_classify, 196 calls in 7d). |
28 (Axiom) | Fail-open: OTHER, the post goes to X. | no |
Structural: _POS_RE (a “#N” figure), static_reason / streams_reason / forecast_reason (number thresholds), forecast_facts (Kalshi fields), top_position (calls kworb.find_chart_entry strict=True with known, which is K2’s matcher and not in this partition).
No semantic sites.
FACT_CHARTS (our chart enum), fact_key / desk_fact / newsroom_fact / milestone_key / newsroom_milestone (exact keys off our own dedup_key and the classifier’s canonical milestone_id), _is_key_suffix.PEAK_CHARTS, rank arithmetic in new_peak_candidates / fallen_peak_candidates, desk_told (reuses chart_fact.desk_fact)._BASIS_PHRASES is key-to-text for a prompt block, not a decision._credit (exact case-folded duplicate party), _identity (Apple id or exact pair), HTTP status sets.retweeted_tweet payload check.| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_fold (strict key) |
feature mark cut, non-alphanumerics dropped | kworb song titles | which page row is the milestone song; the catalog ordinal | – | KEEP-CLOSED | An exact folded-key join. | 0 | No row: no report. | NEW |
_fold_loose / _TAIL_RE residue in build_report |
cuts any “ - …” tail | kworb row vs iTunes tracklist | a row that matches a track ONLY by the loose key (“Plot Twist - Sped Up”) counts as that track’s version | – | MODEL-HAIKU (loose-only residue) | Send each loose-only row to the existing cached claude.release_version_kind(title, base) (purpose=release_version). RECUT or EDITION = the same track (old rule); NEW = a separate song, not counted. Keep the exact track-key join as the fast accept. |
under 1 (only stream milestones with an album resolved) | Model error: the old loose rule. | NEW |
is_single / _SINGLE_TAG_RE |
” - Single” iTunes collection name; fewer than 2 folded tracks | iTunes collection | no album ordinal | – | KEEP-CLOSED | An upstream field with a fixed form, plus a count. | 0 | – | NEW |
Structural: _EDITION_TAIL_RE / display_album and _REMASTER_TAIL_RE / display_title change the shown text only (every key keeps the full title); _nth; _lead_fact ranking by counts.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
GENRE_BUCKETS / genre_bucket |
Apple genre name -> 7 buckets | Apple primaryGenreName |
grading bucket | – | KEEP-CLOSED | An upstream field with a fixed vocabulary. A tag not listed is other. Only the offline scripts/backtest_forecast.py reads it. |
0 | – | NEW |
Structural: HITS_KINDS (our HITS chart keys), the grade arithmetic. It imports artist_priors.same_act (see that file).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
take_names_a_leg (-> market_subject_image.take_references_leg) |
whole-phrase match of a leg title in the take | composed market_alert take on a YouTube daily-chart board, non-leader takes | ship (any leg phrase found) or drop alone | C4 kept it | MODEL-HAIKU (both branches) | classify NAMES_LEG / OTHER_SONG / NO_SONG. Input: the take, the leg labels, and the kworb upload titles from youtube_grounding_block (they name the artist). The phrase match stays the fallback. An alternative: reuse market_take_names_leader with the legs as the closed set. |
1-3 (code: non-leader YouTube alert takes) | Fail closed: OTHER_SONG or model error = drop (as now). | NEW verdict |
Structural: leading_legs (price max, yes_label field), youtube_grounding_block (exact case-folded compare to skip a redundant line), fetch_youtube_rows.
All 14 semantic sites are OWNED:#4412 (coordinator steer, 2026-10-18). Do not put any of them in a batch.
| symbol | new verdict |
|---|---|
_QUALIFIER_RE / has_qualifier |
OWNED:#4412 |
_RANK_RE / _RANK_ORDINAL / _QUANTITY / _rank_matches / _rank_spans (#4471) |
OWNED:#4412 |
_RELEASE_NOUN_RE / _RELEASE_VERB_RE |
OWNED:#4412 |
_SPAN_WORDS / _SPAN_RE / time_span (#4516) |
OWNED:#4412 |
_JOINS_ONLY_RE / joins_as_only (#4516) |
OWNED:#4412 |
_MOST_RE / states_most (#4516) |
OWNED:#4412 |
_QUALIFIER_BEFORE_RE / _DURATION_BEFORE_RE / _LOOKBACK_RE |
OWNED:#4412 |
_FILLER / _MAX_CONTENT_WORDS / _INTENSIFIERS / _is_qualifier_token |
OWNED:#4412 |
_ABBREVIATIONS / _sentence_starts |
OWNED:#4412 |
_PRONOUNS / _capital_mask |
OWNED:#4412 |
_DETERMINERS / _COPULAS / _PHRASE_STOP / leaves_dangling |
OWNED:#4412 |
cut_runs / cut_qualifiers / is_cut |
OWNED:#4412 |
restates_cut |
OWNED:#4412 |
_RANK_SAID_RE / cut_note |
OWNED:#4412 |
Structural: _TOKEN_RE, _QUOTED_RE / _quoted_spans / _title_spans, _SENTENCE_END_RE.
| symbol | new verdict |
|---|---|
_FIRST_RE (first / only / ever / never -> chart-history research) |
OWNED:#4412 |
_SPOTIFY_GLOBAL_RE (Spotify + global in the claim) |
OWNED:#4412 |
_WITH_RE / _MORE_SEPARATORS / _AND_RE / _name_key (credit split for the kworb history read) |
OWNED:#4412 |
check_source_qualifier (check_claim_qualifier path) |
OWNED:#4412 |
Structural: _HISTORY_MAX and the research plumbing.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_HEDGE_RE in parse_nora_text / hedged_rank_sentences |
hedge words | Nora sentence | drop the rank | A16 | OWNED:W19-B3 | – | – | – | no |
nora_rank_is_call / nora_records_checked |
Haiku CALL / CONTEST | hedged residue | keep the rank | A16 SHIPPED | DONE | purpose=nora_rank_check, 14 calls in 7d. |
2 (Axiom) | – | no |
_SUBJECT_HEAD_RE |
subject = text before one of 20 verbs (is, set, projected, aiming, grabs…) | Nora post sentence | (a) the sentence is a projection at all; (b) which words are the subject | – | MODEL-HAIKU | One Haiku JSON extract per post (cached by tweet id): a list of {title, artist, units, rank, chart, hedged}. The verb list and the _TITLE_BY_RE / _POSSESSIVE_RE shapes go in as reference examples. Code keeps the exact checks: each units and rank must appear verbatim in the sentence (number check), the title and artist must be substrings of the post. |
10-20 (Axiom: about 580 Nora rows stored in 30d from 78 store events; posts per day about 10-20) | Model error: the regex parse (the old rule). A field that fails the verbatim check is dropped (absent). | NEW |
_TITLE_BY_RE / _POSSESSIVE_RE / _subject_parts |
“‘T’ by A”, “A’s ‘T’”, unquoted possessive with a space | Nora subject | split title from artist | – | MODEL-HAIKU | Same extract. | (same) | (same) | NEW |
subject.lower().startswith(("nora ", "this week", "follow", "download")) |
4 opener words | Nora subject | drop the sentence alone | – | MODEL-HAIKU | Same extract (the model returns no row for a promo line). | (same) | (same) | NEW |
_chart_named |
“hot 100” substring | Nora sentence | Hot 100 vs Billboard 200 for a rank-only call | – | MODEL-HAIKU | Same extract, chart as a closed label (billboard200 / hot100 / other). |
(same) | Model error: the substring rule. | NEW |
_credited (in history_rows) |
key in kworb._artist_credits(row artist) |
store row credit vs the asked act | admit the row into the act’s history | K2 lists it as a follow-up | MODEL-HAIKU (fragment residue) | Reuse K2: a row admitted only by a PART of an UNRANKED multi-act credit goes to claude.classify ONE / COLLAB (purpose=kworb_act_check, cached 14d per credit). COLLAB admits (old rule); ONE drops. Whole-credit hits and all-ranked-part credits make no call (#4277 fast path). |
under 5 (code; K2 measured 10-30 a day across all its callers) | Model error: the old rule. | NEW |
_RADAR_LINE_RE |
“Name - 46K” list line | Nora RELEASE RADAR post | a units row | – | KEEP-CLOSED | A fixed list format with a number. | 0 | – | NEW |
nora_doc_kind |
“EARLY LOOK” / “RELEASE RADAR” | Nora post | doc kind label | – | KEEP-CLOSED | Nora’s own fixed post headers; only a label. | 0 | – | NEW |
_DEBUT_TITLE_RE / _parse_debut_title |
“Will A’s ‘T’ debut” | Kalshi KXALBUMDEBUT title | (title, artist) | – | KEEP-CLOSED | An upstream fixed question template; a miss is dropped (never a guess). | 0 | – | NEW |
Structural: _UNITS_RE / _RANK_RE (number formats), _PERIOD_HALF_RE / market_window (dates), _split_subject (our own Title -- Artist), _event_status (Kalshi status enum), _is_artist_family (ticker), _HANDLE_RE / _URL_RE / _TRAILING_RE (_clean), _sentences, CHART_LABELS / render code.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_relation (_VARIANT_WORDS_RE 36 words, _DISTINCT_RE sequel / re-record forms) |
the words a longer album title adds | two kworb album titles, one a prefix of the other | merge (variant) or count apart (distinct) alone; only “ambiguous” goes to Haiku | C3 / N11 (list kept, residue to model) | MODEL-HAIKU (the variant and distinct fast paths) | Send every prefix pair to the existing cached claude.album_variant_relation (purpose=album_variant). Feed the word hit as a hint (“the list reads this as VARIANT: ‘edition’”). |
about 3-5 the first week, then under 1 (Axiom: 8 calls in 7d for the ambiguous residue; cached per pair) | Model error: the word list; no list verdict: withhold the count (as now). | NEW verdict |
_group_releases prefix test (folded.startswith(g + " ")) |
folded prefix | album titles | which pairs are compared at all | – | KEEP-CLOSED | A structural prefix on folded keys; only nominates pairs. | 0 | – | NEW |
split_credit / _CREDIT_SPLIT_RE |
split on “,” and “&” | iTunes album credit | acts to count the album for | – | KEEP-CLOSED | Every part is verified by an exact join (lists_album: that act’s own kworb page lists the album id). A wrong split resolves to no page. |
0 | – | NEW |
Structural: base_title, _fold, album_key, lists_album, count_clause, _ordinal_word.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_credited / same_act (via act_keys) |
key overlap after kworb.credit_members split |
store row credit vs an act; HITS vs Billboard credit | which openings form the act’s prior | K2 lists it as a follow-up | MODEL-HAIKU (fragment residue) | Same K2 reuse as chart_history._credited (ONE / COLLAB, kworb_act_check). Only a match through a part of an unranked multi-act credit asks. |
under 2 (code: read per prior; cached) | Model error: the old rule. | NEW |
act_keys alias expansion (canonical_credit, credit_names) |
the shared alias table | an act name | which other names count as the act | – | KEEP-CLOSED here | An exact table lookup. The table itself is artist_watch aliases, OWNED:W19-C1; this file only reads it. |
0 | – | NEW |
Structural: party_set, the prior arithmetic, SAME_ACT_* fit constants.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_anchors + _MOVE_VERBS (about 70 verbs) + _OTHER_CHART_RE (about 30 chart names) + _YEAR_RE look-ahead |
“No. N”, “ |
story paragraph | which rank a units figure belongs to; skip other-chart ranks alone | – | MODEL-HAIKU | One Haiku JSON extract per story (cached by post id): for each printed top-10 row (rank, title, artist off the chart page), the units figure the story states for THIS week, with the sentence it came from. The verb and chart-name lists go in as reference examples. | under 1 (about 1 story a week, plus the settled-market reveal) | Fail closed: no figure for a rank the model does not confirm (absent). Model error: the regex parse plus verify_rows (old rule). |
NEW |
verify_rows |
folded title or artist is a substring of the segment | candidate (rank, units, segment) vs printed row | keep the figure for that rank | – | MODEL-HAIKU | Same extract (it replaces the substring confirm). Code keeps the number check: the units figure must appear verbatim in the story. | (same) | (same) | NEW |
leader_row_for |
folded title substring of the headline + _artist_agrees |
settled Kalshi release vs story headline | the story’s No. 1 figure is this release’s | – | MODEL-HAIKU | classify YES / NO / UNSURE: “is this headline’s No. 1 the release |
under 1 | Fail closed: NO / UNSURE / error = no row (absent, as now). | NEW |
_artist_agrees / credit_parties / _CREDIT_SPLIT_RE |
any credit party is a SUBSTRING of the folded headline | raw Kalshi credit vs Billboard row or headline | the same act | – | MODEL-HAIKU | Folded into the two calls above (a substring of a folded headline is a fuzzy identity join: “ye” is inside many names). | (same) | (same) | NEW |
_QUESTION_RE |
headline opens with will / could / how / … | WordPress post title | drop the candidate alone (a preview question) | – | MODEL-HAIKU (or drop the filter) | The cheapest fix is no model: remove the filter and let parse_story decide, as it already does for the second tier. Else one classify STORY / PREVIEW per post title. |
under 1 | A wrong pass costs one page parse that returns None. | NEW |
_LEADER_HINT_RE (leader paragraph fallback) |
“No. 1”, “atop”, “leader” plus a units figure | the first 6 paragraphs | which paragraph is the No. 1’s | – | MODEL-HAIKU | Same per-story extract. | (same) | (same) | NEW |
_LEADER_TITLE_RE / “billboard 200” title test |
leader words in a post title | WordPress titles | ORDER of candidates only | A16 KEEP | DONE | Only orders the candidates; the page parse decides. The “billboard 200” test is also the WordPress search term. | 0 | – | no |
_units_in / _UNITS_RE / _QUAL / _split / _SPLIT_RE / _sea_streams / _pct |
number + “units”, “SEA units comprise N” | paragraph | the figure | – | KEEP-CLOSED | Number extraction on a fixed phrase. Under the extract above it becomes the verbatim number check. | 0 | – | NEW |
Structural: _WEEK_ENDING_RE / _WEEK_RANGE_RE / _DATED_RE / _month_day / _date_near (dates), _TAG_RE / _STRIP_BLOCK_RE / _PARA_RE (HTML), story_window / story_posts_url.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
same_subject_posts -> claude.market_sibling_claim |
shared title -> Haiku SAME / CONTRADICTS / DIFFERENT | market post vs 6h of posts on other events | drop | #2016 | DONE | Nominate-only: the title match only chooses which posts the model reads, and the model decides every drop. A miss ships, which is this gate’s fail direction (fail-open). | 0 in 7d (Axiom: 0 market_sibling_claim calls; 0 sibling_* drops in 30d) |
Fail-open. | no |
_QUOTED / _TITLE_BY / _names_in |
quoted span; “ |
our own market post text | the title a post names | – | KEEP-CLOSED | It parses the fixed formats our own lanes write. | 0 | – | NEW |
Structural: sibling_drop_reason (verdict enum to reason).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
FEATURE_RE / _STRICT_FEATURE_RE / strip_features / strip_marked_features / bare_title |
feat / ft / featuring / f/ / w/ | titles and credits from Mediabase, Billboard, kworb, the wire | cut the featured part before an exact compare | C3 cites it | KEEP-CLOSED | A closed set of credit markers (a fixed format), applied to both sides before an exact fold. | 0 | – | NEW |
_RADIO_EDIT_RE / strip_radio_edit |
“(Radio Edit)” / “- Radio Edit” | titles | same recording | – | KEEP-CLOSED | One fixed tag. | 0 | – | NEW |
Structural: TRAILING_DASH_RE.
All queries ran on ['tootsies'].
| query (short) | window | result | what it decides |
|---|---|---|---|
claude_api count by purpose, for the purposes in this partition |
7d | x_gate_classify 196, release_version 195, x_artist_mention 35, release_reissue 22, nora_rank_check 14, album_variant 8, chart_age_check 6, market_take_check 2; kworb_act_check 0, market_sibling_claim 0 | Volume of the existing model calls I reuse. album_variant 8/week is the ambiguous residue only, so all pairs will cost a few more a day. |
x_artist_tag by reason, mode, ok |
30d | cached/ok 1331, not_reviewed 404, reviewed/ok 175, pinned/ok 48, error 5, unverified 3; fan_bio 0, not_artist 0, check_failed 0 | Mode is reviewed in production. _FAN_BIO refused nothing in 30 days, so its batch is low priority. scan_names dropped no name with a NO verdict. |
events with reason in (leader_fabrication, leader_check_unavailable, sibling_repeat, sibling_contradiction) |
30d | 0 rows | take_names_a_leg and the sibling judge dropped nothing in 30 days. The take_names_a_leg drop branch costs nothing today. Its risk is the PASS branch: a take that names a leg title and still names the wrong act ships with no model read. |
chart_history by source, phase, ok, reason |
30d | nora: 44 upkeep + 34 backfill stores, 580 rows, 18 no_projections; story: 111 ok (936 rows), 323 ok partial, 76 failed partial, 27 no_story; billboard 206 + 10; hits 132 + 60; kalshi 396 |
Nora volume for its extract (about 20 rows a day). The story parse returns partial on most backfill weeks (399 partial against 111 whole), so the regex anchors miss ranks often. That supports the Billboard batch. |
market_filtered reasons containing fabric / sibling / leader |
30d | only non_leader_chart (kalshi) 3290 |
Confirms no leader-fabrication drops under market_filtered either. |
Merged into the Part 0 batch plan.
utils/x_artist_handles.py is 2569 lines of data only (three tables). It has no logic. The only decision site is in x_artist_tags.py.x_artist_tags.scan_names emitted 0 not_artist / check_failed in 30 days while Haiku answered 35 calls in 7 days. Every judged name was the artist. The goldens in #4199 show the NO side works; production just has not hit it.chart_fact misses 4 of 17 measured double posts (joint credits spelled two ways, an album named two ways). That is an exact-key miss with fail-open (a repeat ships). It is not a word list, so it is not a site. A model join on the residue is possible but the volume (4 a month) does not earn it.billboard_stories returns partial on most backfill weeks (323 ok + 76 failed partial against 111 whole in 30 days). The old audit did not cover this file. That is the strongest brittleness signal in this partition.market_sibling_claims had 0 model calls in 7 days and 0 drops in 30 days. The judge is idle, not broken: market posts on two events about one title in 6 hours are rare (#2016 measured 12 pairs in 30 days).artist_priors.act_keys reads the artist_watch alias table, which is OWNED:W19-C1. P6a-2 must not edit that table; it only adds the ONE / COLLAB residue check.qualifier_trim.py (including time_span, joins_as_only, states_most, _RANK_RE / _RANK_ORDINAL, the release noun / verb lists) is OWNED:#4412 and is in no batch.Repo state: claude/classifier-audit-wave19 = origin/main 4e1b6c0. Read-only pass. Axiom
window: 7 days unless the row says 30 days. Date 2026-10-18.
Scope read: cogs/arcade.py, all 16 utils/arcade/*.py, utils/guess_grading.py,
utils/engagement_labels.py, utils/mention_shadow.py, utils/typesafe_client.py,
utils/deploy_drain.py, utils/loop_watch.py, utils/axiom_dataset.py, and the 22 named
runtime / manual scripts. For the Jev-caller check, I also read the call sites in
cogs/games.py (round loop, _grade_guess, _artist_named, _credit_acts,
_title_credit_artists), cogs/x_game.py (handle_webhook_tweets), cogs/ask.py
(_shadow_jev, _names_other_channel), utils/engagement.py (_tally_content, the seed
keys) and utils/playercard.py (the stat readers). Those files belong to other partitions.
I list their sites only in the “Jev caller leftovers” section.
| file | semantic | structural | KEEP-CLOSED | MODEL-HAIKU | MODEL-JEV | KEEP-PROTECTED | DONE | OWNED |
|---|---|---|---|---|---|---|---|---|
| cogs/arcade.py | 0 | 8 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/arcade/fighter_models.py | 3 | 12 | 2 | 0 | 0 | 1 | 0 | 0 |
| utils/arcade/memory_cities.py | 1 | 2 | 0 | 1 | 0 | 0 | 0 | 0 |
| utils/arcade/ (the other 14 files) | 0 | 30 | 0 | 0 | 0 | 0 | 0 | 0 |
| utils/guess_grading.py | 4 | 2 | 3 | 0 | 0 | 0 | 1 | 0 |
| utils/engagement_labels.py | 1 | 6 | 0 | 0 | 0 | 0 | 1 | 0 |
| utils/mention_shadow.py | 1 | 4 | 0 | 0 | 0 | 0 | 1 | 0 |
| utils/typesafe_client.py, deploy_drain.py, loop_watch.py, axiom_dataset.py | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 |
| Jev caller leftovers (cogs/games.py, utils/engagement.py, utils/playercard.py) | 5 | 0 | 0 | 0 | 5 | 0 | 0 | 0 |
| scripts/artist_sweep.py | 2 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
| scripts/music_drop_manual.py | 3 | 3 | 1 | 1 | 0 | 0 | 0 | 1 |
| scripts/versuz_card_manual.py | 3 | 3 | 1 | 2 | 0 | 0 | 0 | 0 |
| scripts/versuz_recap.py | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| scripts/riaa_credit_audit.py | 3 | 1 | 0 | 2 | 0 | 0 | 0 | 1 |
| scripts/competitor_scoreboard.py | 10 | 6 | 3 | 5 | 0 | 0 | 0 | 2 |
| scripts/called_shot_scorecard.py | 2 | 2 | 2 | 0 | 0 | 0 | 0 | 0 |
| scripts/gen_yearbook.py | 1 | 2 | 1 | 0 | 0 | 0 | 0 | 0 |
| scripts/gen_yearbook_cards.py | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 |
| the other 12 scripts (see Structural lines) | 0 | 10 | 0 | 0 | 0 | 0 | 0 | 0 |
| total | 39 | ~100 | 13 | 12 | 5 | 1 | 3 | 5 |
No semantic site. The cog takes no free text from a user: /arcade takes an opponent
member, and the web hub sends our own op enums.
Structural: _AVATAR_HOSTS (Discord CDN host set), _SLOT_STATE (our kv slot format),
meta.get("status") in ("final","failed") / ("failed","pending") (our row status enum),
str(meta["error"]).endswith("bad_pose") x2 (our own reason slug), _PERSONAL_REFUSALS
(our refusal reason codes), the likeness:* reason strings. The likeness gate calls are
counted under fighter_models.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_draw_sheet (OpenAI branch) "safety" in low or "moderation" in low |
substring on the HTTP 400 body | OpenAI image-edit error body | safety_reject (FINAL: the member never gets a fighter) vs http_400 (retryable) |
none | KEEP-CLOSED | not a model. The body is an upstream error. Read the JSON error.code (a fixed vocabulary, e.g. moderation_blocked) exactly, and keep the substring only as the fallback when the body is not JSON. |
0 model calls; 29 safety_reject in 30 days (measured) |
unknown body: retryable http_400, as today |
NEW |
_draw_grok any(w in low for w in ("safety","moderation","reject","policy")) |
4-word substring list on the 400 body | xAI error body | safety_reject_xai (FINAL) vs xai_http_400 (retryable) |
none | KEEP-CLOSED | same as above: parse the xAI error code field exactly. “reject” and “policy” are wide words: a 400 about a size or a parameter that says “rejected” turns FINAL. | 0 | unknown: retryable | NEW |
LIKENESS_CHECKS / likeness_refusal / likeness_conditions |
code check per constitution.GENERATED_LIKENESS_CONDITIONS name |
the run’s LikenessRequest |
refuse the build | none | KEEP-PROTECTED | constitution check. Not for Jev (brief). The likeness and pose vision judges (fighter_likeness_score, fighter_pose_score) are already models and are not word lists. |
0 | fails CLOSED (no_constitution, unchecked:<name>) |
NEW |
Structural: FINAL_REASONS, _TRIPO_DONE_BAD, RETRYABLE, _AVATAR_OWNER (CDN URL
shape), POSE_REBUILD_ALWAYS / EYES_REBUILD / QUALITY_REBUILD (owner-named
subject_tag hashes, an id set), _ARTIST_OUTAGE, error.startswith("sheet: "), Mixamo bone
prefix, glTF key tests ("TANGENT" in attrs, "matrix" in node, …), allowed={"convert_lo"}.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
cities_in (GAZETTEER ~170 cities + alternates, _RE whole-word, case-sensitive) |
name list as a regex | up to 400 DAILY memory notes per guild | which extra Deathmatch arenas a guild gets (a city needs 2 notes) | none | MODEL-HAIKU (DONE wave 20: confirmed_cities, purpose=memory_city_check; the regex nominates and is the fallback. Dry run 2026-10-18 on all 406 daily notes of the 2 servers: 329 notes asked, 0 run-to-run key-set changes, 1 false keep removed (a small server’s Paris rested on a person’s name), 1 boundary swap at slot 16 between two real cities) |
NOMINATE then confirm. The regex stays and nominates. For each nominated city, one cached classify PLACE / OTHER over the note sentences that name it (“Does this text use ‘ |
measured 25 refreshes in 7 days (3.6/day), 13.2 cities each; with a 1-day cache about 15-50 calls/day | model error: keep the regex hit (a wrong arena is harmless). Haiku only: the input is memory text, so do NOT send it to Jev (a new vendor for memory data needs owner sign-off; the brief excludes the memory pipeline from Jev). | NEW (#3707, 2026-09-25) |
Structural: _BUILT_IN_NAMES (exact set of our own built-in arenas), slug, key_of.
Structural only: artist_portrait._HOSTS (photo host set), artist_roster.artist_slug /
by_slug / stale_entries (exact slug join on our pinned roster; stale_entries has no
production caller), DEEZER_IDS (pinned ids), discord_auth._TOKEN_SHAPE /
INSTANCE_ID_SHAPE, hub._LIVE_URGENT_EVENTS / _ROSTER_CURSOR / op enums, live_feed
_DOWN_STATES / _PHASE / _RANK / method enums, ring_kings.ACTIONS / state sets,
deathmatch SOLID / LAYOUTS / CITIES / VEHICLE_CODE, live_card colour and phase
tuples, room.GAMES / MODES, roster.TABS, web._FIGHTER_PATH / _ARTIST_PIC_PATH /
_SCRIPT_SRC / _PROP_SET / _PROP_FILE / proxy host suffix. game_loop.py, token.py,
__init__.py: nothing.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
names_title / several_titles Nouls + title_verdict threshold |
Jev Noul, 0.5 | guess, title, artist | title win | HYBRID (#4311) | DONE | Jev decides the undecided residue. | 0 in 30 days (measured: no typesafe_api purpose=guess_grade; the last /guess round was 2026-09-18, before Jev) |
Jev None: /guess uses _grade_guess; the X game fails CLOSED |
NEW |
bare_answer + _JOINERS (by, ft, feat, featuring, x, and, with, the) |
exact title span + credited-name tokens + 8 joiners | guess | fast-path WIN, no Jev | none | KEEP-CLOSED | It decides alone, but every word must be the exact folded title or a token of a credited name or one of 8 closed function words. It is an exact identity join on closed round data. Measured (docstring): Jev scored these shapes 0.12-0.33, so the model is the worse judge here. Small risk: a credited-name token that is a common word (“future”, “lil”, “kid”) counts as allowed filler. | 0 | n/a | NEW |
pool_title_hits (>= 2 hits = shotgun list) |
exact title spans of the round pool | guess | fast-path MISS, no Jev | none | KEEP-CLOSED | Counting, which Jev cannot do. Exact folded spans of a closed pool. Risk to record: a one-word pool title used as chat (“my bad, its gods plan”) counts as a second title and the real answer loses. That is the #4311 class in the other direction. A miss lets the player type again, so the fail direction is safe. | 0 | fails toward miss | NEW |
title_contained (HARD “type it right”, #587) |
exact folded substring | guess vs title | HARD: no containment = miss before Jev | none | KEEP-CLOSED | an owner-set game rule on an exact fold. Jev then decides answer vs chat. | 0 | miss | NEW |
Structural: core_title bracket split, TITLE_YES / SEVERAL_YES thresholds.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
question_specs q/l/h Nouls, verdicts |
Jev Noul x3 per message, 20 per request | cleaned message text | labeled question / laugh / hype counts | KEEP + JEV (#4318) | DONE (as a labeler). See leftover L3-L5: no reader uses its output. | Jev | measured 68 requests (1,452 messages) in 7 days, all on 2026-10-18 09:00Z; 0 failed batches | Jev None: the shape-rule verdict per message | NEW |
Structural: _URL_RE, _CUSTOM_EMOJI_RE, _USER_MENTION_RE, _ROLE_MENTION_RE,
_CHANNEL_MENTION_RE (Discord markup), clean_text empty-text rule (no alnum).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
abuse Noul + route / period Choices |
Jev shadow | cleaned mention | nothing ships; agreement metric only | Jev shadow (#4406) | DONE | The shipped verdicts are already models (Haiku classify_abuse, Sonnet classify_mention_intent). |
0 Jev calls so far (measured). The shipped judges: 59 classify_abuse + 10 mention_intent in 7 days, the last before the key went live. |
shadow: no effect | NEW |
Structural: route_verdict / shipped_route / abuse_verdict (closed-label answer
parsers), ROUTES / PERIODS. The cog’s _names_other_channel recap -> ask override reads
message.channel_mentions ids: structural.
Structural only: _RETRY_STATUSES, status in (400, 422), fs.filename.startswith(_ROOT).
deploy_drain.py and axiom_dataset.py have no decision on text.
The brief asked whether a Jev caller still leaves a word list deciding alone. Two do.
| id | symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|---|
| L1 | cogs/games.py _artist_named (whole name, OR the longest token >= 4 chars, OR EASY SequenceMatcher >= _ARTIST_FUZZY_RATIO 0.82), via _win_components and _names_credit |
token containment + fuzzy ratio | guess vs credited acts | artist +1 point, feature +1 point, and the artist-only consolation (ARTIST_ONLY_POINTS) |
KEEP (#4311 left artist credit in code) | MODEL-JEV | Add a third Noul names_artist to the SAME jev_questions() request: “Does guess name one of the acts in acts?”. acts = jev_acts (already built per round: _credit_acts + features + _title_credit_artists), fed in the state as the closed candidate list. The rule stays the nominator: only a guess where _names_credit or _artist_named fires asks Jev about the artist. This is the #4311 class: “the future is bright” names Future by the longest-token rule and banks the consolation. |
~0-30/day (29 /guess rounds in 30 days, all before 2026-09-18; 0 X game rounds in 30 days) |
Jev None: today’s rule | NEW scope (sites old) |
| L2 | cogs/games.py _title_credit_artists (_REMIX_CREDIT_RE + _NON_ARTIST_CREDIT_WORDS, 23 words) |
word list | raw catalog title | which remix credits count as guests | KEEP | MODEL-JEV (by L1) | With L1 the list only builds the candidate acts list. A version phrase that slips through (“Sped Up Mix”) becomes one more candidate, and Jev decides. It turns NOMINATE-ONLY; no separate call. |
in L1 | in L1 | no |
| L3 | utils/engagement.py is_question (endswith("?")) |
shape rule | message | the “questions asked” stat | KEEP + JEV (#4318) | MODEL-JEV | The Jev label is already computed and stored as questions_labeled, but NO reader uses it. utils/playercard.py reads g("questions"). Fix: read questions_labeled when labeled_messages == messages, else the shape key (the rule the seed comment already states). Then run one full labeled /stats rebuild so the condition holds. |
0 added. One rebuild: ~15k requests, ~$3.60 (#4318 docstring). Daily catch-up: ~70 requests (measured). | Jev None: shape key (today) | NEW finding |
| L4 | utils/engagement.py is_own_laugh (_LAUGH_RE + _OWN_LAUGH_EMOJI) |
regex + emoji set | message | “times you laughed” | KEEP + JEV | MODEL-JEV | same: playercard reads laugh_messages, not laugh_messages_labeled. |
in L3 | in L3 | NEW finding |
| L5 | utils/engagement.py is_caps (caps ratio > 0.7) |
shape rule | message | “ALL-CAPS posts” | KEEP + JEV | MODEL-JEV | the Jev key is hype_messages_labeled (excited hype), a different meaning from “ALL-CAPS posts”. The card label must change with the key (“hype posts”), or the card keeps the caps stat and adds hype. Owner choice; the label text is user-facing. |
in L3 | in L3 | NEW finding |
Not leftovers (checked): the EASY _WIN_RATIO / _CLOSE_RATIO title rules run only when
Jev has no answer, and the close band then goes to Haiku judge_song_guess (DONE). The X
game passes pool=[title] and fails closed on no Jev answer (DONE). LAUGH_EMOJI /
BANGER_EMOJI on REACTIONS is a closed emoji set (KEEP-CLOSED, structural).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
row_is_theirs (from utils/artist_watch) |
credit match | chart row credit | which rows are the act’s | not inventoried | OWNED:W19-C1 | consumer only; the matcher is in the C1 scope (aliases, lenient_tier, s_variants). |
manual | — | no |
board_stream_totals(..., ) called with no claude client |
the album-track Haiku match is skipped | album rows | a stream total, or blank | not inventoried | MODEL-HAIKU | Wire the existing Haiku album-track match (the live lane already has it; the code comment says the sweep leaves it out). Pass a ClaudeClient when ANTHROPIC_API_KEY is set. No new method. |
manual, ~0-2 runs/day, a few calls per run | model error: blank, as today | no |
Structural: _slug filename.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
video_kind (_VISUALISER_RE, _LYRIC_RE, default “video”) |
2 regexes | YouTube title | the claim says “official visualiser / lyric video / video” | KEEP (manual) | MODEL-HAIKU | classify labels VISUALISER / LYRIC_VIDEO / MUSIC_VIDEO / AUDIO / LIVE / OTHER over the YouTube title + channel. The two regexes stay as the fallback and go in the task as examples. Today an “(Official Audio)” upload reads “video”, and the claim states “have released the official video”, which is false. AUDIO / LIVE / OTHER need their own claim wording or a refusal (prefer absent). |
manual, ~0-3/day | model error: the regex label | no (old KEEP) |
title_cut |
exact casefold substring of the known title | composed line | flags that a qualifier cut removed the title | none | KEEP-CLOSED | exact identity on a known string | 0 | — | NEW |
qualifier_checked -> Music._qualifier_gate |
qualifier rules | composed line | cut or refuse a wrong “first / ever / most” | none | OWNED:#4412 | qualifier epic | manual | — | NEW (#4473) |
Structural: _SONG_HOSTS, release_clause (“ - Single” / “ - EP”: iTunes collection-name
convention), X-Clip-* header filter.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_similarity / _closest (SequenceMatcher ratio OR title-word overlap, floor _MATCH_FLOOR 0.5) |
fuzzy ratio | host’s poll option text vs the songs the music bot played | which played song each option is (title, artist, link on the card) | KEEP (manual) | MODEL-HAIKU | Keep an exact folded-title equality as the free accept. Else one classify per poll option with labels SONG1..SONGn + NONE over the unused played songs (“Title - Artist” each), so a candidate list is the closed label set. Cache by (night, option text). |
manual, ~1 night/week, ~20-40 calls/night | model error or NONE: the option keeps its own text (today’s miss path) | no (old KEEP) |
option_song (_SUFFIX_RE “ - player”, _LOOSE_FEAT_RE “ft X”) |
delimiter regexes | host-typed option | title vs feature vs player name | KEEP | MODEL-HAIKU | fold into the same call: when the option matches a played song, the played song’s title and credit win, and the shorthand parse matters only on NONE. On NONE, a small Haiku JSON extract {title, feature} is optional; low value. Today _SUFFIX_RE cuts any “ - X” tail, so “Song - Remix” loses “Remix”. |
in the row above | regex | no |
sides_from_titles (_SCORE_RE) |
two numbers | next poll’s title | which option is side A | KEEP | KEEP-CLOSED | number parse | 0 | default True / alternation | no |
Structural: poll_rows match in question (operator argument), apply_fixes startswith
(operator argument), archive_sql, jockie_songs via parse_jockie (another partition).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
_SAME_RECORDING + _recording_key in accept |
phrase list of same-recording brackets | Deezer title vs RIAA title | same recording or “different recording” | KEEP (manual) | MODEL-HAIKU | Exact key equality stays the accept. On a mismatch, one classify SAME / DIFFERENT over the two titles, with the _SAME_RECORDING phrases as examples of SAME and “Remix”, “Live”, a re-recording as DIFFERENT. Reuse the C6 pattern (chart_ages._matching_pick). |
manual; ~264 rows per run, a residue of tens | model error: reject (prefer absent; a wrong entry hands out a plaque) | no |
_NOT_AN_ACT_NAME (soundtrack, orchestra, tribute, karaoke, cover, band, ensemble) |
word list on a name | Deezer contributor name | reject the candidate | KEEP | MODEL-HAIKU | classify ACT / NOT_ACT per guest name, list fed as examples. Keep the regex as an extra reject (both must pass). “band” also rejects real acts (“Band of Horses”); the model admits them. |
manual, a few per run | model error: regex verdict | no |
credit_matches / riaa._credits_act |
credit match | Deezer lead vs RIAA cell | lead check | KEEP | OWNED:W19-C1 | consumer of the artist_watch matcher |
manual | — | no |
Structural: r.format.strip().upper() == "SINGLE".
Runs twice a day inside the ops-monitor GitHub job, not in the bot. It writes
competitor_match events and feeds the ops-monitor “slow lane” finding (WIN_FLOOR 0.5
over MIN_MATCHES 10). It does not change what the bot posts.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
split_matchup no-separator branch (m.casefold() not in text.casefold()) |
substring heuristic | our matchup + our post | “BTS” (act) vs “Taylor Swift Patient Zero” (title + act) | none | MODEL-HAIKU (in the same_story call) | The -- / - / “by” splits read our own field format (structural). Only the no-separator guess is semantic; the pair judge reads the raw matchup instead. |
in same_story | — | NEW |
subject_matches / _artist_named (mn.artist_grounded_in_wire, mn.title_grounded_in_wire) |
wire grounding | their tweet | subject present | none | OWNED:W19-C1 | consumer of the C1 grounding readers. In the batch below it becomes the NOMINATOR for the pair judge. | — | — | NEW |
_work_kind (_ALBUM_RE, _SONG_RE) |
word regex | both texts | album vs song conflict -> reject | none | MODEL-HAIKU | in the pair judge | in same_story | — | NEW |
certs (_CERT_BOUND_RES 15-verb list, _CERT_CONTEXT_RE) |
verb list binds a level word | both texts | a cert level that agrees or conflicts decides the pair | none | MODEL-HAIKU | in the pair judge. The level vocabulary (gold / platinum / diamond / multiplier) is closed; the verb list that decides “is this level a certification here” is not. | in same_story | — | NEW |
same_story final fallthrough (no figure: same chart or no chart) and the act-only rules (named, soft_kind) |
rule ladder | pair | pair or not | none | MODEL-HAIKU | ONE classify SAME / DIFFERENT per nominated pair (subject match + time window + no hard number conflict). Input: our matchup, our 120-char preview, their tweet, both chart keys from chart_keys, both figure sets. Cache by (our event time + matchup, tweet id). The docstring’s rule list goes in the task as the definition. |
Axiom: ~80 tweets per run, 9 runs in 7 days, 161 pairs + 82 misses in 7 days. Estimate ~30-100 pair calls/day. | model error: today’s rule ladder | NEW |
is_story cue admission (mn.chart_cue_strength >= 1) |
cue list | their tweet | counted as a MISS only if it passes | none | MODEL-HAIKU (or Jev Noul) | A tweet with no cue never reaches the miss count: an admission prefilter deciding alone. Ask “is this a music chart / streaming / sales / certification numbers story” per non-reply tweet, cached by tweet id. Jev would fit (per-row shape label, no world facts), but the job has neither key today. | ~160 tweets/day (Axiom: ~80 per run x 2) | model error: the cue rule | NEW |
is_story is_retrospective |
frames regex | their tweet | drop look-backs | none | OWNED:W19-B3 | — | — | — | NEW |
charts_relation (_BILLBOARD_GUESS, _BILLBOARD_FAMILY, _vague, _is_source) |
set logic on chart keys | keys from mn.charts_named / claim_platform |
same / conflict / unknown | none | KEEP-CLOSED | set math on our own chart keys. The text -> key step is in utils/music_news (A2/A12, another partition). |
0 | — | NEW |
figures_agree + counts (_COUNT_RE, _SCALE, _CHART_NAME_RE, FIGURE_TOLERANCE) |
number parse + 2% tolerance | both texts | a count conflict rejects | none | KEEP-CLOSED | number check (brief: exact on a closed format) | 0 | — | NEW |
ranks / is_list / list_entries (_RANK_RE) |
“#5 / No. 5” | both texts | position agree / list split | none | KEEP-CLOSED | number format | 0 | — | NEW |
Structural: COMPETITORS, OUR_EVENTS, _MATCHUP_SEP_RE / _MATCHUP_BY_RE (our own
matchup format), tweet_to_their_post ("RT @" prefix, handle set), dedupe_ours (exact
key), join_crossposts (time join).
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
kalshi_settled_units "equivalent" in title.lower() |
substring | Kalshi KXALBUMEQUIV market title | skip the odd pure-sales ladder | KEEP | KEEP-CLOSED | upstream title of a templated series (a fixed vocabulary) | 0 | skip | no |
apply_billboard_units _key fold |
exact fold join | album, artist | attach the published unit count | none | KEEP-CLOSED | exact identity join | 0 | no match: blank | no |
Structural: dated_label.upper(), accent_columns.
| symbol | pattern (short) | input | decision | old verdict | new verdict | shape + input (list fed) | calls/day | fail direction | NEW? |
|---|---|---|---|---|---|---|---|---|---|
name.lower() in current_names |
exact name equality | a departed member’s name vs current names | skip the alumni portrait (same person on a new account) | structural | KEEP-CLOSED | exact fold. Person identity: a model must not infer it (the names/aliases privacy rule). | 0 | skip | no |
Structural: avatar a_ prefix (animated hash), _CHARACTER_LINES (our archetype labels).
Structural only: "deleted user" (Discord’s fixed placeholder name), _HOLO tier enum,
name_sort / _name_key fold (sort only).
versuz_recap.py (SQL + argparse), gen_market_banner.py (colours, font paths),
generate_help_examples.py (prompt lists, no decision), refresh_patrons_wall.py,
build_share_doc.py ("#" in esc markdown escape), fit_chart_decay.py (SQL),
tripo_props.py (glTF keys), arcade_artist_pilot.py, arcade_landmark_distances.py,
arcade_loco.py, arcade_rk_mocap.py, audition_voice.py, run_evals.py (the
--filter operator argument only).
All against ['tootsies'].
| # | query (short) | window | result | what it decides |
|---|---|---|---|---|
| 1 | typesafe_api count by purpose, surface |
7d and 30d | 68 calls, all engagement_labels / stats, 0 failed; first 2026-10-18 09:00:03Z, last 22 s later |
Jev went live on 2026-10-18. guess_grade and mention_shadow have made 0 Jev calls. |
| 2 | typesafe_shadow by purpose |
30d | 0 rows | No agreement data exists yet for #4311 or #4406. |
| 3 | stats_seed last 6 rows, detail |
7d | 2026-10-18: labels_seen 1452, by_model 1350, no_text 102, fallback 0, flips question 76, laugh 13, hype 110. Earlier days: no label fields. | Jev disagrees with the shape rule on 5.6% (question) and 8.1% (hype) of messages. Only today’s catch-up was labeled, so labeled_messages == messages is false for every member until a full rebuild. L3-L5. |
| 4 | readers of *_labeled keys (code grep, not Axiom) |
— | 0 readers; utils/playercard.py lines ~896-901 read questions, caps_messages, laugh_messages |
The shape rules decide every shown stat alone. L3-L5. |
| 5 | guess_game_* / songbomb_* |
30d | songbomb_started 29, answered 25, expired 3, guess_game_started 1; last 2026-09-18 20:22Z | /guess traffic is near zero; Jev title grading has never run live. L1 volume. |
| 6 | x_game_round / x_game_answer |
30d | 0 | The X game is idle. |
| 7 | claude_api purpose classify_abuse, mention_intent |
7d | 59 and 10; last abuse call 2026-10-17 17:12Z | The mention shadow had no mention after the key went live. |
| 8 | arcade_room action=cities |
7d | 25 refreshes, all ok, avg 13.2 cities | memory_cities volume for the Haiku confirm. |
| 9 | competitor_match by kind |
7d | match 161, miss 82, run 9 | competitor_scoreboard volume. |
| 10 | competitor_match kind=run count |
7d | 60-85 tweets per run | ~160 competitor tweets/day for is_story. |
| 11 | fighter_model by reason, provider |
30d | safety_reject / openai 29 (FINAL); no safety_reject_xai |
The substring rule sends 29 members to a final refusal a month. The event keeps only “HTTP 400”, so I could not check whether any were false. |
Merged into the Part 0 batch plan.
questions_labeled,
laugh_messages_labeled and hype_messages_labeled, and a code comment says a reader
uses them when labeled_messages == messages. No code reads them (grep over cogs/,
utils/, scripts/). The player card shows the shape-rule counts. Also, only the
2026-10-18 catch-up was labeled, so the equality is false for every member until one
full labeled rebuild runs. This is the main answer to the brief’s Jev-caller question.guess_grade and mention_shadow have 0 typesafe_api events and
0 typesafe_shadow events. /guess has had no round since 2026-09-18 and the X game
none in 30 days. So no measured miss rate exists for #4311 or #4406 in production.guess_grading fast paths stay code. bare_answer (fast win), pool_title_hits
(fast miss) and title_contained (HARD rule) decide alone, but each is an exact fold on
closed round data, and the docstring measured Jev worse on the bare-answer shape. One
risk to record: a one-word pool title used as chat counts as a second title, so a real
answer can lose (safe direction: the player types again).safety_reject in 30 days come from a substring test on the error body. Reading the
provider’s JSON error code exactly is the closed-set fix. The Grok list (“reject”,
“policy”) is wider than the OpenAI one. Not filed: I could not see the error bodies.riaa_credit_audit,
called_shot_scorecard, music_drop_manual, versuz_card_manual, gen_yearbook) as
KEEP for “manual”. It did not have competitor_scoreboard (2026-10-04), memory_cities
(2026-09-25), the arcade, or the three Jev modules; those are NEW here.artist_roster.stale_entries has no production caller. Dead code, structural.cogs/games.py) and L3-L5 (utils/engagement.py,
utils/playercard.py) are in files another partition reads. If that partition also
lists them, merge the rows under one batch owner; P6b-1 and P6b-2 are disjoint files.