Skip to content

feat(YT終極強化): 止血gate+贏家公式評分卡+TG漏斗復活+每週贏家飛輪+變現四線+loop無縫剪輯#7

Open
yeyyeyeyyeye wants to merge 194 commits into
mainfrom
feat/ultimate-uplevel-2026-07
Open

feat(YT終極強化): 止血gate+贏家公式評分卡+TG漏斗復活+每週贏家飛輪+變現四線+loop無縫剪輯#7
yeyyeyeyyeye wants to merge 194 commits into
mainfrom
feat/ultimate-uplevel-2026-07

Conversation

@yeyyeyeyyeye

Copy link
Copy Markdown
Collaborator

量化阿森「終極強化」v4/v7 系統批次(本機工作室):

  • 止血: studio_common topic_gate(禁用洗版骨架+語意去重),接news_dept/topic_bank/pull_topic
  • 內容: produce_batch 贏家公式評分卡 title_formula_score + 重生迴圈; render_ffmpeg loop無縫尾
  • 飛輪: weekly_winners(觀看×完播×標題模式→回灌traffic_signals)+ ypp_tracker 四門檻追蹤
  • 變現: tg_magnet upsell + sponsor_outreach(Gmail SMTP驗過)+ 社群付費層/媒體包
  • 修: env_check(SMTP中文電腦名bug→local_hostname); .gitignore補token_manage/token_analytics/*.bak
  • 移除誤追蹤 make_video.py.bak

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18

moneycometomywallet-alt and others added 30 commits July 8, 2026 14:35
量化阿森「終極強化」v4/v7 系統批次(本機工作室):
- 止血: studio_common topic_gate(禁用洗版骨架+語意去重),接news_dept/topic_bank/pull_topic
- 內容: produce_batch 贏家公式評分卡 title_formula_score + 重生迴圈; render_ffmpeg loop無縫尾
- 飛輪: weekly_winners(觀看×完播×標題模式→回灌traffic_signals)+ ypp_tracker 四門檻追蹤
- 變現: tg_magnet upsell + sponsor_outreach(Gmail SMTP驗過)+ 社群付費層/媒體包
- 修: env_check(SMTP中文電腦名bug→local_hostname); .gitignore補token_manage/token_analytics/*.bak
- 移除誤追蹤 make_video.py.bak

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
- A1: produce_batch --flagship格式 AI_COMPANY_RULES + _system_facts()注入本系統真實數字(反造神獨家護城河)
- A2: SEO_TERMS高意圖搜尋詞注入標題/tags/pull_topic加權
- A5: weekly_winners._auto_seed自動增產贏家題+降權輸家題; gen_topics加bias_keywords
- A10: news_dept BIG_KW擴台股觸發詞(財測/00940/投信外資/斷頭)
- B2: tg_magnet upsell接華南銀行匯款(帳號存gitignore的payment_info.json不進版控)+回測不騙人worksheet.csv
- B1(碼): sponsor_outreach加_load_env自載入(Pionex信已實寄)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
- C1 daily_health: 憑證/json完整性/cron失敗/名單/洗版洩漏 一頁健檢+ntfy(每日09:00)
- C2 northstar: 訂閱/觀看/各源收入/YPP缺口/飛輪贏家 聚合→northstar.json+ntfy(每日09:05)
- A3 retention_dept: audienceRetention逐段留存(已驗API可行,回100段)→找drop-off段,首跑結論=最大流失在開頭(鉤子是主戰場)
- A7 探針結果: hour維度API不支援(Studio限定)→誠實沿用既有雙時段,不硬做
- 全排進crontab

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
- _ENGAGE_QS 15→21句,補台股(0050/存股/除權息)+AI題材,對齊內容主軸拉留言
- comment 自動回覆 每2h→每小時(快回覆=Shorts演算法互動加分)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
用真實回測數據的誠實避雷指南(87%→15%、0050 -33.8%vs-22.6%、成本math);導TG bot+頻道;不保證收益守誠信

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
cron由local_cron載env,但直接跑produce_batch(如手動蹭時事)會缺key→LLM全失敗。setdefault不覆蓋cron環境。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
流量診斷=爆發後冷卻非崩;穩定量產到不了YPP→三招破局:
- D2 格式All-in: WINNING_FORMAT模板(金額對比+損失框架+30-45s)+--format-focus旗標+FORMAT_FOCUS env;主產線30天走此格式,news/experiment另路保多樣
- D1 trend_hijack.py: 抓outliers.json競品爆款→LLM改寫成量化阿森誠實同型題(過gate)→產片騎演算法;audio誠實標手動(無API+失分潤)
- D3 sponsor_trigger.py: 讀northstar觸及,達門檻(28天觀看3萬/訂閱200/單片5000)才ntfy提醒接贊助,不在低觸及亂寄;媒體包排週更
- crontab: format-focus主產線/trend_hijack每4h/sponsor_trigger+媒體包

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
首批覆核抓到旗艦爛批(把AI公司題硬塞87%勝率回測避雷=四不像、37訂閱曲解成507支只37能用)→已刪6支爛批:
- AI_COMPANY_RULES加「本題專注·嚴禁混題/編數字」硬約束
- produce_batch加--flagship arg(--topic搭它→category=AI公司揭密觸發旗艦格式+真數據)
- 稽核B修:_rank加flag鍵讓旗艦題(原墊底餓死)最優先自動產
重產驗證:507→37故事連貫誠實、數字正確、真飛輪學習敘事、無混題

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
- weekly_winners: 洗版洩漏監控從「計數vs基準」改「洩漏片標題集合」,片庫長大不再誤報🔴,只有出現集合外新標題才警
- daily_health: 加 analytics/OAuth token 健康檢查(過期會讓northstar/ypp/retention靜默寫null,現在會抓到)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
Carson瀏覽器登入TikTok(@carson.quant)→存storage_state(619 cookies,gitignore不進版控)。
tiktok_upload.py: 載session+Playwright上傳本地mp4(TikTok吃本地檔不用tunnel)、caption取自.md標題+hashtags、tiktok_ledger去重、--slug/--max/--dry。
首測:登入✓檔案✓caption✓,發佈鈕改輪詢等處理完+data-e2e選擇器。TikTok bot偵測/UI改版故headed+多fallback。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
agent根因診斷:TikTok IPv4-only(無IPv6),本機IPv4間歇中斷時page.goto空等timeout=真卡點(非發佈鈕邏輯)。
- _reachable(): 上傳前6s IPv4預檢,斷線即明確診斷不空等45s
- 導頁 wait_until=commit+60s+重試;輪詢等 input[type=file](SPA/iframe)最多40s
- 發佈:每輪先 _dismiss_modals(知道了)關版權彈窗(根因)→ post_video_button(force)→驗證離開compose
IPv4穩定/VPN時可完成;登入+檔案+caption+發佈鈕皆確認存在(MCP DOM佐證)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
品保agent今晚攔下捏造台積電假高點的爛片→系統性修:
- GUARD加硬約束:個股具體價位/歷史高低點非確定為真→用假設語氣,絕不斷言可能造假的史實
- _to_traditional加白名單:s2twp把「参数」過度在地化成「引數」→修回「參數」(配音自然)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
quality_score/audit抓不到事實錯。fact_guard規則偵測「個股名+具體價位/年份高低點斷言」高風險句→
STUDIO/fact_flags.json+ntfy人工複查(只旗標不刪·誤判成本高)。排每天11:30發佈前跑。與GUARD防捏造prompt=防生成+防漏網雙層。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
突破:Playwright .click()被TUXModal-overlay(版權檢查窗)攔截→改 page.evaluate 呼叫
document.querySelector('[data-e2e=post_video_button]').click() JS原生click直接觸發handler、擋不住。
實證:2026-07-09 第一支「定投停利」已發上 @carson.quant(跳content頁+列表可見)。
+設隱私=所有人(否則預設僅自己沒觸及)。跨平台正式活。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
把IG/TikTok觸及導回YouTube衝訂閱/YPP。YT原片不動,只加在跨平台版:
- make_cta_card.py: 暗色片尾卡(YT鈕+訂閱量化阿森+搜尋量化阿森+不喊單只認數據避雷),1080x1920,產一次重用
- append_yt_cta.py: ffmpeg把3秒CTA卡接到原片尾(scale對齊+補靜音)→output/<slug>_ytcta.mp4(驗:72.6→75.7s音軌正常)
- tiktok_upload/ig_reels_upload: 上傳改用_ytcta版+caption加YT導流行;失敗自動退回原片
- YT(upload_youtube/daily_publish)不碰,照用原片

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
驗收帶片尾卡的IG/TikTok跨發成功:TikTok已發43秒(40s+3s訂閱卡)、IG Reels已發布(media_id 18141763915551032)。
ig_reels_upload直跑時os.environ無IG token(cron靠local_cron載)→加_load_env在UID/TOKEN讀取前。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
批量驗收:TikTok 3支全自動發成(JS-click標準腳本可用·無人值守成立)+IG 2支(62折扣/旗艦)全帶片尾卡。
修--max bug:原本會把衍生_ytcta.mp4當原片抓(caption變slug)+發洗版舊片→加skip _ytcta尾+is_banned_skeleton。
排crontab每天15:30 --max 3自動跨發(帶訂閱YT片尾卡)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
修兩個IG營運脆點:
- tunnel_up: ①run_forever保活迴圈每~4分重蓋ts(原本tunnel活著但ts變舊→下游誤判不通)②新增--ensure冪等自癒(不健康才detached重啟常駐,survive父程序)③4xx(fileserver根路徑403)視為通不誤判④排cron每10分自癒
- ig_backfill: 加_load_env(直跑時IG_USER_ID/TOKEN讀不到→誤判整平台未設定跳過)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
跟tiktok_upload同修:ig_backfill待補清單原本含「爆倉還活著」洗版舊片→加is_banned_skeleton+_ytcta過濾。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
- make_landing.py→assets/landing/index.html:暗色手機優先bio樞紐,讀channel_config.affiliates動態產(只列已申請聯盟),YT訂閱/免費檢核表/多聯盟(誠實揭露)/產品階梯(私訊索取不放帳號)/接案詢價/風險聲明;零保證收益零逼單
- tg_magnet:新名單加src歸因(抖/tk→tiktok·ig→instagram·預設youtube)+stage階梯欄,看哪平台最會帶名單
- assets/接案服務包.md+聯盟申請包.md:Carson複製即用去接洽/申請終身手續費分潤;只到詢價不自動簽約動錢
- channel_config.affiliates(本機·gitignore):6源(Pionex一次性+MEXC/Bitget/Bybit終身分潤待KYC+Perplexity官方+TradingView)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
B: 查證2026-07-09 TikTok Creator Rewards/Shop/IG訂閱徽章連結貼紙/YouTube
YPP+Super Thanks 實際門檻與步驟,標明來源與查詢日期;重大發現=TikTok
Creator Rewards與Shop目前多半不對台灣開放(需官方App/後台再確認),
YouTube YPP Tier1(500訂閱)是現階段離變現最近的一步,建議優先順序。

D1: 讀碼列出produce_batch.py/studio_common.py/make_video.py/tts_edge.py
硬編碼語言/persona/hashtags/題材清單(檔案:行號對應),提出
channel_profile.json設計、評估開英文頻道複製A/B/C變現的改動範圍/
風險/成本,結論=現階段不建議(先打通中文頻道漏斗)。只寫報告,
未動任何.py產線檔一行。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
E1 新增 scripts/platform_monetization.py:追蹤 YouTube/TikTok/IG 距原生變現門檻,
YouTube 重用 ypp_progress.json(不重抓)、IG 走官方 Graph API(.env 憑證,查不到優雅
跳過)、TikTok 無官方API絕不硬爬只標記待人工;輸出 STUDIO/platform_monetization.json,
新達標才用現成 notify.push() 推播(防洗版),並把摘要併入 northstar.json;
deploy/crontab.txt 加每週一排程。

A5 gen_media_kit.py 加 TikTok/IG 已發布支數+跨平台總觸及區塊(無真實觸及數據來源
的欄位誠實留0/待接,不臆造),不動既有 YouTube 媒體包內容。

A3 tips_url 維持留空(不硬填);新增 assets/打賞開通.md 說明 Carson 自行開 Ko-fi/
BuyMeACoffee 帳號後怎麼填值+重產 landing 頁;make_landing.py 打賞按鈕邏輯確認已
是「tips_url 有值才顯示」,未改動。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
A2 tg_magnet.py 新增 run_newsletter_pitch(--newsletter):對已買worksheet(stage>=2)
或名單建立滿7天且未推過電子報者,推 NT$99/月付費電子報 pitch(誠信文案:不喊單不保證
收益,交付走TG付費頻道人工拉群);推播成功打上 stage=3(僅代表已推播邀約,非付費確認);
無收款方式(payment_info.json/NEWSLETTER_URL皆空)自動轉dry;leads寫檔改走
studio_common.save_json_atomic 防併發洗檔。

finance_dept.py entries 加 platform/stream 欄(預設 youtube/同type,向下相容舊資料);
TYPE_LABEL 擴充 product/newsletter/vip/tips/sponsor;summarize() revenue 改用
type!=cost(舊資料算法結果不變,新收入線免逐一硬編碼);CLI 加 --platform。

C2 新增 revenue_dashboard.py:唯讀彙整 finance.json+tg_leads.json,輸出
STUDIO/revenue.json(各平台×各收入線進帳矩陣、名單來源分布、名單→付費轉換率),
併入 northstar.json 的 revenue_by_platform(只新增此key不動既有欄位)。
轉換率只計人工確認付費的 stage(2/4),stage=3(電子報已推播未確認)另算
newsletter_pitched_unconfirmed 不計入,避免自動推播灌水轉換率(獨立複查抓到修正)。
deploy/crontab.txt 排北極星之後每天09:06跑一次。

已用假資料本機驗證(語法檢查/--dry試跑/revenue.json結構/stage灌水修復)並清空測試殘留;
獨立 fresh-context agent 複查通過(硬編碼收款/併發寫檔/北極星併寫/文案誠信皆無阻斷問題)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
診斷:memory記的「旁白薄」其實誇大——音檔/字幕讀 voice.txt(實測207字扎實)一直是實的,不薄。真問題在 build_md body 段的「旁白:」寫死成 heading 小標,而 make_video 的 concept card 靠 heading+narration 分類要畫哪張圖(網格/複利/回撤),只給小標訊號太薄→常退回預設圖。
修法:新增 _split_voice 把完整 voice_text 依句末標點切句、平均分到各段,每段概念卡拿到真旁白句→選對圖。零風險:不動音檔/voice.txt/LLM prompt,只豐富 md 段旁白(兼作 voice.txt 缺時的字幕後備)。已測 build_md 各段輸出真句。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
- 補 <!doctype>/<html>/<head> 含 charset=utf-8 + viewport(手機優先bio必需,原本是HTML片段缺這兩個中文/縮放會壞)
- 已部署公開 repo carsonchou/carson-quant-link(只含此乾淨index.html·掃過無密鑰)→ GitHub Pages
- 上線驗證過:https://carsonchou.github.io/carson-quant-link/ 回200·全區塊在·連結正確·零外洩

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
P2(堵新洗版+多樣性):
- studio_common 新增 _skeleton_family/check_skeleton_frequency/record_skeleton_produced:
  用「動作詞+生活比喻詞」抽粗粒度濫用家族指紋,對近7天同家族設週上限(cap=3),
  補 BANNED_SKELETONS 靜態表與 _too_similar(0.82) 因措辭差異攔不到「定投×賓士」型新洗版的缺口;
  非已知濫用家族一律放行,不誤殺一般題/贏家公式單支。
- 新增 skeleton_similar/skeleton_dup_any:去數字+去題材名/血詞後的骨架相似度判定,
  補 _too_similar 之外的「同模板換數字」第二道偵測,供 produce_batch 接線。
- weekly_winners._auto_seed:回灌贏家題前先過 check_skeleton_frequency,
  達週上限的候選題不入庫,堵住飛輪把單一贏家詞回灌成洗版的源頭。

P3(修 topic_gate 對時事的誤縮):
- 新增 _event_tag 粗分類新聞事件屬性(上市/暴跌/爆倉/暴漲/駭客/監管/大戶等7類)。
- topic_gate 加事件識別維度:雙方都有明確且不同的事件標籤時不視為重複
  (即使骨架文字相似),救回「BTC-ETF-上市」vs「BTC-暴跌」這類不同事件被誤判塌縮、
  連帶吃掉 trend_hijack 改寫題的問題;同事件同句式仍照原骨架相似度邏輯擋。

簽名相容:is_banned_skeleton/topic_gate/_norm_skeleton 對既有呼叫方(produce_batch/topic_bank/
trend_hijack)零破壞,純加新函式。自驗:ast.parse 過兩檔;mock 連灌6支「定投×賓士」→第4支起
被頻率上限擋、單支不誤殺;mock BTC-ETF-上市 vs BTC-暴跌 不判重複、同事件同句式判重複;
舊幣圈洗版(爆倉還活著/勝率9X破產)仍被 is_banned_skeleton 擋,無回歸。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
P1鉤子留存:①retention_insights.json的完播診斷結論即時注入HOOK生成prompt(檔不在則優雅跳過)
②HOOK_RULES第一句規則加硬性要求:結論/數字前置、禁鋪陳暖場開場、不得與段落1逐字重複
③_weak_hook新增純加法gate:即使有數字/衝突詞,若第一句仍是典型鋪陳起手詞(你知道嗎/大家好/
今天要跟大家聊聊等)一樣判弱,擋純鋪陳問句開場,沿用既有≤2重生迴圈。

P3時事題保底配額:pull_topic新增_set_batch_plan機制,main()批次開跑前設定本批(~30%、至少2支、
批次<2支不保底)時事題(hotspot/breakout/intel)配額;配額內優先從時事候選挑(仍照原_rank排序
取最優),配額吃滿或庫存無時事題則照原排序自然選,不翻轉整體排序、不誤殺乾淨題,解決143支
hotspot+9支breakout長期被墊底餓死問題。

自驗:①ast.parse過②單測build_md/_weak_hook(mock鋪陳開場判弱、數字+反直覺前置通過)③單測
pull_topic(mock混合題庫9支批次→3支時事題配額全數命中)④sc.is_banned_skeleton/topic_gate等
studio_common呼叫簽名未改動⑤獨立複查:quota=0(未設定批次計畫)行為與修改前完全相同,無回歸風險。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
治 Carson「流量下降」體感誤判(實際近28天滾動觀看 8,565→20,110 是上升,被
每日鋸齒嚇到)。

- northstar.py:新增 _rolling_trend(),從現成 STUDIO/metrics_history.json
  重建近7日/近28日滾動趨勢方向,寫入 northstar.json 的 trend 欄位並在終端
  摘要最上方標「【滾動趨勢·最重要】」,單日增量標注「僅供參考,忽高忽低
  不代表趨勢」弱化其視覺權重。不重打 YouTube API。

- web_center/server.py:修 _series() 的隱藏 bug——metrics_history.json
  混雜 {date,total_views} 與 {t,views} 兩種 schema,舊邏輯對 date-schema
  快照 p.get("views",0) 撈成 0,在決策中心 sparkline 上鑿出假的骨折式驟降
  ,正是鋸齒誤判的元凶之一。新增 _clean_rolling_series() 統一正規化+丟棄
  0值壞快照,_kpi() 新增 trend_7d_pct/trend_28d_pct/trend_direction。

- web_center/index.html:KPI 卡「28D VIEWS 觀看」與左側「28D VIEWS TREND」
  sparkline 都加上方向徽章(▲/▼/▶+近7日%),趨勢向上時線條與文字轉綠色,
  一眼看到方向而非糾結單日數字;沿用既有暗色 HUD 風格,不破壞既有分頁。

- daily_health.py:token 失效偵測接上獨立 ntfy 告警(用現成 notify.push(),
  topic 走現成 _ntfy_topic() 讀取,未硬編),訊息明講「token失效→數據降級
  →重生指令」,別讓 northstar/ypp/retention 靜默寫 null 沒人知道。只在
  --notify 時才真的推播。

自驗:ast.parse 4 檔通過;northstar.py 實跑成功(近7日+14.2%/近28日
+296.5%/上升);daily_health.py 用 mock notify+假 token 失效情境驗證觸發
獨立告警(訊息含 token失效/重生字樣)、無 --notify 時不推播;web_center
本機起服(port 8799)實測 /api/state 與首頁皆 200,JS 語法(node --check)
通過;獨立 fresh-context agent 複查範圍/邏輯/無硬編 topic 過關。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
P5-a 產線止血(07-09 audit_fail 0→10 根因修復):
- 根因查明:三處最終 ffmpeg concat/編碼(靜態/b-roll/動畫)與 moviepy write_videofile
  都直接寫「正式 out_mp4 路徑」,一旦被 produce_batch 逾時整組砍掉(殭屍防護)或編碼
  中途失敗,正式路徑上就留下 0KB/無視訊軌/片長 0-1秒的半成品,audit_video 事後才抓到、
  白算一次有效產量(實測 output/_rejected/ 撈到 5 支 01:45-01:51 同批 0 bytes 的真案例)。
- 修法:render_ffmpeg.py 新增 _encode_and_validate() —— 一律先寫暫存檔,ffprobe 驗證
  (視訊軌/音軌/片長)過了才搬進正式路徑;失敗重試一次;兩次都失敗絕不留壞檔,原因寫進
  STUDIO/ops_log.txt。三個 concat 呼叫點(b-roll/動畫/靜態)全套用。
- make_video.py 對稱處理:build_video() 的 moviepy 輸出同樣先寫暫存檔+驗證才搬入正式
  路徑;main() 對 ffmpeg 後端回傳/moviepy 兩次重試後的最終結果都補一道 _probe_render_output
  防呆(二次驗證+清壞檔),徹底堵死「回傳成功但正式路徑其實是壞檔」的殘餘縫隙。

P5-b fact_guard 補強(fact_flags.json 55 bytes 幾乎沒攔到):
- 新增 _RISK_PERF 規則,攔不掛個股名也危險的「憑空精確績效數字」:回測N檔/勝率X%/
  報酬Y%/N次操作,涵蓋品保實測溜過的三個真案例(回測500檔34.9%會賺/812%程式碼回測/
  當沖1000次),句式順序不拘(口語稿常見「500檔…跑回測」「34.9%真的賺錢」)。
- 新增 _HEDGE 誠實揭露語境放行(示意/假設/僅供參考 + 號稱/拆穿/揭穿/話術等破除語境,
  對齊 audit_video.py 既有 DEBUNK 判斷),避免誤殺「拆解812%神話為什麼是騙點閱」這類
  合理教學內容——已用真實 output/_rejected/ 腳本驗證:debunk 片正確放行、自稱實測片
  正確被攔供人工複查。

P1 首幀視覺 gate:
- render_ffmpeg.py 翻轉 intro 卡優先序:原本「品牌卡優先、hook_card(大數字衝擊卡)只在
  無品牌素材時當備案」,但 assets/brand/intro_template.png 常態存在,導致 hook_card 幾乎
  沒被用到、首幀變成平淡標題卡。改成能從標題抽到數字就優先用 hook_card,抽不到才退品牌卡。
- test-render 實測驗證(ffprobe):51.76s、h264 視訊軌+aac 音軌俱全,t=0.8s 首幀為「10年」
  大數字衝擊卡+反直覺句+懸念句,非空鏡(t=0 有既存 0.5s fade-in 黑幀,非本次改動引入)。

自驗:①四檔 ast.parse 全過。②模擬音檔缺 FATAL 早退、無 0KB 殘留;模擬編碼兩次失敗
(_encode_and_validate 直接測試)不覆蓋既有正式檔、無 tmp 殘留、ops_log 有記錄。
③mock 捏造績效句(500檔/34.9%/812%/1000次)被攔,誠實假設句與 debunk 句不誤殺。
④真實 slug 完整跑一次 make_video.py,ffprobe 確認軌道齊全+首幀為數字衝擊卡。
⑤正常片仍可產出(本次 test-render 本身即為回歸驗證,無異常)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
把 B(cc22b00)在 studio_common 新增的多樣性函式 wiring 進 make_one 標題 gate:
- 重生迴圈加 sc.skeleton_dup_any(同模板換數字複製)+ sc.check_skeleton_frequency(濫用家族本週上限)→試圖多樣化
- 3 次後仍同骨架/家族滿額→跳過該題避免洗版(不硬塞)
- 標題確定產出後 sc.record_skeleton_produced 記家族時間戳供計數
驗證:4 支「定投×賓士」歸同家族,cap=3 第4支被擋;不同題材乾淨題放行不誤殺;syntax OK。
weekly_winners._auto_seed 那條 B 已自接;此 commit 補主產線這條。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ENz2enyytHgQXR58okKP18
moneycometomywallet-alt and others added 30 commits July 17, 2026 09:18
pivot-verify 埋在細節裡的關鍵發現:管線是 produce(06:07)→render(*/15)→
評分(隔天06:40)→可發 = ~27h 延遲。這讓昨天加的 12:30 長片保底補產只能救
「明天」、救不了「今天」——而長片可發庫存一度只剩 3 天,斷炊是現在進行式
(07-16 批次被砍、07-17 整批跳過,已連兩天)。

加 18:00 一班(18:30 發布前 30 分):12:30 補的長片 → 渲染有 5.5h 餘裕 →
18:00 評分 → 18:30 就能發。

成本安全(已查證非假設):quality_score.py:273 `if rescore_ai or not was.get("ai")`
= 冪等,只評沒有有效 ai 分數的片,既有片走 prev 快照不重評、不重複燒 LLM;
且走 OpenRouter 不吃 YouTube 每日 10,000 配額。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
調查(series-integrity)證實換殼比預估嚴重一倍:EP機器人日記 5 個事實產了 23 支
(第26天/+1.76% 產 8 支、第30天/-1.19% 產 9 支);另有 5 支待發標題與已發布片
正規化後完全相同。

去重為何全部失守(三道都在包裝層,沒有一道比「事實」):
1. 既有去重比的是標題/旁白句/骨架/比喻——措辭天差地遠但同一組回測就漏光。
   題庫 78 題帶 fact_key,26 個 fact_key 各掛 2-3 題(如 allin_vs_dca_0050_10y
   掛 3 題),而 used 旗標是**逐題**不是逐 fact_key -> 同一事實被合法重抽。
2. produce_batch:3040 撞名時 `slug += time%10000` **改名硬產**——最後一道防線
   偵測到「已產過」不是跳過而是產第二份(那些 1890/1842/2120 尾綴的來源)。
3. topic_override 一設定,_too_similar 整道被跳過 -> 系列片天生豁免標題去重。

修:_fact_dedup 在抽題階段把「同 fact_key 90 天內已產過」移出候選池(從源頭治,
不是等產完才擋)。used_at 缺 = 舊題庫視為近期保守擋掉(現在的題庫全是近一個月的,
正是要治的那批);新題起都會帶 used_at。抽不到題**不停產**(pull_topic 回 None ->
自由生題),fail-open。實測 728->721 不餓死;前瞻性驗證(3題同key,產第1題後
另2題立刻被擋);單元4例過。

⚠️ commit 衛生問題(我的錯,誠實記錄):`285865d`「fix(CTA錯字掃尾)」本意只改
4 行 CTA 用字,但我用 `git add <file>` 沒先看 diff,把 series-integrity 當時正在
編輯的 daily_publish.py 一起帶走了——**_series_order_gate(約100行)已進版控但
掛在完全不描述它的訊息下**。多 agent 並行時不動歷史(rebase 會弄壞協作者),
在此補記:285865d 實含系列順序閘(同系列已發布集數不重發、只放行已達門檻集數中
編號最小者;只暫緩不丟棄;只讓 score>=75 的集數擋順序,否則 EP3(70分)會把
EP9/EP10 永久餓死)。教訓:多 agent 並行時 commit 前一律先 `git diff --stat` 核對。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
═══ 一、長片被誠信gate擋18%的根因:產製端與發布端用兩把不同的尺 ═══
長片可發僅9支≈3天,而誠信gate正擋掉2支(數字無憑據)。查出:
- 長片題 73% 來自 auto_winner,95/100 無 fact_key -> LLM 拿到零數字的題,
  自己長出「勝率90%」「年化八十」「國外研究發現八成」(假掛名)
- 機制性根因:產製端自癒 _long_fact_heal 用 fact_guard(**只認阿拉伯數字 \d+%**),
  發布端 _factguard_gate 用 fact_source_guard;而長片一律寫**中文唸法**給TTS
  -> **產製端結構上看不見發布端會擋什麼**。實測那兩句編造句 fact_guard 全PASS、
  fact_source_guard 全擋[80.0]
- 第二個bug:heal 的「>=100中文字」門檻對 52 字的 hook 恆不成立 -> 修正稿一律丟棄
  -> hook 永遠治不好,而無憑據數字正好都在 hook
修:_long_fact_heal 接 fact_source_guard(兩把尺複驗)、門檻改
min(100,max(20,原長*0.6))、auto_loop:180 刪掉字面叫選題官「換數字」的指令。
驗證:兩支被擋片的真實句子 原文🔴擋[80.0]→自癒→✅可發(殘留0);對照組(假設語氣
+真數字)不觸發不燒LLM零誤傷。

═══ 二、EP系列同事實換殼(5個事實產23支)═══
根因:pionex_account.py:71-96 **從未更新**——.env 根本沒有 PIONEX_API_KEY,
cron 06:18 每天早退(不是「帳戶沒funded」)。07-12起 day=30/-1.19 凍結,
episodes 25→50 = **同一組事實多產25集**,而 _start_new_season 每10集重置
=同件事重新包裝一輪,這就是穿透口。
🔴 第二條產片路徑:ep_teaser.py 每天06:20 --count 2,**不經pull_topic**,
直讀ep_data把「第30天/-1.19%」寫進prompt當鉤子,且 for range(count) 拿同一個ep
連產2支 -> 只修 produce_batch 這條每天照噴2支。
修:指紋=(day,return_pct)(既是影片宣稱的數字、也是episodes每筆都有的欄位
-> 能從既有50筆歷史回推,零遷移立即生效);_start_new_season **刻意不清空**指紋
(與tw_lab相反,因為季重置正是那個洞);produce_batch._ep_stale_filter 掛 pull_topic
(擋選題層不燒token)+ ep_teaser main() 乾淨return 0。全fail-open。
slug撞名(3152起)改:區分「已有成品→跳過」vs「上次做到一半死掉→維持改名」,
保住重試機制。鐵證:S_0050一次Allinvs每月三千十年差434臺股回 有原版+3501+9235三份。
驗證:verify_ep_guard.py 15/15 PASS(現況不產/新數據產/bump後同事實不產/升季後仍擋/
選題742→653非EP題不受影響/fail-open);實跑 ep_teaser --count 2 → 乾淨跳過 exit 0。
實測 fact_is_fresh(第30天/-1.19%) = False = 不產 ✅

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
獨立驗證(ep0-verify)判定前一版不可用。五個破口複驗全屬實:

1. 【假話·最毒】舊 tw_lab 規則②宣稱「手續費、稅、滑價都算進去」。複驗
   tw_facts_engine.py:471/:677 明寫「未計手續費/滑價」,全檔零成本模型,55組
   回測沒有一組計成本。⚠️ 這句還長在「規則先講死」段——那段全部的作用是證明
   「我值得你訂」。用假話證明誠信=拿誠信換訂閱,比不做還糟。
   → 改成誠實揭露:不含成本 ⇒ 高週轉策略(停利)在我這裡被高估。這是**自我設限**,
     方向天生安全:哪天真加了成本模型,最壞也只是低報自己。
2. 【定位假】兩支自稱「開播/第零集」,但兩系列都已公開播出(tw_lab 14支、
   個股體檢EP1 rwdhTBAfXQI)。觀眾點一下頻道就戳破。
   → 定位改由 uploaded_ledger 真檔算出:已發布>0 一律走「系列說明/中途加入」,
     premiere 語氣結構上不可能生成 + 顯式 fail-closed 拒產。
3. 【數字灌水】舊碼只讀 used_keys,但 tw_lab_engine.py:337 每季收官清空該欄位
   (那是「本季已用」不是「歷來」)→ 且**越播越膨脹**(下季重置會宣稱「跑完55組」)。
   → used = used_keys ∪ episodes[].key(episodes 不受季重置影響)。
   實測:55 key → 語意去重 47 組 → 已用 18 → **未用 29**(舊算法宣稱 46 = 灌水 58%)
4. 【語意重複】同一組回測有兩個名字(legacy vs computed),直接數 key 會數兩次。
   → _canon() 語意指紋去重(認不出就不併,保守下界)。
5. 【fail-closed 破口】stock = max(ready, planned):facts 損壞而 backlog 還在時
   ready=0/planned=1916 → max 過關,實測真的產出「目前體檢完 0 檔」的荒謬承諾。
   → 改 min():任一邊塌掉就拒產。

整合陷阱(額外抓到):舊標題含「EP.0」→ daily_publish.py:309 _EP_NUM_RE 會認成
「第0集」→ 發布順序閘拿它當最小集數**擋住 EP9/EP10**。新標題刻意無 EP<數字> token。

誠信總原則(本檔存在理由):**宣稱句必須能從真實檔案算出或查證,不可寫死在
SERIES 表當文案**。SERIES 表只放「不含數字且已複驗為真」的靜態素材。

✅ 已發布 14 支清查:零事故。「有算成本」樣式命中 0;反而 4 處主動誠實揭露
(fA6BRQaVTdw EP5「手續費還沒算」/ Jad4_8skToo EP7「進出215次,手續費還沒算」)。
那句假話只活在未發布的 SERIES 表,發布前攔下 → 不需動 YT API。

驗證:py_compile 過;7 個 fail-closed 情境全 PASS;--dry 兩支逐句對到真檔。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔴 已發布災情(ffmpeg 抽幀鐵證,非推論):**32 支已發布片畫面燒著與內容無關的假數字**
- Z5BmckFY89U「0050vs00631L十年定投實測」:HUD『DAY10|本金101|餘額101|報酬+0.7%』,
  而**同一幀旁白正在講「年化負二點一趴」**
- D-pWNemxtyk「EP5臺股大盤錯過5天」:HUD 紅字『報酬-0.59%』,**同一幀字幕寫
  「報酬只剩百分之兩百八十三」——畫面自己跟自己矛盾**
族群:台股真相實驗室 EP1–EP8 全系列、0056vs006208 等對比片、台股實測題。
(151支命中exp/race → 95支非機器人系列 → 39支走hud_strip → 32支渲染於HUD進版後確定中招;
 5支渲染於進版前乾淨、2支mp4已刪無法確認。race-only 56支無害——走 render_race_split
 不吃 ep_data。致命組合是「EP+vs」同時命中。)

根因:make_video.py:1883 / render_ffmpeg.py:712 用
`re.search("EP|實測|實驗|vs|對決", title)` 當磁鐵,命中就 `_nums.update(_ep_data_numbers())`
用 Pionex 機器人帳戶狀態蓋掉本片旁白的真數字。設計意圖(EP系列HUD顯示真實帳戶)是對的,
壞在**抓標題關鍵字而非「這支片是否真的屬於該系列」**——「台股真相實驗室」含「實驗」就中。
且守門全在稿子層,這個假數字是**渲染期**注入的,守門的位置根本看不到。

修:新增 `mv._ep_data_applies(title, slug, narr_nums)` 四道門檻——①vs對比片一律不套
②ep_data 須自稱機器人系列(series_name)③本片 title/slug 須有系列題材特徵 ④旁白本金與
帳戶本金差5倍以上不套(擋「HUD燒101、旁白講丟十萬」)。判不出來就退回旁白真數字(那本來
就是正確來源)。**render_ffmpeg 改呼叫 mv._ep_data_applies,不各自複製一份**——複製貼上
正是這個 bug 同時存在兩處的成因。
⚠️ 不可用 ep_data.episodes[].slug 當白名單:該清單已被污染,混著台股真相實驗室的 slug。

附帶修掉第二個誠信bug:`_parse_experiment_numbers` 正負詞只允許空白相隔 →
「虧**了**百分之二十」抓不到「虧」→ 回 +20.0 → HUD 燒**綠字+20%**而旁白講倒賠20%。
ep_data 收窄後更多片會退回吃這條 regex,故一併修。實測現在回 -20.0。
殘留(誠實揭露):「少賺百分之五十」語意本身歧義,regex 治不了。

驗證:verify_hud.py 9/9 PASS;實測機器人EP片仍套用、0050vs00631L/台股真相實驗室/
0056vs006208 全不套、「虧了百分之二十」→ -20.0。全程未渲染未發布未打 YouTube API。

⚠️ 本 commit 只修產線,**不回溯**:32 支已發布片仍掛著假數字。要處理只有重渲染+重上架
(動 YouTube = 紅線,且 32×1600=51,200 units ≈ 5 天配額,還會換新 videoId 失去現有數據)
→ 已列給 Carson 定奪。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔴 已發布災情(逐字比對 title+旁白 vs 來源事實):**6 支問題片,兩支結論相反且都在線**
- Jad4_8skToo(EP7):「回測30年,長抱5.7%…擇時6.9%」-> 擇時贏
- ogQukwzFn1s(EP3):「大盤長抱10年…長抱10.1%…簡單擇時反而少賺」-> 長抱贏
  **同一個問題,兩支片給相反答案**
- 年數不實 4 支:ogQukwzFn1s 真20.1年講「10年」(差一倍)、fA6BRQaVTdw 12.5->10、
  j56NCrb08dA 12.5->10、Jad4_8skToo 29->30
- -jnJRZUvUzA(EP1)旁白813%/24.7%,現行兩份檔都對不上 = 漂移後已無法再驗證

根因(推翻「legacy是過期快照」的假設):legacy `tw_stock_facts.json` 是
crontab:54 每天04:00由 tw_stock_data.py **重生的活檔**,用**滾動20年窗**
(today-20*366天)-> **數字每天漂移**;而 computed `tw_facts_computed.json`
**根本沒有排程**、只能手動跑。兩邊算術都對,差在窗口(legacy滾動20年避開
1997/2000崩盤;computed固定1997起)-> 同題相反結論。
legacy 結構上不可用:①數字每天漂移(已發布片再也驗不了)②無 period/start/end 欄
-> LLM 沒年數可用就自己編(這正是4支年數不實的根因)③完全冗餘(5組 computed 全有)。

修(tw_lab_engine.py):
1. _LEGACY_SUPERSEDED_BY 5對 + _load_facts() **key對key結構性封鎖**。舊 _dedup_sig()
   比對 desc 文字,但兩引擎措辭不同 -> 簽名不同 -> 兩組都進 seeded_keys 各出一集。
   文字比對本質上防不住,改 key 映射。保留 fallback(computed 缺檔時 legacy 仍可用)。
   順手修 as_of(舊版取 legacy 的今天,會把 computed 數字標成今天算的)。
2. _fact_period() + fail-closed:期間永遠有值 + **★年數硬規則禁止約整**
   (fA6BRQaVTdw 證明「有 period 欄」還不夠,要明令)。順手修好 8 組崩盤事實的
   "?~?"(tw_facts_engine.py:585 用 payload.get('start') 但 calc_crash_episode
   回的是 peak_date/latest_date)。
驗證(實跑):55->50組、5對legacy全消失、fact_order 45組、buyhold_vs_timing_twii
in order=False、期間覆蓋45/45(修前8組是"?~?")、fallback OK。

⚠️ 只封住 tw_lab 這條路。仍讀 legacy 的還有 9 處,其中 **fact_source_guard.py:51
含 legacy = legacy 的漂移數字仍被判「有憑據」放行**;根治要動 crontab(停 :54
tw_stock_data.py + 把 tw_facts_engine.py 排進去,現在 computed 沒排程只會越來越舊)
+ 讓那 9 處統一走 computed。影響面 10 檔,風險高,未擅自做 -> 列給 Carson。
6 支已發布問題片:改標題/描述=YT API 紅線,未碰。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
根因回顧:legacy(tw_stock_facts.json)由 crontab:54 每天04:00重算、用滾動窗
`today - years*366` -> **同一個 key 的數字每天漂移**。兩個實害:
①已發布片的數字事後對不回來(-jnJRZUvUzA 講 0050 十年 All-in「813%」,今天同key
  已變 804.5%;apply_repackage3.py:34 記錄過同症狀)
②fact_source_guard 的「有憑據」數字池直接從這份檔攤平 -> **守門在用一把每天變長度
  的尺**,今天放行的數字明天就不存在
鐵證:legacy 5 組**全部 period=''、source=''**(computed 是 50/50 全有)。頻道紅線是
「數字必須可溯源」-> legacy 的數字結構上本來就不該過誠信 gate。**封它是修 bug,不是取捨。**
這也解釋 4 支「年數不實」(20.1年講成10年):LLM 拿到沒有期間欄位的數字,只好自己編。

三步(順序=不可停產的紀律:先讓對的有排程 -> 再遷讀取端 -> 最後才停錯的):
1. computed 上排程 `50 3 * * *`(早於 05:40 種題/06:07 製作/04:05 快照)。成本實測:
   單標的走快取 0.8 秒/12 組、全 15 標的主要成本是 yfinance 下載 ~1 分鐘;**不吃 YT
   配額、不走 LLM**。附帶硬化 SHRINK_GUARD_RATIO=0.6:原本只擋 n==0 不擋部分抓取,
   yfinance 限流時會用剩幾組覆蓋 50 組 -> fact_pool 縮水 -> 待發稿子突然查無憑據被
   fail-closed 擋 = 停產。現在縮水就保留舊檔。
2. 讀取端統一走 computed:tw_facts_engine.py:81 LEGACY_SUPERSEDED_BY + :90
   drop_superseded_legacy(**key對key**,因為 desc 文字比對正是防不住這件事的原因),
   接上 produce_batch:1436 / topics_from_facts:142 / winner_amplifier:228。
   fail-open:computed 全缺時 legacy 保留 5/5(實測三情境過)。
   **附帶修好既有 bug**:_load_tw_facts 的 as_of 取自第一份檔(legacy)-> prompt 注入
   「資料截至 2026-07-17」但數字全是 computed(只到07-13)= **對觀眾報一個沒資料支撐
   的日期**;legacy 凍結後會永遠停在 07-17,故非修不可。改成取「還有事實活下來的檔」
   的最舊 as_of,實測修正為 07-15。
3. 停 legacy 產生(crontab:74 註解掉,可逆)。自驗:tw_stock_data.py 只有 1 個寫檔點
   (:333)、無健檢盯其新鮮度。**故意保留檔案不刪**:已發布/待發布片與 make_thumbnails
   仍讀它,刪檔會讓那些片變「查無憑據」被 fail-closed 擋 = 停產。

刻意不動 fact_source_guard.FACT_FILES(判斷,非漏做):它是**數字白名單**,拿掉 legacy
= 守門變嚴 -> 已寫好待發布、引用 legacy 數字的稿子立刻查無憑據被擋 = 停產。而白名單
**只認證、不注入**,留著不會讓 legacy 進新片;根因(每天滾動重算)已由步驟3 解決,
檔案凍結 = 尺固定。

驗證:162/162/50 組、殘留 legacy=NONE;注入實跑 938 字元含 762.7 不含 804.5;
排程器解析到 tw_facts_engine、due(明天03:50)=True、排程 80->79、明天時序
03:50->05:40->06:07 正確。

⚠️ 唯一還開的洞:make_thumbnails.py:284 只讀 legacy -> 「EP3大盤長抱」封面吐
`+10.2%/長抱不動·20年`,而腳本現在講 5.7%/29年 = **封面自打臉**。不是換檔名就好
(_TW_BRANCH_LABEL:286 寫死 legacy 的 timing_200ma,computed 是 timing_ma,需 schema
適配)-> 下一棒處理。
誠實:tw_facts_engine 全量第一次真跑是明天 03:50(依指示只 --dry 單標的估),失敗有
縮水保險 + cron.log 可查。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
事實庫退役封了 5 條路,但 topic_bank 抽題這條沒封:題庫 1772 題裡有 9 題指向
legacy fact_key,**未用的 7 題** pull_topic() 隨時可抽,而且**數字已經寫死在標題裡**:
「台股20年實驗:All in年化10.1% vs 定投8%」「0050年化24.7% vs 0056僅17.2%」
「00878六年賺230%?0050同期賺430%」「大盤All in慘賠58.3%」…

漂移實證(複驗):標題寫死「All in年化10.1%」-> 今天同key已是10.2%;
「24.7%/17.2%」-> 今天已是 24.5%/17.0%。**這些題的數字連自己的來源檔都對不上。**

⚠️ 先前報「4 題」是假象:那是跑過 _fact_dedup 之後的數,另外 3 題只是**碰巧**有一題
used 且落在 _FACT_REUSE_WINDOW_DAYS=90 窗內,**窗一過就全部復活**。故改用 key 永久擋。

修:_legacy_fact_filter() + pull_topic() 接線(排在 _fact_dedup 之後)。只擋「真的已被
computed 取代」的 key(lk not in results and ck in results)-> computed 缺檔就不擋
(fail-open),包 try,只收緊不放寬。
驗證:未用候選 864->857(少 7 = 0.81%)、殘留 legacy 題 = 0、log_ops 有出。
**停產判定:不會**(濾 0.81%;抽不到題還有 call_claude 自由生題)。

裁決(推翻「別名去重升級成正規化簽名」的提議):**exact-key 就是正確粒度,不該升級**。
① legacy 已從全部 5 條路退役 -> 新題結構上不可能帶 legacy key
② **computed 內部沒有真別名**:唯一像 pair 的 5 組是 __full vs __10y ——那是**不同回測
   期間=不同事實**,合併是錯的;computed 的 key 命名本身已編碼期間
③ **實測證明正規化是錯方向**:tw_lab_engine._dedup_sig() 的文字正規化已經在誤傷——
   fact_order() 事實池 50->45,被吃掉的 5 組**全是 __full**(0050近12年/0056近18年/
   006208近14年/2330近26年/TWII近29年),它洗掉「近\d+年」後誤判成同一組,而且**保留
   資訊量少的 __10y、丟掉 __full**

協調:已驗 produce_batch 的三方改動共存(_fact_dedup :304/:388 + drop_superseded_legacy
+ _legacy_fact_filter),git diff = +46/-0,沒蓋掉任何人的行。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
問題:tw_lab franchise 的 seed_topic_bank **只剩 3 題可種**(seeded 46/fact_order 45,
已涵蓋 42/45)。從沒被 seed 過的 8 個 key 裡有 5 個是 `__full`(0050近12年/0056近18年/
006208近14年/2330近26年/TWII近29年)——被 _dedup_sig 洗掉「近\d+年」後誤判成與 __10y
同一組而丟出 order → **結構上永遠拿不到**。且它保留資訊量少的 __10y、丟掉 __full。
修好後可種 3 → 8。

裁決(既沒「直接移除」也沒「不洗期間」,兩個都不對):
① 當「丟棄器」它已無價值:檔頭註解寫明用途是擋 legacy vs computed 跨檔重複,那件事已由
   drop_superseded_legacy() 用 key 對 key 解決,而且更正確(文字比對正是當初漏掉
   buyhold_vs_timing、釀成兩支已發布片互打臉的原因)。
② **但它編碼的顧慮仍成立**:__10y 與 __full 分數相同、key 字母序相鄰 → 直接移除或
   「不洗期間」都會讓它們緊鄰,連續兩集講幾乎同一件事 = franchise「一集一組新事實」
   的賣點自砸。
③ 故保留簽名、只把角色由**丟棄**改成**延後**(分簽名 round-robin:第一輪每簽名各一組,
   第二輪才輪到第二組)。**而這正是註解一直宣稱的行為**(「其餘讓下一輪/下一季再用」)——
   舊實作 `if sig in seen_sig: continue` 是永久丟棄,且 fact_order 確定性 → 被丟的
   永遠同一批,一輪都輪不到。**這不是改需求,是把實作修成註解說的樣子。**

順手收斂重複實作(今晚一堆同型 bug 的成因):tw_lab_engine:39 改
`from tw_facts_engine import drop_superseded_legacy`,刪掉本地那份 _LEGACY_SUPERSEDED_BY。
無循環 import(tw_facts_engine 模組層只 import 標準庫、pandas/yfinance 在函式內)。
刻意用**模組層 import**:壞掉就讓整支 import 失敗、由 produce_batch:1751 既有 try/except
攔(franchise 跳過、產線續跑),**而不是靜默退回「沒去重」把 legacy 放回池**——
誠信 gate 只能 fail-closed。

驗收(實跑):fact_order 45→50、__full 6 組全回來、legacy 殘留 NONE(沒放寬 gate)、
確定性 True、**嚴格「只增不動」:新版前 45 名逐一比對 == 舊版全部 45 名,既有排程順序
零變動、只在尾巴補 5 組**、同簽名間隔 44~45 集、seed 可種 3→8。
判定:不會停產(只增不動)、不會產重複題(同簽名隔 44~45 集 + _fact_dedup/
_legacy_fact_filter/seeded_keys 三道獨立擋著)。

⚠️ 更正一個我在派工時搞錯的前提(誠實記錄):我以為這修正能救回長片素材——**錯**。
tw_lab_engine 只產 format:"short"(:356/:384),是 Shorts franchise;產長片的
topics_from_facts.py:323 用自己的 loader、不經過 _dedup_sig,其事實池本來就看得到
全部 6 組 __full。**長片供給的單點(可發 9 支≈3 天)完全沒被此 commit 解決,仍待處理。**

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
原任務:事實庫退役後 make_thumbnails.py:284 仍只讀 legacy -> 封面印 +10.2%/20年,
同片腳本講 5.7%/29年 = **封面跟影片自己打臉**。

🔴 過程中抓到比原任務更嚴重的既有 bug:**張冠李戴**。legacy 只有 5 組,
`hidiv_0056_vs_0050` 的 keywords 幾乎吃下所有高股息題,再挑最高分支 = **0050 的
+804.5%**。用真實產線標題實測:「0056 vs 00919 高股息ETF回測」「EP4 槓桿ETF
0050槓桿版」「高股息月配vs年配」——**三支舊碼全掛「市值型·10年 +804.5%」,
印的是 0050 的數字**。
⚠️ 只換檔名不加閘門會更糟:computed 的 keywords 用代碼 TWII / 全名「加權指數(大盤)」
都不是標題子字串 -> 大盤題會跟 0050 平手而吃到 0050 數字。

修:
- _load_tw_facts_merged() 複製**寫稿端 produce_batch._load_tw_facts 的同一套規則**,
  直接 import tw_facts_engine.drop_superseded_legacy(**未複製第二份映射**——重複實作
  正是今晚一連串同型 bug 的成因)
- 標的閘門:標題須點名標的、且事實標的 ⊆ 標題標的(做法同既有 _crypto_card 點名幣種)
- branch label 補 timing_ma/leveraged/base(保留 legacy 的 timing_200ma 供 fail-open)
- 年數改用 period 真值反推、保留 1 位小數(12.5 -> 「12.5年」,不再印「12年」)
  ——今晚抓到 4 支已發布片把 20.1 年講成「10 年」,根因就是 legacy 沒有 period 欄

驗證(零副作用,圖只落 scratchpad\cards):py_compile OK;5 個重疊主題 pct 逐一比對
computed 分支值**全數命中**;擇時卡 = 「跌破年線擇時·29年 / +6.9% / 長抱不動對照 +5.7%」
(無英文 raw key);fail-open 三態(缺檔/壞JSON/tw_facts_engine 載不到)皆不崩、縮圖照樣
產出、且不吐 legacy 的 10.2%。38 支真實台股題:11 支數字修正、4 支新增卡、3 支
「舊有卡→新無卡」**經逐支查核全是上述錯卡** -> 零真實覆蓋率損失。
副作用稽核:used_datacard_numbers.json 測試 slug 留 0 筆、assets/thumbnails 343 張零覆蓋。

⚠️ 待 Carson 定奪(未擅自動):
1. **今天新生的縮圖帶 legacy 數字**:local_cron(PID 2800) 今天 10:01/10:17 還在跑舊碼,
   `S_0050定期定額10年回測All-in竟多賺424存.jpg` 等已寫入 +804.5%/+10.2%。照紅線未覆蓋
   任何既有縮圖 -> 未發布片的縮圖要不要重生請定奪(重生=內部操作;已發布的要動 YT API=紅線)
2. _TW_UNCOVERED_STOCK_KW(台積電/2330)的理由已過期(computed 其實有 2330 真回測),
   維持不掛卡(保守)並在碼裡註記——開放與否屬「點名個股」內容決策,不由縮圖引擎順手放行

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
今晚最深的一個發現(實測,非讀碼推論):`fact_source_guard.fact_pool()` 是**無單位的
2446 個 float 集合**(混了百分比/年化/回撤/本益比/殖利率/年份/檔數),卻被當成有單位在用。

鐵證:`_sourced_strict(37.0) = True` —— **「多賺 37 萬」被池裡的「36.8%」「37.1%」佐證了**;
3.2 撞 2.95、65 撞 64.78。**這比漏網嚴重:守門不是沒看見,是看見了並說「有憑據」——
它在替假數字背書。**

**規模詛咒(反直覺)**:池 2446 個 → 任何兩位數金額都找得到百分比鄰居 → **池越大,守門
越弱**。這違反「事實庫越豐富守門越強」的直覺。

三道逃逸(任一即穿透):①一般句的金額完全不抽(只在 12 個「假掛名詞」句內才跑)
②池不分單位 → 金額撞百分比(最隱蔽:它看起來有溯源)③單位表缺「元」「年」「分」。

文件兩個關鍵結論:
1. **「把元/年/分加進單位表」是錯的修法** —— 實測待發 13 支有 8 支含金額/倍/年在績效
   語境但多數合法(鴻海「7.3倍」、EP9「三年」是期間),加「年」會誤殺。**正解是讓池帶
   單位、同單位子池比對**。
2. **`amount` 在五個庫根本沒有對應子池**(全是報酬率)→ **任何金額宣稱結構上必然無憑據**,
   EP1/EP6 不是個案而是必然。

⚠️ **現在不能修**:收緊池 = 待發稿大量 fail-closed = 停產(同 FACT_FILES 的道理)。
建議先做**觀測模式(只報不擋)**拿真實誤殺率,零風險。優先級 P1,排在遷移計畫後。

佐證:publish_skip 裡前人(2026-07-14)手動擋的 3 支,理由寫著「38萬/90%…湊整撞池內
真數據鄰居繞過守門」——**同一個盲區前面已有人踩過,但只擋了個案沒修根因**。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
有罪,證據確鑿(實跑產線函式出圖,非讀碼推論):那不是裝飾動畫——兩條進度條掛著本片
比較的**兩個標的名**(從標題切出),**條尾還印百分比**。而 `progB = frac * 0.82`
(frac=段落序號進度)代表**每支對比片的最後一格永遠是「A 100% / B 82%」**。

災情:
- GUhjV_E_uUU(已發布):旁白 00878 387% vs 0050 815%(真實差 47%),**畫面印 82%**
- AI選股vs0050:旁白 87% vs 379%(**A 輸**),**畫面卻讓 A 滿格贏——輸贏方向相反**
- All-in vs 定期定額:旁白明說「差了整整一倍」,**畫面只顯 18% 差,把主打的差距抹平**
- 碼裡的契約本來就寫死:_ep_data_applies docstring「該 HUD 語意是兩個標的賽跑,
  **數字必須來自本片旁白**」
**已發布中鏢 46 支**(ledger 721 → 標題命中 73 → 成片仍在本機且渲染於 bug 引入
28b2798(07-08 14:35)之後 = 46;另 22 支成片已不在本機無法核對、5 支渲染於 bug 前=安全)。
今晚剛翻長片優先 + 長片標題大量 A vs B → **正在擴散**。

處置:**拆除整條路,不是改數字**。先照首選路徑實作「用旁白真值算比例」,**實測後自我否決**
——會把固定的謊換成浮動的謊:parser 綁到的是手續費15%/最大回撤22.6%/股息率1.8%/年化32%;
加「只認總報酬」守門後仍 5支綁到、4支綁錯(**精確率 1/5**)。兩個無解根因:①旁白是自由
文字,總報酬/年化/回撤/稅/手續費**全是百分比、長得一樣**(= docs/fact_pool_unit_blindspot.md
的同一個病)②**有些片旁白根本沒講那一側的總報酬**(00878十年、美股ETF只說「少賺58%」)
→ 資料不存在,再好的 parser 也生不出來。依 fail-safe:**對比片不再上任何 HUD**。

改動:兩處**重複**的 progB 呼叫端整段刪除(函式共用、呼叫端各寫一份——正是 HUD 那個
drift 型態);閘門收成 _is_exp;render_race_split 保留但**零呼叫端** + docstring 寫死
禁止餵合成值 + 註明「不要退回用 render_hud_strip 補位」。
驗證:兩檔零賽跑呼叫端、可執行碼零 0.82;對比/對決/賽跑片→不上HUD;**EP片與 EP+vs
混合片→仍上HUD(未改壞)**;render_hud_strip 迴歸正常。

⚠️ 順手挖到同族第 5 顆(建議另派):`_cn_num` 對「千」量級**靜默錯**——一千零五十→10.0、
一千→**0.0**、兩千三百→100.0,**不丟例外**。而 `_parse_experiment_numbers`(EP HUD 的
真數字來源)也用它 → **EP HUD 可能正在燒錯數字**。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
複驗屬實且比回報更廣:36 例邊界測試中 **12 例靜默回錯值**——一千→0、一千零五十→10、
兩千三百→100、十萬→10、一億→0。**錯誤形態是靜默回錯值不丟例外** → 呼叫端 try/except
結構上攔不到。根因有二:①沒有千/萬/億分支 ②收尾 `_CN_DIGIT.get(s, 0)` 把「查無」當成
「答案是零」——**②才是主毒**。

為什麼會咬到:本頻道稿子**一律用中文唸法寫數字給 TTS**(_LONG_DATA_DISCIPLINE),
「一千七百四十六」是常態不是邊緣案例。而 _parse_experiment_numbers(EP HUD 燒進畫面的
「真數字」來源)就是用它;今晚收窄 _ep_data_applies 後更多片退回吃這條 regex。

影響面(實測,非估算):330 支 voice.txt → HUD 啟動 86 → 真燒數字 79。修前/修後全 corpus
逐欄位 diff:**只有 3 支輸出改變,且全是「錯→對」,零回歸**。
- 已發布 2 支:`S_EP6台積電Allin` pct **1.0 → 1746.0**(稿子講「總報酬百分之一千七百四十六」
  ——**畫面燒 1%、旁白講 1746%,差 1746 倍,而該片標題就叫「差多少」**);
  `L_個股體檢EP1台積電` days 918 → 3918
- 未發布 1 支:`L_中華電2412` days 765 → 1765
沒全面炸開是誤打誤撞:舊 `_cn` 字元類**不含「千」**,金額欄整條 match 失敗 → 不顯示。
逃過的是 principal/balance,沒逃過的是 pct/days。

修:_cn_int 重寫成小節累加(個/十/百/千 + 萬/億結算);**回 None 而非猜值**(拿掉「查無當零」);
_cn 補「千」;四處呼叫端改 `is not None`(0 是合法值)。render_ffmpeg 呼叫 mv 的函式自動繼承。
驗證:py_compile 過、邊界 36 例全過(廿→None fail-safe)、79 支只有 3 支改變且全是錯→對。

⚠️ 不收斂 fact_source_guard._cn_num_to_float(agent 判斷,我採納):它**本來就正確處理千**、
契約也不同(對「三十八萬」刻意回 38 供比對事實池);而 make_video import 帶 moviepy/PIL
重副作用,**讓發布端守門去 import 渲染模組 = 把渲染依賴綁進發布路徑,風險遠大於去重收益**。
真要收斂該把純函式抽到 studio_common(另案)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
補上今晚只修了一半的病灶:5466bc2 收窄了 _ep_data_applies(不讓機器人帳戶數字灌進
無關影片),**但沒收窄 _is_exp** —— 所以「個股體檢EP1」(今早 09:15 剛發的那支)因標題
含「EP」仍被判定要上 HUD,四個欄位全錯:本金抓到「每月投入一萬」(實驗本金是一百萬)、
餘額少 5000、報酬率抓到的是**最大跌幅**、天數抓到的是**最長套牢天數**。

⚠️ **agent 拒絕照我的字面指示做,理由我採納**:我要求把 _is_exp 綁成 _ep_data_applies,
但後者含**資料面**門檻(ep_data 讀得到/series_name 對得上/本金 5 倍檢查)——綁上去的話
**ep_data.json 一旦讀不到,真機器人片的 HUD 會整個消失**。「那是讓一個資料檔決定視覺
元素存不存在,是脆弱耦合不是 fail-safe。」
改採:抽出 `_hud_applies(title, slug)` 當**片型判定的單一真相來源**(非 A vs B 且
title/slug 命中 _ROBOT_SERIES_RE);_ep_data_applies = _hud_applies() + 三道資料面門檻。
**片型判定只有一份**(符合「不要各寫一份」的實質),但兩個問題各自保留該有的門檻。

Corpus diff:仍上 HUD 88 支(抽驗全是機器人/網格/bot 題);**不再上、且舊版本來會燒
數字的 50 支**(已發布 38 / 未發布 12)。抽驗確認本來就不該有:個股體檢EP1(四欄全錯)、
L_臺股當沖勝率87(舊燒+20%)、S_0050十年ALLIN賺824(舊燒+824%)、L_派網格vsPython(A vs B)。
驗收四項全過:真機器人 EP 片仍上(S__EP17/S__EP26→True,88 支保留沒改壞)、
個股體檢EP1/臺股真相實驗室EP3/台積電回測實測30天→全 False、py_compile 雙檔過。

給 Carson 的重做決策更新:`S_EP6台積電Allin`(畫面 1% vs 旁白 1746%)收窄後**不上 HUD**
→ 災情性質從「數字錯」變成「**本來就不該有這個 HUD**」。不是把 1% 改成 1746% 就好,
是那組欄位對「All-in vs 定投」根本沒語意。

⚠️ **誠實記錄:這沒有修完**。收窄治的是**片型**(50 支);留下的 88 支仍會燒錯,因為
**挑數字的啟發式分不出「報酬率」和「勝率/比例/佔比」**。兩個已發布實例:
- S_加密網格回測90都輸大盤:旁白「**90% 的網格策略都輸給大盤**」→ HUD 燒**報酬 +90%**。
  **整支片在拆穿網格神話,畫面卻印「+90% 報酬」——招牌被自己的畫面反轉。**
- S_網格機器人90獲利是陷阱:旁白「三十天內**被吃掉**百分之八十七」→ HUD 燒**綠字 +87%**。
  `_sgn` 沒收「吃掉」——**這是「虧了百分之二十」那條的同一個病,換個動詞就漏**。
下一步(未做):pct 加報酬語境要求(借 fact_source_guard.PERF_CTX,命中勝率/佔比就
fail-closed 不填)+ _sgn 補「吃掉/侵蝕/蒸發/縮水/回吐」。需要自己的驗證回合。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
五批災情交叉去重:相加 145 人次、重疊 47 → **實際 98 支**(比先前彙報多,因為
title_drift 只提「~40 支內文漂移」沒列 ID,本輪跑 scan_published.py 全部找出)。
實測曝光 5,187 觀看 = 頻道近 90 天的 16.9%;72 支未進 top200 快取(每支 ≤32 觀看)。
HUD ∩ 賽跑 = 0(兩個閘門互斥,一支片不可能同時中)。

🔴 **推翻先前的排序邏輯**:hud_fix 照「累計觀看」排(543/251/94),但快照 diff 顯示
543 那支 2 天只 +1、251 那支 +0 = **已死**。本頻道片約 4 天死透 → **「重做以阻止未來
曝光」幾乎不成立,曝光在動手前就結束了;剩下唯一理由是永久責任。** 該排**速度**不是累計。

🔴 **race_fix 沒抓到的**:它只找到 1 支方向相反。本輪把有觀看數的 13 支賽跑片旁白**逐支
讀完 → 6 支方向相反(46%)**,含最紅的 xU5wDOnt77Q(畫面說定期定額贏,旁白說
「All-in 823.1% vs 定期定額 380.0%」)。**根因是結構性反相關**:進度條永遠讓「標題先
講的」贏,而頻道鉤子公式「你以為A划算?打臉!」**習慣先講輸家** → **越主打反直覺的片,
畫面越會跟自己旁白唱反調**。

**建議:只花 0.20 天配額做兩件,其餘 91 支保留**
① **6 支封面張冠李戴就地換圖**(thumbnails.set 300 units,**保留 videoId/觀看/排名**)
   —— **全案唯一純贏動作**(先前彙報誤以為修封面也要重上架)
② xU5wDOnt77Q 重渲染重上架(1,650)—— 唯一「最紅 × 方向相反 × 還在長」
全做 98 支要 **16.2 天配額**(等於停產 16 天)去蓋 72 支 ≤32 觀看的尾巴 → 不值得。
**明確不建議改標題**(即使只要 50 units):那 11 支**旁白也講同一漂移數字**(實讀
KKlvwEssg3I/tHux96yaPhA/cPmuqErqZno 的 voice.txt),改了 = 標題對、聲音錯。

**新增嚴重度軸:編造 vs 漂移**。434% 漂移看似錯很多,但兩邊算術都對(窗口不同)、
發布當下是真的、有辯護空間;賽跑條的 82% 是 frac*0.82 **從來不是真的**。
**誠信紅線罰編造不罰過期** → 漂移壓到 S4。S1=8 / S2=35 / S3=35 / S4=20;
S5(年數約整)去重後是空的(4 支全部同時中更嚴重的項)。

更正來源報告三處:race_fix 46→**44**(它用 slug 判閘門,產線讀 _title);
facts_conflict 6→**5**(2 支重複計);thumb_regen 內文寫 5、表格實列 6。

誠實限制:72 支「≤32」是**硬上界非 0**(top200 截斷);31 支賽跑片方向**未驗**;
46% 反轉率是 13 支樣本**不可外推**;mtime 當渲染時間是**代理**;98 是證據支持數非理論上限。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
治最諷刺的一類:**畫面把影片自己的結論反轉**。
- S_加密網格回測90都輸大盤:旁白「**90% 的網格策略都輸給大盤**」(輸家佔比)→ HUD 燒
  **報酬 +90%**。**整支在拆穿網格神話,畫面卻印「+90% 報酬」。**
- S_網格機器人90獲利是陷阱:旁白「三十天內**被吃掉**百分之八十七」→ HUD 燒**綠字 +87%**。

⚠️ **agent 第二次拒絕我的建議,理由我採納**:我要它借 `fact_source_guard.PERF_CTX`,
但實作時發現行不通——PERF_CTX 的用途是「算不算需要溯源的績效宣稱」,所以**刻意同時收
報酬/獲利/年化 和 勝率/機率/佔比**(兩者都要憑據);而這裡要的正好是**把這兩類分開**,
借過來「90%都輸大盤」照樣過關 = 等於沒守。故另立兩張表。
**「常數用途不同,強行共用只是製造假的單一真相來源。」** —— 這比我那條「不要重複實作」
的規則精準:重複要看的是**契約**是否相同,不是字面像不像。

判定(四層 fail-closed):allowlist=帳戶/報酬/年化/總報酬(依據:**113 個子句實掃,真 EP
片的報酬句 100% 都有「帳戶」**)→ veto=勝率/存活率/虧損率/都輸/總資金/利潤/比(實掃干擾:
「單網格不超總資金5%」是部位控管、「手續費吃掉15%利潤」是獲利佔比、「總報酬比持有少23%」
是差距)→ 號誌不明不填 → **全片過關值不一致就不填**。

🔴 **最後一條「輸印成贏」是符號不是詞**:掃到 3 支稿子用 **ASCII hyphen** 寫負號
(「帳戶 -1.19%」「帳戶報酬 -1.19%」),而舊詞表全是中文字 → **帳戶在賠、畫面燒 +1.19%
綠字**。已補符號負號,3 支全部錯→對。(既有 bug,非本次改出。)

⚠️ **agent 自己改出兩個回歸,被 corpus diff 當場抓到並修掉(誠實記錄,也是驗證有效的證據)**:
(a) 把「報酬」放進號誌捕捉群 → 「帳戶報酬率負1.19%」的真號誌「負」被吃掉 → 改成捕捉群
只放負向詞;(b)「由後往前找第一個過關的」→ 跳過真結果、**回頭撿到假設句「帳戶跌百分之
五十」燒 -50%** → 改成全片一致才填。

驗證:①兩支反轉片 90.0→None、87.0→None ②**88 支 diff:50 支改變 = 47 支「錯→不填」
+ 3 支「號誌修正(錯→對)」,零改值、零「對→錯」**——結構性的,所有變更不是→None 就是
轉負,沒有任何一支被改成另一個錯數字 ③真機器人 EP 片 5/5 全對(-0.45/-2.61/1.76/
-1.19/-1.19),沒矯枉過正 ④py_compile 過。仍會燒 pct 的 18 支中,**15 支的數字被自己的
標題背書**(「跑17天虧點零四五」→-0.45、「帳戶-119」→-1.19)。

⚠️ 誠實殘留 1 支(不是輸印成贏):`S_EP2加密網格回測年化80`(已發布)HUD 燒 +80%,
來源是「**年化80%的背後**」——那是**這支片正在揭穿的宣稱**,不是它自己的成績。沒硬加
「背後」veto(one-off hack,治不了「號稱/標榜年化X」同類)。根因是 _hud_applies 看到
標題有「網格」就放行,但**新聞鉤子評論片根本沒有帳戶時間軸**。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
那組 HUD 是**本金/餘額/報酬/天數**,語意就是「**一個帳戶在時間軸上的狀態**」。
`S_EP2加密網格回測年化80`(已發布)燒 +80%,而那個 80% 來自「**年化80%的背後**」=
**這支片正在揭穿的別人的宣稱**,它根本沒有自己的帳戶。**HUD 出現在那裡本身就是錯的,
不管數字對不對** —— 同拆賽跑條的邏輯:把元件放回它有意義的地方。

門檻放 `_hud_applies` 第 3 道(**片型層**,不是欄位層):這是**整個元件**的去留,不是某一欄
填不填。兩處渲染端把「讀稿」提前到判定之前。
結果:88 → **通過 34 支**(真的有數字可燒 29 支);拿掉 15 支(已發布 13 / 未發布 2)。
驗證:①**S__* 真金白銀帳戶 EP 系列 24/24 全數保留、砍 0 支**(事前掃過:沒有一支缺
「帳戶」二字)②S_EP2加密網格年化80 整組不上 ③**零「對→錯」:仍上 HUD 的片,數值與修前
完全相同(0 支變動)**——本次只做「整組不上」,不動任何留下來的數字。

⚠️ **agent 主動更正自己前一則的兩個過度宣稱(誠實記錄,這比成果本身更值得留下)**:
1. 「~18 支」是錯的 —— 那是「會燒 pct 的支數」,而 `_hud_applies` 管的是整組 HUD
   (含 days/principal),正解 34。
2. 上一則報「47 支**錯**→不填」——**那個「錯」是驗證腳本的標籤假設**(`n is None` 就標成
   錯→不填),**沒有逐支確認舊值真的是錯的**。實際至少 1 支是**對→不填**
   (`S_機器人跑26天賺176` 稿子明講「實際虧了百分之零點五」,舊值 -0.5 是對的,因為它寫
   「**帳面**賺了…」不是「帳戶」而被擋)。**站得住的說法是「47 支→不填(fail-closed)」
   +「零對→錯」。fail-closed 本來就有「對的也不顯示」的代價——那是代價,不是勝利。**
3. 被拿掉的 15 支**不是每支數字都錯**:13/15 確實沒有帳戶時間軸,**但 2 支數字是對的**
   (`S_EP10以太坊ETF`「累計30天、報酬1.76%」完全正確,只是那是回測模擬沒有真帳戶)。
   按判準該擋、代價也小,**但這不是零成本的收窄**。

殘留(先天上限):門檻是**詞彙代理**——有「帳戶」二字 ≠ 真有帳戶,理論上評論片提一次就會過
(掃完 corpus 目前無此片)。**根治要產製端在 STUDIO 標記片型,而不是渲染端猜。**

【給 Carson 的災情性質更正】`S_EP2加密網格回測年化80…`(已發布)→ 從「數字錯」改為
**「本來就不該有這個 HUD」**,同 S_EP6台積電Allin 邏輯。不是把 80% 改成別的數字就好。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔴 **最關鍵的根因,今晚沒人發現**:`topic_bank.add_topics()` 的透傳白名單**漏了 fact_key**
→ 無聲剝掉。`winner_amplifier` 明明**驗證過 `fk in facts` 才寫**,125 行後被剝光 = **那段
驗證是死碼**。反證:唯二有 fact_key 的題源(facts_engine / stock_checkup_daily)**都是
繞過 add_topics 直接 save_bank 才活下來的**。
—— 這就是「未用長片題 101 支、有憑據僅 5 支(95% 無憑據)」的真正原因:**不是沒人綁,
是綁了被剝掉**。而 LLM 拿到零數字的題,只能自己編「勝率90%」「年化八十」。

其他三個根因:
2. `auto_winner` 其實在 **auto_loop.py**(不是 winner_amplifier),依據是「完播率贏家角度」
   = 表現統計、**無事實可綁**;prompt 寫了「查不到就選 short」但**零程式碼在擋**。
3. 🔴 **今晚我自己加的 guard 造成的誤殺**:`_ep_stale_filter` 用的 `_ep_topic_like` 缺了
   `is_ep` 的第一條件 `kind=="short"`(EP franchise 是純 Shorts)→ **個股體檢**(標題含 EP)
   被「**Pionex 帳戶沒更新**」這個完全無關的理由擋掉——**而那正是唯一可持續的有憑據長片
   題源**。該 docstring 自己警告過「漂移就有破口」,真的漂了。

改法:topic_bank.py:285 透傳加 "fact_key";auto_loop.py:257 auto_winner 硬寫
format:"short"(降級不丟棄);winner_amplifier.py:381 long 須 fk 驗證過否則降 short;
produce_batch.py:384,451 `_ep_stale_filter(cand, kind)` 只對 short 生效。

驗證(攔截 save_bank 模擬明天 8 支長片):修前**有憑據 0 / 無憑據 8** → 修後**有憑據 4 /
無憑據 4**,不斷炊。回歸:short 路徑 109 題 EP 候選仍全被擋(**保護力未放寬**);long 19 題解封。

⚠️ **agent 拒絕做我要求的「方向B:pull_topic 硬 gate」,理由致命且我採納**:
`produce_batch.py:1751` pull_topic 回 None 時 **call_claude 會自由生題,同樣沒 fact_key**
→ **gate 只是把「題庫的無憑據題」換成「LLM 現場生的無憑據題」,誠信淨收益 = 0**。
要 gate 必須**連自由生題那條路一起封死**。

⚠️ **誠實:這沒有收乾淨。明天起長片題 4/8 仍無憑據**(存量 96 支無憑據長片題還在題庫,
第 5-8 支照樣抽到)。本 commit 只治**流入**+解除**誤殺**。
收乾淨缺一個供給側動作(見下個 commit / task#8):stock_checkup_daily `--count 1 → 8`,
backlog 剩 **1919 檔 → 8 支有憑據長片題/日,剛好對上需求、可撐 240 天**;唯一風險是
FinMind 免費層 rate limit(該檔註解明寫「絕不暴衝」),**要先實測**。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
零風險上線:只**額外記錄**「若池帶單位、只比同單位子池,這個宣稱會不會被擋」,
**完全不改變現行放行/擋下的行為**。
證明:對照 `git show HEAD:` 原版、同進程同輸入 → **335 支 DIFFS=0**、blocked 9=9、
pool identical;故障注入(observe 強制 raise)守門 DIFFS=0 且自我熔斷;kill switch
DIFFS=0;成本 +5.8ms/slug(待發 9 支 ≈ 52ms)。

🔴 **更正 docs/fact_pool_unit_blindspot.md 的決策結論(我採信過那個結論,是錯的)**:
它把兩個變數混在一起——「現在硬修=停產」量到的是 **B(擴大抽取面)**,不是它自己主張的
**A(池單位化)**。實測:
- **A 只把池單位化:待發 9 支誤殺 0、全語料 334 支誤殺 1** → **停產風險實測不存在**
- A+B 併同擴大抽取面:全語料誤殺 85(25%)→ 這才是不能做的那個
A 的那 1 支不是誤殺,是**真憑據問題**(已發布的漂移片)。

🔴 **但 A 治不了 EP1/EP6(別當成已修)**:EP1「多賺三十七萬」**沒有假掛名詞、壓根沒進
抽取器**;EP6 的子句無 PERF_CTX 詞(「吃掉」不在表)**且**被 HEDGE「假設」救援。
**兩道都在單位之前,單位化碰不到。真根因在 PERF_CTX 成本語彙 + HEDGE 過寬,不在單位表,
也不在交接書的修法清單裡。**

活體實例(證明守門真的在背書):已發布片 `L_個股體檢EP1台積電2330…` 口播 **8285.2%**、
真值 **8728.8%**,而現行守門找到的「憑據」是 **8358.0 / 8433.0** —— 兩個毫不相干的數字。

更正 amount 子池:**不是空的**(14 個)但**全是營收級距**(最小 ≈416 億);另有
price_twd=269、amount_twd=69。結論仍成立(**無個人損益級距 → 37萬/3.2萬必然無憑據**),
但理由不是「全庫只有報酬率」。

誠實記錄:agent 自己踩了兩個中文斷詞 bug(「百分之九十」被切成「百」+「分」、
「0050年化」→「0050年」),第一版噴假誤殺,已修。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
這份交接書是今晚我讓人寫的、我也採信了它的結論,而它錯在最關鍵的地方:

1. **「現在不能修,會停產」量錯了變數**。把「只做池單位化(A)」與「單位化併同擴大抽取面
   (A+B)」混在一起量 → 25% 誤殺是 B 的數字。分離後實測:**A 在待發 9 支誤殺 0、
   全語料 334 支誤殺 1,而那 1 支不是誤殺是真憑據問題**(已發布的漂移片)。
   **停產風險實測不存在。** 文件若不改,下一個人會照著錯的結論,繼續不敢修一個零誤殺的東西。
2. **把 EP1/EP6 當成「單位盲區」的代表案例是錯的歸因**。EP1「多賺三十七萬」**沒有假掛名詞、
   壓根沒進抽取器**;EP6 的子句**無 PERF_CTX 詞**(「吃掉」不在成本語彙表)**且**被 HEDGE
   「假設」救援整句。**兩道都在單位之前,單位化碰不到。真根因是 PERF_CTX 不全 + HEDGE 過寬,
   不在單位表、也不在本文原本的修法清單裡。**
3. **amount 子池不是空的**(14 個)但全是營收級距(最小 ≈416 億)。結論(37萬必然無憑據)
   仍成立,但理由要改成「沒有對應量級的子池」而非「沒有子池」。

同時新增活體證據:已發布的 L_個股體檢EP1台積電 口播 8285.2%、真值 8728.8%,而守門找到的
「憑據」是 8358.0/8433.0 —— **兩個毫不相干的數字。守門看了,然後說有憑據,放行。**

教訓(寫給下一個讀這份文件的人):**一份診斷書最危險的不是漏診,是把「不能做」寫得很有
說服力——那會讓後面每個人都不去驗證它。**

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔴 **近失事故(我的錯,agent 在上線前的對照測試抓到)**:我上一輪判定「A 是純贏、
沒有取捨,直接上」。實作後對照原版發現:**單位化第一版反而【放寬】守門——9 支原本被擋
的片變成放行**,含「AI策略回測勝率90」「當沖勝率80」——**正是 2026-07-14 編造事故被
整十數規則擋下的那批片**。
根因:單位化把 `year_return: 0.7973` ×100 = **79.73** 放進 pct 子池,而 **79.73 從來
不在原本的無單位池裡** → **單位化憑空製造了新憑據**。**照我的結論硬上,今晚就重新打開
那個破口。**

修法(比原方案更好):`_sourced_unit()` 改成 **`舊判定 AND 單位判定`** —— **單位化只能
拿掉憑據、永不新增**。「只能收緊或中性」從一個承諾變成**結構上的保證**,不賭單位推斷正確。

上線對照(335 支):原擋 8 → 現擋 13,**新增擋下 5、放寬 0、待發受影響 0**;+9.9ms/slug。
fail-open 實測:單位池強制炸掉 → 退回舊行為 **335/335 完全一致**(擋 8 支,非全擋=沒停產)。
新增擋下的 5 支**全是已發布、且全為真憑據問題**:`少賺三十八萬`(docstring 記載的
2026-07-13 canonical 編造案,舊版撞池裡 38.9 這個百分比而放行)、`8285.2%`(真值 8728.8)、
`798%`(真值 762.7)。能力邊界已寫進 docstring 與 log。

⚠️ **我上一輪指認的「真根因」也是錯的,agent 實測推翻、沒上**:
- PERF_CTX 加成本語彙(掃 corpus 實得 吃掉×13/手續費×15/成本×10/稅×9/滑價×8)→
  **全語料新增擋下 0 支**。因為 **PERF_CTX 只閘百分比,金額走的是「假掛名」那條路**;
  EP6 加了之後 extract 0→4 但 check_slug 仍不擋。且成本語句多數是**合法算術**
  (「十萬元…手續費一百四十元(0.14%)」),收進來只製造誤殺。
- HEDGE 窗口縮到逗號子句 → 機制有效但 production **新增擋下 0、反而 3 支變放行**(負向)。

🔴 **真答案(今晚最刺的一句)**:EP1/EP6 這類**無假掛名詞的金額宣稱,擋不住,而且那兩道
根因修下去也還是擋不住**。真閘是**逃逸#1:金額只有一條路——必須落在假掛名句裡**。
EP1/EP6 都沒有假掛名詞,在 PERF_CTX/HEDGE/單位判定**之前**就出局。
**A 抓得到的是帶了「回測顯示」的同款編造(`少賺三十八萬` 已被擋)。差別只在編造者有沒有
多寫那四個字——這條線仍然開著。**
→ **守門在檢查「宣稱有來源」的句子,不標來源的句子直接放行 = 誠實標註的人被檢查,
不標的人通過。這是結構性的反向誘因,下一輪要治的是這個。**

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
長片是 YPP 存亡格式(只有它計入 4,000 watch hours),而唯一有憑據的長片題源是
stock_checkup(backlog 1903 檔、每題綁 fact_key)。擋路的只有 crontab:32 一句
**沒實測過**的註解:「FinMind 免費層每天只處理 1 檔,絕不暴衝 rate limit」。

實測推翻它,兩點都錯:
- 限制是 **300 requests/小時**(無 token;有 token 600/hr,超量回 402),**不是「每天幾檔」**
- **一檔只打 4 個 call**(月營收/財報/股利/PER;財報被 EPS+毛利率共用、靠快取只打 1 次;
  Info 表 7 天快取共用;價格走 yfinance 不吃額度)
由小而大實測(2→3→8 檔,累計 52 call):**全 HTTP 200、零 402、零限流**,avg 0.31s/req,
第 52 個 call 跟第 1 個一樣快。**8 檔 = 32 call = 時額 11%**;最壞(8成功+5失敗)=17%。
耗時 5.4 分(05:50→05:55),離 06:07 製作批 **11 分餘裕**(瓶頸是 yfinance+LLM 不是 FinMind)。
backlog 1903 檔 = **237 天**。

🔴 **光改 crontab 會是騙人的**:`MAX_ATTEMPTS=5` 是**總嘗試預算且成功也計數** →
`--count 8` 會**無聲地只做 5 檔**,而產線照樣回報「跑完了」。原註解本意是「資料不足別一路撞」
= **失敗預算**。已改 `MAX_FAILS=5` 只計失敗;修後實測回報「**完成 8/8 檔**」(修前會是 5/8)。

**副產品**:實測本身已把未用長片題的**有憑據數 5 → 18 支**,明天「4/8 無憑據」當場補平。
明天 05:50 已驗證:local_cron parse 出 `--count 8`、07-18 05:50 觸發一次、冪等安全。

誠實揭露(agent 自報,未動 gate):
1. 🟡 `--count 8` 那輪印「1 題溯源失敗」是**假警報**:`fact_pool(refresh=True)` 只刷
   `_POOL_CACHE`,但 `unsourced_claims` 另用 `_TYPED_POOL_CACHE`(fact_source_guard.py:696)
   **永不刷新** → 同 process 跑多檔時第 2..N 檔拿舊池在驗。乾淨 process 下該題
   `unsourced_claims->[]`(真有憑據)。**發布端真 gate 是每片獨立 process,不受影響**;
   `--count 1` 時就存在、只是照不到。建議併 task#13 處理。
2. 🟡 執行窗口 50s→5.4 分,會與 tv_curriculum(05:52/05:54)、shorts_funnel(05:55)
   重疊寫 topic_bank。`save_bank` 原子寫**不會寫壞檔**,但不防 lost update;
   parasite_titles(05:50)今天就在重疊 = **既有風險非新增**。
3. 🟠 **內容組成的影響(Carson 該知道)**:`MAX_TOPICS_PER_CODE=1` → 8 檔 = 8 支長片題,
   而長片日需求 8(5+3 保底)→ **長片檔期會幾乎全是「個股體檢」單一 franchise**。
   我的判斷是這樣對:其他長片題源(auto_winner)今晚已因無 fact_key 降級成 short,
   個股體檢是**唯一有憑據的長片來源**,且每集不同股票、本來就是 Carson 拍板的
   「1925 檔一檔一集」原計畫。要保多樣性可改 `--count 5`(20 call=7%,同樣安全),
   但那 3 支缺口只能由無憑據題填 = 白燒。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔴 `concept_visuals._backtest` 的曲線是 `rng.randn()` **亂數**、漲跌是 `rng.rand()>0.5`
**擲骰**,而字卡寫著「**真正能信的是樣本外**」—— **tw_facts_engine 根本沒有樣本外驗證**。
`render_ffmpeg.py:680` 還**強制每支長片**插這個 beat。與已拆的賽跑條**同 species**:
不是「圖畫得不準」,是**宣稱一個我們實際沒有的嚴謹度**(方向=膨脹)。而它直接矛盾於
EP.0 規則②「資料有多長就跑多長」。

**移除不修好**(同拆賽跑條判例):`_backtest` **沒有任何情況下是對的**——就算將來真做了
樣本外,要畫的也是**真實回測結果**不是 rng。整條拆(函式+_DISPATCH+classify 規則),
留長註解防復活,不留 dead code。

同批修的另兩處(同病:渲染/縮圖層只抓標題數字、不懂語意):
- `render_ffmpeg.py:230` hook_card 大數字**只認結果單位**(%/倍/萬/成/億),撈不到→回 None
  不畫卡;`:270` 不再硬切 `[:14]`(「已經拆完 14 集」被切成「已經拆完 1」+巨大紅「14」
  壓在上升淨值曲線 = **把集數演成績效懸念**),改在「|」收尾、**絕不切在數字中間**
- `make_thumbnails.py` `is_debunk` 先去品牌名(`_BRAND_PHRASES`)——**「台股真相實驗室」
  內含「真相」→ 每支 tw_lab 都被判成打假片**,於是把我們自己的存量演成「敵人的神話」
  打紅叉。這是語意反轉的根因。

🔴 **修的過程又抓到第 4 個假話**(長在觀眾看最多眼的那個面):重生縮圖印「**43組實測**」
—— **43 不存在**,是 LLM 把標題的 14(集)+29(組)**自己加起來**的。已加
`_numbers_traceable`:LLM 文字裡每串數字都必須在標題找得到,否則**整包退保底**(保底切
標題來,結構上超不出標題)。重生後封面 = 「29組/真回測」(可查證)。

驗證:py_compile 三檔;**其餘 9 張概念卡 classify+出圖全 OK**(沒拆壞);重渲染 EP.0
EXIT=0、b-roll 2/7、字幕 56、BGM 有、總長 154.6s **與修前完全一致沒少東西**;log 不再
出現「強制回測對比 beat」;抽幀 f{1,15,120}s:首幀=品牌卡、**完整標題「已經拆完 14 集」
正確顯示**、無巨大紅數字、**15s/120s 的亂數樣本外圖已消失**。audit ok=True、fact_source 0、
current_ep 未動。修前證據留 scratchpad\ep0_before\。

🔴 **已發布災情(只查未改)**:長片 75 支中,強制 beat(2026-07-08 上線 28b2798)後
mtime → **21 支確定中鏢**;7 支早於該日安全;**47 支 mp4 已不在本機、此法判不到**。
⚠️ **關鍵字路徑更早更廣**:`_backtest` 自 **2026-06-14 initial commit** 就在,旁白提
回測/樣本外/驗證期就可能觸發 → 已發布長片 **28 支**旁白含這些詞;**此路徑也適用
Shorts(603 支),尚未清查**。mtime=最後渲染非上傳,是**下界不是精確值**。

⚠️ **新發現,未動(超出授權,待判)**:首幀品牌卡的常駐標語寫「我用真回測拆穿割韭菜神話
——**每個結論,都有數據卡佐證**」,是**寫死在品牌 furniture 的方法論宣稱**,同 species。
而 docs/fact_pool_unit_blindspot.md:197 自己就寫著「頻道招牌是『每個結論都有數據卡佐證』,
這道破口直接打在招牌上」——**招牌本身就是那句宣稱**。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
背景:守門的金額宣稱只有落在「假掛名句」才會被檢查 → **誠實標註來源的人被檢查,不標的
人通過**(反向誘因)。而擴大抽取面實測 25% 誤殺、補 PERF_CTX 新增擋 0、縮 HEDGE 反而放寬
→ **守門端救不了金額**。故從產製端治。

🔴 **決定性證據(比原假說更強):裸金額不只查無源,是跟稿子自己矛盾**
- `S_複利20年`:稿子自己說「月投3千/年化10%/20年」→ 實質 ≈ **162萬**,卻講「只剩**四百萬**」
- `S_0050定投10年`:自己說「24.5% vs 16.9%」→ 100萬差 **418萬**,卻講「少賺 **803萬**」
- `S_0050定期定額10年`:自己說「815% vs 380%」→ 湊 180 萬需本金 **41.4萬**(荒謬)
→ **LLM 是獨立於它拿到的真數據另生一個順口金額。不是算錯,是編。**
→ 這也是為什麼「要求同場講出本金+百分比」有效:**把金額鎖進一條可驗算的算式,編不出來**。

Corpus(335 支全掃、人工逐句複核):真裸金額 13 token/12 支 = **3.6%**;12 支成分 =
編造 5(2 支今晚已擋 + **3 支跟自己稿子對不起來**)+ 無憑據 7。分佈極不對稱:
**10/12 裸金額在短片;12 個可推導 token 有 11 個在長片** → 長片本來就在寫
「回撤33.8% → 一百萬變六十六萬」,這條規則對長片幾乎零成本。

⚠️ **內容代價比預期小,而且方向相反——這條規則頻道早就立過了**:`TW_LAB_RULES`
(2026-07-14)已對百分比立過同一條:「**不准只裸講差值**…觀眾有兩邊數字**才有震撼感**
與可驗證性」。**頻道自己的結論是攤開組成數字=更震撼,不是犧牲畫面感。** 本次只是把它從
tw_lab 單 franchise+百分比 → 全 franchise+金額。「投入一百萬、差418萬,夠買一臺賓士」
比「少賺803萬」更有畫面,「一臺賓士」裝置完整保留。

🔴 **絕不做成 gate**(agent 實測後的關鍵修正,我採納):裸金額偵測器**誤殺 8/21 = 38%**,
誤殺樣態與交接書「別把元/年/分加進單位表」**完全同型**——「全臺一百二十萬**人**」
(人數不是錢,**agent 自己犯了交接書正在講的那個單位錯**)、「虧掉五億鎂」(爆倉新聞非回測)、
「號稱滾到千萬」(**在拆穿別人**)、「最大回撤三成→三百萬少一百萬」(合法算術)。
**當 prompt 規則:零誤殺(只引導生成不擋東西);當 gate:38% 誤擋合法內容。**

實作:`_AMOUNT_DISCIPLINE` 掛進 **`GUARD`**(不是 `_LONG_DATA_DISCIPLINE`——後者只掛長片,
而 10/12 裸金額在**短片**;也不是 TW_STOCK_RULES——只掛台股題)。`GUARD` 是唯一全域點,
實測進**全部 6 條**寫稿 prompt。**`GUARD` 本來就寫「不編造個人損益」——本規則是那條老鐵則
的可執行版本。**

附帶重大發現(已回寫交接書):池 2446 → **3777**(今天長片供給修復又灌入 1331),
**規模詛咒對金額已完全飽和**:37/38/87/180/217/230/400/430/803 萬
**全部 `_sourced_strict=True`**,含兩支已知編造片。**守門端對金額已經救不回來了。**

誠實揭露:①裸金額片的觀看/完播**測不到**(12 支一支都不在 `_vidtitles.json`)→
「裸金額是否比較會紅」**無數據可證,不編數字支持自己的結論** ②規則是 prompt 層、
**靠 LLM 遵守不保證**,要驗得看明天新片 ③真想硬保證,唯一零誤殺解是**在事實庫建
「個人損益級距」子池**讓金額有源可溯,不是加 gate ④12 支既有裸金額片沒動(2 支已擋,
剩 10 支下架/重寫 = Carson 決策)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shorts 清查(先前只查了長片):已發布 603 支 → 可判定 254 → **確定中鏢 105 支(41%)**,
其中 **50 支整支都是那張亂數圖**。與既有 98 支重疊 40 → **新增 65(下界)→ 併表 ≥163**。

抽幀鐵證(replay 舊碼 5/5 準,含 1 支對照組確認沒超抓):
- `U2buqw5wBh4`(225v):字幕正在講「**問題出在樣本外測試**」,配的圖是**擲骰子畫的**
  —— **我們教觀眾看樣本外,而我們用亂數演樣本外**
- `MLgck5lMmZg`(191v):字幕「**回測一百檔臺股,三個月後六成套牢**」→ 亂數冒充 100 檔真回測
- `jq8p99tKCTU`(736v):講 0050 扣款日,卻掛「真正能信的是樣本外」分割圖
入口與長片不同:強制 beat 幾乎打不到 Shorts(段數多為 2,迴圈空轉,只中 10 支);
**真兇是關鍵字路徑(自 2026-06-14 initial commit)96 支**,其中 50 支因
`video_concept=classify(標題+小標)` 被當 default_key → **整支預設都是亂數圖**。

🔴 **agent 拒絕執行我的指示,而且是對的**:我根據它前一份報告要求把文件裡的「≤32 觀看」
改成「≤59」。它回頭複驗發現 **59 是它自己算錯的**——`analytics_cache/` 有兩種結構,
top200 大快照是 `dict{video_id:...}` 形,而它第一版只認 `isinstance(d, list)` →
**靜默跳過 29 個檔**,只讀到 100 個 videoId(真實 306)。**它沒有照我說的改,因為那會把
一個錯數字寫進決策文件。** ≤32 維持,並把這次的錯記進 §7 當教訓。

🔴 **我先前給 Carson 的建議 ② 也失效了**:`xU5wDOnt77Q`(原本「唯一還在長」)
07-15=648 → 07-16=721 → **07-17=721(+0)**。那個 +73 是 07-15→07-16 那一格,**再跑一天
就停了**。花 1,650 units 重做它的理由消失。`jq8p99tKCTU`(736v)同樣連兩天 +0、已死透。
**新對象:`QBgjhZulDLg`(452v、+92/24h、唯一還在長、已抽幀證實、屬新增的 65 支)**,
同樣 1,650 units;但它 mtime 07-13、**今天是第 4~5 天 → 要嘛今天做,要嘛別做**。
誠實附註:重上架會歸零它正在長的 452 觀看(**機會成本比死片高**)。

**「105 支全做 = 17.3 天配額」的判斷,數據支持且比原本更強**:進榜 30 支裡 **26 支最後
24h 是 +0** —— 動了也沒人看得到。

**量尺陷阱(agent 自己踩過兩個方向,已寫進 §4.1/§7)**:判死活**只能用最後一格真 24h**。
用 Δ3天 會把「爆完就死」演成全表最猛成長(jq8p99tKCTU Δ3天=+517,實際連兩天 +0);
而 07-17 有 05:37/07:17 兩筆只隔 1.7h,直接取最後兩筆會讓**全部片**顯示 +0。

**349 支獨立成 §6.5「不是清白,是查無資料」**(mp4/md 都不在本機),明寫「真實數字在
**163~512 之間,我不知道落在哪**」;外推的 143 支標成「**不是實測、不要當數字用**」。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
端到端跑「有人付錢 → 收到週報」整條鏈時抓到的(各段單元測試都綠,斷在接縫,
與本專案前三次靜默失敗同型)。**這個 bug 是我自己造成的**:上一個 commit 把
basic 降成 49,但 webhook/config.py:112 有**自己一份硬寫的定價表**,還停在舊價。

  webhook/config.py     basic TWD 99 / full USD 15 / annual USD 129   ← 舊
  ecommerce/config.py   basic TWD 49 / full USD 9  / annual 停售       ← Carson 拍板的

後果:classify_tier(49,"TWD") → "unknown"(|49-99|=50 > 容差 24.75)→ **每一個付新價
49 的基礎版訂閱者名冊 tier 全錯**。若不是 export_active 剛好有「unknown 保底寄 basic」
的防線接住(51b5da1),**每個付 49 的人都會一封都收不到**——運氣救的,不是設計救的。

與 make_landing 把 NT$99 寫死在 HTML(47a334d 修的)是**同一個病**:多個事實來源 +
不同步時零告警。我在同一輪裡修了 landing 那個,然後自己又踩了 webhook 這個。

修:SUBSCRIPTION_TIERS 改從 ecommerce/config.SUBSCRIPTION **導出**,不自己養一份。
- 停售的層級自動不參與分類(annual enabled=False → 不在表裡)
- 導不出任何層級就**炸**(寧可炸也不要靜默判錯 tier)
- 分岔在結構上不可能發生:改一處,兩邊自動一致

順手清掉三個「把舊價寫死在測試裡」的絆腳石(它們紅得正確,但釘的是舊假設):
test_classify_tier / test_sale_and_sub / 我自己的 test_realistic_inputs_produce_unknown
(我當初寫「49=首月促銷價→unknown」時留了註解「若已能正確分層,本測試的前提要更新」
—— 就是現在)。三個都改成讀單一事實來源,以後改價測試自動跟上。

新測試 test_pricing_single_source.py(5 測,結構性釘死):
層級表逐值等於來源 / 照牌價付款必判得出來 / 停售層級不參與 / 改來源會傳播 /
**原始碼掃描:層級表不得又被手寫回硬編碼數字**
突變:把表改回硬寫舊價 → 3 failed;還原 → 全綠

端到端實測(付錢→名冊→寄送名單):付 149→full、付 49→basic、零人收不到
測試:webhook 61 → 66 passed;ecommerce 111;data_hunter 365

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtCyf61cHKCzfbp5y1KqJa
漏 commit 補上。ep0-produce 在按下產片鍵前的最後一道逐句查證抓到的:

3. 【tw_lab 規則②】「標的跟區間是機械掃出來的、**不是我挑的**」= **假**。
   `tw_facts_engine.SYMBOLS` 是**手寫死的 16 檔**,每個家族再手挑子集(停利只跑
   0050/2330/006208、錯過最佳日只跑 0050/TWII),**全檔零行掃市場**;SYMBOLS 註解
   自己還寫著「2026-07-15 新增標的」= 人為決定。(「**區間**機械」是真的,假的是「標的」那半句。)
   → 改成從 `SYMBOLS` **算出來**:「12 檔:7 高股息 ETF、2 市值型、1 槓桿、1 個股、大盤」
   + 崩盤固定 2 段(=CRASH_WINDOWS)。**刻意不用 len(SYMBOLS)=16**——其中 4 檔資料不足
   MIN_YEARS 從沒跑出任何回測,宣稱 16 是膨脹;取 SYMBOLS∩事實庫 = **12**(保守下界,
   將來資料夠會自己納入)。並保留自我設限句:「**但它終究是我列的**,所以『換一檔冷門股
   會不會不同』我的回測回答不了」。
4. 【checkup 規則①】「最常見的是 **ETF 根本沒有財報**」= **假**。缺漏 5 檔裡 ETF 只有 1 檔,
   其餘 4 檔全是個股(國巨/華邦電當然有財報),reason 一律「FinMind 查無資料」=
   **我們自己抓取失敗**。**把自己的管線失敗說成市場結構限制 = 膨脹。**
   → 改成 ETF/個股分開講,個股明說「**是我沒抓到,那是我的問題**」。

判準(agent 提出,已採納並寫進 memory):**COST_DISCLOSURE 是自我設限(最壞低報自己)→
方向安全;這兩句是宣稱一個實際沒有的嚴謹度 → 方向是膨脹。** 同樣是「我們怎麼做」的話,
**方向決定它是誠實還是謊言**。

⚠️ 這是「規則先講死」那一段的**第 3、4 句假話**(前兩句:手續費都算進去、同一把尺)。
**那段的唯一作用是證明「我值得你訂」,而它是整個引擎裡假話密度最高的地方**——
因為沒人會去查一句聽起來像品格宣言的話。
且這兩句**違反本檔檔頭自己寫的總原則**(宣稱句必須能從真實檔案算出,不可寫死當文案)。

災情:**零對外事故**(全產線 grep 只命中這幾行,只活在未發布稿;已發布 14 支不含這些句)。
gate 一個字沒動;audit_video 擋「一定賺」是**對的**(同句判定),已改成同句就講明
「這幾條到底是不是真的,沒什麼人真的拿數據去驗過」,**不用同義詞繞禁語**。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
我改定價(basic 99→49、年繳停售)後**沒把下游清乾淨**,自己回頭盤點抓到的。
同一個病(多個事實來源 + 不同步時零告警)在這個 codebase 的**第四、第五個現場**:

1. listing_templates.py —— 文案硬印年繳
   `_sub_prices()` 無條件塞 annual_y,文案印「完整版年繳 NT$1290(省 28%)」。
   **這份文案是要貼到 Portaly 商品頁的** → 貼上去就是在賣一個 Carson 已拍板停售的方案。
   修:停售的層級回 None,呼叫端不印(對齊 make_landing._tiers_html 的 enabled 過濾)。

2. pinterest_pin_generator.py —— pin 圖燒著舊價,而且檔頭註解還宣稱「價格 = config.py 事實來源」
   5 張 pin 的 price 全是手打字串,旗艦寫死 "NT$99–149 / 月"。
   **這是要貼上 Pinterest 對外引流的圖** → 廣告一個不存在的價格。
   修:全部改從 config 導出(_sub_price_label / _one_price),零手打價格。
   親眼驗:重產後旗艦 pin 顯示 NT$49–149 / 月。

3. GO_LIVE_RUNBOOK.md —— 手冊叫 Carson 去 Portaly 設舊價、還叫他開已停售的年繳
   §1.1「基礎版 NT$99 / 完整版 NT$149 / 完整版年繳 NT$1290」。**他會照著設** →
   設成 99 → 系統認 49 → 每個訂閱者判 unknown(保底規則會接住但名冊全錯)。
   修:改成 NT$49/NT$149、明標年繳暫緩與理由、加一段「價格必須與 config.py 一致,
   那是全系統唯一定價事實來源」的警告;§3.4 的 full_annual 引用一併更正。

順帶修好一個資料遺失:`listings_copy/`(9 份上架文案)與 `pinterest/`(5 張 pin)
在上輪重產 SKU 時被洗掉了,已重產回來——而且重產自動吃到新價。

全線一致性總驗(config 是唯一來源):
  config   basic NT$49 / full NT$149 / annual enabled=False
  webhook  [('basic',49), ('full',149)]        ← 導出
  landing  NT$49 NT$149                        ← 導出
  文案     基礎版 NT$49/月 | 完整版 NT$149/月   ← 導出,零年繳字樣
  pin 圖   NT$49–149 / 月                      ← 導出(親眼看圖確認)
  手冊     NT$49 / NT$149,零舊價、零停售方案
listing --check gate 仍過(9 份、蝦皮 tag≤13、誇大詞 0)
測試:ecommerce 111 passed;webhook 66 passed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtCyf61cHKCzfbp5y1KqJa
landing 由 make_landing.py 重產(價格從 config 導出,非手改 HTML,維持 WYSIWYG);
gauge_history 是掃描器每日自動追加的溫度讀數(那份唯一無法重建的資料)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtCyf61cHKCzfbp5y1KqJa
制度自相矛盾(topic-purge 發現):`_BUCKET_DIRECTIVE` 早把「當沖真實勝率統計」列進
🔴 絕對禁止,但**那是自由生題路徑的禁令,題庫路徑沒有**;而題庫路徑的 `TW_STOCK_RULES`
命令「開場前 3 秒直接砸具體神話數字」、**範例就是「當沖九成畢業」**。
→ **同一件事,一條路禁止,另一條路命令你去做。**

改法(4 處,判準用「**實際有沒有拿到事實**」而非關鍵字黑名單 → 個股體檢**結構上不可能
被誤殺**):
- `:1257` NO_FACTS_INTEGRITY_RULES 標題「(非台股題…)」→「(本題在事實庫查無對應的真回測
  數據可引用)」。**不改這行其他全白做**——把這規則掛到「當沖」這種台股題上時,規則自己
  寫著「非台股題」,LLM 可判定不適用而略過
- `:1278` 新增 `TW_NO_FACTS_OVERRIDE`:光加守門不夠,`TW_STOCK_RULES` 還在同份 prompt
  命令砸數字 → 兩條**互相矛盾**,LLM 會跟更前面更具體那條。本區塊**顯式推翻**它
- `:1948` `_tw_inject=""` 先綁定(原本只在 try 內賦值,`_load_tw_facts` 拋例外就 NameError)
- `:1975` `if not _tw_inject: hook_rules += NO_FACTS + TW_NO_FACTS_OVERRIDE` ← 本體

驗證:①8 支當沖實跑 **8/8** 落守門+推翻砸數字 ②回歸:925 支未用題中**有事實的 269 支**
(含未用長片全部 69 支有憑據的)照舊注入、不加守門;「有事實卻被誤壓成示意」= **0**
(結構保證非測試運氣);🆕 **多守住 12 支短片當沖題**(前一輪 purge 只清長片沒碰到)
= **程式碼修 > 資料清**的實證 ③明天 06:07 的 4 支體檢照拿 8/8/8/13 條事實、無守門

🔴 **agent 拒絕宣稱修好,而且是對的**:「下次來個無資料台股題(融資斷頭/填息機率)還會不會
被命令砸數字?**會**。」——**那 8 支當沖是運氣才落到守門**(標題不含台股關鍵字)。
只要標題含「台股/大盤/0050/存股/ETF」任一 → `:1588 _pick_all` 觸發 → **無視相關性**發前
6 條事實 → `_tw_inject` 非空 → **本 fix 不觸發**,照樣被命令砸數字,**還多一塊
【本片實證數據】幫假數字背書**。合成實測 **5/5 全繞**。
**題庫現存 15 支正在繞過**(13短+2長):全部拿到**同一組完全不相干**的
`0050 All-in vs 定期定額` 事實,去寫「填息天數」「當沖勝率」「AI選股勝率90%」。
→ **這是「假憑據」的完美形式:數字是真的、溯得到源,但用在毫不相干的片上。守門查
「有沒有源」→ 有 → 放行。**

⚠️ **agent 做了黑名單方案、測過(0 誤殺/15 真陽性/理由精準),然後否決自己**:
①事實在 `:1953` 已注入、守門在後才判 → 只加黑名單會造出**同時有【本片實證數據】+
「本題查無數據」的自相矛盾 prompt = 新的失效模式,可能更糟** ②做對要連帶抑制注入,
而 `_facts_raw` 還餵 `:2070 _densify_long` → 又一個要獨立驗證的面 ③**根因是 `_pick_all`
沒有相關性判斷,正是待辦 #13「守門在替假數字背書」的同一個根因**;黑名單是無止盡維護的
補丁,**治 `_pick_all` 一次解 15 支 + 未來全部** ④今晚沒火(2 支長片版排在 18 支 checkup
之下,明天抽不到)。regex + 15 支清單已備妥,下一輪連同 #13 一起治 `_pick_all`。

⚠️ 水龍頭(topic_bank.py:74 CATEGORIES 仍有當沖出題方向)這輪不動:索引耦合有 assert,
且水龍頭現在是關的(--target 50 vs 未用 925 → need<0 直接 return)。
**別誤以為本 fix 讓新當沖題安全了——新題只要標題帶「台股」就繞過。**

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants