コンテンツへスキップ

引用可能なデータセットと監査証跡のためのプロジェクト・スナップショット

Potato プロジェクトの設定、データ、アノテーションを、論文が引用できる ID の下に固定し、二つのスナップショットを比較し、読み手が検証できるハッシュを提供します。

potato snapshot は、プロジェクトの設定、データファイル、アノテーションを、論文やデータセットカードが引用できる ID の下に固定します。各スナップショットは、それらのファイルと回答に対する SHA-256 のコンテンツハッシュを記録し、スナップショットのファイルを持つ人は誰でも、ハッシュを再計算して、手元のコピーが引用されたものであることを確認できます。スナップショットは、その日の一致度の状態として、各アノテーションスキームの Krippendorff のアルファも保存します。スナップショットは Potato 2.12.0 で提供されました。すべてのコマンドは、サーバーが動作しているかどうかにかかわらず、ディスクからプロジェクトを読み取ります。

調査は、論文が書かれた後も変わり続けます。アノテーターが加わり、裁定の後にコードが修正されます。質的研究における監査証跡は、データ、コーディングの判断、分析の手順の記録であり、読み手が分析の信頼性を判断できるようにします(Nowell ら、2017)。一連のスナップショットは、コーディングプロジェクトに、各ラウンドについて、そのラウンドでのコーダー間一致度を伴う、日付とハッシュ付きの項目を与えます。機械学習のチームは、同じコマンドを使って、ラベル付きデータセットのバージョンを管理できます。その場合、モデルカードは、モデルが学習されたラベルのスナップショット ID を挙げられます。

  • コマンド: サブコマンドは create、list、show、diff、tag、verify、deposit で、すべて potato snapshot の下にあります。
  • 保存: 各スナップショットは、タスクディレクトリの snapshots/ の下の一つのフォルダーで、タグは snapshots/tags.json に、Zenodo のデポジットは snapshots/deposits.json にあります。
  • 整合性: Potato はファイルを読み取り専用で書き込み、すべてのファイルが完成してから初めてフォルダーを所定の場所に改名します。
  • 共有: 管理ダッシュボードの Publish Dataset ページには Snapshots カードがあり、二つの管理 API ルートがスナップショットを一覧および作成し、任意のデポジットは、スナップショットを DOI 付きで Zenodo に置きます。

コマンド

すべてのコマンドは、プロジェクトの設定ファイルを取ります。

bash
potato snapshot create config.yaml --note "pilot round finished" --tag pilot
potato snapshot list config.yaml
potato snapshot show config.yaml pilot
potato snapshot diff config.yaml pilot latest
potato snapshot tag config.yaml 20261102-175533 paper-v1
potato snapshot verify config.yaml paper-v1
potato snapshot verify --dir ./downloaded-snapshot
potato snapshot deposit config.yaml paper-v1 --check

Potato のチェックアウトからは、python potato/flask_server.py snapshot が同じ引数を取ります。表は、各コマンドの引数とフラグを一覧します。

コマンド引数とフラグコマンドが行うこと
createconfig、--note TEXT(デフォルトは空)、--tag NAME、--forceプロジェクトを固定します。コンテンツハッシュが最新のスナップショットのハッシュと等しい場合、create は何も書き込まず、その旨を伝えます。--force は、それでも新しいスナップショットを書き込みます。内容が変わっていない場合に指定された --tag は、既存のスナップショットを指します
listconfig、--jsonスナップショットを新しい順に、タグ、アイテム数、アノテーター数、回答数、およびメモとともに一覧します
showconfig、ref(デフォルトは latest)、--json一つのスナップショットのハッシュ、Potato のバージョン、前のスナップショット、デポジット、スキームごとのアルファを表示します
diffconfig、old、new(デフォルトは latest)、--json二つのスナップショットの間で何が変わったかを報告します
tagconfig、ref、name名前をスナップショットに結び付けます。すでに別のスナップショットを指していた名前は移動します
verifyconfig と ref(デフォルトは latest)、または --dir FOLDERスナップショットをマニフェストに照らして再ハッシュします。--dir を使うと、スナップショットのファイルのフォルダーを確認し、設定は不要です
depositconfig、ref(デフォルトは latest)、--token、--production、--publish、--annotator-ids-public、--checkスナップショットのファイルを Zenodo にアップロードします

ref は、latest、完全なスナップショット ID、タグ、または ID やコンテンツハッシュの先頭です。接頭辞は、ちょうど一つのスナップショットに一致しなければならず、曖昧な接頭辞は、一致するものの一覧とともにコマンドを停止させます。タグは、英字、数字、.、_、- からなる 1 から 64 文字で、英字または数字で始まり、latest にはできません。タグは git のタグと同じように機能します。Potato が create の後でストア内で変更するファイルは、タグ用の tags.json と、Zenodo のデポジット用の deposits.json の二つだけです。スナップショットのフォルダーは、create がそのフォルダーを書き込んだ後は、決して変わりません。

show は、スナップショットの概要行、ハッシュ、Potato のバージョン、スキームごとのアルファを表示します。

text
20261102-175504-45d41bfa [pilot]  6 items, 2 annotators, 20 answers  pilot round finished
  created       2026-11-02T17:55:04+00:00
  content hash  45d41bfad181190c161eff442c2bd3e65bd0546f3a55c197f356db4447e72c93
  bundle sha256 addd652f15ee682301c6cab6968d8aa2f0b6d05e1e5fc6748d242d07f9f07af4
  potato        2.13.1
  alpha sentiment: 0.511
  alpha aspects: 0.718

上の数のうち、回答とは、一人のアノテーターが一つのアイテムの一つのスキームに付けたラベルです。create は、新しい ID とコンテンツハッシュ、設定以外の調査のファイルの数、認証情報として除外された各ファイル、設定が指定しているがスナップショットがコピーしない各フォルダー、そしてタスクディレクトリの外にあるファイルに対する警告を表示します。

スナップショット内のファイル

各スナップショットは、タスクディレクトリの snapshots/<id>/ というフォルダーです。ID は、作成時の UTC の時刻に、コンテンツハッシュの最初の八文字が続く形で、20261102-175533-68e05868 のようになります。フォルダーには四つのファイルがあります。

ファイル内容
bundle.tar.gz設定、調査のファイル、アノテーションの出力ディレクトリ、およびプロジェクトの SQLite データベース。すべて project/ の下にあります。データベースは project.sqlite(メモ、コードブック、ケース、タイピングセッション、レビューのワークフロー)、datasets.sqlite、engine.sqlite(ラベリングエンジン)です
annotations.jsonlアノテーター、アイテム、スキームごとに一行。アノテーターが保存したすべてのラベルとスパンを、固定された並び順で含みます。diff は annotations.jsonl を読み取ります
items.jsonデータファイルからのアイテム ID。ファイルの順
manifest.jsonID、作成時刻、メモ、タスク名、Potato のバージョン、ハッシュ、数、一致度の要約、調査のファイル、除外されたファイル、前のスナップショットの ID、連番

annotations.jsonl の各行は、ラベルの回答を "labels" の下に、スパンの回答を "spans" の下に、[label, start, end] の三つ組として保持します。ラベルの回答を持つ行は、次の行のようになります。

json
{"annotator": "bob", "item": "r2", "schema": "sentiment", "value": {"labels": [["neutral", "true"]]}}

調査のファイルとは、データファイルに加え、設定内の文字列が指すすべてのファイルです。フェーズとアンケートのファイル、注意チェックとゴールドアイテムのファイル、同意と説明のページ、カスタムレイアウトは、すべて数えられます。Potato は、参照される YAML ファイル内の参照も、三階層の深さまでたどります。manifest.json は、調査のファイルを project_files の下に一覧します。Potato は、設定が指定する各フォルダーを referenced_directories の下に一覧し、フォルダーはコピーしません。音声や画像のフォルダーは、どんな大きさにもなりうるためです。そのようなフォルダー内のファイルは、コンテンツハッシュの外にあります。メディアは別にアーカイブし、スナップショットの隣でそのメディアのアーカイブを引用してください。

タスクディレクトリの外にある調査のファイルは、external/<name> としてバンドルに入り、create は警告を表示します。Potato は、プロジェクトの外を指す設定の提供を拒否するため、そのように固定された調査は、書かれたままでは起動できません。ファイルをタスクディレクトリに移し、新しいスナップショットを取ってください。

除外される認証情報

スナップショットは、引用され、引き継がれることを目的に作られるため、バンドルは三種類の認証情報を除外します。

  • アカウントの名簿とそのパスワードハッシュは含まれません。名簿は、authentication.user_config_path が設定されている場合はそのファイルで、そうでない場合は出力ディレクトリの隣の user_config.json、または output_annotation_dir が / で終わる場合は出力ディレクトリの内側にあるものです。
  • パスワード、シークレット、トークン、認証情報、API キー、または秘密鍵に言及する設定キーの下に名前が挙げられたファイルは、含まれません。この規則は、ssl_key と、sp_key_file のように key_file で終わるすべてのキーをカバーします。
  • admin_api_key.txt は含まれません。

manifest.json は、除外された各ファイルを、理由とともに omitted の下に一覧し、create はその一覧を表示します。除外されたファイルは、どれもコンテンツハッシュに含まれません。スナップショットから展開したプロジェクトにはアカウントがなく、名簿を自分のコピーから復元しない限り、アノテーターは再度登録します。

コンテンツハッシュ

content_hash は、設定ファイル、バンドル内の名前の下にある各調査のファイル、アイテム ID のリスト、アノテーションの行に対する、この順序での SHA-256 ダイジェストです。このハッシュは、設定、調査のファイル、またはいずれかの回答が変わると変わります。SQLite データベースはバンドルにありますが、ハッシュの外にあります。

データベースがハッシュの外にあるのは、サーバーが動作している間に、サーバーがデータベースを書き換えるためです。書き換えのたびに変わるハッシュでは、アノテーションが変わったかどうかを読み手に伝えられません。QDA モードのメモ、コードブック、ケースは project.sqlite にあります。メモやコード定義だけの編集は、コンテンツハッシュを変えず、create は何も変わっていないと報告します。回答を変えなかったコードブックの改訂を固定するには、--force を渡してください。

verify は、三つのチェックを実行します。

  1. bundle.tar.gz が、マニフェストの bundle_sha256 と一致しなければなりません。
  2. annotations.jsonl が、annotations_sha256 と一致しなければなりません。
  3. バンドルから展開された設定と調査のファイルを、アイテム ID とアノテーションの行とともにハッシュした結果が、content_hash を再現しなければなりません。

四つのファイルだけを持つ読み手は、--dir で同じチェックを実行できます。

text
$ potato snapshot verify --dir ./downloaded-snapshot
20261102-175533-68e05868: OK
  content hash 68e058683e7088e3a344d56d7e39172b3d7d3b9b469ba9e1a4a1876b4296b4d2
  Compare it with the hash the paper or dataset card cites.

チェックに合格しても、示されるのは、同じフォルダー内のマニフェストとファイルが一致していることだけです。ほかのスナップショットも、自分自身のチェックには合格します。表示されたハッシュを、論文が引用しているハッシュと比較してください。変更または破損したファイルについては、verify は問題ごとに一行、たとえば annotations.jsonl does not match annotations_sha256 のように表示し、ステータス 1 で終了します。

二つのスナップショットの比較

diff は、二つのスナップショットを回答ごとに比較し、追加、削除、変更された回答を数えます。回答は、アノテーター、アイテム、スキームで対応づけられます。レポートは、追加または削除されたアイテムとアノテーターも一覧し、設定が変わったかどうかを述べ、各スキームの前後のアルファを示します。

text
$ potato snapshot diff config.yaml pilot paper-v1
20261102-175504-45d41bfa -> 20261102-175533-68e05868
Items: +0 -0
Annotations: +0 -0 changed 1
  changed  bob  r2  sentiment
Alpha aspects: 0.718 -> 0.718 (+0.000)
Alpha sentiment: 0.511 -> 0.298 (-0.213)

例の二つのスナップショットの間では、一人のアノテーターが一つの回答を変更し、六アイテムの sentiment スキームのアルファは 0.511 から 0.298 に下がりました。テキストのレポートは、各種類について最大 20 行を挙げます。--json は、同じ行を持つ完全な数を、機械可読な形で返します。コンテンツハッシュが等しい二つのスナップショットでは、diff は Same content. と表示します。

スナップショット内のアルファは、ペーパーモードが計算するのと同じ係数である、Krippendorff のアルファ(名義)です。multiselect のスキームは、アイテムとラベルごとに採点されます。各スキームには、Krippendorff の解釈のいずれか、0.800 以上の「acceptable agreement」、0.667 以上の「tentative agreement」、または 0.667 未満の「low agreement」も付きます。アルファを計算できないスキームには、n/a が表示されます。

スナップショットの復元

Potato には、復元コマンドがありません。スナップショットの bundle.tar.gz は、設定、調査のファイル、アノテーションの出力、データベースを含む project/ フォルダーに展開されます。Potato は、展開された設定から、ほかのプロジェクトと同じように起動します。

bash
mkdir restored
tar -xzf snapshots/20261102-175533-68e05868/bundle.tar.gz -C restored
potato start restored/project/config.yaml -p 8000

復元されたプロジェクトには、アカウントも、コピーされたメディアフォルダーもありません。アノテーターが戻る前に、referenced_directories の下に一覧されたフォルダーを、自分のアーカイブからコピーして戻してください。

管理ダッシュボードのスナップショット

管理ダッシュボードの Publish Dataset ページには、Snapshots カードがあります。このカードは、プロジェクトのスナップショットを、アイテム数、アノテーター数、回答数とともに一覧し、メモと任意のタグからスナップショットを作成します。二つの管理ルートが、HTTP 経由で同じことを行います。

ルート呼び出せる人結果
GET /admin/api/snapshots管理 API キー、または管理ダッシュボードを閲覧できるセッション{"snapshots": [...]}。新しい順で、それぞれにマニフェスト、タグ、デポジットが付く
POST /admin/api/snapshots管理 API キー、または export_data 権限を持つセッション新しいマニフェストとともに 201。何も変わっていない場合は "unchanged": true と既存のスナップショットとともに 200。無効なタグでは、何も書き込まれず 400。同じスナップショットの別の作成が実行中の間は 409

POST のボディは、すべて任意の note、tag、force を取ります。

bash
curl -H "X-API-Key: $KEY" http://localhost:8000/admin/api/snapshots
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
     -d '{"note": "second coding round", "tag": "round-2"}' \
     http://localhost:8000/admin/api/snapshots

Publish Dataset ページからの各リリースの前に、Potato はスナップショットを固定するか、何も変わっていなければ最新のスナップショットを再利用します。ローカルのアーカイブ、Hugging Face Hub、または Zenodo へのリリースは、同じ方法でスナップショットを得ます。生成されるデータセットカードは、引用のセクションでスナップショットを挙げます。

This release is Potato snapshot 20261102-175533-68e05868 (content hash 68e058683e70…). Anyone holding the project folder can check that their copy is this one with potato snapshot verify config.yaml 20261102-175533-68e05868.

固定に失敗した場合、リリースは続行され、Potato は失敗を警告として表示します。python -m potato.publish はスナップショットを固定せず、そのコマンドが書き込むデータセットカードは、スナップショットを挙げません。コマンドラインでのリリースの前に potato snapshot create を実行し、ID は自分で引用してください。

Zenodo へのスナップショットのデポジット

potato snapshot deposit は、スナップショットの四つのファイルと短い README を、新しい Zenodo のレコードにアップロードします。読み手はファイルをダウンロードし、ダウンロードしたフォルダーで potato snapshot verify --dir を実行できます。レコードのタイトル、著者、ライセンス、キーワード、説明は、設定の dataset_metadata ブロックから取られます。Potato は、デポジット時点の設定のままで、そのブロックを読み取ります。レコードのバージョンはスナップショット ID で、説明にはスナップショット ID、数、コンテンツハッシュが加わります。設定に dataset_metadata ブロックを追加します。

yaml
dataset_metadata:
  pretty_name: Clinic Access Interviews (coded excerpts)
  description: Interview excerpts coded for barriers to clinic access by two coders.
  license: cc-by-4.0
  keywords: [qualitative-coding, health-services]
  authors:
    - name: A. Researcher
      affiliation: University of Example
      orcid: 0000-0002-1825-0097

デポジットは、別に指定しない限り、未公開の下書きとして Zenodo のサンドボックスに送られます。

bash
export ZENODO_TOKEN=...
potato snapshot deposit config.yaml paper-v1 --check
potato snapshot deposit config.yaml paper-v1 --annotator-ids-public
potato snapshot deposit config.yaml paper-v1 --annotator-ids-public --production --publish

最初のコマンドは、ファイルを一覧し、以下のチェックを実行し、何も送信しません。二つ目は、サンドボックスの下書きを作成します。三つ目は、zenodo.org にレコードを公開し、DOI を発行します。

フラグデフォルト効果
--tokenZENODO_TOKENZenodo のアクセストークン
--productionオフ(サンドボックス)sandbox.zenodo.org ではなく zenodo.org にデポジットします
--publishオフ(下書き)レコードを公開し、DOI を発行します。下書きは、公開されるまで予約された DOI を保持します
--annotator-ids-publicオフアノテーター ID を保存されたとおりに公開してよいことを確認します
--checkオフ何も送信せずに、ファイルを一覧し、チェックを実行します

ハッシュのチェックはバイト列に依存するため、ファイルは固定されたとおりに送信されます。Potato は何かを送信する前に二つのチェックを実行し、認証情報のチェックを上書きするフラグはありません。

  • 認証情報。 Potato は、設定と、バンドル内の、データファイルを除くすべての YAML、JSON、.env、TOML ファイルを解析します。それらのファイルの一つに、api_key、token、password、client_secret のようなキー、または _api_key、_secret、_token、_password で終わるキーがあり、その値が 12 文字以上のリテラルの場合、デポジットは停止します。既知のプロバイダーのキーの形をした値は、カスタムレイアウトの HTML や JavaScript を含む、どのファイルでもデポジットを停止させます。どのファイルの PEM 秘密鍵も、解析できない設定ファイルも、8 MB を超える設定ファイルも、同じようにデポジットを停止させます。各値を ${ENV_VAR} に置き換えるか、ファイルをプロジェクトの外に移し、新しいスナップショットを取り、新しいスナップショットをデポジットしてください。
  • アノテーター ID。 Potato は、回答と、バンドル内のすべての保存された状態に含まれるアノテーター ID を数え、メールアドレスに見える ID を挙げ、--annotator-ids-public を渡さない限りデポジットを停止します。保存された状態は同意とアンケートの回答を含むため、保存された状態があり回答がないアノテーターも数えられます。

デポジットされたスナップショットはアノテーター ID を保存されたままの形で保持し、python -m potato.publish はデフォルトでアノテーター ID を A1 から An に置き換えます。ID を非公開に保つ必要がある場合は、パブリッシャーを使ってください。各デポジットは snapshots/deposits.json に記録され、show は各デポジットを Zenodo の URL と DOI とともに表示します。スナップショットが zenodo.org で公開された DOI を持つと、そのスナップショットとして固定されたリリースのデータセットカードは、その DOI にリンクします。

スナップショットの削除

スナップショットのファイルは読み取り専用です。ファイルを書き込み可能にし、フォルダーを削除し、そのスナップショットを指していたタグを snapshots/tags.json から削除します。

bash
chmod -R u+w snapshots/20261102-175504-45d41bfa
rm -rf snapshots/20261102-175504-45d41bfa

途中で中断された create は、どのコマンドも読み取らない <id>.partial フォルダーを残します。そのフォルダーは、同じ方法で削除できます。Another snapshot create is writing … right now というメッセージは、同じ内容の二つの作成が同じ秒に開始されたことを意味します。二つの作成のうち一つがスナップショットを書き込み、potato snapshot list が結果を表示します。

関連資料

実装の詳細については、ソースドキュメントを参照してください。

参考文献

  1. Nowell, L. S., Norris, J. M., White, D. E., & Moules, N. J. (2017). Thematic Analysis: Striving to Meet the Trustworthiness Criteria. International Journal of Qualitative Methods, 16(1). doi:10.1177/1609406917733847