テスターの一覧を毎朝開いて参加中の人数を数える、という日課がしばらく続いた時期がありました。ある朝、12 だったはずの数字が 11 になっていて、胃のあたりがすっと冷えたのを覚えております。
ここまで積んだ日数が、すべて水の泡になるのか。それとも、抜けた 1 人の分だけ待てばよいのか。検索すると「全員やり直し」という声も「その人の分だけ」という声も出てきて、どちらを信じてよいか分かりませんでした。
最初にお伝えしたいのは、**数えるのは「全体の日数」ではなく「一人ひとりの連続日数」**だという点です。Rork で作ったアプリを Google Play に出す準備をしている方に向けて、公式ヘルプの文面から読み取れることと、手元で数える方法を書き残します。
公式ヘルプに書かれている条件
対象は、2023 年 11 月 13 日より後に作成した個人のデベロッパーアカウントです。Google Play Console ヘルプの「新しい個人用デベロッパー アカウントのアプリテスト要件」では、次の内容が示されています。
| 項目 | 書かれていること |
|---|---|
| 人数 | クローズドテストに 12 人以上がオプトインしている |
| 期間 | 各テスターが 14 日以上オプトインしている |
| 連続性 | 途切れずに参加し続けている必要がある |
| 途中で抜けた人 | 14 日に届く前に抜けると数えられない |
| 出戻り | 再参加しても、その時点から 14 日を連続で数え直す |
| 12 人に満たないとき | クローズドテストを走らせ続ける必要が出る |
テストの条件を満たしたら、Play Console のダッシュボードから「本番環境へのアクセスをリクエスト」の申請に進みます。フォームは、クローズドテストの内容、アプリの内容、本番公開の準備状況の 3 つに分かれており、審査は通常 7 日以内に終わるものの、それより延びることもあると書かれています。
「全員やり直し」ではなく「その人の時計だけが戻る」
先ほどの表を、素直に読み直します。14 日という期間はテスターごとに付いています。ですから 1 人が 9 日目に抜けても、残りの 11 人の日数は止まりません。止まるのは、抜けた人が 12 人の枠を支えていた分だけです。
つまり、必要なのは次の 2 つが同時に成り立つ日です。
- 途切れず 14 日に届いた人が、12 人以上になっていること
- その 12 人が、申請の時点でもオプトインしたままであること
抜けた人が戻ってくる場合、その人は再参加した日から数え直しです。以前の 8 日や 9 日は持ち越せません。したがって「12 人目が 14 日に届く日」は、足りなくなった枠を埋める人が参加した日の 14 日後に延びます。
ここは公式の文面からの私の読み取りであり、画面上の表示で「何日目」と明示されるわけではない点はご承知おきください。申請ボタンが押せるかどうかが、最終的な答えです。
手元で数える小さなスクリプト
画面で見える「参加中の人数」だけでは、14 日に届いた人が何人いるのか分かりません。私は参加日と離脱日を表にして、人ごとに数えるようにしました。何を解決するかといえば、「12 人目が 14 日に届く日」を日付で出すことです。
from datetime import date, timedelta
REQUIRED_TESTERS = 12
REQUIRED_DAYS = 14
# 参加(opt-in)と離脱(opt-out)の記録。離脱が None ならいまも参加中です。
log = {
"tester01": [(date(2026, 10, 1), None)],
"tester02": [(date(2026, 10, 1), date(2026, 10, 9)), (date(2026, 10, 12), None)],
"tester03": [(date(2026, 10, 2), None)],
}
def longest_streak(spans, today):
"""1 人のテスターが途切れず参加した最長の日数を返します。"""
best = 0
for start, end in spans:
best = max(best, ((end or today) - start).days)
return best
def completed_date(spans):
"""途切れず 14 日に達する最初の日(なければ None)を返します。"""
for start, end in sorted(spans):
done = start + timedelta(days=REQUIRED_DAYS)
if end is None or end >= done:
return done
return None
def report(log, today):
ok = []
for name, spans in sorted(log.items()):
s = longest_streak(spans, today)
d = completed_date(spans)
mark = "OK " if d and d <= today else "待ち"
print(f"{mark} {name}: 最長連続 {s:>2} 日 / 14 日到達 {d or '-'}")
if d:
ok.append(d)
ok.sort()
if len(ok) >= REQUIRED_TESTERS:
print(f"12 人目が 14 日に届く日: {ok[REQUIRED_TESTERS - 1]}")
else:
print(f"14 日に届く見込みの人: {len(ok)} 人。あと {REQUIRED_TESTERS - len(ok)} 人足りません")
report(log, date(2026, 10, 19))3 人分のサンプルで動かすと、出力は次のようになります。
OK tester01: 最長連続 18 日 / 14 日到達 2026-10-15
待ち tester02: 最長連続 8 日 / 14 日到達 2026-10-26
OK tester03: 最長連続 17 日 / 14 日到達 2026-10-16
14 日に届く見込みの人: 3 人。あと 9 人足りませんtester02 は 9 日目に一度抜けているので、戻った 10 月 12 日から数え直し、14 日に届くのは 26 日です。ここで completed_date を「開始日から 14 日後」にしているのは、離脱日が 14 日後以降であれば、その区間で条件を満たしたと扱えるからです。離脱が 14 日より前なら、その区間は丸ごと捨てます。
参加日と離脱日の記録は、Play Console のテスター画面を見ながら手で書き写しています。自動で取れる手段があるのかは、私は確認できておりません。
私が間違えた線引き
最初のうち、私は人数だけを見ておりました。「11 人になったから、1 人入れて 12 人に戻せばよい」と考え、補充した人を含めて同じ日に申請しようとしたのです。結果は芳しくありませんでした。いま思えば、数字の見方そのものが違っていたのかもしれません。補充した人はまだ数日しか経っておらず、条件を満たしていませんでした。
いまは、補充する前に 「人数ではなく、14 日に届いた人の数を見る」 という線引きにしています。そのために、上のスクリプトを申請の前に必ず 1 回走らせます。
抜けにくくするために、始める前にできること
抜けてしまってから慌てるより、最初に余裕を持たせるほうが、はるかに楽だったのだと思います。
- 12 人ちょうどで始めず、数人多めに招くこと
- 「14 日間はオプトアウトしないでください」と、依頼の文面に書いておくこと
- 参加直後に抜ける人もいるため、最初の数日は毎朝人数を見ること
- 全員が同じ日に始める必要はありませんが、12 人目が揃った日から 14 日が必要になること
最後の点は、遅く参加した人がいると全体の完了日が後ろにずれる、という意味です。急ぐ場合ほど、早く揃えたほうが得です。
期限が別にあるときは、先に逆算します
Play には、テストの日数とは別に、ターゲット API レベルの期限もあります。重なりそうな場合は、先に逆算しておくと慌てません。
- target API 36 の8月31日は、更新を出す人と出さない人で意味が違います
- RorkアプリをAndroidに展開して最初に驚いたこと — App StoreとGoogle Playの設計思想の違い
今日できる次の一歩は、いまのテスターの参加日と離脱日を表にして、上のスクリプトを 1 回走らせることです。この数え方だけは、次にアプリを出すときも守るようにしています。