これは BrowserHive WACZ Profile 1.2.0 の日本語訳です。正典は 英語原典であり、判断の根拠にする場面ではそちらを確認してください。 訳と原典が食い違った場合は原典が優先します。
本仕様は [[WACZ]] のプロファイルです。WACZ パッケージの書き方を制約し、BrowserHive が その中に記録する追加の member を定めます。アーカイブだけを手にした読み手が、その取り込みが 何を取得し何を取得できなかったか、どのような設定の下で走ったかを判断できるようにするためです。
これは作業中の草案です。BrowserHive が現在書き出しているものを記述しています。同プロジェクト 以外での位置づけを持たず、[[WACZ]] の発行者から承認されたものでもありません。
この版は settings に blockUrlPatterns を必須の member として
足し、cache member を session に置き換えました。したがって
1.1.0 に対して書かれたパッケージは 1.2.0 には適合しません。これは意図された
もので、conformsTo が版を名指ししているのはそのためです ——
古いパッケージを持つ読み手も、それが何に対して書かれたかを辿れます。
1.0.0 と 1.1.0 がそれぞれの URL で公開され続けるのはこの理由によりますが、
BrowserHive はもうそれらを出力しません。
1.1.0 は、取り込みが browser の HTTP キャッシュをどう扱ったかを述べる
cache member を必須としていました。これを書いた producer は
ありません —— その member が述べていた設定は、当時すでに browser context 全体を
覆うより広い設定に畳まれており、いま session が名指ししているのが
それです。並置ではなく削除としたのは、どの実装も書かない必須 member があると、
適合が何についての主張でもなくなるためです。
[[WACZ]] のパッケージは、何が取り込まれたかを述べます。しかし何が抜けたかは述べず、 どのような条件下で取り込みが走ったかも述べません。それらは取り込み時にしか知り得ず、 取り込みを行ったプロセスが終了した時点で失われます。
この喪失が問題になるのは、旅をするのがアーカイブの方だからです。3 年後にパッケージを開いた 読み手には、ログも API の応答も、それを作った機械も残っていません。「ここに欠けているものは あるか」にパッケージ自身が答えられないなら、他の誰も答えられません。
そこで本プロファイルは、パッケージが取り込みについての自身の申告を運ぶことを要求します —— どの本文が欠けていてそれはなぜか、どの上限が効いていたか、どのリクエストをどのパターンで 見送ったか、各オリジンがどの証明書を提示したか。これらは [[WACZ]] の意味を何ひとつ変えません。変えずに、そのままでは取り戻せないものを 記録します。
本仕様の適合対象はパッケージ、すなわちファイル 1 つです。適合はファイルの性質で あって、それを書くソフトウェアの性質ではありません。ある実装が、あるときは適合する パッケージを、別のときは適合しないパッケージを書くことはあり得ます。本仕様はそのどちらで あるかについて何も述べません。
適合するパッケージは、適合する [[WACZ]] パッケージです。本仕様は要求を追加します。 取り除くことも、緩めることもしません。
本仕様における MUST(〜しなければならない)、 MUST NOT(〜してはならない)、 SHOULD(〜すべきである)、 MAY(〜してもよい)は [[RFC2119]] の記述に従って解釈されます。
JSON の member 名は大文字と小文字を区別します。timestamp を保持すると記した member の値は、 UTC の [[RFC3339]] date-time でなければならない。
browserhive:capture member
適合するパッケージの datapackage.json は、値が JSON オブジェクトである
browserhive:capture という名前の member を持た
なければならない。
この member を config または metadata の中に置いては
ならない。これらの名前は [[WACZ]] の読み手にとって意味を持ちます
( を参照)。
ここで定義されていない member が browserhive:capture に存在しても
よい。読み手は認識しない member を無視し
なければならない。
browserhive:capture は、そのパッケージが満たすと主張する本仕様の版の URL を
値とする conformsTo という member を持たなければならない。
"browserhive:capture": {
"conformsTo": "https://uraitakahito.github.io/browserhive-specs/wacz-profile/1.2.0/"
}
宣言をここに置き、datapackage.json の profile member に置かないのは、
そちらがこの用途に使えないためです。
読み手は browserhive:capture が存在するというだけで適合を推定しては ならない。conformsTo が無ければ、そのパッケージが どの版に向けて書かれたかは不明です。
build
browserhive:capture は、パッケージを作ったソフトウェアを機械可読な形で
識別する build member を持たなければならない。
| Member | 型 | 必須 | 意味 |
|---|---|---|---|
version | string | はい | リリースの識別子。 |
revision | string | はい | ビルド元のソース revision。 |
buildTime | string | はい | ソフトウェアがビルドされた時刻。 |
"build": {
"version": "3.4.0",
"revision": "0776cae",
"buildTime": "2026-08-21T04:04:09.000Z"
}
version の書式は定めません。リリースそのものから作られた build は
"3.4.0" のような値を持ちますが、リリースとリリースの間で作られた build は
"3.4.0-12-gabc1234" のように、直近のリリースからの距離を含んだ値になり
得ます。どちらも「どの build か」を言うという点では同じで、読み手はこれを版数として
解釈するのではなく、同じ値なら同じ build であるという識別子として
扱うべきです。
[[WACZ]] は既に software を定めています。あちらは散文で、書き方が producer
ごとに違うため誰も解析しません。build があるのは、同じ事実を形式を推測せずに
機械が読めるようにするためです。
browser
browserhive:capture は、取り込みを行った browser を記述する browser
member を持たなければならない。値が string である
product member を持たなければならない。
"browser": {
"product": "Chrome/151.0.7922.137"
}
綴りは定めません。値は browser 自身が名乗るものなので、別のエンジンが作った パッケージは別の形を運びます。読み手は 2 つの値が等しいかどうかを比べられますが、 書式を仮定することはできません。
値は代用のものであってはならない。これを取得できない producer は、 適合するパッケージを作ってはならない。記録した browser が不明な アーカイブはこのプロファイルの外にあり、member を省くことはそれを表明する手段では ありません。
settings
browserhive:capture は、この取り込みに効いていた設定を記録する
settings member を持たなければならない。
値は解決後の値でなければならない。要求が指定した値ではありません。 何も指定しない要求も何らかの設定の下で走っており、アーカイブが報告すべきなのはその設定です。
| Member | 型 | 必須 | 意味 |
|---|---|---|---|
signature | string | はい | "required" または "none"。この取り込みが署名なしで
出されてよかったか。 |
viewport | object | はい | member width と height。ともに整数、単位は CSS ピクセル。 |
devicePixelRatios | array of number | はい | ページを読み込んだときの device pixel ratio を、読み込んだ順に。要素数が そのまま読み込みの回数。 |
session | string | はい | その取り込みのために作られ、終われば捨てられる browser context で 走ったのか、取り込みをまたいで使い回される context で走ったのか。 前の取り込みが残した状態にパッケージが依存しうるかどうかを、 読み手はこれで判定します。 |
behaviors | array of string | はい | 実際に走った behavior。有効化されていたものではありません。 |
limits | object | はい | この取り込みに効いていた本文の上限。member maxResponseBytes と
maxTaskBytes。ともに整数で、単位はバイト。 |
blockUrlPatterns | array of string | はい | この取り込みに効いていた URL のパターン。いずれかに一致した リクエストは記録されますが、本文は取得されません。 blocked request を参照。 |
acceptLanguage | string | いいえ | 取り込みが設定したときにのみ存在する。オリジンが返すものが変わるため。 |
"settings": {
"signature": "none",
"viewport": { "width": 1280, "height": 800 },
"devicePixelRatios": [1],
"session": "isolated",
"behaviors": ["autoscroll", "autofetch"],
"limits": {
"maxResponseBytes": 20971520,
"maxTaskBytes": 209715200
},
"blockUrlPatterns": ["*://*.example-analytics.com/*"]
}
この例の session は、取り込みがそれ自身の context で走ったことを
表しています。devicePixelRatios の要素が 1 つなのは、ページを
1 回だけ読み込んだという意味です。behaviors に並ぶ 2 つは実際に走った
behavior です —— 有効化されていた
ものの一覧ではありません。acceptLanguage は、この取り込みが設定しなかった
ので在りません。値そのものは producer が決めるもので、ここに挙げた綴りを
このプロファイルが定めているわけではありません。
devicePixelRatios が数値ではなくリストなのは、取り込みがページを 2 回以上
読み込むことがあるためです。単一の値で記録すると、在る描画が無いと読み手に
伝えてしまいます。
値は読み込んだ順序で並んでいなければならない。読み手が 「どの版がアーカイブに在るか」だけでなく「どの版が最後に描かれたか」を言えるように するためです —— ページの見た目を伴う成果物は、最後の読み込みが残した状態に従います。
2 回読み込む取り込みでは、読み込んだ数だけ値が並びます。要求が
acceptLanguage を指定した場合は、それもここに現れます:
"settings": {
"signature": "required",
"viewport": { "width": 1280, "height": 800 },
"devicePixelRatios": [1, 2],
"session": "isolated",
"behaviors": ["autoscroll"],
"acceptLanguage": "ja,en;q=0.9",
"limits": {
"maxResponseBytes": 20971520,
"maxTaskBytes": 209715200
},
"blockUrlPatterns": []
}
2 つは測る対象が違います。maxResponseBytes は
レスポンス 1 件の本文に掛かり、maxTaskBytes はこのパッケージへ書いた
本文の累計に掛かります。
この違いは読み手にとって実際的です。maxResponseBytes は 1 件ずつを量るので、
それを下回るレスポンスは何件でも入り、パッケージ全体の大きさはこの値からは
分かりません。maxTaskBytes は積み上げた総量を見るので、線を越えた
後は大きさに関わらず本文が落ちます —— 落ちた中に小さなレスポンスが
混じっていても、それは矛盾ではありません。
本文が 1 つも落とされなかった場合でも limits は存在し
なければならない。切り詰めがどの線を超えたのかを
アーカイブが言える場所は、ここだけです —— 切り詰めの記録は落とした事実と実際の
大きさを運びますが、その大きさが多すぎたかどうかは線と並べて初めて分かります。
completeness の truncatedUrls は、この 2 つのどちらを超えて落ちたのかを
区別しません。
対処が違う (前者は 1 件が大きすぎ、後者はページ全体が重い) にもかかわらずです。
区別が要る読み手は、パッケージの外 —— 取り込みが出した報告 —— を見ることになります。
completeness
browserhive:capture は、そのパッケージが保持していない本文についての
自身の申告である completeness member を持たなければならない。
| Member | 型 | 必須 | 意味 |
|---|---|---|---|
bodylessUrls | array of string | はい | 304 としてしか現れなかった URL。本文が wire を渡っていないので、
アーカイブは保持し得ません。 |
truncatedUrls | array of string | はい | サイズ上限に達して取り込みが本文を落とした URL。 |
complete | boolean | はい | 両方の配列が空のとき、かつそのときに限り true。 |
"completeness": {
"bodylessUrls": [],
"truncatedUrls": [],
"complete": true
}
何も欠けなかった取り込みはこの形になります。complete は両方の配列から
導かれるので、空の配列 2 つと false という組み合わせは現れません。
次は、両方の理由で本文を欠いた取り込みです:
"completeness": {
"bodylessUrls": [
"https://example.com/assets/app.css"
],
"truncatedUrls": [
"https://example.com/media/hero.mp4",
"https://example.com/media/poster.png"
],
"complete": false
}
この取り込みでは、CSS が 304 としてしか現れませんでした —— 本文が wire を
渡っていないので、アーカイブは持ちようがありません。動画とポスター画像は上限に当たって
落ちたものです。同じ URL が 2 回落ちても、配列には 1 度だけ現れます。
同じページの 2 つの取り込みを比較できるよう、両方の配列は整列されて いなければならない。
2 つが別の member なのは、求められる対応が違うからです。304 はオリジン側の
事情でここからは回復できませんが、上限で落とした本文はこちら側の事情で、上限を上げれば
戻ります。
正当に本文を持たないレスポンスを列挙してはならない ——
redirect、204、および要求者が設定した content-type フィルタで省かれた本文。
最後のものを報告しても、読み手が既に決めたこと以上を何も伝えません。
coverage
browserhive:capture は、取り込みがページのどこまで下れたかを記述する
coverage member を持ってもよい。
| Member | 型 | 必須 | 意味 |
|---|---|---|---|
scrollExhausted | boolean | はい | スクロールがページの終端ではなく段数の上限で止まったとき true ——
つまりその下にあるものが一度も要求されていないとき。 |
scrollSteps | number | はい | 実際に進んだ段数。 |
scrolledPx | number | はい | 到達した深さの概算。段数 × viewport の高さ。 |
"coverage": {
"scrollExhausted": true,
"scrollSteps": 40,
"scrolledPx": 32000
}
3 つの値は互いを読み合うためのものです。scrolledPx は
scrollSteps に settings が記録した viewport の高さを
掛けたもの —— ここでは 40 × 800 —— なので、読み手は一方を他方で検算できます。
そして scrollExhausted が true である以上、
この 32,000 ピクセルは取り込みが止まった地点であって、ページが
終わった地点ではありません。その下にあったものは一度も要求されておらず、
したがってパッケージの他のどこにも痕跡を残していません。
スクロールの behavior が何も報告しなかった場合、coverage は存在しては
ならない。既定値を入れて書いてはならない ——
scrollExhausted: false はページを覆えたという主張であり、一度もスクロール
しなかった取り込みはその主張を得ていません。
tls
browserhive:capture は、各 HTTPS 接続について browser が見たものを記録する
tls member を持ってもよい。存在する場合、
hosts と chains を持たなければならない。
tls.hostshost を鍵とするオブジェクト。各値は以下の member を持つオブジェクトか、null。
| Member | 型 | 必須 | 意味 |
|---|---|---|---|
protocol | string | はい | ネゴシエートされた TLS の版。 |
cipher | string | はい | ネゴシエートされた cipher。 |
subject | string | はい | subject の common name。browser が報告したそのまま。 |
san | array of string | はい | その証明書が有効な host 名の一覧 (subjectAltName)。SAN を持たない証明書では空。 |
issuer | string | はい | issuer の common name。 |
validFrom | string | はい | 証明書の有効期間の開始。 |
validTo | string | はい | その終了。 |
chainRef | string | いいえ | tls.chains への鍵。チェーンを取得できなかったときは存在しない。 |
HTTPS で到達したが接続が何も明かさなかった host は、値 null として記録され
なければならない。鍵ごと省くと「この host は素の HTTP だった」と
読めてしまいますが、それは別の事実です。
host 名の照合に使われるのは subject ではなく san です。
subject が記録するのは common name であり、現在の読み手はこれを照合に
用いません —— subject の値をもって「その host 名で通用した」と読んでは
ならない。
chainRef が無いことを「この host は証明書を提示しなかった」と読んでは
ならない。チェーンの取得は host と無関係な理由でも失敗します。
tls.chains
鍵が chainRef の値であり、値が base64 符号化された DER 証明書の配列である
オブジェクト。各配列はリーフを先頭として並んでいなければならない。
チェーンを共有する host は 1 つの項目を共有すべきである。 1 ページの host 間で証明書が再利用されることは多く、host ごとに複製を持つとパッケージが 何の利得もなく膨らみます。
チェーンは参照ではなく保存します。Certificate Transparency が同じバイト列を持っては いますが、第三者のサービスが到達可能であり続けることに依存する証拠は、その分だけ弱く なります —— そして検討する価値のある事例である私設 CA のチェーンは、そもそもそこに 記録されたことがありません。
"tls": {
"hosts": {
"example.com": {
"protocol": "TLS 1.3",
"cipher": "AES_128_GCM",
"subject": "example.com",
"san": ["example.com", "www.example.com"],
"issuer": "Example Issuing CA",
"validFrom": "2026-06-30T20:37:58.000Z",
"validTo": "2026-09-28T21:37:55.000Z",
"chainRef": "9a57318f8c89976c"
},
"cdn.example.net": {
"protocol": "QUIC",
"cipher": "AES_128_GCM",
"subject": "*.example.net",
"san": ["*.example.net", "example.net"],
"issuer": "Example Issuing CA",
"validFrom": "2026-08-05T20:42:14.000Z",
"validTo": "2026-10-28T20:42:13.000Z",
"chainRef": "c52653c92800f6fd"
},
"img.example.net": {
"protocol": "TLS 1.3",
"cipher": "AES_128_GCM",
"subject": "*.example.net",
"san": ["*.example.net", "example.net"],
"issuer": "Example Issuing CA",
"validFrom": "2026-08-05T20:42:14.000Z",
"validTo": "2026-10-28T20:42:13.000Z",
"chainRef": "c52653c92800f6fd"
},
"api.example.org": {
"protocol": "TLS 1.3",
"cipher": "AES_256_GCM",
"subject": "api.example.org",
"san": ["api.example.org"],
"issuer": "Example Issuing CA",
"validFrom": "2026-05-14T09:03:11.000Z",
"validTo": "2026-08-12T09:03:10.000Z"
},
"beacon.example.org": null
},
"chains": {
"9a57318f8c89976c": [
"MIIDbzCCAxSgAwIBAgIRALaMq73qMP3mE30B…",
"MIICjDCCAhKgAwIBAgIQf5wJDMcM1Y2ZBpFB…"
],
"c52653c92800f6fd": [
"MIIIUDCCBzigAwIBAgIQHnJSlrCYIdkSw8c/…",
"MIIFCzCCAvOgAwIBAgIQVJ5xIVMKmZ0sNHxs…"
]
}
}
この例は 5 つの host を記録しています。上の規定がそれぞれどう現れるかを見てください。
cdn.example.net と img.example.net は同じ
chainRef を指しています —— 同じ証明書を提示したので、チェーンは
chains に 1 度だけ保存されています。api.example.org には chainRef がありません。
証明書は提示されており (subject 以下がその証拠です)、取れなかったのは
チェーンだけです。beacon.example.org は null です。HTTPS で到達しましたが、
接続は何も明かしませんでした。鍵ごと省いていないのは、省くと「この host は素の HTTP
だった」と読めてしまうためです。cdn.example.net の protocol は "QUIC" です。
この member は browser が報告した文字列であり、TLS の版とは限りません。
chains の値は base64 符号化された DER です。例では読みやすさのため途中で
切ってありますが、実際には 1 通あたり 1–2 KB 程度の文字列になります。
取り込みは、blockUrlPatterns に挙げたパターンのいずれかに URL が
一致するリクエストについて、その本文の取得を見送ることがあります。そうした
リクエストのそれぞれについて、パッケージは WARC の metadata
レコード —— 以下 blocked request のレコード —— を
MUST 含みます。そのリクエストが行われたことを、
アーカイブが記録するためです。
レコードの WARC-Target-URI はリクエストの URL で
MUST。本文は application/warc-fields で、
次を MUST 含みます:
| Field | 必須 | 説明 |
|---|---|---|
blocked | はい | リテラル true。パッケージが運ぶ他の
metadata レコードと、このレコードを区別します。 |
reason | はい | 本文が無い理由。この版が定めるのは
block-url-pattern のみです。 |
pattern | はい | 一致したパターン。blockUrlPatterns に現れるとおりの
綴りで —— 読み手がそちらで引き当てられるようにするためです。 |
method | はい | リクエストのメソッド。 |
resourceType | いいえ | ページが何を取りに行っていたか。取り込みが知っている場合に。 |
WARC/1.1 WARC-Type: metadata WARC-Target-URI: https://www.example-analytics.com/collect?v=2 WARC-Date: 2026-09-06T02:14:31.882Z Content-Type: application/warc-fields Content-Length: 118 blocked: true reason: block-url-pattern pattern: *://*.example-analytics.com/* method: POST resourceType: XHR
blockUrlPatterns は、一致したリクエストが 1 件も無かった場合でも
存在して MUST、空の配列は「効いていたパターンが無い」
という意味で MUST。この規則が無いと読み手は、
何も要求しなかったページと、要求されたものを記録しないことにした取り込みとを
区別できません。同じパッケージについての、別の主張です。
この要件は settings の limits に掛かるものと同じ形で、
理由も同じです —— パッケージの中身を変える設定は、それが発火したかどうかに
関わらず、パッケージから読み取れなければなりません。
blocked request のレコードはレスポンスも本文も持ちません。主張しているのは、 そのリクエストが行われたこと、そしてこのプロファイルの producer が返ってきたものを 記録しないと決めたこと —— リクエストが失敗したという意味でも、オリジンが何も 返さなかったという意味でもありません。
blocked request のレコードは、パッケージの CDXJ 索引に現れることを要求されません。 これを探す読み手は WARC を読みます。
storage member
browserhive:capture は、取り込んだ origin が保持していた web
storage を記録する storage という member を
持たなければならない(MUST)。この member が記録するのは、その storage の
存在と形です。保存されていた値を
含んではならない(MUST NOT)。
web storage を記録するのは、後から復元できないからです。ネットワークを一度も
渡らないため、どの WARC レコードもこれを保持していません ——
localStorage から描画するページは、アーカイブが持っていない
データから描画しています。この member が無いと、読み手はそうしたページと
「本当に見せるものが無かったページ」を区別できません。
completeness は助けになりません ——
あれが報告するのはパッケージが保持していない body であり、
storage は一度も body になっていないからです。
{
"browserhive:capture": {
"storage": {
"profile": "browserhive:storage/1",
"stage": "after-behaviors",
"valuesRecorded": false,
"origins": [
{
"origin": "https://www.example.co.jp",
"local": { "keys": 2, "bytes": 32, "digest": "sha256:b58f31fdc511fb94c356ae7f6d64ac71e5bf056584653c3f3ec61a1f08bfaa0f" },
"session": { "keys": 1, "bytes": 13, "digest": "sha256:8ce272dea9fc6d7902b23f10411da49a7fb2e3c954ba9f1580cc087292eaafc2" }
},
{ "origin": "https://ads.example.net", "unreadable": true }
]
}
}
}
storage は profile、stage、
valuesRecorded、origins を
持たなければならない(MUST)。
profile —— この member が従う規則。本仕様のこの版では値は
"browserhive:storage/1" でなければならない(MUST)。
記録する内容や digest の計算方法を変えた producer は、この値を
変えなければならない(MUST)。
stage —— 取り込みのどの時点で storage を読んだか。この版では値は
"after-behaviors" でなければならない(MUST)。
stage が規範なのは、内容が変わるからです ——
ページは動作しながら storage に書き込むので、behavior が走る前に読んだものと
後に読んだものは、別の状態を表します。
valuesRecorded —— このパッケージが、下で定義するディレクトリに
保存されていた値も併せて運んでいるかどうか。
を参照。
origins —— 取り込みが観測できた origin ごとに 1 つの項目を持つ配列。
各項目は origin を持たなければならない(MUST) ——
値は [[WACZ]] の enclosing document と同じ直列化形式、すなわち scheme・host、
および既定でない場合の port です。
web storage は origin ごとに区切られており、ページは日常的に自分以外の origin の
文書を埋め込みます —— 広告、計測のフレーム、埋め込みのプレイヤー。それらは
それぞれ自分の storage を持ち、ページ自身の origin からは見えません。
したがってこれは「そのページの storage」の記録ではありません ——
取り込みが観測できた origin ごとに 1 項目であり、
第三者の origin の項目が在ることは異常ではなく想定どおりです。
そもそも storage を持てない origin —— about:blank の文書や
data: URL のような opaque origin —— は記録するものが無いので
現れません。
各項目は、local と session の両方を持つか、あるいは
unreadable という単一の member を値 true で持つかの
いずれかでなければならない(MUST)。後者は「その origin の storage を
取り込みが読めなかった」という意味です。これは storage が空だった origin
—— "keys": 0 の area として書かれる —— とは別です。
同じ形で記録すると、この member が取り除こうとしている曖昧さが戻ってきます。
ここの項目と storage/origins.jsonl の行は、1 つの記録の
2 つの半分です。項目はその origin の storage が
どう見えたかを述べ —— 鍵がいくつ、何バイト、digest は何 ——
常に在ります。行は何が入っていたかを述べ、値を求められたときにだけ
在ります。どちらをパッケージが持っているかは valuesRecorded が
述べます。unreadable として記録された origin に行が無いのは、
行に入れるものが無いからです。
local と session はそれぞれ以下を
持たなければならない(MUST)。
keys —— その area が保持していた鍵の数。bytes —— その area の合計の大きさ。すべての鍵と値の
UTF-8 表現で数えます。browser 自身の quota 会計が使う
UTF-16 コード単位ではありません。
digest —— "sha256:" に続けて、その area の SHA-256 を
小文字の 16 進で。計算は、鍵をコードポイント順に並べ、各要素が
key U+0000 value U+0000 を UTF-8 で寄与する形で行います。
並べ方と区切りは規範です —— これを決めないと同じ内容が別の digest になり、
取り込みをまたいで比較するという digest の目的が失われます。
digest を値へのコミットメントとして扱ってはならない(MUST NOT)。 値はしばしばエントロピーが低く —— フラグ、テーマ名、時刻 —— そのような digest は推測で容易に逆算できます。
storage directory
[[WACZ]] は、archive・indexes・pages を避け、
datapackage.json の resources に列挙する限り、追加の
ファイルやディレクトリを認めています。適合するパッケージは、その許可を
2 つ目のエントリに使ってもよい(MAY)。
適合するパッケージは storage/origins.jsonl というエントリを
持ってもよい(MAY)。存在する場合、他のファイルと同様に
resources で宣言しなければならず(MUST)、
JSON Lines でなければならない(MUST) —— 1 行 1 つの JSON
オブジェクトで、各オブジェクトは 1 つの origin が保持していた web storage を
記録します。
このエントリが存在する場合、valuesRecorded は
true でなければならない(MUST)。存在しない場合、
valuesRecorded は false でなければならない(MUST)。
したがって読み手は、アーカイブ本体を開かずに、そのパッケージが保存されていた値を
運んでいるかどうかを判別できます。
{
"profile": "browserhive:storage/1",
"origin": "https://www.example.co.jp",
"takenAt": "2026-09-06T01:22:14.881Z",
"stage": "after-behaviors",
"areas": {
"local": { "feed.cache": "[{\"id\":1}]", "ui.theme": "dark" },
"session": { "nav.scroll": "820" }
}
}
各行は profile、origin、[[RFC3339]] のタイムスタンプと
しての takenAt、stage、areas を
持たなければならない(MUST)。areas は
local と session を
持たなければならない(MUST) ——
それぞれ、area が保持していたとおりに鍵を値へ写像するオブジェクトです。
storage で unreadable として記録された origin は、
ここに行を持ってはならない(MUST NOT)。
[[WACZ]] は、archive・indexes・pages を
避け、datapackage.json の resources に列挙する限り、
追加のファイルやディレクトリを認めています。適合するパッケージは、その許可を
エントリ 1 つに使います。
適合するパッケージは accessibility/axtree.jsonl というエントリを
持ってもよい(MAY)。存在する場合、他のファイルと同様に
resources で宣言しなければならず(MUST)、
JSON Lines でなければなりません
(MUST)—— 1 行 1 つの JSON オブジェクトで、各
オブジェクトは、取り込んだページに対して browser が計算したアクセシビリティ
ツリーのスナップショット 1 枚を記録します。
この木を記録するのは、後から作り直せないからです。DOM とレイアウト
ツリーの両方から作られ、対応する DOM ノードを持たないノード(CSS の
生成内容、リストの記号)を含み、aria-owns がノードの親を付け替える
ため、その形は文書の木とは異なります。将来の browser で archive を再生しても、
別の木ができます。tls を参照ではなく記録している理由と同じです。
各行は profile・url・takenAt・
stage・tree を含まなければなりません
(MUST)。
profile —— その行が従う刈り込み規則。本仕様のこの版では、値は
"browserhive:axtree/1" でなければなりません
(MUST)。刈り込み規則を変える producer は、この値も
変えなければなりません(MUST)—— 読み手が、何が
捨てられたのかを言えるようにするためです。url —— そのスナップショットが記述するページ。takenAt —— 撮った時刻。[[RFC3339]] のタイムスタンプ。stage —— 取り込みのどの時点で撮ったか。この版では値は
"after-behaviors" でなければなりません
(MUST)。時点が規範的なのは、木が変わる
からです。 autoscroll は lazy load を発火させるので、behavior の
前に撮った木と後に撮った木は、別のページを記述しています。tree —— ノードの配列。次節を参照。
各行はさらに devicePixelRatio・viewport・
nodes を持つべきです(SHOULD)——
順に、そのスナップショットがどのパスのものか、効いていた viewport、そして
刈り込む前のノード数。最後の 1 つによって、読み手はどれだけ
捨てられたのかを見ることができます。
{
"profile": "browserhive:axtree/1",
"url": "https://www.iana.org/",
"takenAt": "2026-08-22T02:55:56.759Z",
"stage": "after-behaviors",
"devicePixelRatio": 1,
"viewport": { "width": 1280, "height": 800 },
"nodes": 255,
"tree": [
{
"role": "RootWebArea",
"name": "Internet Assigned Numbers Authority",
"children": [
{ "role": "heading", "name": "Domain Names", "level": 2 },
{ "role": "image", "name": "logo",
"url": "https://www.iana.org/_img/iana-logo-header.svg" }
]
}
]
}
読みやすさのため複数行で示しています。ファイル中では、各スナップショットは ちょうど 1 行を占めます。
すべてのノードは role を持たなければなりません
(MUST)。ノードは role・
name・level・url・checked・
expanded・disabled・required・
value・children 以外の member を持ってはなりません
(MUST NOT)。
このうち 2 つは、他より重い意味を持ちます:
level —— 見出しの深さ。これが無いと heading の
ノードを互いに区別できず、この木が記録するために在る文書構造そのものが
失われます。url —— 画像やリンクが指す先。ノードと archive/ に
記録されたレスポンスを結ぶのはこれで、「ここに図があった」から「その図の
バイト列」へ辿れるようになります。
値が無い・空・false の member は書いてはなりません
(MUST NOT)。全ノードに既定値を書くと、それが囲んでいる
中身より嵩が大きくなります。
browser が ignored と印を付けたノードは tree に現れてはなりません
(MUST NOT)。その子は残し、最も近い残されたノードの
下に付けなければなりません(MUST)。
これが、隠されたテキストを記録に持ち込まないための仕掛けです。
aria-hidden や display: none で外された部分木は
ignored なノードなので、そもそもこのファイルに届きません。したがって読み手は、
この木を「見えていたもの」の記述として扱えます —— WARC の
本文だけからは支えられない、より強い主張です。
role が generic・none・InlineTextBox の
ノードも tree に現れてはならず(MUST NOT)、
その子は同じように残さなければなりません(MUST)。
これらの role はそれ自体では意味を持たず、残すと木の深さが倍になるだけで、
読み手が使えるものは何も増えません。
viewport の外にあることを理由にノードを落としてはなりません (MUST NOT)。エージェントにとっては妥当な判断です —— 見えないものは操作できないので。しかし、誰もスクロールしなかった部分を捨てた アーカイブは、そのページの記録ではありません。
この節の要求は [[WACZ]] に由来しません。既存の WACZ 読み手が実際に行っていることに由来し、 これらを無視したパッケージは、基底の仕様を満たしていても実務上は読めません。
datapackage.json の profile member は
"data-package" でなければならない。読み手はこの値で
分岐し、知らない値を拒むため、本プロファイルを識別する用途には使えません。
を参照。
datapackage.json の config と metadata を、本仕様が
定める値を運ぶために使ってはならない。読み手がこれらに意味を
割り当てています。
response レコードのペイロードは、交信を運んだプロトコルの版に
関わらず HTTP/1.1 形でなければならない。
.gz で終わらないパスに格納され
なければならない。読み手は拡張子で位置を特定し、
展開を行いません。
ここに記すのは、パッケージの作成者がこれらを満たせるようにするためです。それぞれが なぜ存在するかは実装史の問題であり、本仕様の外で文書化されています。
tls は来歴の証明ではありません。証明書は公開情報で、誰でも取得して複製を提示できます。
これらのフィールドを持っていることは、誰が要求に応答したかについて何も言いません。保存する
価値があるのはもっと狭い 2 つです —— issuer は接続が傍受されたときに変わり、
有効期間は取り込みが主張する時刻と突き合わせられます。そしてどちらも、書き留めなければ
取り込みの後には残りません。
completeness が主張するのは不在であって、正しさではありません。このパッケージが 実証的に保持していない本文を報告します。保持している本文がオリジンの配信したものである、 とは主張しません。
パッケージは completeness に URL を、tls に host 名を記録します。取り込んだ ページが URL に個人データを載せていた場合、それらの URL はアーカイブとともに旅をします。
アクセシビリティツリーは、browser が要素に対して計算した名前を運びます。それは
ページの可視テキストから作られるもので、そのテキストは WARC の本文に
既に入っています —— つまりこの木を記録しても、パッケージが
それまで持っていなかったものが増えるわけではありません。むしろ刈り込み規則に
よって、露出は本文より狭くなります: ignored なノードを除くので、
aria-hidden や display: none で隠されたテキストは、
レスポンス本文には在っても、この木には現れません。
storage は、パッケージが既に保持している以上のものを晒しません。 記録するのは鍵の数・バイト数・digest です。値は記録せず、digest は値では ありません —— ただし上に書いたとおり、エントロピーの低い内容に対する digest は 隠し場所にもなりません。
storage/origins.jsonl を併せて持つパッケージは、
より多くを晒します。web storage は bearer token、
セッション識別子、未送信の下書きを日常的に保持しており、そのどれも WARC の
payload には現れません。この profile の中で、取り込みがネットワークから
一度も受け取っていない資料を適合パッケージが運びうる場所は、ここだけです。
producer は既定でこのディレクトリを出力しないべきである(SHOULD)。
読み手は valuesRecorded によって、アーカイブ本体を開かずに
どちらであるかを判別できます。
browser は記録を行った build を名指しし、これは必須です。origin へ別の身元を
提示する producer — たとえば User-Agent を差し替えた場合 — でも、
この member は変わりません。サーバへ送るものと、パッケージが報告するものは別です。
build の版を秘匿したい運用者は、適合するパッケージがそれを開示することを知っておく
必要があります。