散文で書いたルールは守られない — 実名の漏れをCIの機械ゲートで閉じた話

  • #CI
  • #運用設計
  • #ガードレール
  • #ブランド保護
散文で書いたルールは守られない — 実名の漏れをCIの機械ゲートで閉じた話

この記事について

外部に公開する制作ログの初稿に、伏せて運用しているはずの姉妹プロジェクトの名前とリポジトリの実パスが載ったまま上がってきたことがあった。ルール自体はドキュメントに明文化されていたが、「書く側が毎回思い出す」ことに依存していたため守られなかった。この記事は、その対処を3段階に分けて作り、最後にもう一段深いところまで直した記録。

起きたこと

複数の媒体を運用していると、ある媒体は「独立して運営している体」で回すことに意味がある場合がある。この場合、外部公開する原稿にその媒体の名前・ドメイン・リポジトリの実パスが載ってしまうと、運営元が同一であることがそのまま露呈する。

実際、外部公開バウンドの原稿の初稿に、伏せているはずの媒体名がドメインとリポジトリパス付きでそのまま書かれていた。ルールはドキュメントにあったのに、通ってしまった。

第1段:散文ルールを機械ゲートにする

最初の対処は3つに分けた。

  1. 走査スクリプトを作り、外部公開バウンドな原稿だけを対象に禁止トークンを探す。1件でも見つかれば exit 1
  2. それを CI に組み込み、PR 作成時と main への push で必ず走らせる
  3. 禁止トークンをスクリプト側にハードコードせず、台帳ファイルの JSON ブロックから読む構成にする
def load_ledger(path):
    text = path.read_text(encoding="utf-8")
    m = re.search(r"^```json\n(.*?)^```", text, re.MULTILINE | re.DOTALL)
    return json.loads(m.group(1))["media"]

3番目が地味だが重要だった。禁止語をコードに直書きすると、対象の媒体が増えるたびにスクリプトを触る必要がある。台帳を単一の真実源にしておけば、媒体が増えても台帳に1行足すだけでゲートに反映される。

第2段:ファイル名も見る

内容だけを走査していたところ、本文はきれいでもファイル名そのものに媒体名が入っている記事が1本残っていることが分かった。静的サイトではファイル名がそのまま公開URLのスラッグになるため、本文を直してもURLに媒体名が残る。しかもリネームは404とインデックス消失を招くので、後から直すのが難しい。

この発見を受けて、ゲートは本文だけでなくファイル名も走査するようにした。後から直しにくい漏れほど、書く前に止めるしかないという教訓が、次の段の判断につながった。

第3段:境界を「公開直前」から「書き始める瞬間」に前倒しする

ここまでの構成は「実名で書いてから、公開直前に機械ゲートで弾く」という設計だった。これは書く側が実名を知っている前提のまま、出力の直前で止めているに過ぎない。最初に起きた漏れも、根っこは同じ「実名で書いてから、後から気づく(あるいは気づかない)」という設計思想にあった。

そこで、伏せる対象の媒体にはそれぞれ符牒(コードネーム)を割り当て、外部原稿は執筆の最初の一文からその符牒で書く運用に変えた。「実名で書いてから最後に置換する」は必ずどこかで取りこぼす、という前提に立った変更で、切り替えの境界を「公開ボタンを押すとき」から「原稿を書き始めるとき」へ動かしたことになる。

内部のやり取り・設計メモ・コミットメッセージまで全部符牒にする案も一度検討したが、それは棄却した。理由は単純で、運用者本人がどれがどれだか追えなくなる。読めない規約は結局守られない。範囲は「外部に出る原稿だけ」に絞り、内部は実名のままにした。

やってみてわかったこと

  • 散文で書かれたルールは「知っている人が思い出せば」しか機能しない。同じルールでも、CIで exit 1 にすると機械的に機能する
  • ルールをコードに直書きすると、対象が増えるたびにコードを触ることになる。ルールの中身は別ファイル(台帳)に出し、コードは「台帳を読んで判定するだけ」にしておくと変更コストが下がる
  • 機械ゲートは「書いてしまった後で弾く」設計だと、書く側の頭の中は結局実名のままになる。本当に取りこぼしを減らしたいなら、ゲートの位置ではなく書き始める時点の語彙を変える必要があった
  • 全部を一律に隠すのではなく、「どこまで匿名化して、どこで止めるか」を先に決めておく。全部隠すと運用者自身が読めなくなり、規約として機能しなくなる

更新履歴

  • 2026-07-31: 初出。