直したはずの不具合が戻ってくる:変更の記録を残す
遊びをつくる執筆にClaudeを使用しています。

ブラウザゲームのヒントボタンが、特定の操作のあとで押せなくなる不具合を見つけた場面を考えてみます。原因を調べて直し、公開内容を更新しました。ところが数日後、別の機能を足してもう一度更新すると、同じ症状が戻ってきます。直したのは確かなのに、なぜ戻るのでしょうか。 多くの場合、直したこと自体は記憶にあっても、何をどう直し、どう確かめたかは残っていません。記憶頼みの修正は、次の変更で簡単に上書きされます。この記事では、不具合が戻る経路を整理し、記録に残す項目と確認手順を、アソバースの確認済みの仕組みに沿って組み立てます。公式作品の設計から読み取れることも、再発しやすい場所の手がかりとして使います。
不具合が戻ってくる4つの経路
再発は、おおむね次の4つのどれかで起きます。
- 症状だけを直していた:ボタンが押せない状態を見た目だけ直し、押せなくなった状態そのものが作られる原因は残っています。別の操作順で同じ状態に入ると再発します。
- 古い版を上げ直した:手元に作業フォルダが複数あり、直す前のファイルから作ったHTMLやZIPを公開してしまうケースです。
- 別の経路から同じ状態に入る:通常のプレイでは起きなくなっても、保存データの読み込み、言語の切り替え、画面サイズの変更など、別の入口から同じ壊れた状態に入れることがあります。
- 確認手順が頭の中にしかない:直した人は再現手順を覚えていても、数週間後には忘れます。確認しない修正は、直ったかどうかが分からないままです。
1〜3は原因の問題ですが、4は記録の問題です。4を解消すると、1〜3も見つけやすくなります。再現手順が残っていれば「症状だけ直したのか、原因まで直したのか」を後から検証できるからです。
記録に残す最小の項目
記録は長く書く必要はありません。次の6項目が埋まっていれば、再発したときに調べる出発点になります。
- 症状、書く内容:画面で何が見えたか、書かないと起きること:同じ不具合かどうか判定できない
- 再現手順、書く内容:操作を番号付きで、書かないと起きること:直ったことを確認できない
- 原因、書く内容:コードのどの前提が崩れたか、書かないと起きること:症状だけの修正になる
- 直した場所、書く内容:ファイル名と関数名、書かないと起きること:次の変更で巻き戻しに気づけない
- 確認方法、書く内容:何を見れば直ったと言えるか、書かないと起きること:確認が人によってぶれる
- 反映した版、書く内容:日付と、公開内容を更新した記録、書かないと起きること:古い版の上げ直しに気づけない
「原因」の欄が最も重要です。「ボタンの状態更新を追加」ではなく、「手を戻したあとに、ヒント用の状態が古いまま残っていた」のように、前提が崩れた理由を一文で書きます。
保存場所は、作業フォルダの中のテキストファイルで十分です。アソバースの投稿画面には下書き保存や公開内容の更新がありますが、更新の履歴をどこまで見られるかは、確認済みの案内にはありません。履歴の確認方法は現在の案内で確認し、確認できるまでは手元の記録を正本にしておくと安全です。
公式作品の設計から読み取れる、再発しやすい場所
公式作品の確認済み事項を見ると、不具合が起きやすい場所の手がかりがいくつか読み取れます。内部の経緯は分からないため、あくまで仕様から読み取れる範囲です。
言語変更と画面拡大で進行を保つ
13作品に共通して、言語の変更とプレイ画面の拡大で進行を保つと案内されています。表示を作り直す操作のたびに、ゲームの状態が失われやすいことの裏返しと読めます。たとえば、言語を切り替えると表示を描き直しますが、そのときスコアや盤面まで初期化してしまうのは、よくある再発の型です。自作のゲームでも「プレイ中に言語を切り替える」「全画面や拡大表示にする」を確認項目に入れておくと、見落としが減ります。
保存形式に版番号を持たせる
保存があるのは余白の庭、WAVE / WAVE、かたちのあいだの3作品です。古い保存(version1)は新しい形式(version2)へ移行すると案内されています。保存データに版番号を持たせ、読み込み時に新しい形式へ変換する設計です。
この設計がないと、機能を足したあとに、古い保存を読んだプレイヤーだけが壊れる不具合が起きます。開発者の手元では新しいデータしか使わないので、気づきにくい不具合です。
なお、他の10作品の記録や録音は画面を開いている間だけ残ります。保存の有無を作品ごとに決めて明記しておくのも、「消えた」という報告がバグなのか仕様なのかを切り分けるうえで役立ちます。
仕様として決めておく挙動
かたちのあいだでは、「一手戻す」を使っても手数は減らず、ヒントは最短手とは限らないと案内されています。盤面は戻るのに手数は戻らない、という挙動を仕様として書いているわけです。
こう書いておかないと、「戻したのに手数が減らない」は不具合報告になり、直すと別の挙動が壊れて、また元に戻す、という往復が起きます。潮目のオセロで、ヒントと一手戻すがひとり対局のみとされているのも同じです。条件によって機能が出ない場合は、仕様として記録に書いておきます。
自分の作品でも、迷いやすい挙動は「仕様メモ」として1行ずつ残しておくと、不具合とそうでないものを区別できます。
確認手順を回帰チェック表にする
再発防止の中心は、直した不具合を二度と見逃さない確認表です。過去に直した不具合の再現手順を、そのまま次回以降の確認項目に積み上げます。確認する場面は、アソバースの投稿の流れ(入力→表示の確認→公開)に合わせると運用しやすくなります。
- 入力の前(手元):過去の不具合の再現手順を、上から順に実行します。
- 表示の確認:アソバース上の表示で、同じ手順をもう一度実行します。手元で動いても、sandbox付きのiframe上で動かなくなることがあります。
- 公開の直後:公開した版を開き直し、いちばん新しい修正の再現手順を実行します。古い版を上げていないかの確認にもなります。
アップロードに関する項目も表に入れておきます。直下にindex.htmlがあること、素材を相対パスで指していること、サーバー用コードやサービスワーカーを含めていないこと、サイズが上限内であることです。ZIPを作り直すたびに階層がずれるのは、よくある再発の原因です。1人あたりのアップロード回数にはUTC1日10回の上限があるため、確認は公開前に手元で済ませておきます。公開内容の更新がこの回数にどう数えられるかは、現在の案内で確認してください。
動きを抑える設定にも対応する作品が多いので、この設定を有効にしたときの表示も確認項目に加えると、後から足した演出で壊れる事態を防げます。
保存形式の再発を防ぐ最小のコード
保存形式の変更は、再発の温床になりやすい箇所です。次のコードは、版番号つきのデータを新しい形式へ変換する関数と、サイズの確認だけを持つ最小構成です。クラウドセーブは作品ごとにJSONで128KiBまでと案内されているため、その上限を超えないかも確かめられるようにしています。
function migrate(raw) {
let d = raw && typeof raw === "object" ? { ...raw } : {};
if (d.version === undefined) d.version = 1;
if (d.version === 1) {
// 例:v1は best(数値)、v2は bests(配列)と仮定
d = { version: 2, bests: d.best != null ? [d.best] : [] };
}
return d; // version 2 以上は変更しない
}
function fits(d, limit = 128 * 1024) {
return new TextEncoder().encode(JSON.stringify(d)).length <= limit;
}
// 過去の不具合を再現する確認
const old = { version: 1, best: 12 };
const once = migrate(old);
const twice = migrate(once);
console.assert(once.bests[0] === 12, "v1の記録が失われた");
console.assert(JSON.stringify(once) === JSON.stringify(twice), "二重に変換すると変わる");
console.assert(migrate({}).version === 2, "空データで失敗");
console.assert(fits(once), "サイズ上限を超えた");ブラウザの開発者ツールのコンソールに貼ると、問題がなければ何も表示されません。失敗した項目だけがメッセージつきで出ます。
ここで二重に変換しても結果が変わらないことを確かめているのは、同じ読み込み処理が複数回走る場面があるためです。新しい不具合が見つかるたびに、console.assert を1行ずつ足していくと、そのまま回帰チェックの一部になります。変換を書き換える際は、過去の assert がすべて通るかを見れば、前の修正を壊していないか分かります。
なお、アップロードした作品内の localStorage や sessionStorage は一時メモリーの互換処理と案内されています。このコードは保存先に依存しない関数だけで書いてあるので、保存先の仕様が変わっても確認が使い回せます。
再発を見つけたときの手順
同じ症状が戻ってきたら、すぐにコードを直さず、先に記録を見ます。次の順に進めます。
- 記録を探す:過去の症状欄と再現手順に当たるものがあるか確認します。
- 過去の再現手順を実行する:再現すれば「直したはずが戻った」、再現しなければ「別の原因の同じ症状」です。
- 戻った場合、原因を調べる:古い版を上げていないか、直した箇所が後の変更で書き換わっていないか、別の経路から同じ状態に入れていないかを確かめます。
- 別の原因だった場合、新しい記録を作る:古い記録は消さず、「同じ症状、別原因」と相互に書いておきます。
- 再現手順を確認項目に追加する:コードで確かめられるなら assert に、画面の操作なら回帰チェック表に足します。
起こりやすい誤りは、症状が似ているというだけで過去の記録と同じものと決めつけることです。再現手順を実行して初めて、同じ原因かどうかが分かります。
次の行動
まず、いま作品にある不具合を1件選び、症状・再現手順・原因・直した場所・確認方法・反映した版の6項目を、テキストファイルに書いてみてください。次に、再現手順を1本だけ回帰チェック表に入れ、次回の更新前に必ず実行します。保存機能がある作品なら、migrate のような変換関数に、古い形式のデータを入れる assert を1行足すところから始められます。
