Skip to main content

ゴール

このチュートリアルでは、kameleoon_to_confluence.py スクリプトの動作をステップごとに説明します。Kameleoon の実験 ID、Confluence のサイト、Confluence のスペース ID を指定すると、スクリプトは実験のメタデータと統計結果を取得し、最も成果の良いバリエーションを判断して、Confluence ページ上のテーブルにレコードをアップサートします。同じ実験に対してスクリプトを再実行すると、重複を作成する代わりに既存の行を更新します。 ステップ 1~5 は、Airtable エクスポートチュートリアル と同じリクエストとポーリングのフローを再利用します。変わるのは送信先だけです。

代替手段: スクリプトの代わりに AI アシスタントを使用してエクスポートする

スクリプトを実行するには Python 環境、4 つの保存済み認証情報、そしてエクスポートしたい実験ごとの手動での再実行が必要です。すでに Claude のような MCP 対応の AI アシスタントを使用している場合は、Kameleoon と Atlassian のそれぞれのリモート MCP(Model Context Protocol)サーバーに、コーディングツール経由または Claude アプリで直接接続することで、代わりに会話から同じエクスポートを実行できます。Claude を使って結果をエクスポートする方法については、ガイド に従ってください。
Atlassian MCP サーバーは Jira、Confluence、Bitbucket を対象とするツールを公開しており、Confluence ページへの書き込みアクセスを含みます。Kameleoon MCP サーバーは実験やフィーチャーフラグの開始・一時停止・停止・削除も行えます。いずれのコネクタが提案する操作も、承認する前に確認してください。

要件

  • Kameleoon API の認証情報。 Automation API にはアクセストークンが必要です。スクリプトは client_credentials グラントを使用して、client_idclient_secret からプログラムでアクセストークンを取得します。アクセストークンを取得する を参照してください。
  • Confluence API トークン(トークンが属するアカウントのメールアドレスとペア)。id.atlassian.com/manage-profile/security/api-tokens でトークンを作成してください。スクリプトは両者を HTTP Basic 認証として、すべての Confluence リクエストに送信します。
  • Confluence スペースの数値スペース ID(ページをホストするスペース用)。Notion のデータベース ID や Airtable のベース ID と異なり、スペースの数値 ID はその URL に表示されず(URL には代わりにスペースキーが表示される)、Confluence ウェブ UI のどこにも表示されません。MCP に接続した AI アシスタントに検索させるか、Confluence REST API の Get spaces エンドポイントから自分で取得してください。
  • Python 3.9 以上requests ライブラリを含む(pip install requests)。
Confluence は Notion データベースや Airtable テーブルのようなあらかじめ構築する機能を持ちません。スクリプトは送信先ページをそれ自体で作成し、テーブルと共にそのページを初回実行時に生成します。以降の実行では、タイトルでそのページを検出して更新します。
すべての認証情報は環境変数に保存してください。スクリプトにシークレットをハードコードしないでください。
このチュートリアルでは、例として実験 Product Page Redesign(ID 188308)を使用します。オリジナルバリエーションに加えて、2 つのバリエーション 828220828221 があります。

1. Automation API で認証する

エンドポイント: トークンエンドポイントに POST リクエストを送信して、アクセストークンを取得します。
例:
レスポンス:
以降のすべての Automation API リクエストで、返された access_tokenBearer トークンとして送信してください。アクセストークンはデフォルトで 2 時間有効です。

2. 実験を取得する

エンドポイント: Get an experiment エンドポイントに GET リクエストを送信して、実験のメタデータを取得します。
例:
レスポンス(一部省略):
スクリプトは、Confluence 行用に namestatusdateStarteddateEndeddescription を読み取り、次のステップで結果リクエストの範囲を絞り込むために mainGoalId を読み取ります。
API はデフォルトで mainGoalId を返すため、これを読み取るために optionalFields パラメータは必要ありません。Automation API は status フィールドの固定された列挙値を公開していませんが、API 全体の他のステータス系フィールドは一貫して大文字のトークン(たとえば STOPPEDACTIVEDRAFT)を使用します。ステップ 6 では、この前提のもとで status フィールドをマッピングします。マッピングに依存する前に、実際のリクエストでアカウントが返す正確なトークンを確認してください。

3. 実験の結果をリクエストする

エンドポイント: Request experiment’s results エンドポイントに POST リクエストを送信して、結果レポートの生成をトリガーします。
例:
レスポンス:
Kameleoon はレポートを非同期で生成します。エンドポイントは dataCode を返し、ステップ 4 ではこれを使用して結果をポーリングします。
このスクリプトには bayesian: true が必要で、sequentialTesting: false を設定します。bayesiansequentialTesting は有意性を算出するための代替手法であり、このチュートリアルはベイズ成功確率をレポートします。ベイズ推定を有効にすると、レポートの reliability の値にベイズ成功確率(あるバリエーションが参照バリエーションに勝る確率)が反映され、スクリプトはこの値を Probability 列にマッピングします。アカウントが別のデフォルトの統計手法を使用している場合は、Kameleoon アプリ内の同じレポートと照らして値を確認してください。

4. 結果をポーリングする

エンドポイント: Poll results エンドポイントに GET リクエストを送信し、レポートが準備できるまで取得を繰り返します。
レスポンスの status は、Kameleoon がレポートを計算している間は WAITING、データが利用可能になると READY、失敗時は ERROR または TIMEOUT になります。ステータスが ERROR または TIMEOUT の場合、レスポンスにはトップレベルの errorDescription が含まれます。スクリプトは、ステータスが READY になるまで一定の間隔でポーリングします。 例:
レスポンス(一部省略):

5. 最も成果の良いバリエーションを選択する

結果には、variationData の下にバリエーションごとに 1 つのエントリと、オリジナルページ用の _reference の行が含まれます。各バリエーションについて、リクエストしたゴールの指標は breakdownData._reference.generalData.goalsData[goalId] の下にあります。 スクリプトは _reference エントリをスキップし、各バリエーションの improvementRatereliability(ベイズ成功確率)を読み取り、改善率が最も高いバリエーションを最も成果の良いものとして選択します。次のステップでマッピングされる Result 列には、そのバリエーションが実際に勝利したかどうか、つまり十分に高い成功確率と正の上昇率を達成したかどうかが記録されます。 例:
この例では、両方のバリエーションが 100% のベイズ成功確率に達していますが、バリエーション 828220 は +211.48% の改善を示しているのに対し、バリエーション 828221 は -43.33% です。したがって、バリエーション 828220 が最も成果の良いバリエーションであり、95% を超える確率と正の上昇率を伴う正真正銘の勝者です。

6. データを Confluence 列にマッピングする

スクリプトは、実験のメタデータと最も成果の良いバリエーションの指標を Confluence テーブル行に変換し、Notion と Airtable エクスポートと同じ 8 列を使用します。 例:
Automation API は実験の status フィールドに固定された列挙値を公開しておらず、トークンは今後変わる可能性があります。map_status は大文字・小文字を区別せずにマッチングし、認識できないステータスに対しては None を返すため、誤った値を書き込む代わりに Status セルへの書き込みを省略します。1 回の GET /experiments/{experimentId} でアカウントが返すトークンを確認し、必要に応じて STATUS_MAP を拡張してください。

7. 既存の Experiments テーブルをパースする

Confluence は Notion データベースや Airtable テーブルオブジェクトを持ちません。代わりに、スクリプトは 1 つの専用ページに 1 つの HTML テーブルを保持し、バリエーションごとに 1 行ずつ置き、Experiment Name 列を Notion が Title プロパティを扱う方法や Airtable がマージフィールドを扱う方法と同じ方法で扱います—アップサートキーとして。スクリプトはテーブルを full-width レイアウトで構築します。Confluence のデフォルトの狭いページ幅では、8 列の適度な長さのヘッダーが単語の途中で折り返されてしまうためです。 Confluence のストレージフォーマット(ページの本体が保存されるマークアップ)ではすべてのセルのテキストが <p> タグでラップされ、新たに作成されたページのヘッダー行は <thead> で囲まれていない単純な <tr><th>...</th></tr> セルです。以下のパーサーは Python 標準の html.parser.HTMLParser に基づいており、ベアヘッダーケースと <thead> ラップケースの両方に対応し、空のセルを Confluence が <p></p> でレンダリングするか自己クローズ <p /> でレンダリングするかに関わらず同じものとして扱います。また最初の </table> で停止するため、ページの他の場所に手で追加した 2 番目のテーブルはパースされた結果にマージされません。また、不正な編集によって開かれたままになっている行またはセルをクローズし、次のタグが新しい行を開いても、テーブル自体が終わっても対応するため、開かれたままのタグが誤って行をドロップすることはありません。 例:
reorder_row は、Confluence エディタで列をドラッグするなど、列が手動で並び替えられたテーブルに対応します。これがなければ、位置による参照は新しい行の Experiment Name を既存テーブルの現在その位置に座っている任意の列と比較し、誤った行をマッチングするか何もマッチングしません。真の並べ替え(同じ 8 つのラベル、異なる順序)のみを再整列します。ヘッダーセルのテキストが編集された場合(たとえば NotesComments に改題)、ラベルはもはや HEADER と照合されません。その場合、関数は既存の列の順序にフォールバックし、推測の代わりに警告を出力し、そのカラムのデータをすべての行で無言でブランク化することはありません。

8. Confluence ページを検出、作成、または更新する

検出: titlespace-id クエリパラメータを Get pages エンドポイントで使用してスペース内のページをタイトルで検索します。body-format=storage を渡すと、同じ呼び出しで現在のテーブル内容が返されます。
作成: ページが一致しない場合、Create page エンドポイントで新しいページを作成します。テーブルは 1 行から構築されます。
更新: ページが一致する場合、既存の行と新しくアップサートされたものからテーブル全体を再構築し、Update page エンドポイントでページを上書きします。
Confluence には行単位または フィールド単位のアップデートエンドポイントがありません。ページを更新するとその本体全体が置き換わるため、スクリプトは常に現在のテーブルを読み取り、1 行をメモリ内でアップサートし、テーブル全体を書き戻します。この全体的な置き換えは Airtable エクスポート(単一レコードをパッチ)や Notion エクスポート(単一ページのプロパティをパッチ)と異なります。
Notion および Airtable API と異なり、Confluence は呼び出し元に対して更新ごとに version.number をインクリメント(現在のバージョン番号に 1 を加えたもの)するよう要求しています。現在の番号を再度送信するか、version を省略すると、リクエストは失敗します。MCP に接続した AI アシスタントが Atlassian 独自のツールを使用すると、これは自動的に処理されます。本スクリプトのような直接 REST 呼び出しには適用されません。
例:
レスポンス(一部省略):

9. スクリプトを実行する

実験 ID、Confluence サイト、スペース ID を引数として渡します:
スクリプトは各ステップを出力します—認証、取得した実験、最も成果の良いバリエーション、マッピングされた行、そして Confluence ページを作成したか更新したか。--page-title でデフォルトの Experiments 以外のページ名を指定します。

スクリプト全文

以下の完全なスクリプトは、kameleoon_to_confluence.py と関数単位で一致しています。そのままコピーするか、リンク先からファイルをダウンロードしてください。

カスタマイズに関する注意事項

  • ステータスマッピングSTATUS_MAP 定数にあり、API が返す大文字のステータストークンをキーとします。Status 列が Running / Implementing / Completed / Defunct と異なる場合はターゲットの値を調整し、マッピングに依存する前に実際の GET /experiments/{experimentId} リクエストでアカウントが返すトークンを確認してください。
  • Probability は測定されたベイズ成功確率から取得され、結果リクエストで bayesian: true が必要です。事前実験の見積もりが必要な場合は、build_row から Probability の行を削除してください。
  • ゴールの選択 には実験の mainGoalId を使用します。別のゴールについてレポートするには、そのゴール ID を request_resultspick_best_variation に渡してください。
  • アップサートキー。 Experiment Name との正確な一致により、大文字・小文字や空白の違いは既存の行を更新する代わりに新しい行を作成してしまいます。既存の行を誤って更新したり、重複を作成したりするのを避けるために、このページでは各実験の名前を一意に保ってください。
  • ページ全体の更新。 Confluence には行単位の書き込みがないため、すべての更新はテーブル全体を再構築します。スクリプトは常に現在のテーブルを読み取り、メモリ内で 1 行をアップサートし、テーブル全体を書き戻します。スクリプトの実行の合間にページを手動で編集する場合は、編集内容をスクリプトが構築するテーブル内に収めてください。スクリプトは現在、そのテーブル外のコンテンツを保持しません。
  • バージョン競合。 スクリプトは常に書き込む直前にページの現在の version.number を読み取ります。読み取りと書き込みの間に手動編集があると、次の PUT がバージョン競合で失敗します。このような場合はスクリプトを再実行してください。
  • レート制限。 Automation API は 10 秒あたり最大 50 リクエスト、1 時間あたり最大 1,000 リクエストまで許可していますが、Kameleoon はアカウントごとに 1 分あたり 12 コール未満に抑えることを推奨します。Confluence Cloud は独自のレート制限を実施しており、計画によって異なります。詳細は Atlassian のレート制限ドキュメント を参照してください。複数の実験をバッチ処理するには、トークンをキャッシュし、リクエストをスロットルし、大容量のニーズについては Data API を検討してください。