Skip to content

fix(pages): favicon SVG 同梱 + post-deploy 404 検知 gate を追加 - #585

Merged
ayutaz merged 3 commits into
devfrom
fix/pages-favicon-and-404-gate
Jun 29, 2026
Merged

fix(pages): favicon SVG 同梱 + post-deploy 404 検知 gate を追加#585
ayutaz merged 3 commits into
devfrom
fix/pages-favicon-and-404-gate

Conversation

@ayutaz

@ayutaz ayutaz commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

GitHub Pages (https://ayutaz.github.io/piper-plus/) のブラウザコンソールに favicon.ico:1 Failed to load resource: 404 が出続けていた。 HTML に <link rel="icon"> が無く、 ブラウザの defacto auto-fetch が /favicon.ico を 404 にしていた状態。 HF Space の sdk_version drift と同じ「deploy 工程は green / 利用時に初めて顕在化する」silent failure で、 deploy 後の live URL 検証が無いことが根本原因。

Affected Components

  • Python (training / src/python_run)
  • Rust (piper-core / piper-cli / piper-python / piper-wasm)
  • C# (PiperPlus.Core / PiperPlus.Cli)
  • C++ (libpiper_plus / iOS / Android)
  • Go (src/go)
  • WASM / npm (src/wasm/openjtalk-web)
  • Docker
  • CI / CD
  • Documentation

Type

  • Bug fix
  • New feature
  • Refactoring
  • Documentation
  • CI/CD
  • Dependencies

Risk Level

  • Patch (bug fix / 内部改善のみ — 既存 API / output に影響なし)
  • Minor (新機能 / 非破壊変更)
  • Major (破壊的変更)

Contract Impact

  • None — docs/spec/*.toml への影響なし。 deploy bundle と CI gate のみの変更で、 ランタイム / API / 音響パリティに変更なし

変更内容

機能名 動作 これがないと起こること
SVG favicon 新規追加 src/wasm/openjtalk-web/assets/favicon.svg (304B、 #4CAF50 アクセント + 音声バーモチーフ) を deploy bundle に同梱 ブラウザの /favicon.ico auto-fetch が 404 を返し、 コンソールに毎ロード 2 行のエラーが残る
HTML に <link rel="icon"> 明示 multilingual-demo/index.html (および sed 経由で deploy 後の index.html / 404.html / multilingual-demo/index.html) に <link rel="icon" type="image/svg+xml" href="../../assets/favicon.svg"> を追加 favicon link 不在のため、 modern browser でも fallback fetch /favicon.ico が走り 404 を出す
.nojekyll 同梱 deploy/.nojekyll を deploy 直前に touch GitHub Pages が Jekyll を自動起動し、 _ 始まりの将来追加ファイル / ディレクトリを silently filter する潜在リスク
Pre-deploy gate deploy/.nojekyll / deploy/assets/favicon.svg / 主要 JS/WASM の存在を bundle build 直後にチェック。 全 HTML に <link rel="icon"> が含まれることも検証 将来また「bundle 作成時に asset が落ちていて 404」 が再発しても deploy 前に気付けない
Post-deploy gate (scripts/verify_pages_assets.py 新設) actions/deploy-pages 完了後に live URL を HEAD probe、 主要 14 アセットいずれかが non-2xx で deploy job を fail させる (リトライ 6 回 / 15s 間隔で Pages の伝播ラグを吸収) deploy-pages は upload accept で常に green。 live URL の 404 が誰かが画面を開くまで気付かれない (今回の favicon 404 と同じ failure mode)

設計判断

  • favicon.ico を repo に置かない: <link rel="icon"> が存在すれば Chrome/Firefox/Safari は /favicon.ico の auto-fetch を抑止するため、 binary blob の commit は不要。 SVG 1 ファイルで完結し grep / diff 可能
  • SVG モチーフは #4CAF50 の音声バー (4 本): ページ内アクセント色と一致、 16×16 でも判別可能、 既存 etc/logo.svg (横長バナー、 favicon としては不適) と用途分離
  • gate 哲学を HF Space 側 (verify_hf_space_runtime.py) と統一: deploy-pages / upload_folder の non-deterministic な「accept 後の build / 配信」 phase を post-deploy で polling、 silent 404 / BUILD_ERROR を即 CI red に昇格。 同じ機構を pages / HF Space で重複させ単一抽象化しないのは、 retry / poll / 完了判定の semantics が両者で異なるため (HF は stage 名で判定、 Pages は HTTP code)
  • retry budget: --retries 6 --retry-delay-seconds 15 = 約 90 秒の伝播ラグ吸収。 Pages CDN cache invalidation が稀に 30-60 秒かかる事例を考慮、 余裕を持って 90 秒。 これ以上長くすると本物の broken deploy 検出が遅れる
  • pre-deploy gate と post-deploy gate を両方走らせる: pre は bundle 内容、 post は live origin。 pre が clean でも live で 404 になる経路 (例: Pages 側の filter / Jekyll 残留設定) を post で塞ぐ。 二重チェックは HF Space 側で実証済みの pattern
  • /favicon.ico 自体は post-deploy gate の必須リストから除外: <link rel=icon> 付与で auto-fetch は抑止される定説に依拠。 仮に一部古い browser で fetch が残っても機能影響ゼロ (single 404 の cosmetic noise) なので binary 追加コストに見合わない

Test Plan

  • python scripts/verify_pages_assets.py --base-url https://ayutaz.github.io/piper-plus --retries 0 をローカル実行し、 現状 (favicon.svg 未配信) で 2 件の FAIL が出ることを確認 (PR merge 前)
  • python scripts/verify_pages_assets.py --base-url https://ayutaz.github.io/piper-plus --retries 6PR merge → deploy 完走後 に再実行し、 全 13 アセット 2xx を確認
  • https://ayutaz.github.io/piper-plus/ をブラウザで開き、 DevTools console に favicon.ico / Failed to load resource の 404 が 出ないこと を確認
  • DevTools Network タブで assets/favicon.svg が 200 で読まれていることを確認
  • python - <<<'import yaml; yaml.safe_load(open(".github/workflows/deploy-webassembly-demo.yml"))' で YAML 構文健全性確認
  • python -m py_compile scripts/verify_pages_assets.py で syntax 確認
  • CI: Deploy WebAssembly Demo to GitHub Pages workflow が Pre-deploy gate / Post-deploy verification の両ステップで全 200 を返して green
  • CI: 他言語ランタイム (Python / Rust / C# / Go / WASM npm test) には影響しないこと (paths filter 一致なし)

Checklist

  • Tests pass locally (yaml.safe_load / py_compile / verify_pages_assets.py --help)
  • No GPL / LGPL deps introduced (SVG は新規自作、 verify_pages_assets.py は Python 標準ライブラリのみ)
  • Documentation updated (該当なし — deploy 構成変更のみで spec 文書への影響なし)
  • .gitignore の allowlist に新 script を登録済み

Related Issues

なし (本 PR が PR #583 の HF Space 修正に続く「deploy 後の live 検証」フェーズの GitHub Pages 版)

GitHub Pages 上で /piper-plus/favicon.ico が 404 を返し、 ブラウザの自動 fetch
がコンソールエラーとして可視化されていた (Failed to load resource: status 404 /
favicon.ico:1)。 これは <link rel="icon"> 不在による defacto auto-fetch であり、
HF Space の sdk_version drift と同じく「CI / deploy 工程は通っているが利用時に
初めて顕在化する」 silent failure。 deploy-pages は upload が通れば常に green、
deploy 後に live URL を確認していなかったため気付けなかった。

修正:
- SVG favicon (304B、 #4CAF50 アクセント + 音声バーモチーフ) を新規作成
- 多言語デモ HTML に <link rel="icon" type="image/svg+xml"> を追加
- deploy workflow に .nojekyll 同梱を追加 (underscore-prefix 抑止)
- pre-deploy gate: bundle 内の必須 artifact + favicon link 不在を fail-fast
- post-deploy gate: live URL を HEAD probe、 404 が 1 件でも残れば deploy 失敗

verify_pages_assets.py は HF Space の verify_hf_space_runtime.py と同一哲学。
favicon.ico 自体は要求しない (<link rel=icon> 付与で auto-fetch は抑止される、
binary blob を repo に commit する必要なし)。
Copilot AI review requested due to automatic review settings June 29, 2026 03:31
@github-actions

Copy link
Copy Markdown
Contributor

Action SHA drift report

Collected pins (3 actions) — expected_total_pins=3

Action Pinned SHA Resolved Status
dawidd6/action-download-artifact 8a33849 (commit-only) OK
dawidd6/action-download-artifact 8a33849 (commit-only) OK
mymindstorm/setup-emsdk 6ab9eb1 (commit-only) OK

Summary: total=3, ok=3

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Required status-check gate (deferred)

Head SHA 1275210 is no longer the branch tip (latest: 00c26c9). Waiting for the new commit's spoke runs to complete before re-evaluating.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

GitHub Pages デプロイ後に初めて顕在化する “silent 404” を防ぐため、favicon を明示同梱しつつ、デプロイ前後でアセット存在確認を行う CI ゲートを追加する PR です(Pages での favicon.ico 自動 fetch 404 を根本的に解消し、再発も検知)。

Changes:

  • SVG favicon を追加し、デモ HTML に <link rel="icon"> を明示
  • Pages デプロイ bundle に .nojekyll を追加して Jekyll の自動処理を無効化
  • Pre-deploy の bundle 完全性チェックと、Post-deploy の live URL HEAD probe 検証スクリプトを追加

Reviewed changes

Copilot reviewed 3 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/wasm/openjtalk-web/test/multilingual-demo/index.html favicon の <link rel="icon"> を追加
src/wasm/openjtalk-web/assets/favicon.svg 新規 SVG favicon を追加
scripts/verify_pages_assets.py Pages の post-deploy 検証(HEAD probe + retry)を新設
.gitignore 新設スクリプトを ignore 例外に追加
.github/workflows/deploy-webassembly-demo.yml .nojekyll 追加、pre/post deploy ゲートを追加

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/verify_pages_assets.py
Comment thread .github/workflows/deploy-webassembly-demo.yml
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Runtime Parity Deep — audio (informational tier)

Pairs compared: 15, failing: 13, runtimes skipped: 0.

A B Tier Result Detail
cpp csharp sha256 ⚠️ 0d5a48672394 vs 255ee27e5477
cpp csharp peak_rms ⚠️ Δrms=0.22041 (≤ 0.005)
cpp csharp snr ⚠️ frame count differs: 3129 vs 6615
cpp go sha256 ⚠️ 0d5a48672394 vs 90f2a6d61f37
cpp go peak_rms ⚠️ Δrms=0.12659 (≤ 0.005)
cpp go snr ⚠️ SNR=-0.99 dB (≥ 60.0)
cpp python sha256 ⚠️ 0d5a48672394 vs fdea4a129e20
cpp python peak_rms Δrms=0.00215 (≤ 0.005)
cpp rust sha256 ⚠️ 0d5a48672394 vs 52e1cfedca87
cpp rust peak_rms ⚠️ Δrms=0.12571 (≤ 0.005)
cpp rust snr ⚠️ frame count differs: 3129 vs 7539
cpp wasm sha256 ⚠️ 0d5a48672394 vs b3378dcb24fe
cpp wasm peak_rms ⚠️ Δrms=0.43326 (≤ 0.005)
cpp wasm snr ⚠️ frame count differs: 3129 vs 3328
csharp go sha256 ⚠️ 255ee27e5477 vs 90f2a6d61f37
csharp go peak_rms ⚠️ Δrms=0.09382 (≤ 0.005)
csharp go snr ⚠️ frame count differs: 6615 vs 3129
csharp python sha256 ⚠️ 255ee27e5477 vs fdea4a129e20
csharp python peak_rms ⚠️ Δrms=0.22255 (≤ 0.005)
csharp python snr ⚠️ frame count differs: 6615 vs 3129
csharp rust sha256 ⚠️ 255ee27e5477 vs 52e1cfedca87
csharp rust peak_rms ⚠️ Δrms=0.09470 (≤ 0.005)
csharp rust snr ⚠️ frame count differs: 6615 vs 7539
csharp wasm sha256 ⚠️ 255ee27e5477 vs b3378dcb24fe
csharp wasm peak_rms ⚠️ Δrms=0.21285 (≤ 0.005)
csharp wasm snr ⚠️ frame count differs: 6615 vs 3328
go python sha256 ⚠️ 90f2a6d61f37 vs fdea4a129e20
go python peak_rms ⚠️ Δrms=0.12873 (≤ 0.005)
go python snr ⚠️ SNR=-1.54 dB (≥ 60.0)
go rust sha256 ⚠️ 90f2a6d61f37 vs 52e1cfedca87
go rust peak_rms Δrms=0.00088 (≤ 0.005)
go wasm sha256 ⚠️ 90f2a6d61f37 vs b3378dcb24fe
go wasm peak_rms ⚠️ Δrms=0.30667 (≤ 0.005)
go wasm snr ⚠️ frame count differs: 3129 vs 3328
python rust sha256 ⚠️ fdea4a129e20 vs 52e1cfedca87
python rust peak_rms ⚠️ Δrms=0.12786 (≤ 0.005)
python rust snr ⚠️ frame count differs: 3129 vs 7539
python wasm sha256 ⚠️ fdea4a129e20 vs b3378dcb24fe
python wasm peak_rms ⚠️ Δrms=0.43541 (≤ 0.005)
python wasm snr ⚠️ frame count differs: 3129 vs 3328
rust wasm sha256 ⚠️ 52e1cfedca87 vs b3378dcb24fe
rust wasm peak_rms ⚠️ Δrms=0.30755 (≤ 0.005)
rust wasm snr ⚠️ frame count differs: 7539 vs 3328

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Bundle size gate

Status Ecosystem Package Baseline Observed Delta Tolerance
SKIP npm piper-plus n/a 59.2 KiB n/a ±3%
SKIP npm @piper-plus/g2p n/a 71.1 KiB n/a ±3%
SKIP nuget PiperPlus.Core n/a 111.6 KiB n/a ±5%
SKIP nuget PiperPlus.Cli n/a 125.38 MiB n/a ±5%
SKIP cargo piper-plus n/a n/a n/a ±5%
SKIP maven piper-plus-g2p-android n/a 2.92 MiB n/a ±5%

Summary: 0 fail / 6 skip / 0 ok

SKIP means the artifact was not built in this job, or the baseline is a placeholder. The gate never fails on SKIP.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Multi-Runtime RTF Benchmark

Policy: warn-only (thresholds: RTF +/-10%, P50 +/-10%, P95 +/-15%)

Model: test/models/multilingual-test-medium.onnx (warmup=5, runs=30)

Runtime Text RTF P50 (ms) P95 (ms) Baseline RTF RTF Δ Baseline P50 P50 Δ Baseline P95 P95 Δ
python short 4.4869 6111.1 6244.3 4.4317 +1.2% 6324.8 -3.4% 6757.1 -7.6%
python medium 1.197 6566.2 6860.0 1.0438 +14.7% ⚠️ 5882.0 +11.6% ⚠️ 6208.1 +10.5%
python long 0.2414 8256.9 8539.0 0.2251 +7.2% 7755.6 +6.5% 8124.9 +5.1%
rust short (missing) - - 0.8309 - 1310.9 - 1359.6 -
rust medium 0.2581 1654.0 1684.6 0.2501 +3.2% 1614.3 +2.5% 1636.8 +2.9%
rust long 0.1028 3631.0 3662.4 0.1039 -1.1% 3673.8 -1.2% 3697.7 -1.0%
go short 2.3482 3027.4 3110.4 2.3051 +1.9% 3125.1 -3.1% 3216.7 -3.3%
go medium 0.5685 3493.3 3780.8 0.5123 +11.0% ⚠️ 3158.6 +10.6% ⚠️ 3358.1 +12.6%
go long 0.1436 5054.6 6325.8 0.1464 -1.9% 5374.6 -6.0% 5467.3 +15.7% ⚠️
csharp short 2.7667 1505.6 1584.5 2.8462 -2.8% 1542.0 -2.4% 1627.3 -2.6%
csharp medium 0.8853 1597.5 1702.0 0.8929 -0.9% 1608.6 -0.7% 1811.7 -6.1%
csharp long 0.1819 2354.8 2379.3 0.1413 +28.7% ⚠️ 1813.8 +29.8% ⚠️ 1913.0 +24.4% ⚠️
cpp short 0.8311 1260.2 1293.1 0.8694 -4.4% 1402.4 -10.1% 1431.6 -9.7%
cpp medium 0.2367 1554.4 1612.9 0.2529 -6.4% 1686.2 -7.8% 1724.0 -6.4%
cpp long 0.1037 3743.0 3789.6 0.0988 +5.0% 3573.3 +4.7% 3641.5 +4.1%
wasm short (missing) - - n/a - n/a - n/a -
wasm medium (missing) - - n/a - n/a - n/a -
wasm long (missing) - - n/a - n/a - n/a -

⚠️ One or more cells regressed beyond the RTF, P50, or P95 threshold. Warn-only while the baseline is being calibrated; this will become a hard gate once we have ~2-3 weeks of variance data.

ayutaz added 2 commits June 29, 2026 16:03
1. scripts/verify_pages_assets.py
   - verify() に渡された Iterable を tuple() で materialize してから for ループ
   - 旧コードは for で消費した後 len(list(paths)) を再評価しており、
     caller が generator を渡すと success 行が「OK: all 0 assets」と誤報する
   - caller は現状 list を渡しているので無症状だが contract 上のバグ。
     generator を渡した unit test で 0→正数になることを確認

2. .github/workflows/deploy-webassembly-demo.yml (pre-deploy gate)
   - REQUIRED 配列に deploy/multilingual-demo/index.html を追加
   - 旧コードの favicon-link 検証 for ループは
     `for html in ... deploy/multilingual-demo/*.html` で
     subdir が空 / 不在の場合 glob が literal のまま残り `[ -f ]` で全件 skip。
     結果 pre-deploy gate が favicon 検証「0 件」で silent pass する穴があった
   - shopt -s nullglob で空配列に展開し、 ${#HTMLS[@]} -lt 3 を assert。
     subdir absent / empty / populated の 3 scenario をローカルで検証済み
@ayutaz
ayutaz merged commit b28aeb6 into dev Jun 29, 2026
122 checks passed
@ayutaz
ayutaz deleted the fix/pages-favicon-and-404-gate branch June 29, 2026 11:58
ayutaz added a commit that referenced this pull request Jun 29, 2026
PR #585 で追加した pre-deploy gate が初回デプロイで favicon-<link> 不在を
4 件検出 (multilingual.html / piper-espeak-{complete,english}.html /
simple-multilingual.html)。 gate が gate として機能したケース。

PR #585 では index.html のみに <link rel="icon"> を追加していたため、
deploy bundle にコピーされる他の demo HTML 4 個では browser auto-fetch
による favicon.ico 404 が残る状態だった。 root cause を直す
(gate を緩める band-aid は採らない、 feedback_no_band_aid_fixes)。

5 個全 HTML が deploy 後に <link rel="icon" type="image/svg+xml"
href="../../assets/favicon.svg"> を持ち、 deploy 側 sed で
multilingual-demo/ subdir 配置の場合は ../assets/favicon.svg に
正しく書き換わる。
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