Skip to content

ADR-0003: EDItEUR スキーマの取得方法 (要判断) - #58

Merged
kogai merged 14 commits into
mainfrom
claude/adr-schema-acquisition
Sep 13, 2026
Merged

kogai merged 14 commits into
mainfrom
claude/adr-schema-acquisition

Conversation

@kogai

@kogai kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner

この PR にはメンテナの判断が必要です。 実装は含まず、制約の記録と選択肢の提示だけを行います。

base は #56 (claude/bump-deprecated-github-actions) です。docs/adr/ が #56 で追加されるため。

なぜ書いたか

コード生成が 2 方向から塞がっていて、どちらもバージョンを変えれば直る類のものではありません。次に誰かが着手する前に、観測した事実と各選択肢のコストを残します。

1. CI から: 202 Accepted が返る

WARNING: Download from https://www.editeur.org/files/ONIX%202.1/...Issue_36.zip
         failed: UnrecoverableHttpException GET returned 202 Accepted

zip の代わりに 202 が返り、Bazel は回復不能なエラーとして扱います。1 回再実行して同じ結果だったので、一時的な不調ではありません。

2. 開発環境から: そもそも到達できない

egress ポリシーで www.editeur.org:443 への CONNECT が 403 拒否されます。URL の確認も、http_archive が要求する sha256 の計算もできません。

この結果、コード生成と最新スキーマへの追従 (現在 2.1 Issue 36 / 3.0 Issue 52、EDItEUR の最新は 3.1.3 + codelists Issue 73) が止まっています。ユニットテストは #56 で切り離したので影響を受けません。

なぜ Proposed のままか

恒久的な解決策の有力な 2 つ (vendoring / ミラー) は、いずれも第三者の配布物の再配布にあたります。これは技術的な選択ではなくライセンスの判断で、メンテナが行うべきものです。ここで勝手にファイルをコミットすると、判断を経ずに既成事実にしてしまいます。

なお User-Agent を偽装して 202 を回避する案は、明示的に却下しました。配布元が設けたアクセス制御を、権利者の意図を確認せずに迂回する行為だからです。

暫定運用

--distdir を推奨します。EDItEUR が意図する配布経路 (ブラウザでのダウンロード) をそのまま使い、何も回避せず、リポジトリに再配布物も置かず、sha256 による検証も効いたままです。

mkdir -p third_party/distdir
mv ~/Downloads/ONIX_BookProduct_XSD_schema+codes_Issue_52.zip third_party/distdir/
npx bazelisk build --distdir=third_party/distdir onix_v3

schema/v2 / schema/v3 を手で置いた場合も動きます。

確認したこと

  • 「ディレクトリが既に存在すれば make はダウンロードを試みない」を、schema/% パターンルールを再現したスクラッチ Makefile で実際に検証しました。v2 だけ存在する状態では v3 のみ取得する、という粒度でも期待どおりでした。
  • editeur.org の URL 一覧と最新リリースの正確な zip 名は確認できていません (到達不可)。ADR 中の Issue 73 / 3.1.3 は Web 検索由来の情報で、一次情報での裏取りができていません。

判断していただきたいこと

  1. スキーマをリポジトリに取り込む (vendoring) — ライセンス上問題ないか
  2. ミラーを用意する — 維持する意思があるか
  3. 当面 --distdir 運用のままにする

いずれかが決まれば ADR を Accepted に更新し、最新スキーマへの追従に着手できます。

🤖 Generated with Claude Code

https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z


Generated by Claude Code

kogai and others added 4 commits September 13, 2026 06:49
Both CI jobs currently fail two seconds after starting, before any build
step runs:

    ##[error]This request has been automatically failed because it uses a
    deprecated version of `actions/cache: v2`.

GitHub has closed down actions/cache v1 and v2 and now auto-fails runs
that reference them at action-download time, so the workflow cannot get
as far as `make test` or the bazel e2e target.

Bump actions/cache to v4 to unblock that, and bump the remaining actions
still on the Node 12 runtime at the same time:

- actions/checkout v2 -> v4
- actions/setup-node v2.1.4 -> v4
- haskell/actions/setup v1 -> haskell-actions/setup v2 (repository moved)

Tool versions are left as they are (GHC 8.8.3, stack 2.5.1, Node 12.x) so
this change is limited to action versions. haskell-actions/setup v2 still
exposes the stack-path output the cache step depends on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
With the deprecated actions bumped, the Haskell job now reaches `make
test` and fails there instead: `make test` depends on the `schema`
target, which fetches the EDItEUR archives, and editeur.org now answers
bazel's request with `202 Accepted` instead of the zip.

The test suite does not need those archives. Everything under test/ reads
fixtures/test_*.xsd; the only reader of ./schema is schemaRoot in
src/Lib.hs, which is the code-generation path. The dependency was an
over-specification that tied the whole feedback loop for the parser to
the availability of an external service.

Drop it from `test` and keep it on `build`, where generating code really
does need the schema. This does not fix the 202 itself: generation and
tracking new schema releases still need the download.

Also introduce docs/adr/ to record decisions like this one, with a
template, an index, and the two decisions made here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
Code generation is blocked from two directions and neither is fixable by
picking a different version number, so write down what was observed and
what the options cost before anyone tries again.

From CI, editeur.org answers bazel's request with `202 Accepted` instead
of the zip, and repeating the run reproduced it, so it is not transient.
From the development sandbox the host is refused outright by the egress
policy, which also means the sha256 that http_archive requires cannot be
computed here.

The ADR stays Proposed on purpose: the two durable fixes (vendoring the
schemas, or hosting a mirror) both redistribute a third party's files,
and that is a licensing call for the maintainer rather than something to
settle by committing files. Spoofing a User-Agent to get past the 202 is
listed and rejected — it circumvents an access control the publisher put
there.

As an interim, the ADR documents bazel's --distdir, which reuses a
manually downloaded zip while keeping the sha256 check intact. It also
notes that a hand-placed schema/ directory is honoured; verified with a
scratch Makefile reproducing the `schema/%` pattern rule, which skips a
target whose directory already exists, per directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
The previous commit dropped the `schema` prerequisite from `make test` on
the claim that nothing under test/ reads schema/. That claim was wrong,
and review caught it: fixtures/test_mixed_html.xsd included
../schema/v2/ONIX_XHTML_Subset.xsd directly. Xsd.getSchema follows
includes recursively and resolves that relative path with readFile, which
throws when the file is absent, and schema/ is gitignored — so on a clean
checkout the suite would have failed instead of running.

Commit 9352123 confirms the dependency was deliberate: it added
`test: schema` in the same change that deleted the vendored
2_1_rev03_schema/ tree and repointed this fixture at ../schema/v2/.

Rather than restore the prerequisite, move what the fixture needs into
the repository. test_mixed_html_xhtml_subset.xsd declares the 40 element
names the fixture refers to, each as a mixed complex type. That is the
property the assertions actually rest on: TestModel expects
Model.collectElements to come back empty, and that filter keeps only
elements with complexMixed = False, so the test means "XHTML elements do
not leak into models". Deleting the include instead would have made the
assertion vacuous.

The stand-in is written here rather than copied from the EDItEUR
distribution, so it raises no redistribution question.

ADR-0002 is rewritten around what is actually true, including why the
dependency was real and why a stand-in is enough.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner Author

レビュー

全体として、この ADR は正確で、推論も妥当です。技術的な主張の中核 — schema/% パターンルールの挙動、--distdir が sha256 検証を保ったまま機能すること、Bazel 3.7.0 の http_archive がカスタムヘッダを持たないこと、202 が回復不能エラーになること — は、実際に手を動かすか Bazel 3.7.0 のソースにあたるかして全部裏が取れました (詳細は末尾)。決定を保留してライセンス判断をメンテナに返す構成も、この件の性質に合っています。ただし Accepted に進める前に直したい点が 2 つあります。1 つは上流バージョンの記述が、この ADR 自身が「到達できない」と言っている情報を断定で書いていること、もう 1 つは**「手で用意した場合も動く」という手順が、そのとおりにやると動かないこと**です。残りは、あれば次の人が助かる、という水準の追記です。


findings

1. 【必須】上流バージョンが断定で書かれている

docs/adr/0003-editeur-schema-acquisition.md「背景」:

  • 最新スキーマへの追従 (現在 ONIX 2.1 Issue 36 / 3.0 Issue 52。
    EDItEUR の最新は ONIX 3.1.3 + codelists Issue 73)

前半 (Issue 36 / Issue 52) は WORKSPACE から確認でき、正しいです。問題は後半で、同じ ADR の 8 行上で「egress ポリシーにより www.editeur.org:443 への CONNECT が 403 で拒否される」「URL の確認も…できない」と書いておきながら、その確認できないはずの情報を断定形で置いている点です。PR 本文には「Web 検索由来で一次情報での裏取りができていない」と書かれていますが、PR 本文は残りません。残るのは ADR のほうです。

私のほうで第三者情報源にあたった限り、ONIX 3.1.3 (2026-03) も codelists Issue 73 (2026-04) も実在するようで、内容としては当たっている可能性が高いです。ただし**WORKSPACE の書き換えに実際に必要なのは zip の URL とファイル名で、そこは完全に不明**のままです。「最新は 3.1.3」と読んだ次の人が、その 1 行を根拠に URL を組み立てて詰まる、という壊れ方をします。

書き換え案:

- 最新スキーマへの追従 (現在 ONIX 2.1 Issue 36 / 3.0 Issue 52)。
  上流の最新版は、二次情報では ONIX 3.1.3 + codelists Issue 73 とされるが、
  editeur.org に到達できないため一次情報では未確認。追従の際は、
  バージョンだけでなく zip の URL とファイル名を editeur.org 上で確認すること
  (現在の WORKSPACE の URL がそのまま使える保証もない)。

2. 【必須】「手で用意した場合も動く」が、そのとおりにやると動かない

「決定」節:

schema/v2 / schema/v3 を手で用意した場合も動く。schema/% は prerequisite を持たない
パターンルールなので、ディレクトリが既に存在すれば make はそのターゲットを最新とみなし、
ダウンロードを試みない。

後半の make の挙動についての主張は完全に正しい (再現して確認済み、末尾参照)。問題は前半の「手で用意した場合も動く」で、必要なレイアウトが書かれていないことです。実際にはフラットに、この名前で置く必要があります。src/Lib.hs:

    schemaRoot =
      "./schema"
        ++ ( case version of
               V2 -> "/v2/ONIX_BookProduct_Release2.1_reference.xsd"
               V3 -> "/v3/ONIX_BookProduct_3.0_reference.xsd"
           )

一方 EDItEUR の zip は ONIX_BookProduct_XSD_schema+codes_Issue_52/ というトップレベルディレクトリを含んでいます (org_editeur_v3.bazel の glob がその prefix 付きで書かれていることから分かる)。つまり素直に unzip -d schema/v3 すると schema/v3/ONIX_BookProduct_XSD_schema+codes_Issue_52/*.xsd になり、Lib.hs は読めません。BUILD.bazel の genrule が cp $(SRCS) $(RULEDIR)/v3 で平坦化しているのが本来の形です。

書き換え案 (該当段落を差し替え):

`schema/v2` / `schema/v3` を手で用意することもできる。`schema/%` は prerequisite を持たない
パターンルールなので、ディレクトリが既に存在すれば make はそのターゲットを最新とみなし、
ダウンロードを試みない (`schema/v2` だけ存在する状態なら `schema/v3` だけ取得する)。

ただし zip をそのまま展開しただけでは動かない。zip はトップレベルに
`ONIX_BookProduct_XSD_schema+codes_Issue_52/` のようなディレクトリを含むが、
`src/Lib.hs` が読むのは `./schema/v3/ONIX_BookProduct_3.0_reference.xsd` (v2 は
`./schema/v2/ONIX_BookProduct_Release2.1_reference.xsd`) なので、
BUILD.bazel の genrule と同じく **xsd を平坦に置く**必要がある。

    unzip -j ONIX_BookProduct_XSD_schema+codes_Issue_52.zip '*/*.xsd' -d schema/v3

3. 【推奨】--distdir が make build に効かない

「決定」節の暫定運用:

npx bazelisk build --distdir=third_party/distdir onix_v3

このコマンド単体は正しいのですが、生成を回す入口は make build であって、Makefile にはフラグを渡す口がありません:

schema/%:
	mkdir -p schema
	$(BZL) build onix_$(@F)
	cp -r $(BZL_BIN)/$(@F)/ schema/$(@F)/

ADR のコマンドを打っても bazel-bin/v3 ができるだけで schema/v3 はできず、続けて make build を叩くと $(BZL) build onix_v3 がフラグなしで走ります。実際には一度 fetch 済みの external repo と repository cache に当たるので結果的に通りますが、それは ADR に書かれていない副作用に頼っている状態です。.bazelrc に置けば Makefile 経由でも自動で効きます (現状の .bazelrc は --verbose_failures 3 行のみ):

# .bazelrc
common --distdir=third_party/distdir

なお --distdir の相対パスは cwd ではなくワークスペースルート基準で解決されるので (BazelRepositoryModule.java で確認)、.bazelrc に相対パスで書いて問題ありません。

あわせて 1 行足しておくと親切な失敗モードがあります。指定したディレクトリが存在しない場合、Bazel はエラーにせず INFO: non-existent distdir <dir> を出してネットワークに出ます。つまりパスを間違えると、症状は元の 202 エラーとまったく同じに見えます。

4. 【推奨】third_party/distdir が .gitignore に入っていない

mkdir -p third_party/distdir
mv ~/Downloads/ONIX_BookProduct_XSD_schema+codes_Issue_52.zip third_party/distdir/

.gitignore には /schema はありますが third_party/ はありません。「ライセンス判断を経ずに再配布を既成事実にしない」というのがこの ADR の主旨なのに、その ADR が勧める手順が、リポジトリ内に untracked の EDItEUR zip を置かせるという形になっています。.gitignore に /third_party/distdir/ を足すか、リポジトリ外 (~/.cache/onix-codegen/distdir など) を勧めるかのどちらかにしてください。前者なら ADR にその 1 行も併記を。

5. 【推奨】検討漏れ: --override_repository

「検討した他の選択肢」に --override_repository がありません。Bazel 3.7.0 に存在します (RepositoryOptions.java: help = "Overrides a repository with a local directory.")。

これは --distdir の劣化版ではなく、性質が違うので独立に挙げる価値があります。--distdir は「WORKSPACE の sha256 と一致する zip」を要求しますが、この ADR が挙げている制約はまさに「http_archive が要求する sha256 の計算もできない」です。つまり上流の新版に追従しようとした瞬間、--distdir は使えなくなります (新しい zip の sha256 が WORKSPACE にまだ書けないので)。--override_repository は sha256 を通らないため、その局面で唯一動く手になります。

npx bazelisk build --override_repository=org_editeur_v3=/abs/path/to/unpacked onix_v3

トレードオフも明記が要ります: (a) 同一性検証が一切効かない、(b) http_archive の build_file = "//:org_editeur_v3.bazel" は適用されないので、指定ディレクトリ側に BUILD.bazel を自分で置く必要がある。日常運用は --distdir、新版の sha256 が未知のあいだの調査用に --override_repository、という書き分けが実態に合うと思います。

6. 【推奨】e2e の守備範囲が実際より広く書かれている

「結果」節:

  • CI で検証できるのは、ユニットテスト (ADR-0002) と、コミット済み生成物に対する
    e2e スナップショット (//e2e/go:snapshot_test) の 2 つ。後者は生成物の実行時の挙動を
    守り続けるので、生成が止まっている間も回帰は検出できる。

e2e/go/BUILD.bazel の helper_lib の deps は ["//generated/go/v2:go"] の 1 つだけです。つまり守られているのは generated/go/v2 だけで、generated/go/v3 と generated/typescript/v2 は CI で一切触られていません。「生成物の実行時の挙動」と書くと全体をカバーしているように読めます。

後者が守るのは generated/go/v2 の実行時の挙動に限られる (//e2e/go:snapshot_test は
//generated/go/v2:go にしか依存していない)。generated/go/v3 と
generated/typescript/v2 には CI の網がかかっていない。

7. 【推奨】追従の障害は取得だけではない

vendoring かミラーのいずれかが決まれば、CI でも生成と差分確認ができるようになり、

取得が解決しても、3.0 Issue 52 → 3.1.x への移行にはバージョン番号がハードコードされた箇所の書き換えが別途要ります。次の人がここを見積もれるよう、1 行足しておくと良いです。

  • org_editeur_v3.bazel — glob の prefix ONIX_BookProduct_XSD_schema+codes_Issue_52/
  • BUILD.bazel — filegroup onix3p0p7 の 8 ラベル (と、名前自体が 3p0p7)
  • src/Lib.hs — "/v3/ONIX_BookProduct_3.0_reference.xsd"

8. 【任意】User-Agent 却下の論拠は妥当。ただし技術的な補強ができる

ただし Bazel 3.7.0 の http_archive はカスタムヘッダに対応しておらず、独自の
repository rule が要る。何より、配布元が設けたアクセス制御を迂回する行為であり、
権利者の意図を確認せずに実装すべきではない。採らない。

却下の理由づけ (権利者の意図を確認せずに回避しない) には全面的に同意します。手段の可否ではなく是非で切っているのが正しい。技術的主張のうち「カスタムヘッダに対応していない」も正しいです (3.7.0 の http_archive にあるのは netrc / auth_patterns のみで、これは Authorization ヘッダしか生成しません)。

2 点だけ精度の話:

  • 「独自の repository rule が要る」は少し不足で、独自 repository rule を書いても足りません。repository_ctx.download の auth も同じく Authorization 専用なので、User-Agent を差し替えるには repository_ctx.execute(["curl", ...]) で外部コマンドに逃がす必要があります。「Bazel のダウンローダを捨てて curl を呼ぶしかない」と書くほうが、コストが正しく伝わります。
  • そもそも効かない可能性が高いという補強ができます (Gen fields of type #9)。

9. 【任意】202 の原因説明が一般論として断定されている

202 を返すのは bot 対策の中間応答として
一般的な挙動で、GitHub Actions のような自動化された経路が弾かれていると考えられる。

末尾は「考えられる」で推論とわかりますが、「一般的な挙動で」は断定です。bot 対策で一般的なのは 403 / 429 / 503 で、202 はむしろ珍しく、特定製品の挙動です。具体的には AWS WAF の Challenge アクションが、トークンが無い/失効しているリクエストに x-amzn-waf-action: challenge ヘッダ付きで HTTP 202 を返します。

これを名指しすると 2 つ得があります。(a) 次の人が curl -I でレスポンスヘッダを見れば原因を確定できる。(b) もし AWS WAF Challenge なら、通過には JS で生成する aws-waf-token が必要で、User-Agent の詐称では突破できません — #8 の却下が、倫理面だけでなく技術面でも裏打ちされます。

202 は bot 対策の中間応答として返されることがある (例: AWS WAF の Challenge アクションは
x-amzn-waf-action: challenge 付きで 202 を返す)。GitHub Actions のような自動化された
経路が弾かれていると考えられるが、原因は未確定。到達できる環境から
curl -sI <url> でレスポンスヘッダを見れば確定できる。

10. 【任意】sha256 省略の却下理由をもう一段強くできる

sha256 を省略する: http_archive は sha256 なしでも動くが、202 の問題は解決しないうえ、
取得物の同一性検証を捨てることになる。採らない。

もう 1 つ、この ADR にとって重要な理由があります。Bazel 3.7.0 の DownloadManager.download() では、distdir を探索するコード全体が if (checksum.isPresent()) の内側にあります。つまり sha256 を消すと、この ADR が推している --distdir が丸ごと無効化されます。「同一性検証を捨てるうえ、本 ADR が推奨する --distdir も同時に使えなくなる」と足しておくと、選択肢どうしの関係が閉じます。


検証したこと / できなかったこと

検証できたこと

主張 方法 結果
WORKSPACE の http_archive 引用 git show <ref>:WORKSPACE 一致。sha256 = "8fe93242..." は 8fe932426066538a1d4ef17f41a70432d3eef7bb09c54e9262b24cc883cdb461 の省略で正しい (引用が build_file = "//:org_editeur_v2.bazel" を省いている点だけ、#5 との関係で注意)
現行版が 2.1 Issue 36 / 3.0 Issue 52 同上 (URL とファイル名) 正しい
test が schema に依存しない / build は依存する git show <ref>:Makefile 正しい (build: schema .stack-work、test: は prerequisite なし)
schema/% はディレクトリがあれば再取得しない 自前のスクラッチ Makefile で再現 (リポジトリ外の一時ディレクトリ、GNU Make 4.3)。$(BZL) を @echo に差し替えて実行 正しい。 初回は v2/v3 とも実行 → 2 回目は make: Nothing to be done for 'schema'. → rm -rf schema/v3 後は v3 のみ実行。PR 本文の「v2 だけ存在する状態では v3 のみ取得する」も再現した
--distdir が Bazel 3.7.0 に存在する RepositoryOptions.java @ tag 3.7.0 存在する。 name = "distdir", oldName = "experimental_distdir", help: "Additional places to search for archives before accessing the network to download them."
--distdir でも sha256 検証が効く DownloadManager.java @ 3.7.0 効く。 distdir 探索は if (checksum.isPresent()) の内側にあり、採用条件は RepositoryCache.getChecksum(cacheKeyType, candidate).equals(cacheKey)
置く zip のファイル名 同上 (getCandidateFileNames) URL の basename と一致が必要。ONIX_BookProduct_XSD_schema+codes_Issue_52.zip で正しい (URL の %20 はディレクトリ部分だけなので basename に影響しない)
ディレクトリが無い場合エラーになるか 同上 エラーにならない。 eventHandler.handle(Event.info("non-existent distdir " + dir)) を出して、そのままネットワークにフォールバックする → #3 に記載
--distdir の相対パス基準 BazelRepositoryModule.java @ 3.7.0 ワークスペースルート基準 (env.getBlazeWorkspace().getWorkspace().getRelative(path))
3.7.0 の http_archive はカスタムヘッダ非対応 tools/build_defs/repo/http.bzl @ 3.7.0 正しい。 認証系の属性は netrc と auth_patterns のみ、後者のドキュメントは "as the value for the Authorization field of the HTTP request" — User-Agent は設定不可。なお Bazel 自身は User-Agent: Bazel/<version> を固定送信 (HttpConnectorMultiplexer.java)
202 が回復不能エラーになる HttpConnector.java @ 3.7.0 正しい。 200/206 のみ成功、3xx はリダイレクト、それ以外の code < 500 は throw new UnrecoverableHttpException(...) に落ちる。202 はここ。リトライされないので「1 回再実行しても同じ」も整合する
--override_repository の存在 (#5) RepositoryOptions.java @ 3.7.0 存在する
//e2e/go:snapshot_test の依存 git show <ref>:e2e/go/BUILD.bazel //generated/go/v2:go のみ → #6
/schema が gitignore 済み / third_party は未登録 git show <ref>:.gitignore そのとおり → #4

検証できなかったこと

  • editeur.org 上の実際の URL・zip 名・レスポンス。この環境からも www.editeur.org / ns.editeur.org とも curl: (56) CONNECT tunnel failed, response 403 で、ADR の言うとおり到達できません。したがって 202 が今も返るのか、x-amzn-waf-action が付いているのかは未確認です。
  • ONIX 3.1.3 / codelists Issue 73 の一次情報。二次情報 (BookNet Canada の Issue 73 リリース記事 2026-04-13、および ONIX 3.1.3 の変更点をまとめた第三者ミラー) では両方とも実在するようで、ADR の記述はおそらく正しいです。ただし一次情報にあたれていないこと、そして実務上必要な zip の URL とファイル名はまったく不明であることは変わりません。Configure Renovate #1 はこの状況を ADR 側に明記してほしい、という指摘です。
  • --distdir の実挙動の実地確認。ソース読解のみで、実際に Bazel 3.7.0 を動かしての確認はしていません (アーカイブ取得自体がこの環境から不可能なため)。

Generated by Claude Code

kogai and others added 3 commits September 13, 2026 07:12
BZL_BIN used `:=`, so `$(shell npx bazel info bazel-bin)` ran while make
parsed the file — on every target, `make test` included. The Haskell job
runs `make test` without ever installing node_modules, so that expansion
just fails there. Measured in this environment: `make -n test` took
18.1s and printed a bazel download error before doing anything, and
0.011s with the assignment deferred to `=`. Nothing outside the schema
recipes reads BZL_BIN, so deferring it costs nothing.

Also drop the `ls -lah` step that printed the stack tool path; it was
debugging output for the cache setup, not a check anything depends on.

Both spotted in review of this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
The two things that would have misled a reader:

The ADR asserted "EDItEUR の最新は ONIX 3.1.3 + codelists Issue 73" flatly,
eight lines after saying editeur.org is unreachable. Secondary sources do
corroborate the version, but the zip URL, filename and sha256 — what
WORKSPACE actually needs — are unknown, so say that instead.

"schema/v2 / schema/v3 を手で用意した場合も動く" was under-specified
enough to be wrong. The archives carry a top-level directory while
src/Lib.hs reads flat paths, matching what BUILD.bazel's genrule
flattens, so a plain unzip does not work. Spell out `unzip -j`.

Also: --distdir does not compose with `make build`, since the Makefile
passes no flags through, so point at .bazelrc; note that a missing
distdir is only an INFO, which makes a typo look exactly like the
original 202; add --override_repository as a distinct option, since it
skips the sha256 check and is therefore the one that works when chasing a
release whose checksum is not known yet; correct the claim that the e2e
snapshot guards the generated output, which holds only for
generated/go/v2; and record that the schema version is hardcoded in three
more places.

.gitignore now covers third_party/distdir, which the ADR tells people to
create.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner Author

レビューありがとうございます。必須 2 件と推奨 5 件すべて反映しました (116f35a)。

必須 1: バージョンの断定

ご指摘のとおりです。「到達できない」と書いた 8 行後に最新版を断定していては、読む人を騙します。次のように書き直しました。

追従先の最新版がどれかは、この ADR の時点では確定できていない。二次情報では ONIX 3.1.3 + codelists Issue 73 (2026-04) とされているが、editeur.org に到達できない以上、一次情報での裏取りができていない。そして WORKSPACE が実際に必要とするもの、すなわち zip の URL とファイル名、その sha256 は完全に不明である。

必須 2: 手動配置の手順が動かない

これも確認しました。決定的だったのは genrule です。

$ grep -A4 'name = "onix_v3"' BUILD.bazel
    cmd = "mkdir $(RULEDIR)/v3 && cp $(SRCS) $(RULEDIR)/v3",
$ grep -n 'ONIX_BookProduct_3.0_reference' src/Lib.hs
85:               V3 -> "/v3/ONIX_BookProduct_3.0_reference.xsd"

cp $(SRCS) が平坦化した結果に Lib.hs が合わせているので、zip をそのまま unzip すると階層がひとつ深くなって読めません。unzip -j を使う手順に差し替えました。動かない手順を書いた ADR は、無いより悪いので、これは必須の指摘だと思います。

推奨

  • --distdir が make build と噛み合わない: そのとおりで、Makefile にフラグの素通し口がありません。.bazelrc に common --distdir=... と書く方法を追記しました。存在しない distdir が INFO で素通りする点も、元の 202 と見分けがつかない失敗になるので明記しました。
  • third_party/distdir が gitignore されていない: ADR 自身の指示が EDItEUR の zip を untracked で置かせる形になっていました。.gitignore に追加しました。
  • --override_repository: 選択肢に追加しました。ご指摘のとおり --distdir の変種ではなく、sha256 の検証を経由しない点が本質です。この ADR の出発点が「sha256 が計算できない」ことなので、新しいリリースを追う場面ではこちらしか使えません。「既知の版を再現するなら --distdir、未知の版を試すなら --override_repository」と使い分けを書きました。
  • e2e カバレッジの誇張: //e2e/go:snapshot_test の依存は //generated/go/v2:go だけで、generated/go/v3 と generated/typescript/v2 は無カバレッジです。「生成物の回帰を検出できるのは Go の v2 に限られる」と訂正しました。
  • 版が 3 箇所にハードコード: org_editeur_v3.bazel の glob、BUILD.bazel の onix3p0p7、Lib.hs の schemaRoot。「取得の問題が解けても追従はそれだけでは終わらない」として結果セクションに追記しました。

任意

  • repository_ctx.download の auth も Authorization 専用: 却下の理由は変えず(正当性の問題であって実現可能性の問題ではないため)、技術的な補足として「独自 rule を書いても足りず結局 curl を呼ぶことになる」を追記しました。
  • sha256 省略と distdir の関係: distdir 探索が sha256 のある場合にしか走らない、という指摘を却下理由に追加しました。自分の推奨策を自分で無効化する、というのは説得力のある論拠です。
  • AWS WAF の Challenge (202 + x-amzn-waf-action: challenge): 診断方法として有用なのは同意ですが、curl -sI で確かめられない(到達不可)以上、また推測を 1 つ増やすことになるため、今回は入れませんでした。原因の断定は避け、観測事実に留めています。到達できる方が確認できたら追記したいところです。

Generated by Claude Code

kogai and others added 3 commits September 13, 2026 07:39
ADR-0003 records that CI gets 202 Accepted instead of the archive, and
that this environment cannot reach the host at all to check anything
first-hand — not the URLs, not the current release, not the sha256. That
leaves the ADR resting partly on secondary sources, and leaves the next
step guessing.

A CI runner can reach the host, so ask it. This job issues plain GETs and
prints the status, headers and first bytes of what comes back, then lists
the zip links the download pages advertise. No headers are forged and
nothing is worked around; it only observes.

Manual trigger only, so it never runs on push. It is deleted again in the
next commit once it has produced its output, and the findings go into
ADR-0003.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
workflow_dispatch cannot be dispatched through the API for a workflow
that does not exist on the default branch, so the run never started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
The probe ran and answered the question the ADR had been guessing at. The
202 is a CAPTCHA challenge:

    HTTP/2 202
    server: nginx
    sg-captcha: challenge
    x-robots-tag: noindex
    <meta http-equiv="refresh"
      content="0;/.well-known/sgcaptcha/?r=%2Ffiles%2F...zip&y=ipc:...">

It is not specific to the archives: the download page itself answers the
same way, and the redirect embeds the requesting runner's IP, so the
decision is made about the caller rather than the file.

That settles three things the ADR previously left open. The URLs are not
stale, so pointing at a newer release changes nothing. Retries and mirror
URLs cannot help. And CI can never fetch these archives without solving
the CAPTCHA — which is precisely the control the publisher put there, so
that route is closed on purpose rather than by accident.

It also makes the User-Agent option moot on its own terms: passing the
challenge needs JavaScript and a cookie, not a header. The reason for
rejecting it is unchanged, but it is no longer only a matter of
principle.

The practical consequence, now recorded: manual acquisition is not a
stopgap until something is fixed upstream. It is permanent unless the
schemas are vendored or mirrored — which is the licensing decision this
ADR is waiting on.

The probe workflow is removed again in the same change; it existed only
to produce that output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner Author

202 の正体が判明しました: SiteGround の CAPTCHA

推測のまま残すのが嫌だったので、CI ランナーから素の GET を投げて確認しました(一時的なワークフローを追加して 1 回実行し、同じコミットで削除しています。ヘッダの偽装などは一切していません)。

HTTP/2 202
server: nginx
sg-captcha: challenge
x-robots-tag: noindex
content-type: text/html
content-length: 248

<html><head><meta http-equiv="refresh"
  content="0;/.well-known/sgcaptcha/?r=%2Ffiles%2FONIX%202.1%2F...zip&y=ipc:132.196.94.33:...">
</head></html>

これで確定したこと

ファイル固有の問題ではありません。 同じ応答が返るのは zip だけでなく、ダウンロードページ /93/Release-3.0-and-3.1-Downloads/ 自体も同様でした(そのためページから zip リンクを抽出する試みも空振りしています)。sg-captcha: challenge と、リダイレクト先に埋め込まれたランナーの IP (y=ipc:132.196.94.33) から、判定はリクエスト元に対して行われていると分かります。

したがって、

  1. URL が古いから失敗しているのではありません。 最新リリースの URL に変えても結果は同じです。この PR が「最新版の zip 名が不明」としていた点は、そもそも解決しても意味がありませんでした
  2. リトライやミラー URL の追加では解決しません
  3. CI から自動でダウンロードすることは、CAPTCHA を解かない限り不可能です。 そして CAPTCHA は、まさに配布元が自動アクセスを制限するために置いたものです

判断への影響

これは当面の不便ではなく恒久的な制約です。「そのうち直る」類の問題ではないので、判断を先送りするほど生成系が止まり続けます。ADR の「結果」にもその旨を明記しました。

選択肢は実質 2 つに絞られます。

  1. スキーマをリポジトリに取り込む(vendoring) — ライセンス確認が必要
  2. ミラーを用意する — 同上 + 維持コスト
  3. (現状維持)メンテナが手元に zip を用意できる環境でのみ生成系が動く

なお User-Agent 偽装案は、原則の問題である以前に技術的にも成立しません。CAPTCHA の通過には JS の実行とクッキーの保持が要り、ヘッダを 1 つ足して済む話ではありませんでした。却下理由は変えていませんが、単なる建前ではなくなっています。

この PR の状態

ADR-0003 を推測ではなく観測事実に基づく内容に書き直しました。プローブ用ワークフローは同じコミットで削除済みなので、この PR の差分は docs/adr/ と .gitignore だけです。

判断をお願いします(1 / 2 / 3 のいずれか)。決まり次第、ADR を Accepted に更新して最新スキーマへの追従に着手します。


Generated by Claude Code

Base automatically changed from claude/bump-deprecated-github-actions to main September 13, 2026 10:36

@kogai kogai left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

提案を承認

Both .gitignore additions are kept: node_modules/ from the npm work on
main, /third_party/distdir/ from this branch's ADR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z
Leaving the blocker at 'this needs a licensing decision' was too vague to
act on, so look up the terms instead.

EDItEUR describes the specifications and tools as free under a
'highly-permissive licence', no registration and no royalties, which
reads as though redistribution were fine. The licence text itself is
narrower: it has the user agree not to copy any part of the DTD or XML
Schema for use outside strictly internal use in their own organisation,
and to notify EDItEUR first for anything beyond that.

If that is right, it moves both durable options. Vendoring into a public
repository and hosting a mirror are not 'strictly internal', so they
likely require notifying EDItEUR rather than merely reading a licence —
which is more reason for the maintainer to make this call, not less. The
--distdir route is unaffected: the maintainer downloads for their own
use and nothing is redistributed.

This is secondary-source reading. editeur.org, where the actual licence
lives, is unreachable from here, and the ADR says so.

Also correct the codelist issue number: newer information puts Issue 74
as the current one for 3.0 and 3.1, not 73.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner Author

ライセンス条件を調べました(判断が軽くなるどころか、重くなりました)

「ライセンスの判断が要る」で止めるのは雑だったので、条件そのものを調べました。期待とは逆の結果です。

EDItEUR は対外的に「仕様・ツールは無料、登録不要、ロイヤリティ不要、highly-permissive licence」と説明しており、ここだけ読むと再配布も問題なさそうに見えます。しかし利用許諾の本文とされる記述は、はるかに限定的でした。要旨は以下です。

DTD または XML Schema の一部を、自組織内での厳密に内部的な利用を除いて、追加・削除・改変したり、外部での利用のために複製したりしないことに同意する。内部的でない目的で追加・改変・抜粋を行いたい場合は、まず EDItEUR に通知すること。

これが正しければ、判断の性質が変わります。

選択肢 影響
リポジトリへの取り込み(vendoring) 公開リポジトリは「厳密に内部的な利用」ではない → EDItEUR への事前通知が要る可能性が高い
ミラー設置 同上(加えて維持コスト)
--distdir 運用 影響なし。 メンテナが自分で使うために手元に落とすだけで、何も再配布しない

つまり前 2 つは「ライセンスを読めば済む」話ではなく、権利者への連絡を伴う行為でした。こちらの一存で進めなくて正解だったと思います。

重要な限定: これは二次情報です。一次情報である editeur.org には到達できません(この PR で実証したとおり CAPTCHA で塞がれています)。ADR にもその旨を明記しました。実際に vendoring / ミラーへ進むなら、まず一次情報の確認を推奨します。

あわせて codelists の号数を訂正しました。当初 Issue 73 と書きましたが、より新しい情報では Issue 74 が 3.0 / 3.1 共通の現行版のようです。

この PR の現状

差分は docs/adr/ と .gitignore のみ。main(#55 / #56 / #57 のマージ後)を取り込み済みで、.gitignore の衝突は両方の追加を残す形で解決しています。

判断は変わらず vendoring(+通知)/ ミラー(+通知)/ --distdir 運用のまま の 3 択です。


Generated by Claude Code

Missed on the first pass: commit 9352123 (2021-01-19) deleted
2_1_rev03_schema/, and the full ONIX 2.1 rev03 set is still reachable
from its parent. Six XSDs, no network required, so v2 code generation can
be unblocked today with git alone.

It also sits differently from vendoring and mirroring on the licensing
question. Those would start redistributing; these files have been in this
repository's public history since 2021 and still are. Restoring them
acknowledges a publication that already happened rather than making a new
one. The maintainer deleted them deliberately, so it is still their call
— but it is a smaller one.

It does not reach the goal: only 2.1 is in the history, not 3.0 or 3.1.

Reading those recovered files also settles what the ADR could say about
the licence. readme.txt, readme2.txt and the XSD headers carry copyright
notices and nothing else — no grant of any kind. The licence text exists
only on editeur.org, which is unreachable, so the ADR's licensing
discussion stays secondary-source and now says so explicitly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner Author

見落としがありました: v2 のスキーマはこのリポジトリの履歴に残っています

「取得手段が無い」と繰り返し書いていましたが、足元を見ていませんでした。2021-01-19 のコミット 9352123 が 2_1_rev03_schema/ を削除しており、その親コミットから ONIX 2.1 rev03 の一式(XSD 6 本)がネットワークなしで取り出せます。

mkdir -p schema/v2
for f in ONIX_BookProduct_CodeLists.xsd ONIX_BookProduct_Release2.1_reference.xsd \
         ONIX_BookProduct_Release2.1_short.xsd ONIX_XHTML_Subset.xsd \
         ONIX_XHTML_Subset_reference.xsd ONIX_XHTML_Subset_short.xsd ; do
  git show 9352123^:2_1_rev03_schema/$f > schema/v2/$f
done

これで v2 のコード生成は今日から動きます(make schema を経由せずディレクトリを置けば make はダウンロードを試みません。検証済み)。

再配布の観点でも、他の選択肢と質的に違います

vendoring とミラーは「これから配布を始める」行為ですが、これらのファイルは 2021 年から現在まで、このリポジトリの公開履歴に存在し続けています。復元は新たな公開ではなく、既に起きている公開の追認です。判断は依然必要ですが、ずっと軽い判断です(意図的に削除された経緯があるため、そこは尊重します)。

ただし履歴にあるのは 2.1 だけで、3.0 / 3.1 はありません。 最新スキーマ対応には依然として取得手段が要ります。

ライセンス一次情報についての結論

復元したファイルで EDItEUR の配布物そのもの(readme.txt / readme2.txt / 各 XSD ヘッダ)を確認しました。記載は著作権表示のみで、許諾条項は含まれていません。

COPYRIGHT (c) EDItEUR 2005–2013
(c) 2004-2006 EDItEUR / http://www.editeur.org/

許諾の本文は editeur.org 上にしかなく、到達できない以上、この ADR のライセンス記述は二次情報のままです。ADR にもその限界を明記しました。

選択肢は 4 つになりました

  1. git 履歴から v2 を復元(新規の再配布ではない。v2 のみ)
  2. vendoring(+ EDItEUR への通知)
  3. ミラー(+通知)
  4. --distdir 運用(再配布なし)

3.0 / 3.1 に到達するには 2〜4 のいずれかが要ります。


Generated by Claude Code

kogai approved the proposal on #58, so the ADR moves to Accepted and the
interim it recommends stops being advice and becomes wiring:
.bazelrc gains build --distdir=third_party/distdir, and that directory
gets a README with the procedure. Archives stay gitignored, so nothing
from EDItEUR is committed and the sha256 check is untouched — a wrong
download still fails loudly.

What the approval covers is written into the ADR explicitly, because a
two-word approval on a document offering several options should not be
read broadly: --distdir is adopted, and the choice between vendoring and
a mirror stays open. Both of those likely require notifying EDItEUR, and
this ADR defers them by design; approving the document is not the same as
making that call.

Note the review landed on 1ba635d, before the two commits that added the
licence findings and the git-history recovery route. Both are material to
the deferred choice, so they are worth a second look.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 13, 2026

Copy link
Copy Markdown
Owner Author

承認ありがとうございます。狭く解釈して反映しました (8ccf915)。

何を承認されたものとして扱ったか

「提案を承認」だけでは 4 択のどれを指すか判断できないため、ADR が「決定」として書いていた内容、つまり以下を承認されたものとしました。

  • ✅ --distdir を正式な取得手段として採用
  • ⏸️ vendoring / ミラーの選択は保留のまま

後者を含めなかったのは、この ADR 自身がその判断を保留しており、かつ両者とも EDItEUR への通知を伴う可能性が高いためです。複数の選択肢を提示した文書への短い承認を、その中で最も踏み込んだ選択肢の承認として読むべきではないと判断しました。もし vendoring まで含むご意図だった場合は、その旨お知らせください。 すぐ実施します。

実装したこと

--distdir を「推奨」から「実際に動く経路」にしました。

# .bazelrc
build --distdir=third_party/distdir

third_party/distdir/ に手順を書いた README を置き、アーカイブ自体は gitignore(/third_party/distdir/* + README のみ除外)。EDItEUR のファイルは 1 つもコミットされず、sha256 の検証もそのままなので、誤ったダウンロードは静かに通らず失敗します。

ADR-0003 は Accepted に更新し、「何が承認され、何が保留か」を本文に明記しました。

ご確認いただきたい点

承認は 1ba635d に対するもので、その後の 2 コミットが入る前の状態です。 以下は保留中の判断に直接効く材料なので、目を通していただく価値があります。

  1. ライセンス条項: EDItEUR の許諾は複製を「厳密に内部的な利用」に限定し、それ以外は事前通知を求めている模様(二次情報。一次情報は editeur.org 上にあり到達不可)
  2. git 履歴からの復元: ONIX 2.1 一式がこのリポジトリの履歴に残っており、ネットワークなしで復元可能。Restore ONIX 2.1 from git history instead of the network #70 で make ターゲット化済み

3.1 について

--distdir が正式採用されたことで、あとは zip を置いていただければ 3.0 / 3.1 に進めます。ブラウザでダウンロードして third_party/distdir/ に置くだけです(ファイル名は変更不要)。置いていただければ、MODULE.bazel の URL・sha256・BUILD.bazel の filegroup・Lib.hs の schemaRoot を更新し、生成物の差分を確認して後方互換性を検証します。


Generated by Claude Code

@kogai
kogai merged commit 0642757 into main Sep 13, 2026
2 checks passed
@kogai
kogai deleted the claude/adr-schema-acquisition branch September 13, 2026 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants