STEP 1827 — dist-renderer/data/** byte-match CI gate

land 2026-09-06 · 藤本さん recommendation #4 の 独立 gate · STEP 1826 の workflow embed と 相補、 machine-driven 側 (自動 mirror) と human-driven 側 (手動 mirror 忘れ) を 別 layer で 予防 · STEP 1802 bake-sync gate 同型

この STEP が やること 1 行

push / PR の 度に dist-renderer/data/** の 全 file を scan、 data/<rel> or public/data/<rel> に source が 存在するのに byte-match しない file が 1 つでも あれば workflow を fail、 actionable な cp command を エラー message に 含めて 修正手順 を 提示。

設計

scope

exit codes

code意味
0全 file 一致 (drift 0)
1drift 検出 or IO error (report enumerate)
2usage / script IO error (比較開始前)

実行 (local 動作確認)

# 全 tree scan
npm run check:dist-renderer-mirror

# 出力例 (現状 clean tree):
[dist-renderer/data mirror gate — STEP 1827]
  root:           C:\Users\user\rei-aios
  total files:    3926
  with source:    3925
  matched:        3925
  drifted:        0
  dist-only:      1
  IO error:       0
  elapsed:        4406ms

[dist-renderer/data mirror gate] OK

drift 検出時 の 出力例 (test で 動作確認済)

DRIFTS (dist-renderer/data files that do not byte-match their source):
  ✗ comparator/gauge.json
    dist 20B vs data 19B, byte-diff
    fix: cp data/comparator/gauge.json dist-renderer/data/comparator/gauge.json

drift が 40 件超えたら enumeration を 先頭 40 で 打ち切り、 「… and N more」 で 残数 を 明示 (log を 汚さない)。

CI 統合

# .github/workflows/dist-renderer-mirror-check.yml (STEP 1827)
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

runs-on: ubuntu-latest
steps:
  - Checkout
  - Setup Node.js 20
  - Remove git-based rei-pl dependency  # comparator-cron.yml と同じ
  - Install tsx typescript
  - Run mirror check
    npx tsx scripts/check-dist-renderer-data-mirror.ts

実行時間 ~4 秒 / 3,926 file / 52 MB、 rei-pl 依存 なし、 build なし、 純 fs read。 PR ごとに 走っても 開発体験 に 影響 なし。

STEP 1826 と STEP 1827 の 相補

Machine-driven 側 と human-driven 側 の 独立 layer 化: STEP 1826 は comparator-cron.yml workflow 内 で mirror step を embed = 自動 gauge refresh 時 の mirror 忘れ を 予防。 但し 「藤本さん or 別 tab が 手 で dist-renderer/data を 編集して 忘れる」 or 「別 workflow が data/ を 更新して mirror step 呼び忘れ」 pattern は cron 経路 外 で 発生。 STEP 1827 は push / PR ごとに byte-diff で 独立 catch、 他 workflow の 過失 も PR 段階で fail
predatorSTEP 1826 で 予防STEP 1827 で 予防
comparator-cron.yml が mirror step 呼び忘れ✓ (workflow embed)✓ (次 push で fail)
別 workflow が data/ 更新 で mirror 忘れ✓ (PR 段階で fail)
人間 が dist-renderer/data を 直接編集 忘れ✓ (PR 段階で fail)
人間 が data/ 更新 で mirror 忘れ✓ (PR 段階で fail)
rebase collision で mirror だけ stash に 捕獲✓ (次 push で fail)

動作検証

tsc --strict scripts/check-dist-renderer-data-mirror.ts test/step1827-*.ts
→ 0 error

npm run test:step1827
→ 34 passed, 0 failed
(10 test group: 1 match / 2 drift + fix message / 3 dist-only / 4 data 優先 /
 5 data 優先 で public 一致でも drift / 6 length-equal 内容 diff / 7 空 tree /
 8 nested walk / 9 40 件 打ち切り / 10 実 repo 現状 clean)

npm run check:dist-renderer-mirror   (実 repo)
→ 3,926 file / 3.8-4.4s / 全 match / drifted=0

本 STEP scope 外 (defer)

藤本さん recommendation #4 の 引用

「mirror と source が一致していることを CI で落とす gate を足す価値があると思います。 dist-renderer/data/**public/data/**(または data/comparator/**)とバイト一致しなければ fail、というだけのものです。 これは STEP 1802 の bake sync gate と完全に同じ形——「どこかに焼いたコピーが原本から静かにずれる」という同一クラスの問題で、あちらを解いた道具立てがそのまま使えます。 今回の 377 も、結局は「コピーが原本からずれていても誰も落ちない」から 2 日跨いだわけで。」

本 STEP は 上記 の 直接 実装。 STEP 1802 の scripts/check-verilog-bake-sync.ts と 同じ 「CI-time drift gate」 pattern、 対象 は Verilog constant → dist-renderer/data mirror。

rei-aios / .github/workflows · STEP 1827 · dist-renderer/data/** byte-match CI gate · STEP 1802 bake sync gate 同型