この記事で扱うこと
一日で五つの技術線を扱った。個人ブログのドキュメント関係グラフに Canvas 星明かりノードを入れ、別コードベースでは Playwright CI ログを全数調査して flaky と deterministic failed を分離した。同文脈で Service Worker 画像キャッシュ(stale-while-revalidate + byte-LRU)を作り、マスキング・ログアウト時に generation guard で原本再露出を防いだ。デザインシステム側は MCP だけでは不足で ESLint guardrail プラグインを追加した。
各作業は 前提知識 → どんな状況だったか → 中心の作業 → 教訓 の順でまとめる。
一日のまとめ
| 作業 | 何をしたかったか | やったこと | 結果 |
|---|---|---|---|
| 1. 星明かりグラフノード | 関係グラフがチャートの点に見えた | ID ハッシュベース Canvas 色・きらめき・shadow | テスト・VR 通過 |
| 2. Playwright CI triage | 赤 CI が flaky かバグか | 392 件ワークフローログ全数分類 | flaky 36 vs failed 分離 |
| 3. SW 画像 SWR | 画像再表示のたびネットワーク待ち | stale-while-revalidate + 100MB LRU | 単体・E2E green |
| 4. マスキングキャッシュ境界 | マスキング後の原本キャッシュ再露出 | 削除 ACK → UI 更新 + generation | セキュリティ順序確立 |
| 5. DS ESLint guardrail | AI が native UI を再実装 | prefer-ds-component・no-reimplement | コンシューマ repo で検証 |
1. Canvas 星明かり(starlight)ノード
前提知識(概念)
- Canvas 2D: ブラウザがピクセルバッファに直接描く API。DOM ではないため CSS アニメーションをノードに直接当てられない。
- force-directed graph: ノード間の引力・斥力で配置するグラフ可視化。通常 Canvas 上に描く。
- prefers-reduced-motion: OS・ブラウザの「アニメーションを減らす」設定。
どんな状況だったか
- Knowledge・TIL 詳細のローカル関係グラフノードがオレンジの点のように見え、夜空トーンと合わなかった。
- パネル背景の CSS 星はきらめくが、ドキュメントノードは Canvas 内にあり同方式は使えなかった。
中心の作業
- ドキュメント ID ハッシュで色(暖白・白・冷白)・きらめき周期・位相を安定計算。
- draw コールバックで
globalAlpha・shadowBlur適用後に状態復元。 autoPauseRedraw={reducedMotion}でモーション減少時にきらめき停止。- 凡例は中立色 — ノード色はドキュメント種別を表さない。
教訓
- Canvas は描画状態が次フレームまで残る — alpha・shadow は必ずリセット。
- visual メタは attach 時に一度、フレームごとは時間ベース alpha のみ。
→ Canvas deterministic node rendering
2. Playwright flaky vs failed
前提知識(概念)
- flaky: 初回失敗 → retry 成功。
- deterministic failed: すべての retry が同じ理由で失敗。
- CDP: ブラウザ例外の URL・行番号を読む診断プロトコル。
どんな状況だったか
- E2E CI が不安定に見え、特定 spec が flaky か毎回壊れるかの区別が必要だった。
中心の作業
- 数ヶ月分 push ワークフローログ全数分析 → flaky 36 件・8 テスト。
- 100% 同一 SyntaxError は custom webpack
splitChunksが CSS を JS entry に入れた ビルド欠陥 と確認。 - SSE タイマー・Radix portal focus・
networkidle・緩いwaitForRequestが flaky 上位原因。
教訓
- CI conclusion だけで flaky 判定しない — retry 結果を見る。
- production build + CDP で deterministic failed を再現する。
→ Playwright flaky vs failed triage · Webpack splitChunks trap
3. Service Worker stale-while-revalidate
前提知識(概念)
- Service Worker: fetch を横取りし Cache Storage に応答を保存するブラウザスクリプト。
- stale-while-revalidate: キャッシュ即返却 + バックグラウンド最新化。
- presigned URL: 有効期限署名付き一時ダウンロード URL。
どんな状況だったか
- クラウドストレージ画像を開き直すたびネットワーク待ちが必要だった。
中心の作業
- キャッシュ hit 時即返却、miss のみ await。
- 認証クエリだけキャッシュキーから除去、
masked=1等の意味クエリ維持。 - 100MB byte-LRU(本文 + アクセスメタ)。
教訓
- presigned キャッシュは「クエリ全体削除」ではなく「署名だけ strip」。
- byte LRU は本文・メタを一緒に動かす。
→ Service Worker stale-while-revalidate · Presigned URL cache key normalization
4. マスキング・ログアウトキャッシュセキュリティ
前提知識(概念)
- SWR は 性能 パターンだが、マスキング直後は 原本再露出 がセキュリティ問題。
- race condition: 削除中 in-flight fetch が原本を再保存しうる。
- generation: 削除のたび上げる世代番号で保存資格を判定。
どんな状況だったか
- マスキング API 成功後もブラウザキャッシュ原本が一瞬見えうる状態だった。
中心の作業
- マスキング成功 → キャッシュ削除 ACK 待ち → UI データ更新。
- generation guard で削除前開始 revalidate の
putをブロック。 - ログアウト両経路で画像キャッシュ全体削除。
教訓
- 機微データでは「削除」と「進行中リクエスト保存キャンセル」は別問題。
- セキュリティ境界では ACK が UI 更新より先。
→ Cache generation stale-write guard
5. デザインシステム ESLint guardrail
前提知識(概念)
- ESLint プラグイン: コードパターン違反を静的解析で報告。
- MCP: AI エージェントが外部ドキュメント・ツールにアクセスする標準 — DS ドキュメントを push 提供。
- guardrail は MCP(push)と ESLint(catch)が相互補完。
どんな状況だったか
- AI・開発者が native
<button>・ローカル Modal を再実装し DS を迂回した。 - hex・spacing ハードコードは許可、「DS 未使用」だけ捕まえたかった。
中心の作業
prefer-ds-component、no-reimplementの 2 ルール。- メッセージに import パス・MCP ツールヒント(agent-cognizable)。
- ワークスペース・per-package CI publish 整備。
- プラグインは コンシューマ repo のみ — DS 本体ソースには未適用。
教訓
- DS guardrail は「値禁止」より「コンポーネント迂回禁止」が実用的。
- publishable pkg 追加時は lockfile + CI publish job を一緒に確認。