Skip to content

spec(wiki): a withheld reap candidate consumes a delete slot and can starve real deletions #197

Description

@liplus-lin-lay

目的

孤児削除で保留(withheld)になったページが削除枠を消費するため、その後ろに並ぶ「本当に消えたページ」が処理されないまま滞留しうる。枠の勘定を見直す。

前提(#196 で導入された挙動)

reap ループは orphans.slice(0, deleteBudget) を回し、存在確認が gone 以外だった候補は continue で抜ける。したがって保留も 1 枠を消費する。

孤児リストは compareSlugs で安定ソートされているため、_pages の列挙が恒常的に短い状態が続く間、同じ候補が毎 run 先頭 5 件を占める。その後ろに実際に削除されたページが並んでいると、列挙が回復するまで処理されない。

これは #187 が禁じた「列挙が正しく縮んだ場合に永久に削除できなくなる」形ではない(正しく縮んだ場合は保留が発生しない)。また #196 以前はその 5 件を削除していたので退行でもない。滞留するのは削除であって、索引の正しさは損なわれない。

制約

方針(採用)

削除枠と probe 枠を分ける(検討 3 案のうち 1 番目)。保留は probe 枠だけを消費し、削除枠は実削除にのみ使われる。

  • MAX_WIKI_REAP_PROBES_PER_REPO_PER_RUN を新設する。値は 15(削除枠 5 の 3 倍)
  • reap ループを orphans.slice(0, deleteBudget) ではなく orphans 全体に対して回し、removed >= deleteBudget || probes >= probeBudget で break する
  • probesprobeWikiPageAlive を呼んだ回数で数える

予算の根拠: probe は 1 候補あたり最大 WIKI_EXTENSIONS.length = 2 subrequest(probeWikiPageAlive の doc comment)。probe 枠 15 で上限 30、実削除の fan-out が 5 × 約 4 = 20。walk 側の fetch 予算 20 とは別枠で、invocation あたり 1000 に対して余裕がある。

orphansDeferred の意味を合わせること。現在は orphans.length - deleteBudget で計算しているが、枠を分けた後は「この run で到達しなかった候補数」= orphans.length - 処理した候補数 でなければログと実態がずれる。

採らなかった案と理由:

受け入れ条件

  • 保留候補が先頭を占めた状態で、後ろに並ぶ「実際に削除されたページ」が同一 run で削除されることがテストで固定されている
  • per-run の probe 回数に上限があり、テストで固定されている
  • orphansWithheld とログの内容が従来どおり
  • orphansDeferred が「この run で到達しなかった候補数」を表すことがテストで固定されている

想定変更箇所

  • src/poller.ts(reap ループの枠勘定)
  • src/poller-wiki.test.ts
  • 対応する docs

Metadata

Metadata

Assignees

No one assigned

    Labels

    done役目完了、orchestration (review / merge / close) フェーズ待ちready本文が実装開始できる形まで収束している状態。ただし更新は継続可能specLi+の挙動に影響する仕様・ポリシー・定義

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions