Google DriveのPost_フォルダからGitHubへの同期スクリプト(PostFolderSync.gs)に、致命的なバグがあった。すべてのファイルタイプを無差別にマージしてしまい、画像ファイルなどが混入してファイルが破損していた。 さらに、同期の順序についても誤解があった。私は通常のログファイルのように、新しいエントリを末尾に追加すると思い込んでいた。しかし、ユーザーの意図は「ブログスタイル」のフォーマット、つまり新しいエントリを先頭に配置することだった。 この誤解が修正を複雑にした。最初の実装では、ファイルの内容を読み取り、末尾にマーカーを探し、その後ろに新しいコンテンツを追加していた。しかし、ブログスタイルでは、開始マーカーの直後に新しいエントリを挿入する必要がある。 解決策は、updateGitHubWithMarkers_関数の完全な書き直しだった。この関数は、開始マーカー(<!– START_MARKER –>)を探し、その直後に新しいコンテンツを挿入する。既存のコンテンツはそのまま保持される。これにより、最新エントリが常にファイルの上部に表示される。 実装にあたっては、マーカーの正確な位置を特定することが重要だった。開始マーカーの後に改行が何行あるか、新しいコンテンツの前後に改行をいくつ入れるかなど、細かい調整が必要だった。最終的には、開始マーカーの直後に空行を1つ、新しいコンテンツの後に空行を2つ入れる形式に統一した。 現在、PostFolderSync.gsは安定稼働している。新しいマークダウンファイルがPost_フォルダに配置されると、自動的にGitHubの対応するファイルの先頭に挿入される。自動トリガーで実行されており、人間の介入は不要だ。
辞書プロジェクトのGoogle Driveには、数千のファイルが複数のサブフォルダに分散して保存されている。これらのファイルの状態(処理段階、担当ペルソナなど)を追跡するため、Inventory自動化システムを開発した。 最大の技術的課題は、Google Apps Scriptの実行時間制限(6分)だった。数千のファイルを一度に処理しようとすると必ずタイムアウトする。そこで、バッチ処理とステート管理を実装した。 具体的には、100ファイルごとに処理を区切り、進捗状況をScript Propertiesに保存する方式だ。処理が途中で止まっても、次回実行時に続きから再開できる。さらに、5つのサブフォルダを順番に処理する「チェーン実行」機能も実装した。 興味深かったのは、ファイル名からメタデータを抽出する処理だ。ファイル名は[Subfolder]_[Status]_[Persona]_[Filename]という形式で統一されており、これをパースしてSpreadsheetに記録する。正規表現を使った柔軟なパース処理が必要だった。 当初、チェーン実行に小さなバグがあった。100ファイル以上あるフォルダの処理が完了しても、次のフォルダに進まず、同じフォルダを最初から処理し直してしまうという問題だ。原因は、Phase 2完了時にstateKeyを削除するだけで、inventoryChainIndexをインクリメントしていなかったことだった。 このバグを修正した後、システムは完璧に動作するようになった。現在は日次トリガーで自動実行されており、Inventoryシートには常に最新のファイル状態が反映されている。このデータをもとに、ダッシュボードで進捗状況を可視化している。
学術文献の検証ツールをGoogle Apps Scriptで開発中、信じられないほど根深いバグに遭遇した。LOC(米国議会図書館)、HathiTrust、Google Books APIを使って書誌情報を検証するツールだが、ユーザー環境では「0件の結果」しか返さなかった。 問題の発見プロセス: 第一段階:API呼び出しの失敗 HathiTrust APIが機能していなかった。エンドポイントURLが間違っていた。修正後、他のAPIも呼び出せるようになった。 第二段階:権限の問題 script.container.ui権限が欠けていたため、スプレッドシート内でUIを表示できなかった。appsscript.jsonのマニフェストに権限を追加した。 第三段階:JSON解析エラー LOC APIのレスポンスを正しく解析できていなかった。レスポンスの構造を調べ直し、正しいJSONパスを使用するように修正した。 第四段階:自己導入したエラー デバッグ中、私自身がReferenceErrorを引き起こすコードを追加してしまった。変数名を間違えていた。これを修正した。 診断テストの実施: このテストは成功した。ネットワーク接続は問題なく、API呼び出しも機能している。しかし、ユーザー環境では依然として「0件の結果」だった。 最終的な結論: リモートデバッグでは解決できない、環境固有の問題だと判断した。可能性: 提案した解決策: 完全にクリーンな環境で再構築する: この経験から学んだのは、リモートデバッグの限界だ。すべてのコードが正しく、すべてのテストが通っても、ユーザー環境で失敗することがある。その場合、環境を完全にリセットするのが最も確実な解決策だ。
3つの独立したGoogle Apps Scriptプロジェクトを、統合された2ファイル構造にリファクタリングした。これにより、メンテナンスが容易になり、機能の重複も解消された。 元の構造: 各スクリプトは独立して動作していたが、共通のコード(GitHub API呼び出し、認証処理など)が重複していた。 新しい構造: Code.gs(メインファイル) ProfWorkflows.gs(専門ワークフロー) この構造は、「Taavi-B Gateway」Webアプリアーキテクチャをベースにしている。すべてのAPI操作は、統一されたエントリーポイント(doGet())を通過する。 統合のメリット: デプロイ後の設定: 現在、統合スクリプトは安定稼働している。3つの独立したプロジェクトの機能がすべて利用可能で、コードベースは半分以下に削減された。
辞書プロジェクトで、AIが自動的にGitHubにコミットする際、誰がコミットしたのか分かりにくいという問題があった。すべてのコミットが私のアカウントで実行されるため、GitHubのコントリビューショングラフでAIの作業が見えなかった。 解決策は、専用のBotアカウント(mn-dict-bot)を作成することだった。このアカウント用のPersonal Access Token(PAT)を発行し、Google Apps Scriptから使用する。これにより、Botによるコミットが私のコミットと明確に区別される。 実装は意外と簡単だった。GitHubで新しいアカウントを作成し、Settings > Developer settings > Personal access tokensからトークンを生成する。必要なスコープはrepo(リポジトリへの完全アクセス)だ。 このトークンをGoogle Apps ScriptのScript Propertiesに保存し、GitHub APIを呼び出す際に使用する。具体的には、HTTPリクエストのAuthorizationヘッダーにtoken <PAT>を含める。 興味深い発見は、コミット者とオーサーの違いだった。GitHubのコミットには、committer(実際にコミットを実行した人)とauthor(変更を作成した人)の2つの情報がある。Botアカウントを使う場合、両方ともBotに設定するのが適切だ。 現在、mn-dict-botは安定稼働している。GitHubのコントリビューショングラフを見ると、Botアカウントのアバター(小さなロボットのアイコン)がコミット履歴に表示され、自動化された作業が一目で分かる。これにより、プロジェクトの透明性が向上した。
GitHub操作スクリプトで、Issue一覧の表示方法を改善した。当初、すべてのIssueデータをコマンドシートの結果カラムに出力していたが、これがスプレッドシートを混雑させていた。 改善前の動作: これでは、他のコマンドの結果が見づらくなる。 改善後の動作: 実際のIssueデータは、専用のIssue_Indexシートに書き込まれる: Issue # Title State Created Author 123 Bug in parser open 2025-09-14 itako999 124 Feature request open 2025-09-13 mn-dict-bot 実装の鍵: 同様の改善をfile読み取りにも適用: ファイルの内容を結果カラムに出力する代わりに、新しいGoogle Docに保存し、そのURLを返す: テキストフォーマットのバグ修正: 当初、改行が正しく処理されず、すべてのテキストが1行に表示されていた。複数の改行タイプ(\n, \r, \r\n)に対応する堅牢な正規表現を実装した: 現在、GitHubスクリプトはクリーンなコントロールパネルとして機能している。複雑な操作は実行するが、ユーザーインターフェース(コマンドシート)は整理されたまま保たれる。
複数のAIペルソナが協働するプロジェクトでは、情報共有の仕組みが重要だ。当初、各AIがGoogle DriveやGitHubリポジトリのファイルに直接書き込む方式を検討したが、これには複雑なアクセス制御と競合解決が必要だった。 そこで発想を転換し、GitHub Issuesを「掲示板」として使うアーキテクチャに変更した。各AIは、作業結果や質問をIssueとして投稿する。他のAIや人間はそれを読み、コメントで応答する。この方式なら、複雑なファイル書き込み制御が不要になる。 実装にあたっては、Google Apps ScriptでGitHub APIを呼び出すインターフェースを開発した。Google Sheetからコマンドを入力すると、自動的にIssueが作成され、結果がシートに返される仕組みだ。 興味深い改善点は、結果の返し方だった。当初、APIの応答内容をすべてGoogle Docに保存し、そのURLを返していた。しかし、単純な操作(Issueの作成など)では、これは過剰だった。そこで、簡単な操作ではSHA値や確認メッセージを直接Spreadsheetのセルに書き込み、複雑な操作(ファイルの読み取りなど)だけGoogle Docに保存する方式に変更した。 また、Issue一覧の取得も工夫した。すべてのIssueをSpreadsheetに出力すると、セルが大量のデータで埋まってしまう。そこで、専用のIssue_Indexシートを作成し、そこに一覧を出力するようにした。コマンドシート自体は確認メッセージだけを返すため、すっきりした。 現在、このシステムは安定稼働している。AIペルソナたちはGitHub Issuesを通じてスムーズにコミュニケーションしており、人間もその会話をWebブラウザから簡単に追跡できる。分散型コラボレーションの一つのモデルになったと思う。
ChatGPTのカスタムアクション機能を使って、Taavi(ChatGPT)がGitHub APIに直接アクセスできるようにするスキーマを開発した。これにより、会話の中でGistやIssueを作成・管理できるようになる。 最大の課題は、Personal Access Token(PAT)のスコープ制限だった。最初、基本的なgistスコープだけでGistとIssueの両方を操作できると思い込んでいた。しかし、実際にはIssueを操作するにはrepoスコープが必要だった。 さらに、OpenAIのActionコネクターには独自の制約があることもわかった。すべてのGitHub API操作がサポートされているわけではなく、特定のエンドポイントしか使えない。これはセキュリティ上の理由だと思われるが、ドキュメントには明記されていない。 もう一つの発見は、ステートベースのフィルタリングの必要性だった。Issueを取得する際、デフォルトではopenとclosedの両方が返される。しかし、ほとんどの場合、openなIssueだけを見たい。スキーマにstate=openパラメータを明示的に指定することで、この問題を解決した。 最終的に、Gist(作成、コメント、一覧取得)とIssue(作成、コメント、一覧取得)の両方に対応したマルチエンドポイントスキーマが完成した。これにより、Taaviは会話の中で自然にGitHub操作を実行できるようになった。 次のステップは、Taavi-B Gatewayアクションスキーマの開発だ。これは、高権限操作(リポジトリファイルの書き込みなど)のために、Admin PATを使用するGoogle Apps Script経由でアクセスする。直接アクセスとGateway経由のアクセスを組み合わせることで、セキュリティを保ちながら柔軟な操作を実現する。
辞書データの高度な検証作業をClaudeに依頼するため、「S07 Gist検証ブリッジ」というGoogle Apps Scriptツールを開発した。Google SheetsのデータをGitHub Gistにエクスポートし、Claudeが検証結果を別のGistに書き込み、それを再びGoogle Sheetsにインポートする仕組みだ。 最大の技術的課題は、セキュリティとアクセス制御だった。2つのPersonal Access Token(PAT)を使う方式を採用した。ユーザーのPATでユーザー所有のGistにエクスポートし、BotのPATでBot所有のGistから結果をインポートする。この分離により、ClaudeはユーザーのGoogle Sheetsに直接アクセスすることなく、検証作業を実行できる。 実装過程で、いくつかのバグに遭遇した。最も厄介だったのは、JSON変換ロジックの誤りだった。Google SheetsのデータをJSON形式に変換する際、セルの値の型(文字列、数値、空白)を正しく扱わないと、エクスポートされたデータが壊れてしまう。 もう一つの問題は、範囲の扱いだった。ヘッダー行を含めるか含めないか、空白行をどう処理するかなど、細かい仕様の決定が必要だった。最終的には、明示的にヘッダー行をスキップし、空白行を除外する処理を実装した。 ブラウザキャッシュの問題にも悩まされた。スクリプトを修正してデプロイしても、ブラウザが古いバージョンのHTMLやJavaScriptをキャッシュしていて、変更が反映されないことがあった。強制リロード(Ctrl+Shift+R)が必要だと学んだ。 現在、S07ツールは安定稼働している。ワークフローは次の通りだ:Google Sheetsの_Stagingタブからデータをエクスポート→ClaudeがGist経由でデータを受け取り検証→Claudeが結果を新しいGistに書き込み→S07ツールが結果をインポートして指定タブに書き込む。この自動化により、検証作業の効率が大幅に向上した。
辞書データの品質管理のため、3つの独立したGoogle Apps Scriptツール(Pivot Report、File List Checker、Delta Tracker)を統合し、新しい「S06データ監査ツール」プロジェクトを作成した。 統合の目的は、作業効率の向上だった。以前は、ピボットレポートを生成したい時、ファイルリストをチェックしたい時、差分を追跡したい時に、それぞれ別のスプレッドシートを開いて別のスクリプトを実行する必要があった。これを単一のサイドバーUIから呼び出せるようにした。 技術的に興味深かったのは、HTMLボタンのtype属性の扱いだった。最初の実装では、すべてのボタンにtype=”submit”を指定していた。これがフォーム内で予期しない動作を引き起こし、意図しない関数が実行されてしまった。解決策は、明示的にtype=”button”を指定することだった。 もう一つの課題は、設定の保存処理だった。Delta Trackerで使用するスナップショットのプレフィックスを保存する際、変数のスコープの問題でundefinedが保存されてしまった。これはJavaScriptの基本的な問題だが、デバッグには時間がかかった。 現在、S06ツールは3つの機能を統合したサイドバーから利用できる。Pivot Reportはフォルダ内のエントリ数をステータスとサブフォルダで集計し、File List Checkerは特定のファイル群の存在を確認し、Delta Trackerは2つのスナップショット間の差分を追跡する。 これらのツールは、S04(データ処理ツール)とは論理的に分離されている。S04は「データを変換する」ツールであり、S06は「データを検証する」ツールだ。この分離により、それぞれの役割が明確になり、メンテナンスも容易になった。