[{"data":1,"prerenderedAt":609},["ShallowReactive",2],{"content-/beat-monitoring-scatter-fcf-toggle":3,"all-pages-for-dir":607,"og-image-/beat-monitoring-scatter-fcf-toggle":608},{"id":4,"title":5,"body":6,"category":590,"description":591,"extension":592,"meta":593,"navigation":182,"ogImage":594,"path":595,"project_name":596,"published":597,"publishedAt":598,"seo":599,"stem":600,"tags":601,"todo":594,"unpublished":597,"updatedAt":594,"__hash__":606},"pages/2026-06/2026-06-16/beat-monitoring-scatter-fcf-toggle.md","beat-monitoring scatter に FCF 基準トグルを追加して 13 銘柄の割安成長ゾーンを別軸で読む",{"type":7,"value":8,"toc":578},"minimark",[9,13,26,41,44,50,86,93,96,99,243,257,282,286,289,344,362,388,391,394,411,418,425,445,448,451,467,481,484,529,532,574],[10,11,12],"h2",{"id":12},"何をやったか",[14,15,16,20,21,25],"p",{},[17,18,19],"code",{},"/beat-monitoring/scatter"," は 13 銘柄を「Forward P/E × NTM EPS 成長率」の平面にプロットしている自作の散布図ページで、PEG（成長率÷PER）を 2 軸に開いた図と同じ意味を持つ。ここに「指標基準」のトグルを足し、軸の計算式を ",[22,23,24],"strong",{},"EPS 基準 ↔ FCF 基準"," で差し替えられるようにした。BCU の Yartseva 2025 が 464 銘柄・2009〜2024 の米国 10 倍株分析で「FCF 利回りが主要駆動要因」と特定していたのを取り込みたかった。",[14,27,28,29,32,33,36,37,40],{},"実装の前日（2026-06-15）に Phase 4 の純粋関数と scatter.vue 側のトグル UI、E2E スモークまでを一気に投入していた。ところが翌朝（2026-06-16）に積み残しを点検したら、",[17,30,31],{},"BeatValuation"," 型に FCF フィールドを足し忘れていたのが見つかった。スクリプト側のテンプレートには入っているのに、実体の ",[17,34,35],{},"valuation.ts"," の interface だけ古いまま残っていて、データ行には ",[17,38,39],{},"ntmFcfps"," が入っているのに型では存在しない、というねじれが起きていた。",[10,42,43],{"id":43},"朝の点検で見つけた型のねじれ",[14,45,46,47,49],{},"claude-code-sync のログに「積み残しを教えて」と打ったら、3 本のうち 1 本としてこの計画書が返ってきた。実装は完了していると Claude Code は答えたが、念のため ",[17,48,35],{}," をフルで開いて 23-38 行目あたりを目視確認させた。",[14,51,52,55,56,59,60,59,63,59,66,69,70,59,72,59,75,59,78,81,82,85],{},[17,53,54],{},"interface BeatValuation"," の中に ",[17,57,58],{},"ntmEps",", ",[17,61,62],{},"ltmEps",[17,64,65],{},"ntmEpsGrowth",[17,67,68],{},"ntmPe"," などは並んでいるのに、",[17,71,39],{},[17,73,74],{},"ltmFcfps",[17,76,77],{},"ntmFcfGrowth",[17,79,80],{},"ntmFcfYield"," の 4 つだけ抜けていた。一方でファイル下部のデータ行のほうには FCF の数値が入っていた。スクリプト側のテンプレートを Phase 2 で書き換えたのは正しいのに、Phase 3 で interface を書き換えるはずだったコミット（",[17,83,84],{},"82117e63","）に拾われていなかった。",[14,87,88,89,92],{},"ねじれが残っていた理由は明確で、現スナップショットの 30 銘柄中 10 銘柄しか FCF を持たない部分充足状態だった。required にすると残り 20 銘柄の null/undefined で型エラーが噴き出す。",[17,90,91],{},"optional + nullable"," で 4 フィールドを足すのが筋だった。",[10,94,95],{"id":95},"修正の方針",[14,97,98],{},"interface の追補は 4 行で済んだ。",[100,101,106],"pre",{"className":102,"code":103,"language":104,"meta":105,"style":105},"language-typescript shiki shiki-themes vitesse-light vitesse-light","// 既存\nntmEps: number | null\nltmEps: number | null\nntmEpsGrowth: number | null\nntmPe: number | null\n\n// 追加（optional + nullable で後方互換）\nntmFcfps?: number | null\nltmFcfps?: number | null\nntmFcfGrowth?: number | null\nntmFcfYield?: number | null\n","typescript","",[17,107,108,117,138,151,164,177,184,190,204,217,230],{"__ignoreMap":105},[109,110,113],"span",{"class":111,"line":112},"line",1,[109,114,116],{"class":115},"sxvE3","// 既存\n",[109,118,120,123,127,131,135],{"class":111,"line":119},2,[109,121,58],{"class":122},"senZ8",[109,124,126],{"class":125},"shFtX",":",[109,128,130],{"class":129},"s4oTP"," number",[109,132,134],{"class":133},"stQ0i"," |",[109,136,137],{"class":133}," null\n",[109,139,141,143,145,147,149],{"class":111,"line":140},3,[109,142,62],{"class":122},[109,144,126],{"class":125},[109,146,130],{"class":129},[109,148,134],{"class":133},[109,150,137],{"class":133},[109,152,154,156,158,160,162],{"class":111,"line":153},4,[109,155,65],{"class":122},[109,157,126],{"class":125},[109,159,130],{"class":129},[109,161,134],{"class":133},[109,163,137],{"class":133},[109,165,167,169,171,173,175],{"class":111,"line":166},5,[109,168,68],{"class":122},[109,170,126],{"class":125},[109,172,130],{"class":129},[109,174,134],{"class":133},[109,176,137],{"class":133},[109,178,180],{"class":111,"line":179},6,[109,181,183],{"emptyLinePlaceholder":182},true,"\n",[109,185,187],{"class":111,"line":186},7,[109,188,189],{"class":115},"// 追加（optional + nullable で後方互換）\n",[109,191,193,195,198,200,202],{"class":111,"line":192},8,[109,194,39],{"class":129},[109,196,197],{"class":133},"?:",[109,199,130],{"class":129},[109,201,134],{"class":133},[109,203,137],{"class":133},[109,205,207,209,211,213,215],{"class":111,"line":206},9,[109,208,74],{"class":129},[109,210,197],{"class":133},[109,212,130],{"class":129},[109,214,134],{"class":133},[109,216,137],{"class":133},[109,218,220,222,224,226,228],{"class":111,"line":219},10,[109,221,77],{"class":129},[109,223,197],{"class":133},[109,225,130],{"class":129},[109,227,134],{"class":133},[109,229,137],{"class":133},[109,231,233,235,237,239,241],{"class":111,"line":232},11,[109,234,80],{"class":129},[109,236,197],{"class":133},[109,238,130],{"class":129},[109,240,134],{"class":133},[109,242,137],{"class":133},[14,244,245,248,249,252,253,256],{},[17,246,247],{},"optional"," を選んだのは「将来 ",[17,250,251],{},"generate-beat-valuation.mjs"," を再実行すれば、データのない銘柄も ",[17,254,255],{},"null"," で全銘柄分が揃う」状態に持っていけるから。required に倒すと一時的な不整合期間に TypeScript が騒ぎ、その間 scatter ページがビルドできなくなる。",[14,258,259,260,263,264,267,268,271,272,271,275,278,279,281],{},"直後に ",[17,261,262],{},"pnpm test:run"," を回したら 4 ファイル合計 134 件すべて pass。",[17,265,266],{},"scatterSplit.test.ts"," の 43 件には、前日に書いた ",[17,269,270],{},"computeFcfYield"," / ",[17,273,274],{},"computeFcfGrowth",[17,276,277],{},"getYAxisDisplay"," の境界テストが入っていて、ここで ",[17,280,255],{}," の伝搬を踏ん張ってくれた。",[10,283,285],{"id":284},"scatter-ページの実装中に-codex-が刺した-4-ラウンドの指摘","scatter ページの実装中に Codex が刺した 4 ラウンドの指摘",[14,287,288],{},"前日（2026-06-15）のセッションで Codex に 4 ラウンド回したログが計画書に残っていて、致命点 7 件を反映した経緯がある。一番効いたのは 2 件。",[14,290,291,294,295,298,299,302,303,305,306,309,310,313,314,317,318,271,321,323,324,327,328,331,332,335,336,339,340,343],{},[22,292,293],{},"1 件目",": ",[17,296,297],{},"pe"," フィールドに FCF 利回りを詰める設計は危険、という指摘。",[17,300,301],{},"ScatterPoint"," の ",[17,304,297],{}," を再利用しただけだと、scatter.vue 側で ",[17,307,308],{},"fmtPe(p.pe)"," のような PER 前提の固定関数が走り、「FCF 利回りを ",[17,311,312],{},"12.5x"," と PER 表記で出す嘘グラフ」が生まれる。対策として ",[17,315,316],{},"MeasureBasis = 'eps' | 'fcf'"," 型を新設し、",[17,319,320],{},"ScatterMetrics",[17,322,301],{}," の両方に ",[17,325,326],{},"measure?: MeasureBasis"," を持たせ、",[17,329,330],{},"getYAxisDisplay(measure)"," で ",[17,333,334],{},"{title, format, direction}"," を一元化した。scatter.vue 側は ",[17,337,338],{},"measureDisplay.value.title"," を軸タイトルに、",[17,341,342],{},"measureDisplay.value.format"," をツールチップの数値整形に通すだけにした。",[14,345,346,349,350,353,354,357,358,361],{},[22,347,348],{},"2 件目",": ADR 銘柄の FCF 利回りの式が逆、という指摘。TSM は 1 ADR = 5 普通株なので、EPS と PER の関係は ",[17,351,352],{},"ADR後PER = price / (eps × ratio)"," で「掛けてから割る」。FCF Yield は PER の逆数なので ",[17,355,356],{},"ADR後Yield = (fcfps × ratio) / price"," で「掛けて、分子に置く」になる。先に書いた ",[17,359,360],{},"price / (ntm_fcfps × ratio)"," は FCF Multiple（倍率）で、利回りではない。TSM のプロット位置が完全に壊れる手前で止まった。",[14,363,364,365,368,369,372,373,376,377,368,380,383,384,387],{},"このあと「",[17,366,367],{},"basis"," を ",[17,370,371],{},"epsBasis"," にリネーム」と書きながら一部で ",[17,374,375],{},"basis.value"," 参照が残っているとか、",[17,378,379],{},"measureDisplay",[17,381,382],{},"computed"," にしたのに ",[17,385,386],{},".value"," で unwrap してない、みたいな細かい指摘も Codex が拾った。4 ラウンド目で「致命点なし」と出てから実装に入った。",[10,389,390],{"id":390},"ゾーン解釈をどう保つか",[14,392,393],{},"EPS 基準のときは「左下＝割安成長」「右上＝割高停滞」で読む。PER は小さいほど良いので、縦軸は下に向かって良くなる。",[14,395,396,397,368,400,271,403,406,407,410],{},"FCF 基準だと利回りは大きいほど良いので、何も考えずに普通に描くと「左上＝割安成長」「右下＝割高停滞」に裏返る。ゾーンの読みが揺れると、頭の中で毎回反転計算をやることになる。対策として ",[17,398,399],{},"YAxisDisplay.direction",[17,401,402],{},"'higher-is-better'",[17,404,405],{},"'lower-is-better'"," で持たせ、scatter.vue 側で y 座標計算を反転する ",[17,408,409],{},"Multiple 表記"," に倒した（最終的に FCF Multiple = 1/Yield 表示に切り替え、縦軸反転トリックは不要になった）。これで両基準とも「下に行くほど良い」が保たれる。",[14,412,413,414,417],{},"ガイド記事（",[17,415,416],{},"/beat-monitoring-scatter-guide","）に「FCF 基準で見る」セクションを追加し、Yartseva 2025 へのリンクと「Multiple 表示にした理由」3 点を残しておいた。",[10,419,421,422,424],{"id":420},"phase-5-の-basis-リネームで残った警戒","Phase 5 の ",[17,423,367],{}," リネームで残った警戒",[14,426,427,428,430,431,433,434,437,438,440,441,444],{},"scatter.vue 側で既存の ",[17,429,367],{}," ref（Non-GAAP / GAAP 切替用）を ",[17,432,371],{}," にリネームしたとき、テンプレートの class binding・aria-label・disclaimer 表示条件まで波及した。Codex は「",[17,435,436],{},"split"," computed で ",[17,439,375],{}," 参照のまま残っている」と刺してきた。",[17,442,443],{},"grep -n \"basis\" apps/web/app/pages/beat-monitoring/scatter.vue"," で残存ゼロを確認してから commit した。リファクタで変数名を変えるとき、SFC のテンプレート側を全部追えてない事故は何度もやっているので、grep を 1 回挟むだけで救われる。",[10,446,447],{"id":447},"コミットの順序",[14,449,450],{},"朝の点検で見つけたねじれを 2 コミットに分けた。",[452,453,454,461],"ul",{},[455,456,457,460],"li",{},[17,458,459],{},"5548092d"," feat(beat-monitoring): BeatValuation 型に FCF フィールドを追補",[455,462,463,466],{},[17,464,465],{},"47add3b6"," docs(takken): scatter FCF 拡張プランを完了状態に更新",[14,468,469,470,302,473,476,477,480],{},"1 本目で型のねじれを直し、2 本目で ",[17,471,472],{},"memo/2026-06-15/scatter-fcf-extension-plan.md",[17,474,475],{},"implementation-status"," を「完了（2026-06-16）」に書き換え、Phase 0 〜 6 すべてのチェックボックスを ",[17,478,479],{},"[x]"," で埋めた。Codex 4 ラウンドの反映ログ表も計画書に残してある。",[10,482,483],{"id":483},"学び",[452,485,486,496,510,516],{},[455,487,488,491,492,495],{},[22,489,490],{},"データだけ入って型が抜けるケースは生成スクリプト経由だと普通に起こる","。スクリプトのテンプレートを書き換えるコミットと、再実行で実体ファイルを更新するコミットは別になるので、間で型不整合が走る。",[17,493,494],{},"tsc --noEmit"," をプッシュ前に挟むのが正解だが、それでも optional フィールドだとどっち向きにも倒せて気付きにくい。",[455,497,498,501,502,505,506,509],{},[22,499,500],{},"「同じ平面を測り分ける」発想は、軸の計算式を注入できる構造があると 5 行で足りる","。",[17,503,504],{},"buildScatterSplit(tickers, getMetrics)"," がメトリクス供給を関数注入で受け取る形になっていたおかげで、",[17,507,508],{},"fcfMetrics(t)"," を 1 個書き足すだけで第 2 軸が増えた。最初の設計のときに「将来 GAAP / Non-GAAP も切り替えたい」と思って関数注入にしておいたのが、9 ヶ月後に FCF 軸の追加で効いた。",[455,511,512,515],{},[22,513,514],{},"Codex は「設計のねじれ」を体系的に拾える","。型・フィールドの意味の流用が危険なケース、ADR 比率の式の向きが逆になるケース、リネームで参照漏れが残るケース。1 ラウンドで全部拾えるわけではないが、4 ラウンド回すと致命点が枯れる。「瑣末な点へのクソリプはするな」と最初に釘を刺すと、本質的な指摘だけ残る。",[455,517,518,521,522,271,525,528],{},[22,519,520],{},"ゾーン解釈は数値の向きで揺れる","。「右下＝割安成長」を保ちたいなら、軸の direction を ",[17,523,524],{},"lower-is-better",[17,526,527],{},"higher-is-better"," でメタとして持ち、y 座標計算で反転する。FCF Multiple 表示に倒せば反転自体が不要になる、という落としどころも見えた。",[10,530,531],{"id":531},"明日に残ったタスク",[452,533,536,549,562,568],{"className":534},[535],"contains-task-list",[455,537,540,544,545,548],{"className":538},[539],"task-list-item",[541,542],"input",{"disabled":182,"type":543},"checkbox"," Normalized FCF（5 年平均 capex 引き）を別計画で切り出す。",[17,546,547],{},"memo/2026-06-?/scatter-normalized-fcf.md"," で立てる",[455,550,552,554,555,302,558,561],{"className":551},[539],[541,553],{"disabled":182,"type":543}," 3 年 CAGR の横軸オプションを追加する。",[17,556,557],{},"buildScatterSplit",[17,559,560],{},"growth"," 計算を NTM 単発 / 3 年 CAGR で切り替える設計を考える",[455,563,565,567],{"className":564},[539],[541,566],{"disabled":182,"type":543}," factor lattice（点サイズ・色・形で 3 ファクター重ね）。small-cap / high-profitability の視覚化を入れたい",[455,569,571,573],{"className":570},[539],[541,572],{"disabled":182,"type":543}," FCF が欠損している 3 銘柄（13 銘柄中）を EDGAR フォールバックで埋める案を検討。XBRL 抽出は別パイプラインなので別計画扱い",[575,576,577],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":105,"searchDepth":119,"depth":119,"links":579},[580,581,582,583,584,585,587,588,589],{"id":12,"depth":119,"text":12},{"id":43,"depth":119,"text":43},{"id":95,"depth":119,"text":95},{"id":284,"depth":119,"text":285},{"id":390,"depth":119,"text":390},{"id":420,"depth":119,"text":586},"Phase 5 の basis リネームで残った警戒",{"id":447,"depth":119,"text":447},{"id":483,"depth":119,"text":483},{"id":531,"depth":119,"text":531},"dev","BCU Yartseva 2025 の FCF 利回り発見を取り込むため、自作の Forward P/E × NTM EPS 成長率の散布図に「EPS 基準 / FCF 基準」のトグルを足した。BeatValuation 型の FCF フィールド追補と、Codex 4 ラウンドのレビュー反映までの記録。","md",{},null,"/beat-monitoring-scatter-fcf-toggle","mdx-playground",false,"2026-06-16T00:00:00.000Z",{"title":5,"description":591},"2026-06/2026-06-16/beat-monitoring-scatter-fcf-toggle",[602,603,604,605],"beat-monitoring","FCF","scatter","Vue","NoSrS_XH-KTJYENFtxWi0dIYpC7IdqW0eaE7fXKtt24",[],"https://log.eurekapu.com/og/blog/beat-monitoring-scatter-fcf-toggle.png?v=2026-06-16T00%3A00%3A00.000Z&title=beat-monitoring%20scatter%20%E3%81%AB%20FCF%20%E5%9F%BA%E6%BA%96%E3%83%88%E3%82%B0%E3%83%AB%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%A6%2013%20%E9%8A%98%E6%9F%84%E3%81%AE%E5%89%B2%E5%AE%89%E6%88%90%E9%95%B7%E3%82%BE%E3%83%BC%E3%83%B3%E3%82%92%E5%88%A5%E8%BB%B8%E3%81%A7%E8%AA%AD%E3%82%80&author=Kei%20Komatsu&sig=62db0656cba9a315",1782176328260]