「送らなかった行はゼロ」で在庫が消える事故を防ぐ
在庫・棚卸・名簿など全件置換APIに部分入力を通すと、入力しなかった行が静かにゼロで上書きされる。事故の見つけ方、省略時の3方針、書き込み前に現在値を取る据え置き実装、行を消さずに復旧する手順、拠点を取り違えないUI、そして「送らなかったキー」の回帰テストまでの型。
約3.9万トークンの節約 (API料金換算で約58円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「「送らなかった行はゼロ」で在庫が消える事故を防ぐ」は、開発プロセスカテゴリのAI指示書(MDファイル)です。在庫・棚卸・名簿など全件置換APIに部分入力を通すと、入力しなかった行が静かにゼロで上書きされる。事故の見つけ方、省略時の3方針、書き込み前に現在値を取る据え置き実装、行を消さずに復旧する手順、拠点を取り違えないUI、そして「送らなかったキー」の回帰テストまでの型。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.9万トークン(API料金換算で約58円)・92%のトークンを節約できます。
- カテゴリ
- 開発プロセス
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.2万トークン
- この巻物使用時
- 約3,200トークン
- 節約量
- 約3.9万トークン (約58円)
- 更新日
- 2026-09-03
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-4afd0cf7/raw を読み込んで、この指示書どおりに実装して"
中身
「送らなかった行はゼロ」で在庫が消える事故を防ぐ — 全件置換APIに部分入力を通す前の設計
在庫・棚卸・名簿・シフトなど「全件を書き直す」APIに、現場が一部だけ入力したデータを渡すと、入力しなかった行が静かにゼロ(または空)で上書きされる。実際に起きた事故と、その復旧・恒久対策・回帰テストまでを型にしたもの。
対象読者は、業務システムのバックエンドに「実数を確定する」系のエンドポイントを持たせている人。フレームワーク・言語は問わない(例は表計算をデータストアにした構成だが、RDB でも同型)。
1. 事故の形(まずこれを自分のコードで探す)
事故は次の3つが揃うと起きる。
- サーバ側: 確定APIが「有効な拠点 × 全カテゴリ」を必ず書き、リクエストに含まれなかった組み合わせを
0で埋める - 画面側: 入力フォームが全拠点分の行を一度に表示し、まとめて送信する
- 現場: 担当者は自分の拠点だけを数え、他拠点の行は触らずに既定値のまま送信する
担当者にとって他拠点の行は「触っていない空欄」でしかないが、サーバから見ると 0 と区別できない。結果、数えていない拠点の在庫が全部消える。
この事故は単体テストに出ない。 テストは「送った行が正しく保存されるか」を見るので、「送らなかった行がどうなるか」を誰も書いていない。
自分のコードで探すときの目印
// 危険: 入力に無いキーを 0 で埋めている
activeSites.forEach(site => {
categories.forEach(cat => {
const qty = input[key(site, cat)] || 0; // ← ここ
rows.push([id, date, site, cat, qty]);
});
});
|| 0 / ?? 0 / get(key, 0) / COALESCE(x, 0) のように、「キーが無い」と「値がゼロ」を同じに扱っている箇所が該当する。
2. 設計の原則
書き込みAPIを作るときは「送られてこなかったものをどう扱うか」を必ず決めて、コードに書き残す。 省略=ゼロは、暗黙のまま放置すると必ず事故になる。選択肢は3つ。
| 方針 | 挙動 | 向く場面 |
|---|---|---|
| A. 据え置き | 送られなかったキーは現在の値をそのまま書く | 部分入力が前提の業務(拠点ごとの棚卸) |
| B. 明示必須 | 全キーが揃っていなければ 400 で拒否 | 全件を一度に確定する運用(月次締め) |
| C. 部分更新に分ける | 全件置換APIと部分更新APIを別エンドポイントにする | 両方の運用が併存する場合 |
現場が一部だけ数える運用なら A が正解。以下は A の実装。
A の実装で外してはいけない点
// 送られてきたキーを記録する
const submitted = {};
input.rows.forEach(r => { submitted[key(r.site, r.category)] = true; });
// ★ 現在値の算出は「書き込む前」に行う
// 書いた後に読むと、書いたばかりの自分自身を基準点にしてしまう
const current = estimateCurrentState(data, input.date);
// 送られなかったキーは現在値を据え置く
activeSites.forEach(site => {
categories.forEach(cat => {
if (submitted[key(site, cat)]) return;
rows.push({ site, category: cat, qty: clampToValid(current[site][cat]) });
});
});
落とし穴が2つある。
- 現在値の算出タイミング。確定処理の中で「今の在庫」を求める関数を呼ぶ場合、書き込みより前に呼ぶこと。後で呼ぶと、いま書いた行を基準点にして値が固定され、据え置きが機能しない。
- 推定値がバリデーションを通らないことがある。在庫推定は「実績が入力過多で負になる」ことを意図的に許す設計になっていることが多い。一方で書き込み側は「0以上の整数」を要求する。据え置き値は書き込み側の制約に合わせて丸める(
max(0, round(x)))。丸めが起きたことを警告として返すかは運用次第。
3. 事故後の復旧手順(データを消してしまってから読む人向け)
元の行を消したり直接書き換えたりする前に、次の順でやる。
3-1. まず「保存されたのか」を本番データで確認する
現場からの報告は「反映されていない」という形で来ることが多い。これを保存の失敗と読むと、正常なデータを触って壊す。先に本番の実データを read-back して、保存の有無を確定させる。
このとき、報告の文面(「反映されない」)と実際の障害(「他拠点が消えた」)が別物であることがよくある。読んだデータを全部見て、報告されていない異常も探すこと。
3-2. 履歴が追記型なら「正しい値でもう1本入れる」
棚卸のように「最新の1件を基準点にする」設計なら、行を消さずに正しい実数でもう1件登録するだけで復旧できる。同じ日付でも、レコードIDに時刻を含めていれば新しい方が最新として採用される。
- 数えた拠点 → 実測値をそのまま
- 数えていない拠点 → 事故前の最新値をそのまま
この方法は元の行を触らないので、間違えてもやり直せる。行の物理削除は最後の手段。
3-3. 派生パラメータの汚染を確認する
確定処理が副作用として学習パラメータを更新していることがある(棚卸から消費比率を逆算する等)。在庫を戻しても、比率は事故時の値のまま残る。設定保存APIで明示的に戻すこと。戻したあと、パラメータの「出典」表示が実態と合っているかも確認する(「実測由来」と表示されたまま手動値が入っていると、次に読む人が誤解する)。
3-4. 誤登録行を消すなら、消す機能を先に作る
管理コンソールから手で行を消させるのは事故の元。IDを指定して削除するコマンドを1つ実装し、それを通して消す。 最低限のガードを入れる。
if (!targetId) throw new Error("IDを指定してください");
const remain = rows.filter(r => r.id !== targetId);
if (remain.length === rows.length) throw new Error("見つかりません: " + targetId);
if (remain.length === 0) throw new Error("全件削除はできません");
削除後は必ず read-back して、削除によって他の値が変わっていないことを確認する。
4. 画面側の恒久対策
サーバを直しても、入力する人が拠点を取り違えるリスクは残る。
- 一度に確定するのは1拠点だけにする。フォームの先頭で拠点を1つ選ばせ、その拠点の行だけを表示・送信する。他拠点の行を DOM に置かない(置くと、送信時のセレクタが拾ってしまう事故が起きる)
- 選択中の拠点を、色と文字の両方で示す。拠点ごとに色を割り当て、①プルダウン本体 ②その下の帯 ③表の各行の拠点名 ④表全体の縁 を同じ色で揃える
- 色は「そのデータが扱っている色」と被らせない。商品の色や状態色(赤=危険/緑=正常)を画面が既に使っているなら、拠点にはそれ以外の色相を使う。同系色を当てると区別の役に立たず、かえって取り違えが増える
- 色だけに意味を持たせない。「いま入力しているのは ○○拠点 です。他の拠点の在庫は変更されません。」のように、選択中の対象を必ずテキストで出す(色覚特性への配慮でもあり、思い込みの防止でもある)
- 拠点の色は設定項目にしない。拠点リストの並び順からパレットを機械的に割り当てる。設定項目を増やすと、そこ自体が新しい間違いの種になる
- 確認ダイアログに対象名と影響範囲を書く。「『○○拠点』の在庫をこの内容で確定します。他の拠点の在庫は変更しません。」
保存後に画面を更新し忘れない
同じ画面内に「保存後に再読込するボタン」と「しないボタン」が混在すると、しない方が「保存できていない」と報告される。 実際は保存されているのに、画面が保存前のスナップショットを表示し続けるだけ。書き込み系のハンドラを追加したら、再読込をセットで入れる。レンダリングだけを見るテストではこの抜けは検出できないので、レビューで「保存後に画面はどう変わるか」を必ず問うこと。
5. 回帰テスト(ここまでやって初めて再発が止まる)
サーバ側(単体テスト)
「送らなかったキーがどうなるか」を書く。 これが無いと同じ事故が戻ってくる。
// 2拠点を有効にし、拠点Bにだけ在庫がある状態を作る
// 拠点Aだけを数えて確定する
const sent = captureWritePayload(() =>
submitCount({ date: "...", rows: [{ site: "A", category: "X", qty: 50 }] })
);
const b = sent.rows.find(r => r.site === "B" && r.category === "X");
assert.ok(b, "数えていない拠点の行も書かれること");
assert.equal(b.qty, 500, "数えていない拠点は据え置き、0にしない"); // ← 事故の再現
assert.equal(sent.rows.find(r => r.site === "A").qty, 50);
assert.equal(result.breakdown.length, 1, "内訳は数えた拠点だけ");
画面側(DOM を実際に描いて判定)
ヘッドレスDOMでフォームを描画し、次を判定する。
- 表の行数が選択中の1拠点分だけであること
- 全行の
data-siteが選択中の拠点と一致すること(他拠点の行が紛れていない) - 拠点を切り替えると、行がその拠点のものだけに入れ替わること
- プルダウン・帯・表の縁に同じ拠点色クラスが付き、切り替えでまとめて入れ替わり、切替前のクラスが残らないこと
- 帯のテキストに選択中の拠点名が含まれること
「切替前のクラスが残らない」を明示的に見ること。クラスを add するだけで remove を忘れる実装が通ってしまう。
6. チェックリスト
- 書き込みAPIで「入力に無いキー」と「値がゼロ」を同じに扱っていないか(
|| 0を全部見る) - 省略時の方針(据え置き / 拒否 / 別API)をコードのコメントに書いたか
- 現在値の算出は書き込みの前に行っているか
- 据え置き値は書き込み側のバリデーションを通る形に丸めているか
- 一度に確定する対象を1つに絞り、他の対象を DOM に置かない作りか
- 選択中の対象を色とテキストの両方で示しているか。その色は既存の意味色と被っていないか
- 書き込み後に画面を再読込しているか
- 「送らなかったキー」のテストと、DOM の切り替えテストがあるか
- 誤登録を消す手順が、手作業ではなくコマンドとして存在するか
よくある質問
+「「送らなかった行はゼロ」で在庫が消える事故を防ぐ」とは何ですか?
在庫・棚卸・名簿など全件置換APIに部分入力を通すと、入力しなかった行が静かにゼロで上書きされる。事故の見つけ方、省略時の3方針、書き込み前に現在値を取る据え置き実装、行を消さずに復旧する手順、拠点を取り違えないUI、そして「送らなかったキー」の回帰テストまでの型。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.2万トークンかかりますが、この巻物を使えば約3,200トークンで済みます。差し引き約3.9万トークン(API料金換算で約58円)・92%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
ドキュメント駆動開発プロセス CLAUDE.md — 作るものを固めてから書かせる
「AIが暴走して意図と違うものを作る」を根絶する開発プロセス指示書。UI仕様→機能設計→実装の順をAIに強制し、1ファイルごとに承認ゲートを挟む。受託開発・チーム開発向け。
AIに指示書マーケットを自動参照させ、終了時に自動出品させるMD
開発依頼を受けた瞬間にマーケットの完成済み指示書を検索してAIに読ませ、セッション終了時には汎用ノウハウを自動出品させる仕組みの作り方。全台配布・秘密情報スキャン・実際に踏んだ配布バグ3つの回避込み。
「そのPCにしか直せない障害」をAIに自分で気付かせて着手させる
特定の1台にしかリポジトリが無い機能は、修正手順を書いても誰にも実行されず放置される。SessionStart hook で当該PCのAIだけに指示を出し、完了後は指示書へ状態を書き戻して再実装事故を防ぐ型。走査の時間予算とセッション跨ぎの再開、メール一致だけの自動承認がなりすまされる理由と署名キー方式、状態問い合わせAPI、鍵の自動配布、no-op通知の抑止まで、実際に94件の滞留を解消した実例に基づく手順。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア