これは BrowserHive WACZ Profile 1.4.0 の日本語訳です。正典は 英語原典であり、判断の根拠にする場面ではそちらを確認してください。 訳と原典が食い違った場合は原典が優先します。
本仕様は [[WACZ]] のプロファイルです。WACZ パッケージの書き方を制約し、BrowserHive が その中に記録する追加の member を定めます。アーカイブだけを手にした読み手が、その取り込みが 何を取得し何を取得できなかったか、どのような設定の下で走ったかを判断できるようにするためです。
これは作業中の草案です。BrowserHive が現在書き出しているものを記述しています。同プロジェクト 以外での位置づけを持たず、[[WACZ]] の発行者から承認されたものでもありません。
この版は dismissal —— 取り込みが記録の前にページから何を取り除いたか —— を足しました。したがって 1.3.0 に対して書かれたパッケージは 1.4.0 には 適合しません。これは意図されたもので、conformsTo が版を名指ししているのは そのためです —— 古いパッケージを持つ読み手も、それが何に対して書かれたかを 辿れます。以前の版 —— 1.0.0・1.1.0・1.2.0・1.3.0 —— がそれぞれの URL で公開され続けるのはこの理由によりますが、 BrowserHive はもうそれらを出力しません。
1.3.0 までは、ページが配信された時点では在った要素がパッケージから欠けていても、 それについて何も述べられませんでした。同意バナーを取り除いたページと、 もともとバナーの無いページを、読み手は区別できませんでした。 dismissal は結果を記録しますが、結果だけでは検証できません —— 取り除きが空であることは、20 本の選択子を探した場合でも 1 本も探さなかった場合でも 「何にも当たらなかった」と読めてしまいます。そこでこの member は、効いていた 選択子も一緒に運びます —— 1 件も濾さなかった取り込みにも urlPolicies を 必須にしているのと同じ理屈です。両方が在れば、取り除きは読み手が保存された HTML に対して確かめられる部分集合になり、そもそも選択子として成立していなかったものは、 黙って「当たらなかった」に数えられるのではなく名指しされます。
[[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.4.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。ともに整数で、単位はバイト。 |
urlPolicies | array of object | はい | 効いていた URL パターンのそれぞれに対して取り込みが何をしたかを、 評価した順に。urlPolicies を参照。 |
contentTypePolicies | array of object | はい | 効いていたメディア型のそれぞれに対して取り込みが何をしたか。 contentTypePolicies を参照。 |
acceptLanguage | string | いいえ | 取り込みが設定したときにのみ存在する。オリジンが返すものが変わるため。 |
"settings": {
"signature": "none",
"viewport": { "width": 1280, "height": 800 },
"devicePixelRatios": [1],
"session": "isolated",
"behaviors": ["autoscroll", "autofetch"],
"limits": {
"maxResponseBytes": 20971520,
"maxTaskBytes": 209715200
},
"urlPolicies": [
{ "pattern": "*://*.example-analytics.com/*", "action": "deny" }
],
"contentTypePolicies": []
}
この例の 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
},
"urlPolicies": [],
"contentTypePolicies": [{ "prefix": "video/", "action": "no-body" }]
}
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 はページを覆えたという主張であり、一度もスクロール
しなかった取り込みはその主張を得ていません。
dismissal
browserhive:capture は、取り込みが記録の前にページから何を取り除いたか、
そして何を探したかを記録する dismissal member を持ってもよい。
同意バナーを取り除いた取り込みは、そのあと保存する文書そのものを変えています。 それを述べるものは他にありません —— 取り除かれた要素は WARC にも索引にも 描画後のスナップショットにも痕跡を残さず、読み手はもともとバナーの無いページと 区別できません。
| Member | 型 | 必須 | 意味 |
|---|---|---|---|
selectors | object の配列 | はい | 効いていた選択子。評価した順のまま。
member は framework と selector で、どちらも文字列。 |
heuristic | object | はい | どの選択子も名指ししていない要素の除去を支配していた閾値。
member は enabled (boolean)・
minViewportCoverageRatio (number)・
minZIndex (number)。 |
framework | 文字列または null | いいえ | 最初に一致した項目の framework。閾値だけが発火したときは
"heuristic"。何も取り除かなかったときは null。 |
removedSelectors | 文字列の配列 | いいえ | 要素が取り除かれた選択子。selectors の部分集合で、評価した順。 |
unusableSelectors | 文字列の配列 | いいえ | ページを読む側が評価できなかった selectors の項目。
これらが何にも当たらなかったのは選択子として成立していなかったからであって、
「当たらなかった」とは別の主張。 |
removedOverlays | number | いいえ | 選択子ではなく閾値によって取り除かれた要素の数。 |
devicePixelRatio | number | いいえ | どの読み込みの観測か。devicePixelRatios の項目のいずれか。 |
unreadable | true | いいえ | 除去を試みたが遂行できなかったときに在る。 |
"dismissal": {
"selectors": [
{ "framework": "OneTrust", "selector": "#onetrust-banner-sdk" },
{ "framework": "Cookiebot", "selector": "#CybotCookiebotDialog" }
],
"heuristic": { "enabled": true, "minViewportCoverageRatio": 0.3, "minZIndex": 1000 },
"framework": "OneTrust",
"removedSelectors": ["#onetrust-banner-sdk"],
"unusableSelectors": [],
"removedOverlays": 0,
"devicePixelRatio": 1
}
除去を試みなかった場合、dismissal は存在しては
ならない。したがって不在は「配信されたままのページを
保存した」を意味します。「何も見つからなかった」ではありません。
dismissal が在るとき、何も取り除かなかった場合でも
selectors と heuristic は在らなければならない。
結果を検証可能にしているのはこの 2 つです —— 20 件の項目の隣に在る空の
removedSelectors は「そのどれもが名指しするバナーをページは持たなかった」
と述べますが、項目が 1 件も無い隣の同じ空リストは「何も探さなかった」としか
述べません。1 件も濾さなかった取り込みにも urlPolicies を必須にしているのと
同じ理屈です。
パッケージは unreadable を framework・
removedSelectors・unusableSelectors・
removedOverlays と並べて持ってはならない。
遂行できなかった除去は何も観測しておらず、その隣に空の結果を書くことは
「ページはバナーを持たなかった」という主張になります。
スクロールもまた取り込みが見るものを変えますが、それが何をしたかは既に coverage —— ページのどこまで下れたかを述べるもの —— が記録しています。 同じ行為の 2 つ目の申告をここに置けばそれは写しであり、いずれ片方が 古いほうになります。
ページを 2 回以上読み込む取り込みは、読み込みごとに要素を取り除きます ——
除去は同意ではないので、同意フレームワークは次の読み込みで再び描画されます。
removedSelectors は読み込みをまたいだ和ではなく、ある瞬間の
1 つの文書に対する観測であり、それをどの読み込みのものかに結び付けるのが
devicePixelRatio です。
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 程度の文字列になります。
取り込みは、一部のリクエストを他と違う扱いにすることがあります ——
送らない、記録しない、本文なしで記録する。
browserhive:capture.settings は何をしたかを
MUST 記録します。取り込みの設定に手が届かない読み手が、
そのどれであったかを判定できるようにするためです。
urlPoliciesurlPolicies は順序付きの配列です。各項目は 2 つの member を持つ オブジェクト:
| Member | Type | 必須 | 説明 |
|---|---|---|---|
pattern | string | はい | 効いていたパターン。取り込みが設定されたとおりの綴りで。 |
action | string | はい | 下の値のいずれか。 |
action | リクエストの送信 | パッケージが持つもの |
|---|---|---|
deny | しない | リクエストの記録のみ。その URL について取り込みを行った機械から 出たものは無く、それを通じて取り込みを知ったオリジンも在りません。 |
no-archive | する | リクエストの記録のみ。オリジンは応答しましたが、パッケージは その応答を保持しません。 |
no-body | する | request / response のレコード。ただし response の本文は含みません。 |
この配列は空のときでも存在して MUST、 空の配列は「効いていた policy が無い」という意味で MUST。この規則が無いと読み手は、 特別なものを何も要求しなかったページと、要求されたものを記録しないことにした 取り込みとを区別できません。同じパッケージについての、別の主張です。
順序は取り込みがパターンを評価した順であり、取り込みは 一致した最初の項目を適用して MUST。 順序を記録することが、複数のパターンが当たりうる URL について 「どの policy が適用されたのか」に読み手が答えられる根拠になります。
"urlPolicies": [
{ "pattern": "*://cdn.example.com/tracker.js", "action": "deny" },
{ "pattern": "*://cdn.example.com/*", "action": "no-body" }
]
この例では tracker.js へのリクエストは一度も送られず、
同じホストの他のものは取得されて本文なしで記録されます。2 つを入れ替えると
取り込みがしたことが変わります —— 広いほうのパターンが先に当たり、
tracker は取得されます。
contentTypePolicies
contentTypePolicies は、prefix
(応答のメディア型に当てる)と action を持つ項目の配列です。
この版が定める action は no-body のみ ——
メディア型は応答が届いてからしか分からないので、deny は
適用できません。
この配列も、空のときでも存在して MUST。 理由は urlPolicies と同じです。
"contentTypePolicies": [
{ "prefix": "video/", "action": "no-body" }
]
deny または no-archive の policy が適用された
リクエストのそれぞれについて、パッケージは WARC の metadata
レコード —— 以下 withheld request のレコード —— を
MUST 含みます。その
WARC-Target-URI はリクエストの URL で
MUST、application/warc-fields の
本文は次を MUST 含みます:
| Field | 必須 | 説明 |
|---|---|---|
action | はい | 適用された action: deny または
no-archive。リクエストが送られたかどうかを
述べるのはこの欄です。 |
pattern | はい | 一致したパターン。urlPolicies に現れるとおりの綴りで、 読み手がそちらで引き当てられるように。 |
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: 112 action: deny pattern: *://*.example-analytics.com/* method: POST resourceType: XHR
withheld request のレコードはレスポンスも本文も持ちません。主張しているのは、 ページがその URL を要求したこと、そしてこのプロファイルの producer が それについて何をするか決めたこと —— リクエストが失敗したという意味でも、 オリジンが何も返さなかったという意味でもありません。オリジンに到達 できなかった取り込みは、これをこの形で報告しては MUST NOT。
no-body の policy はこの種のレコードを生みません。
request / response のレコードは通常どおり書かれ、欠けている本文は
他の欠けている本文と同じ形で報告されます。
withheld 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 の版を秘匿したい運用者は、適合するパッケージがそれを開示することを知っておく
必要があります。