Skip to content

feat: CompressionHint に値域 (rangeMin / rangeMax) を足し、aliases を schema:alternateName の下位プロパティとして宣言 - #26

Merged
nagata-yoshiteru merged 6 commits into
mainfrom
claude/compression-hint-value-range-and-alias-alignment
Aug 8, 2026
Merged

feat: CompressionHint に値域 (rangeMin / rangeMax) を足し、aliases を schema:alternateName の下位プロパティとして宣言#26
nagata-yoshiteru merged 6 commits into
mainfrom
claude/compression-hint-value-range-and-alias-alignment

Conversation

@nagata-yoshiteru

@nagata-yoshiteru nagata-yoshiteru commented Aug 7, 2026

Copy link
Copy Markdown
Member

exdata-inc/dbp-data-catalogue の Issue #16(データ項目型カタログの整備)を進める中で、この語彙の側が足りていない点が 2 つ見つかったので提案します。カタログ側 curator の合意は
こちらのコメント(「よい! あと、その PR で出す新 schema に従って今のコードも書いちゃって ok」)で取れています。

1. dbp:CompressionHint に値域(dbp:rangeMin / dbp:rangeMax)を追加

原因 / 背景

dbp:precisionBytes は「値域と粒度(rangeMin / rangeMax / decimalPlaces)から、その float / int を表現するのに必要なバイト数」として決めています(カタログ側はこの導出値と一致することを CI で検証しています)。

ところが値域は dbp:DataFieldType にしか書けません。そのため 同じ項目型でも、ユースケースによって覆う値域が違う ケースで、狭い側の hint まで「項目型が許容すべき最も広い値域」から導出した幅を持つことになります。

例(カタログの acceleration):

実際に覆う値域 現状
人・自転車の加速度計 数 g 項目型の値域(強震計を覆う広い側)から導出せざるを得ない
強震計(地盤・構造物) 桁違いに広い 項目型の値域はこちらを覆う必要がある

幅が実際より広いのは無駄なだけでなく、圧縮後サイズの過大申告dbp:lossyCompressionRate の既定値が precisionBytes / 8 なので、そのまま比にも波及する)になります。いまカタログ側はこの差を dbp:accuracyNote の日本語散文で書いていて機械可読になっておらず、値域が割れる 9 エントリが値域を宣言できずに止まっています

修正内容

dbp:rangeMin / dbp:rangeMaxschema:domainIncludesdbp:CompressionHint を追加しました(.protomessage CompressionHint にフィールド 18 / 19 を足した結果として生成されます)。読み方は:

  • 省略時 — 所属する dbp:DataFieldType の値域を継承する(=従来どおりの意味)
  • 記述時 — そのユースケースが実際に覆う範囲まで値域を狭める

なので 既存データの意味は変わりません(省略が従来の挙動)。

2. dbp:aliasesschema:alternateName の下位プロパティとして宣言

dbp:aliases は「項目名の別表記(検索キー)」で、schema.org の alternateName と同じものを指しています。schema.org しか知らない利用者からも別名が引けるよう、rdfs:subPropertyOf schema:alternateName を宣言しました。

.proto のフィールドは型とコメントしか持てず、「これは schema.org の X を狭めたもの」にあたる情報を書く場所がありません。一方 dbp-schema.jsonldProtoToJsonld.py の生成物なので、.jsonld を手で直すと次の生成で消えます。そこで既存の CONTAINS_NODE_RELATIONS と同じく 生成器側の定数表SUB_PROPERTY_OF_RELATIONS)として宣言し、rdf:Property の出力に rdfs:subPropertyOf を挿すようにしました。今後 schema.org と対応する dbp プロパティが増えたら、この表に 1 行足すだけで済みます。

確認方法

  • dbp-schema.jsonld / dbp-schema.ja.jsonldProtoToJsonld.py を再実行して生成しました。差分が上記 2 点の 15 行のみであることが、生成が再現していることの確認になっています(既存の 143 ノードは 1 バイトも動いていません)。
  • 生成後の JSON-LD が JSON として妥当で、dbp:aliasesrdfs:subPropertyOfdbp:CompressionHintschema:rangeIncludesdbp:rangeMin / dbp:rangeMax が入っていることを確認済み。
  • dbp_schema.sql(dbdiagram のソース)の CompressionHint テーブルにも 2 列を追記しました。
  • dbdiagram-oss_exported_data.json(同じ DBML を埋め込んでいる方)にも同じ 2 列と、CompressionHint のレイアウト高さを反映しました。両方の DBML ソースを @dbml/core でパースし、28 テーブルすべてで列名・列順が一致することを確認済みです。

⚠️ 未実施 — dbp_schema.pb.gosrc/dbp_schema.rs

この PR では Go / Rust の生成物を更新していません。実行環境に protoc・Go ツールチェーン・build.rs が要求する protobuf のチェックアウトが無く、中途半端なバージョンで再生成すると無関係な差分が大量に出るためです。このリポジトリの従来どおり、別途「update Rust / proto」の手順での再生成をお願いします。

再生成で出る差分は「新フィールド 2 つ」だけではありません(当初の見積もりを訂正します)。レビュー対応で .proto のコメントを書き換えたため、既存フィールドの doc comment も動きます:

  • CompressionHintrange_min / range_max(tag 18 / 19)の 2 つの Option<String> が増える
  • RealWorldDataStructurePropertyrange_min / range_max / precision_bytes / decimal_places(tag 80〜83)の doc comment が、継承・絞り込み・導出規則を書いた新しい文面に変わる(例: src/dbp_schema.rs:534/// Minimum value of numeric range
  • CompressionHintdecimal_places / precision_bytes(tag 10 / 12)に doc comment が付く

無関係な差分ではないので、そのまま取り込んでいただいて問題ありません。

@nagata-yoshiteru レビューをお願いします。

…alternateName の下位プロパティとして宣言

exdata-inc/dbp-data-catalogue#16 のカタログ整備で 2 点、この語彙の側が足りないことが分かったため。

## 1. dbp:CompressionHint の値域 (rangeMin / rangeMax)

dbp:precisionBytes は「値域と粒度からその値を表現するのに必要なバイト数」として決めている
(dbp-data-catalogue 側は CI でその導出値と一致することを検証している)。ところが値域は
dbp:DataFieldType にしか書けないので、**同じ項目型でもユースケースによって覆う値域が違う**
場合に、狭い側の hint まで「項目型が許容すべき最も広い値域」から導出した幅を持つことになる。

例(dbp-data-catalogue の acceleration): 人・自転車の加速度計の列は数 g で収まるが、
強震計(地盤・構造物)の列は桁違いに広い。項目型の値域は後者を覆う必要があるため、
前者の hint の precisionBytes も後者から導出されてしまい、実際より広い幅=圧縮後サイズの
過大申告になる。いま dbp-data-catalogue はこの差を dbp:accuracyNote の日本語散文で書いており、
機械可読になっていない(値域が割れるエントリが 9 件あり、いずれも値域を宣言できずにいる)。

そこで rangeMin / rangeMax の domainIncludes に dbp:CompressionHint を足し、
**省略時は所属する DataFieldType の値域を継承/記述時はそのユースケースが覆う範囲まで狭める**
という読み方にした。既存データへの影響は無い(省略が従来どおりの意味)。

## 2. dbp:aliases → schema:alternateName

dbp:aliases は「項目名の別表記(検索キー)」で、schema.org の alternateName と同じものを
指している。schema.org しか知らない利用者からも別名が引けるよう、
rdfs:subPropertyOf schema:alternateName を宣言した。

.proto のフィールドは型とコメントしか持てず、「これは schema.org の X を狭めたもの」に
あたる情報を書く場所が無い。一方 dbp-schema.jsonld は ProtoToJsonld.py の生成物なので、
.jsonld を直接手で書くと次の生成で消える。そのため CONTAINS_NODE_RELATIONS と同じく
生成器側の定数表(SUB_PROPERTY_OF_RELATIONS)として宣言し、rdf:Property の出力に
rdfs:subPropertyOf を挿すようにした。

## 生成物について

dbp-schema.jsonld / dbp-schema.ja.jsonld は ProtoToJsonld.py の再実行で更新した
(差分は上記 2 点のみ = 生成は再現している)。dbp_schema.pb.go と src/dbp_schema.rs は、
この環境に protoc / Go / protobuf のチェックアウトが無いため**再生成していない**。
従来どおり別途「update Rust / proto」の手順でお願いします。
Copilot AI lite review requested due to automatic review settings August 7, 2026 04:49
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nagata-yoshiteru's task —— View job


レビュー結果

  • 変更ファイルの読み込み(ProtoToJsonld.py / .proto / .jsonld / .sql
  • 生成物の整合性確認
  • レビュー所見の投稿

方向性は妥当だと思います(値域を CompressionHint にも置けるようにする、aliasesschema:alternateName に紐づける、どちらも語彙として素直)。既存データへの影響が無い(省略=従来の意味)点、SUB_PROPERTY_OF_RELATIONS を生成器側の定数表にして .jsonld の手編集を避けた点は特に良いです。以下、指摘です。


🔴 1. dbdiagram-oss_exported_data.jsondbp_schema.sql と乖離します

dbp_schema.sql は更新されていますが、dbdiagram-oss_exported_data.json が更新されていません。このファイルは DBML ソースを丸ごと埋め込んでおり(accuracyNote 等の CompressionHint の列が入っています)、履歴上も dbp_schema.sql常に同じコミットで動いています(直近は 31b8baa "add DataFieldType/CompressionHint to dbdiagram artifacts"、それ以前も同様)。

  • 現状: JSON 側に このユースケースが覆う値域 の文字列は存在しません(= rangeMin / rangeMax の 2 列が欠落)。
  • Go / Rust の生成物は PR 本文の「⚠️ 未実施」で明示されていますが、こちらは言及がないため、意図的なのか漏れなのか判別できません。

dbdiagram での再エクスポートをして頂くか、少なくとも「未実施」欄に追記して頂けると良いと思います。

🟠 2. 新しく書いた rangeMin / rangeMax のコメントが JSON-LD に一切出ていません

これが一番実質的な指摘です。dbp_schema.proto:585 に書いた「省略時は DataFieldType の値域を継承/記述時は狭める」というこの PR の肝である読み方が、生成された語彙には載っていません。

ParseProto() は、既に登場済みの property に対しては domainIncludes / rangeIncludes を足すだけで、コメントは破棄します(ProtoToJsonld.py:240-244)。rangeMinRealWorldDataStructurePropertydbp_schema.proto:264)が初出なので、生成結果は:

{
  "@id": "dbp:rangeMin",
  "rdfs:comment": "Minimum value of numeric range",
  "schema:domainIncludes": [ ..., {"@id": "dbp:CompressionHint"} ]
}

domainIncludesdbp:CompressionHint が増えただけで、CompressionHint に付いたときは継承/絞り込みの意味になる」ことを JSON-LD だけ読む利用者は知りようがありません。 「カタログ側の日本語散文(accuracyNote)を機械可読にする」という動機からすると、意味論が .proto のコメントに留まっているのは惜しいです。

対応案(どれか):

  • a. 初出側(dbp_schema.proto:264-265 / .ja.proto の対応行)のコメントを、両ドメインを覆う表現に書き換える。ここを直せば rdfs:comment に反映されます。例:
    // Minimum value of numeric range. On a CompressionHint it narrows the range of the DataFieldType to the subset the use case covers; omitted, the DataFieldType range applies
  • b. README に CompressionHint の値域の節を足す(現状 README には CompressionHint の記述自体がありません)。
  • c. 現状のままとし、.proto コメントは実装者向け・語彙は domainIncludes のみ、と割り切る(その場合は PR 本文にその旨を書いておくと後で迷わないです)。

個人的には a を推します(.jsonld の再生成だけで済み、既に「初出のコメントが代表になる」というこのリポジトリの挙動に沿っています)。

🟡 3. 片方だけ書いたときの解釈が未定義です

rangeMin だけ書いて rangeMax を省いた場合、

  • 継承はフィールド単位rangeMax だけ DataFieldType から継承)なのか
  • ペア単位(両方揃って初めて有効/片方だけは不正)なのか

が決まっていません。precisionBytes を導出する実装は必ずここに突き当たるので、コメントか README で一言決めて頂けると良いです。カタログ側 CI に実装が入る前に決まっている方が安全です。

🟡 4. 「hint の値域 ⊆ 項目型の値域」を保証する仕組みがありません

CompressionHint 側に項目型より広い値域を書けてしまいます(書けた時点で precisionBytes の導出前提が壊れます)。この語彙リポジトリに制約記述(SHACL 等)の仕組みは無いので、dbp-data-catalogue 側の CI で包含関係を検証する前提だと思いますが、その前提を .proto コメントか README に明記しておくと、語彙だけ見た人が誤用しにくくなります。

🔵 5. getJsonld() の dict 重複(ProtoToJsonld.py:148-152

sub_property_of の有無で dict リテラルを丸ごと 2 本書いているので、今後 rdf:Property にキーが増えるたびに分岐が倍になります。キー順(=出力の差分安定性)を保ったまま重複を消せます:

elif self.type == 'rdf:Property':
    jsonld = {'@id': self.id, '@type': self.type, 'rdfs:comment': self.comment, 'rdfs:label': self.label}
    if self.sub_property_of is not None:
        jsonld['rdfs:subPropertyOf'] = {'@id': self.sub_property_of}
    jsonld['schema:domainIncludes'] = self.domainIncludes
    jsonld['schema:rangeIncludes'] = self.rangeIncludes

これなら出力バイト列は現状と同一のはずです(rdfs:labelschema:domainIncludes の間に挿入される順序が保たれるため)。rdfs:Class 側の contains_node 分岐も同じ形にできますが、そちらは既存コードなのでこの PR の範囲外で構わないと思います。

🔵 6. SUB_PROPERTY_OF_RELATIONS のキーが誤っていても黙って無視されます

SUB_PROPERTY_OF_RELATIONS.get(self.id)ProtoToJsonld.py:109)なので、dbp:alias(s 抜け)のような typo を書くとエラーも警告も出ずに rdfs:subPropertyOf が消えますCONTAINS_NODE_PARENT_IDS も同じ弱さを持っていますが、表が育つ前に検知を入れておくと安いです。WriteJsonld() の最後あたりで、

emitted = {n['@id'] for n in graph}
unused = set(SUB_PROPERTY_OF_RELATIONS) - emitted
if unused:
    raise ValueError(f'SUB_PROPERTY_OF_RELATIONS has unmatched keys: {sorted(unused)}')

程度で十分だと思います。あわせて、この表のキーは WriteJsonld()item.key == -1 フィルタを通る id(= schema.org に同名が無い dbp 独自プロパティ)でなければ出力自体が落ちる、という制約もコメントに 1 行足しておくと親切です。


確認できたこと

  • rdfs プレフィックスは @context に定義済みなので、rdfs:subPropertyOf / schema:alternateName はどちらも解決します。
  • 英語版・日本語版の .proto / .jsonld が対称に更新されています(dbp-schema.ja.jsonld 側も dbp:aliasesrdfs:subPropertyOfdbp:rangeMin / dbp:rangeMaxdomainIncludesdbp:CompressionHintdbp:CompressionHintrangeIncludes に両プロパティが入っています)。
  • フィールド番号 18 / 19CompressionHint の既存最大 17 の次で、reserved 宣言も無いので衝突しません。後方互換です。
  • CompressionHint には既に decimalPlaces10)があるので、precisionBytes 導出の 3 入力(rangeMin / rangeMax / decimalPlaces)が hint 内で完結するようになります。設計として一貫しています。
  • dbp:aliasesdomainIncludesdbp:DataFieldTypeschema:Intangible の下位)なので、schema:alternateName(domain: schema:Thing)の下位プロパティとして矛盾しません。
  • dbp_schema.sql の 2 列は .proto と一致しています(型・コメントとも既存の書式に沿っています)。

確認できなかったこと

  • ProtoToJsonld.py の再実行による生成再現性は検証できていません。 このスクリプトは起動時に schema.org 21.0 の JSON-LD をネットワーク取得し、実行許可も無かったため、生成物は目視での差分確認に留まります。
  • このリポジトリにテストはありません。「コミット済みの生成物が生成器の出力と一致するか」を機械的に確かめる手段が無いため、今回のように .pb.go / .rs / dbdiagram JSON が置いていかれても気付けません(本 PR がまさにその状態です)。CI 変更は差し控えますが、ProtoToJsonld.py を回して git diff --exit-code するだけのチェックがあると、この種の乖離は防げると思います。

いずれもブロッカーではありませんが、1(dbdiagram JSON)と 2(コメントが語彙に出ない) は取り込み前に判断しておいた方が良いと思います。
· branch claude/compression-hint-value-range-and-alias-alignment

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

本PRは、データフィールド型カタログで必要になった語彙拡張として、dbp:CompressionHint にユースケース別の値域(dbp:rangeMin / dbp:rangeMax)を持てるようにし、あわせて dbp:aliasesschema:alternateName の下位プロパティとして宣言できるよう JSON-LD 生成器を拡張するものです。

Changes:

  • CompressionHintrangeMin / rangeMax(tag 18/19)を追加し、JSON-LD 側でも dbp:rangeMin / dbp:rangeMaxdomainIncludesdbp:CompressionHint を反映
  • dbp:aliasesrdfs:subPropertyOf schema:alternateName として出力するため、ProtoToJsonld.py に関係定義テーブルを追加
  • 生成物(dbp-schema.jsonld / dbp-schema.ja.jsonld)と dbp_schema.sql を更新

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
ProtoToJsonld.py rdfs:subPropertyOf を生成するための定数表(SUB_PROPERTY_OF_RELATIONS)と出力分岐を追加
dbp-schema.jsonld aliasesrdfs:subPropertyOf と、rangeMin/rangeMaxdomainIncludesCompressionHint を反映
dbp-schema.ja.jsonld 日本語版 JSON-LD に同内容を反映
dbp_schema.sql CompressionHint テーブルに rangeMin / rangeMax 列を追加
dbp_schema.proto CompressionHintrangeMin / rangeMax フィールドを追加
dbp_schema.ja.proto 日本語コメント版 .proto に同フィールドを追加

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dbp_schema.proto Outdated
Comment on lines +586 to +588
// Value range this use case covers. Omitted, the hint inherits the range of the DataFieldType it belongs to; declared, it narrows that range to the subset the use case actually spans, so precisionBytes follows from that subset rather than from the widest range the field type has to allow
optional string rangeMin = 18;
optional string rangeMax = 19;
#26 に頂いたレビューへの対応。指摘の番号は元コメントに対応。

## 1 (🔴) dbdiagram-oss_exported_data.json が dbp_schema.sql と乖離していた

このファイルは DBML ソースを丸ごと埋め込んでおり、履歴上も dbp_schema.sql と常に
同じ commit で動いている(31b8baa ほか)のに、前 commit で更新し漏れていた。
埋め込み DBML の CompressionHint に rangeMin / rangeMax を追記(このファイルの
既存の書式どおり Text 型・CRLF)。あわせて chart.tables の CompressionHint
("28")の height を 455 → 515 に更新した — 既存 28 テーブルすべてで
height = 30 * 列数 + 35 が成り立つので、2 列増で +60。

両方の DBML ソース(dbp_schema.sql と埋め込みテキスト)を @dbml/core で
パースし、28 テーブルすべてで列名・列順が一致することを確認済み。
JSON はテキスト blob と height の 2 行だけの差分で、他は再整形されていない。

## 2 (🟠) 新しく書いた読み方が JSON-LD に一切出ていなかった

ParseProto() は既出の property についてはコメントを捨てるため、rangeMin /
rangeMax の rdfs:comment は初出(RealWorldDataStructureProperty・
dbp_schema.proto:264)のものが代表になる。CompressionHint 側にどれだけ書いても
語彙には出ない状態だったので、推奨されていた案 a のとおり初出側のコメントを
両ドメインを覆う表現に書き換えた(.ja.proto も対称に更新)。
再生成した .jsonld の差分はこの 2 つの rdfs:comment のみ。

## 3 (🟡) 片方だけ書いたときの解釈を決めた

**フィールド単位で継承する**(rangeMin だけ書けば rangeMax は DataFieldType から
継承したままで、それは不完全な hint ではなく妥当な hint)。ペア単位の必須化はしない。
初出コメント・CompressionHint 側コメント・README に明記。

## 4 (🟡) 「hint の値域 ⊆ 項目型の値域」の前提を明記した

記述した側は狭めることはあっても広げない、という前提であること、この語彙には
制約記述(SHACL 等)の仕組みが無いので検証は利用者側(precisionBytes を導出する
consumer)の責務であること、を同じ 3 箇所に書いた。README には CompressionHint
自体の記述が無かったので「Data Field Catalogue」の節を新設している。

## 5 (🔵) getJsonld() の dict 重複を解消

rdf:Property 分岐を、分岐ごとの dict リテラル 2 本からキー単位の組み立てに変更。
挿入順は従来どおり(rdfs:subPropertyOf は rdfs:label と schema:domainIncludes の
間)なので出力はバイト単位で不変 — 再生成した .jsonld の差分が指摘 2 の
rdfs:comment 2 本だけであることがその確認になっている。
rdfs:Class 側は既存コードなのでレビューどおり手を付けていない。

## 6 (🔵) SUB_PROPERTY_OF_RELATIONS のキー誤りを検出するようにした

表のキーが 1 つも一致しないまま黙って rdfs:subPropertyOf が消えるのを防ぐため、
WriteJsonld() で「graph に出した @id」と突き合わせ、未一致キーがあれば
ValueError で落とす。**検査はファイルを開く前**に行うので、表を書き間違えても
commit 済みの .jsonld が 0 バイトに切り詰められることはない(従来は with open が
関数全体を包んでいたため、この種の例外は必ず空ファイルを残していた)。
キーが満たすべき条件(WriteJsonld の item.key == -1 フィルタを通る id である
こと)も定数表のコメントに残した。

負のプローブ: 表に "dbp:alias"(s 抜け)を足すと exit 1 で
`SUB_PROPERTY_OF_RELATIONS keys not emitted into dbp-schema.jsonld: ['dbp:alias']`
と名指しし、両 .jsonld の md5 が変わらないことを確認。

## 生成物について

dbp-schema.jsonld / .ja.jsonld は ProtoToJsonld.py の再実行で更新(HEAD の状態で
一度回して差分ゼロ = 生成が再現することを先に確認したうえで実施)。
dbp_schema.pb.go / src/dbp_schema.rs は前 commit と同じく再生成していない
(この環境に protoc / Go が無い)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nagata-yoshiteru

Copy link
Copy Markdown
Member Author

レビューありがとうございます。6 件すべて対応しましたf9d1c3f)。番号は頂いたコメントに対応しています。

🔴 1. dbdiagram-oss_exported_data.json の乖離 → 更新しました

漏れでした(意図的ではありません)。埋め込み DBML の CompressionHint に 2 列を追記し、あわせて chart.tables"28"(= CompressionHint)の height を 455 → 515 にしました。既存 28 テーブルすべてで height = 30 × 列数 + 35 が成り立つので、2 列増で +60 です。

確認方法: dbp_schema.sql と埋め込みテキストの両方を @dbml/core でパースし、28 テーブルすべてで列名・列順が一致することを確認しました(型名の VARCHAR(256) / Text の違いはご指摘のとおり従来からの表記差で、この差分が持ち込んだものではありません)。JSON 側の差分はテキスト blob と height の 2 行だけで、他の再整形は起きていません。

🟠 2. コメントが JSON-LD に出ていない → 案 a を採りました

ご指摘のとおりで、これが一番実質的でした。ParseProto() が既出 property のコメントを捨てるので、CompressionHint 側にいくら書いても語彙には出ません。初出側(dbp_schema.proto:264-265.ja.proto の対応行)のコメントを両ドメインを覆う表現に書き換えました。再生成した .jsonld の差分は、この dbp:rangeMin / dbp:rangeMaxrdfs:comment 2 本だけです。

なお「narrows / omitted は継承」という言い回しは CompressionHint に付いたとき と明示的にスコープしてあります(このプロパティは RealWorldDataStructureProperty / DataFieldType にも付くので、無条件に書くと他 2 ドメインについて嘘になるため)。

🟡 3. 片方だけ書いたときの解釈 → フィールド単位の継承に決めました

rangeMin だけ書けば rangeMaxDataFieldType から継承したままで、それは不完全な hint ではなく妥当な hintとして扱います。ペア単位の必須化はしません。初出コメント・CompressionHint 側コメント・README の 3 箇所に書きました。

🟡 4. 「hint の値域 ⊆ 項目型の値域」→ 前提として明記しました

ご想像のとおりカタログ側 CI で検証する前提です。「記述した側は狭めることはあっても広げない」「この語彙には制約記述の仕組みが無いので、広い値を書いてもここでは弾かれず、precisionBytes を導出する利用者側が検証の責務を負う」を同じ 3 箇所に書きました。README には CompressionHint の記述自体が無かったので、「Data Field Catalogue」の節を新設してそこに 3 と 4 をまとめています。

🔵 5. getJsonld() の dict 重複 → 頂いた形にしました

キー単位の組み立てに変更しました。挿入順が変わらないので出力はバイト単位で不変で、再生成後の差分が 2 の rdfs:comment 2 本だけであることがその確認になっています。rdfs:Class 側はご指摘どおり本 PR の範囲外として触っていません。

🔵 6. SUB_PROPERTY_OF_RELATIONS のキー誤り → 落とすようにしました

WriteJsonld() で「graph に出した @id」と突き合わせ、未一致キーがあれば ValueError にします。頂いたスニペットから 1 点だけ変えていて、検査をファイルを開く前に移しました。従来は with open(jsonldfile, 'w') が関数全体を包んでいたので、この種の例外は必ず commit 済みの .jsonld を 0 バイトに切り詰めた状態で終わってしまうためです。キーが満たすべき条件(item.key == -1 フィルタを通る id であること)も定数表のコメントに残しました。

負のプローブ: 表に "dbp:alias"(s 抜け)を足すと exit 1 で SUB_PROPERTY_OF_RELATIONS keys not emitted into dbp-schema.jsonld: ['dbp:alias'] と名指しし、両 .jsonld の md5 が変わらないことを確認しました。


「確認できなかったこと」について

  • 生成の再現性 — 今回は requests を venv に入れて ProtoToJsonld.py を実際に回せました。まず HEAD の状態で 1 回回して差分ゼロ(= 生成が再現する)ことを確かめてから、コメントを直して再生成しています。
  • 生成物と生成器の一致を機械的に確かめる手段が無い — おっしゃるとおりで、まさに今回の dbdiagram JSON がその状態でした。ProtoToJsonld.py を回して git diff --exit-code する CI は有効だと思いますが、この PR の範囲を越える(CI 変更 + 起動時に schema.org 21.0 を fetch するのでネットワーク前提になる)ので手を付けていません。ご要望があれば別 PR で出します。
  • dbp_schema.pb.go / src/dbp_schema.rs は前回と同じく再生成していません(この環境に protoc / Go が無いため)。PR 本文の「⚠️ 未実施」もそのままです。

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nagata-yoshiteru's task —— View job


追加レビュー(f9d1c3f

  • 差分の全体確認(f9d1c3f
  • 1. dbdiagram JSON の同期を検証
  • 2. 初出コメント → JSON-LD 反映を検証
  • 3/4. 片側記述・包含関係の記述を確認(.proto / README)
  • 5. getJsonld() の出力バイト不変性を検証
  • 6. SUB_PROPERTY_OF_RELATIONS 検査の実装を確認
  • レビュー所見の投稿

6 件すべて、報告どおりに直っていることを確認しました。 特に 2(案 a の採用)と 6 の「検査を open() の前に移した」判断は良いです — 後者は指摘したスニペットをそのまま入れると commit 済み .jsonld を 0 バイトにする、という私の見落としで、そちらの修正が正しいです。

以下、検証内容と、残っている小さい点です。


検証できたこと

1. dbdiagram JSON — 埋め込み DBML の CompressionHintrangeMin / rangeMax の 2 列が入り、dbp_schema.sql:395-396 と列名・列順が一致しています。他のテーブルに混入が無いことも確認しました(列トークン数が blob 全体で 223 → 225 の +2 のみ、Table 宣言は 28 のまま)。height も裏が取れています:

key テーブル 列数 height 30×列数+35
"27" DataFieldType 27 845 845 ✓
"28" CompressionHint 16 515 515 ✓

"28"CompressionHint であることも、dbp_schema.sqlTable 宣言順(28 個、最後が CompressionHint)と一致します。

2. コメントが語彙に出るようになったdbp-schema.jsonld:1728 / :1748.ja.jsonld の同位置で、dbp:rangeMin / dbp:rangeMaxrdfs:comment に継承・絞り込み・包含前提の 3 点が載りました。.jsonld の差分がこの 4 行(英日 2 本ずつ)だけである点も確認済みです。

5. 出力バイト不変ProtoToJsonld.py:154-165 の挿入順は @id@typerdfs:commentrdfs:label → (rdfs:subPropertyOf)→ schema:domainIncludesschema:rangeIncludes で、変更前の 2 本のリテラルと同一です。.jsonld の差分が 2 の rdfs:comment だけであることが実測の裏付けになっています。

6. 検査の実装ProtoToJsonld.py:318-323graph 構築後・open() 前で、指摘どおり commit 済みファイルを壊しません。

その他.proto の解析には影響なし(ParseProto()line[0].startswith('//') の行を捨てるので、dbp_schema.proto:586-588 の 3 行コメントは無視され、末尾コメントを持つ初出行だけが rdfs:comment になります)。README の主張(dbp:compressionHintsDataFieldType に付く、DataFieldTypeschema:Intangible の下位)も .proto と一致しています。


🟠 Go / Rust の再生成 — 想定より差分が増えています

未実施であること自体は PR 本文と Copilot のコメントで既知ですが、f9d1c3f で PR 本文の見積もりが古くなっています。 本文は

CompressionHintrange_min / range_max の 2 つの Option<String> が増えるだけのはずです

と書いていますが、2 の対応で初出コメントを書き換えたので、RealWorldDataStructureProperty 側の既存フィールドの doc comment も動きます:

  • src/dbp_schema.rs:534/// Minimum value of numeric range → 新しい長文(range_max の分も同様)
  • dbp_schema.pb.go の対応するコメントも同じく

再生成する人が「無関係な差分が出た」と誤解しないよう、本文の「⚠️ 未実施」欄を 1 行直しておくと親切です。現状の生成物に range_min が無いことは確認済みです(src/dbp_schema.rs:1115-1146CompressionHint は tag 17 まで)。

🟡 dbp:decimalPlaces の継承だけ未定義のまま残っています

3 で rangeMin / rangeMax の継承を決めましたが、decimalPlaces は同じ形をしていて、同じ導出式の 3 つ目の入力なのに、何も決まっていません。

  • dbp_schema.proto:543DataFieldType.decimalPlaces = 34
  • dbp_schema.proto:577CompressionHint.decimalPlaces = 10

つまり precisionBytes の 3 入力(rangeMin / rangeMax / decimalPlaces)のうち 2 つは「省略時は項目型から継承・片方ずつ」と明記され、3 つ目は無言です。CompressionHint 側の decimalPlaces が省略されたとき項目型の値を使うのか、それとも「未指定=丸めない」なのかで、導出バイト数が変わります。README の 1 文(「片方ずつ継承」の隣)に decimalPlaces も同じ扱いだと書けば済むと思います。既存フィールドなので本 PR の範囲外と判断されるなら、それでも構いません。

🔵 dbp:precisionBytes 側から導出規則に辿れません

dbp-schema.jsonld:1766-1781 の通り、dbp:precisionBytesdomainIncludes には dbp:CompressionHint が入っているのに、rdfs:comment は変更前のまま「Number of bytes used for numeric representation during compression」です。導出規則は rangeMin / rangeMax の側にしか書かれていないので、precisionBytes(=実際に導出される値そのもの)を引いた利用者は規則に辿り着けません。 dbp_schema.proto:266 の末尾コメントに「follows from rangeMin / rangeMax / decimalPlaces(on a CompressionHint, from the narrowed range)」程度を足すと、2 と同じ経路で語彙に出ます。

🔵 検査が「property として出したか」まで見ていません

ProtoToJsonld.py:318emittedgraph全ノード@id なので、クラスの id も含みます。sub_property_ofgetJsonld()rdf:Property 分岐でしか読まれない(rdfs:Class 分岐は無視する)ため、表に

"dbp:DataFieldType": "schema:Intangible",   # クラスを書いてしまった

を書くと検査は通り、rdfs:subPropertyOf は黙って消えます — 6 で塞ぎたかった穴がそのまま残る形です。1 語で締まります:

emitted = {node['@id'] for node in graph if node['@type'] == 'rdf:Property'}

🔵 値側の typo は依然として通ります

キーは検査されるようになりましたが、"schema:alternateName")は無検査なので、schema:alternatName と書くとどこにも存在しない @id を指す rdfs:subPropertyOf が出力されます。キーの typo(=関係が消える)より、こちらの方が下流には厄介です。このスクリプトは起動時に schema.org のグラフを schemaidsschema:alternateName 形式の id リスト)として読み込んでいるので、検査はほぼ無料です:

for key, value in SUB_PROPERTY_OF_RELATIONS.items():
    if value.startswith('schema:') and value not in schemaids:
        raise ValueError(f'SUB_PROPERTY_OF_RELATIONS[{key!r}] is not a schema.org term: {value}')

🔵 README の見出しと項目 1 が噛み合っていません

README.md:41 の「Two things this vocabulary states but does not enforce」の下で、項目 2(広げない)は確かに「述べるが強制しない」ですが、項目 1(片方ずつ継承)は強制の話ではなく読み方の定義です。「Two things to know」程度にするか、項目 1 を上の Omitted / Declared のリストに寄せる方が読みやすいと思います。


今回も確認できなかったこと

この実行環境では python3 / node の実行が許可されておらず(Bash は git / grep / sed 相当の読み取りのみ)、ProtoToJsonld.py の再実行による生成再現性と、負のプローブの再現は私の側では検証できていません。 そちらで実行された旨と、.jsonld の差分が申告どおり 4 行だけであること(これは確認済み)を根拠に、報告を妥当と判断しています。

.pb.go / .rs / dbdiagram JSON の置いていかれを機械的に検出する手段が無い件は、おっしゃるとおり別 PR が適切だと思います。


結論: 取り込んで良いと思います。 上記のうち残る要対応は 🟠(PR 本文の「⚠️ 未実施」欄の見積もり修正、および merge 後の Go / Rust 再生成)だけで、🟡 / 🔵 は次の機会でも構いません。

@nagata-yoshiteru ご確認ください。

· branch claude/compression-hint-value-range-and-alias-alignment · View job

追加レビュー(`f9d1c3f` に対するもの)の 🟡 1 件・🔵 3 件と、
それに対する追加レビューで出た指摘を消化した。🟠(PR 本文の
「⚠️ 未実施」欄の見積もり修正)は PR 本文側で対応。

1. 🟡 `decimalPlaces` の継承が未定義だった
   `precisionBytes` の 3 入力のうち `rangeMin` / `rangeMax` は
   「省略時は DataFieldType から継承・片方ずつ」と決めたのに、
   3 つ目の `decimalPlaces` は無言のままで、hint が省略したときに
   導出が定義されない状態だった。値域の両端と同じ読み方
   (省略時は DataFieldType の値・記述すればその hint に適用)に
   決めて、初出(tag 83)の末尾コメントと README に書いた。
   あわせて「記述する場合は DataFieldType より多くの桁を保持しない」
   (値域が狭まる側にしか動かないのと同じく、桁は粗くなる側にしか
   動かない)も、値域の包含と同じ「述べるが強制しない」項目として明記。

2. 🔵 `precisionBytes` 側から導出規則に辿れなかった
   規則は値域の側にしか書かれておらず、導出される値そのものを引いた
   利用者は規則に辿り着けなかった。初出(tag 82)の末尾コメントに
   導出式と、CompressionHint に付いたときの入力(記述されていれば
   狭めた値域・無ければ項目型の値域)を書いた。`CompressionHint`
   ブロック側の tag 10 / 12 にも同じ内容を短く置いた(こちらは
   JSON-LD には出ないが、Go / Rust の doc comment には出る)。

3. 🔵 `SUB_PROPERTY_OF_RELATIONS` のキー検査がクラスを通していた
   `emitted` が graph の全ノードの `@id` だったため、クラスの id を
   キーに書くと検査を通り、`rdfs:subPropertyOf` は黙って消えていた
   (`getJsonld()` は `rdf:Property` の分岐でしか `sub_property_of` を
   読まない)。`rdf:Property` のノードだけに絞った。

4. 🔵 値側の typo が無検査だった
   キーの typo(関係が消える)より、存在しない `@id` を指す
   `rdfs:subPropertyOf` が出る方が下流には厄介。schema.org の
   **プロパティ**の id 集合を新たに作り、値が必ずそこに含まれることを
   要求する。プレフィックスで分岐すると `shema:` のような
   プレフィックス自体の typo が素通りするため、分岐せず一律に検査する。
   クラス・データ型を指す値も同じく落ちる。報告はキー検査と同じく
   全件まとめて。

5. README の見出しと項目の噛み合わせ
   「Two things this vocabulary states but does not enforce」の項目 1
   (片方ずつ継承)は強制の話ではなく読み方の定義だったので、
   Omitted / Declared のリストへ移した。残る「述べるが強制しない」は
   値域の包含と、上の桁の包含の 2 点。

検証:
- `ProtoToJsonld.py` を再実行。`.jsonld` の差分は初出コメントを
  書き換えた `dbp:precisionBytes` / `dbp:decimalPlaces` の
  `rdfs:comment` **4 行のみ**(英日 2 本ずつ)。他 141 ノードは不変。
  再実行前に HEAD の状態でも 1 回回して差分ゼロを確認済み。
- 負のプローブ 7 通り(値のプレフィックス typo / 語の typo /
  クラス / データ型、キーのクラス id / typo、旧 `emitted` での
  クラス id)すべてで exit 1・原因を名指し・commit 済み `.jsonld` の
  md5 不変。旧 `emitted` ではクラス id が exit 0 で通り関係が消える
  ことも実測(この commit で塞いだ穴の再現)。
@nagata-yoshiteru

Copy link
Copy Markdown
Member Author

追加レビューありがとうございます。残っていた 🟠 / 🟡 / 🔵 の 5 点すべてに対応しました5235829 + 本文の更新)。

🟠 PR 本文の「⚠️ 未実施」欄 → 直しました

ご指摘のとおり見積もりが古くなっていたので、本文を書き換えました。今回の commit でさらに precisionBytes / decimalPlaces(tag 82 / 83)のコメントも動くので、再生成で出る差分は 3 種類になります:

  • CompressionHintrange_min / range_max(tag 18 / 19)が増える
  • RealWorldDataStructurePropertyrange_min / range_max / precision_bytes / decimal_places(tag 80〜83)の doc comment が変わる
  • CompressionHintdecimal_places / precision_bytes(tag 10 / 12)に doc comment が付く

🟡 decimalPlaces の継承 → 値域の両端と同じに決めました

本 PR の範囲に入れました。導出の 3 入力のうち 2 つだけ決めて 3 つ目を無言で残すと、hint が decimalPlaces を省略した瞬間に導出そのものが未定義になるためです。

  • 省略 → DataFieldType の値が適用される(1 プロパティずつ継承。rangeMin / rangeMax と同じ)
  • 記述 → その hint に適用される

あわせて 包含の向きも書きました: 記述する場合は DataFieldType より多くの桁を保持しない(値域の端が狭まる側にしか動かないのと同じく、桁は粗くなる側にしか動かない)。圧縮は桁を捨てる側なので、項目型が「無い」と言っている桁を hint が要求するのは、広い値域を書くのと同じく導出の前提を壊します。README の「述べるが強制しない」項目はこれで値域・桁の 2 点になりました。

初出(tag 83)の末尾コメントに書いたので、2 と同じ経路で語彙にも出ています。

🔵 precisionBytes から導出規則に辿れない → 初出コメントに導線を足しました

頂いた文面どおり、tag 82 の末尾コメントに導出式と、CompressionHint に付いたときの入力(記述されていれば狭めた値域・無ければ項目型の値域)を書きました。CompressionHint ブロック側の tag 10 / 12 にも短い版を置いています(JSON-LD には出ませんが、Go / Rust の doc comment には出るので、生成物だけを読む人にも届きます)。

🔵 検査が「property として出したか」を見ていない → 頂いた 1 語で締めました

emitted = {node['@id'] for node in graph if node['@type'] == 'rdf:Property'}

穴の実在も先に再現しました: 旧 emitted のまま "dbp:DataFieldType": "schema:Intangible" を足すと exit 0 で通り、生成された dbp:DataFieldType ノードに rdfs:subPropertyOf が無いことを確認しています。現在は同じ表で exit 1 になります。

🔵 値側の typo が通る → 検査しました(頂いた案から 2 点強めています)

  1. プレフィックスで分岐しない。 頂いた value.startswith('schema:') and value not in schemaids だと、プレフィックス自体が typo のときshema:alternateName)に分岐へ入らず素通りします。分岐せず「値は必ずこの集合に含まれること」を要求する形にしました。他語彙を指す値はここで落ちますが、それは意図した挙動です(表を広げるときに検査も一緒に広げる、という形にしておかないと 1 件だけ無検査で通る道が残るため)。
  2. 集合は schema.org の「プロパティ」だけ。 schemaids はクラス・データ型・列挙メンバも含むので、schema:Thingschema:Text を指す rdfs:subPropertyOf が通ってしまいます。キー側を rdf:Property に絞ったのと揃えて、値側も rdf:Property のノードだけを集めた schemapropertyids と突き合わせます(@type は当該リリースでは素の文字列ですが、リストでも落ちないように正規化しています)。

報告はキー側の検査と同じく全件まとめて(1 件ずつ直させないため)にしました。

🔵 README の見出しと項目 1 → 項目 1 を上のリストへ移しました

ご指摘のとおり項目 1 は強制の話ではなく読み方の定義だったので、Omitted / Declared のリストに「One end at a time」として並べました。「述べるが強制しない」に残るのは、値域の包含と、上で足した桁の包含の 2 点です。


検証

  • ProtoToJsonld.py を再実行。.jsonld の差分は dbp:precisionBytes / dbp:decimalPlacesrdfs:comment 4 行のみ(英日 2 本ずつ)で、他 141 ノードは 1 バイトも動いていません。再生成の前に HEAD の状態でも 1 回回して差分ゼロを確認してあります。
  • 負のプローブ 7 通り(値: プレフィックス typo / 語の typo / クラス / データ型、キー: クラス id / typo、および旧 emitted でのクラス id)。前 6 つは exit 1・原因を名指し・commit 済み .jsonld の md5 不変、最後の 1 つは exit 0 で通ることを実測(塞いだ穴の再現)。
  • ECC の code-reviewer / python-reviewer にも掛けました。CRITICAL 0 件。python-reviewer の HIGH 2 件(上記 🔵 の 1、およびその根拠を書いたコメントが実装より強い保証を主張していた点)と MEDIUM 1 件(🔵 の 2)、code-reviewer の MEDIUM 1 件(decimalPlaces に包含の但し書きが無い)はすべてこの commit に取り込んでから push しています。

.pb.go / .rs の再生成は引き続きそちらの「update Rust / proto」の手順にお願いします。

@nagata-yoshiteru ご確認をお願いします。

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nagata-yoshiteru's task —— View job


Claude finished @nagata-yoshiteru's task —— View job


追加レビュー(5235829

  • 差分の全体確認
  • 🟠 PR 本文の「⚠️ 未実施」欄を確認
  • 🟡 decimalPlaces の継承・包含の記述を検証
  • 🔵 precisionBytes からの導線を検証
  • 🔵 キー検査の rdf:Property 絞り込みを検証
  • 🔵 値側検査の実装を検証
  • 🔵 README の構成を検証
  • 新規差分の点検・所見の投稿

前回残っていた 5 点はすべて直っていることを確認しました。 特に値側検査で頂いた案から 2 点強めた判断(プレフィックスで分岐しない/集合をプロパティだけに絞る)は、どちらも私の案より正しいです。前者は shema: を素通しにする穴が実際にありましたし、後者は rdfs:subPropertyOfschema:Thing を指す出力を許してしまっていました。

ただ、この commit で 1 件、意図しないファイルが混入しています。


🔴 __pycache__/ProtoToJsonld.cpython-314.pyc がコミットされています

5235829__pycache__/ProtoToJsonld.cpython-314.pyc(15,413 bytes のバイナリ)が追加されています。今回 ProtoToJsonld.py をローカルで実行した副産物で、意図的なものではないはずです。

  • git log --all -- __pycache__ の結果は この PR の commit が唯一で、履歴上これまで一度も追跡されていません。
  • .gitignore には Rust / Cargo / RustRover のセクションしかなく、Python のセクションが丸ごとありませんpycache / .pyc の文字列がゼロ)。追跡中の Python は ProtoToJsonld.pyconvert-jsonld-graph-to-ntriple.ipynb の 2 つなので、放置すると次に誰かがスクリプトを回すたびに再発します(.ipynb_checkpoints/ も同様)。

対応としては、この 1 ファイルを削除したうえで .gitignore

# Python
__pycache__/
*.py[cod]
.ipynb_checkpoints/

を足すのが良いと思います。バイトコードはインタプリタのバージョン(cpython-314)に紐づく生成物なので、他のバージョンで回す人には無効なファイルが残るだけですし、この PR がまさに「生成物と生成器の一致」を議論している最中なので、生成物でないものが混ざるのは特に紛らわしいです。

.pyc の存在自体は実行に影響しません。Python は元 .py の mtime / size と照合するので、古い .pyc が使われることはありません。純粋にノイズの問題です。)


検証できたこと

🟡 decimalPlaces の継承dbp_schema.proto:267(tag 83)の初出コメント経由で語彙に出ています(dbp-schema.jsonld:1785 / .ja.jsonld 同位置)。「省略時は継承/記述時はその hint/precisionBytes の 3 つ目の入力/粗くなる側にしか動かない」の 4 点が入っており、README(README.md:44-47, :52-56)・CompressionHint 側(dbp_schema.proto:577)と食い違いがありません。

包含の向きの理屈も妥当だと思います。値域は「狭める」、桁は「粗くする」で向きが逆に見えますが、どちらも precisionBytes を減らす方向なので、導出の前提としては同じ向きです。ここを「桁も狭める」と書いていたら曖昧でしたが、coarsens, never refines と言い切ってあるので誤読の余地がありません。

🔵 precisionBytes の導線dbp_schema.proto:266(tag 82)→ dbp-schema.jsonld:1768。導出式と、CompressionHint に付いたときの入力の解決順が載りました。CompressionHint ブロック側の tag 10 / 12 に短い版を置いた判断も妥当です(ParseProto() は既出 property のコメントを捨てるので JSON-LD には出ませんが、.pb.go / .rs の doc comment には出るため、生成物だけを読む人には届きます)。「下の rangeMin / rangeMax」という参照も、CompressionHint 内での宣言順(1018/19)と一致しています。

🔵 キー検査の絞り込みProtoToJsonld.py:359node['@type'] == 'rdf:Property' になり、getJsonld()sub_property_of を読む分岐(ProtoToJsonld.py:162-169)と一致しました。graph の全ノードは getJsonld() 産で必ず @type を持つので KeyError の心配もありません。

🔵 値側検査ProtoToJsonld.py:340-349schemapropertyidsProtoToJsonld.py:14-27)との突き合わせで、プレフィックス typo・語の typo・クラス・データ型の 4 通りがすべて落ちます。@type のリスト正規化も、リリースが変わったときに黙って集合から漏れて検査が緩む(= 偽陰性)方向の事故を防いでいて、方向として正しいです。

🟠 PR 本文 — 「⚠️ 未実施」欄が 3 種類の差分に更新されているのを確認しました。今回の commit で tag 82 / 83 と CompressionHint の tag 10 / 12 のコメントが動いたことと一致しています。

その他 — 検査 2 本はどちらも open() の前(ProtoToJsonld.py:369 が唯一の open)にあり、commit 済みファイルは壊れません。dbp_schema.sql / dbdiagram-oss_exported_data.json は今回の commit で触られていませんが、今回は列の増減が無く comment のみの変更なので、乖離は発生していません(前回同期した状態のままで正しい)。


🔵 dbp → dbp の rdfs:subPropertyOf が書けなくなっています

値側検査を value not in schemapropertyids の一律要求にしたことで、値は schema.org のプロパティでなければならないという制約が入りました。今の表(dbp:aliases の 1 件)では正しいのですが、この表の次に来そうな用途のひとつは「dbp のプロパティが別の dbp プロパティを狭める」で、それが今は検査で落ちます。

「表を広げるときに検査も一緒に広げる」という方針は伺いましたし、それ自体は同意です(無検査の道を残さないのは正しい)。ただ dbp 内部の参照は既に手元に情報があるので、広げるコストは 1 行です。emitted の計算を値検査より前に移せば:

emitted = {node['@id'] for node in graph if node['@type'] == 'rdf:Property'}

bad_values = sorted(
    (key, value)
    for key, value in SUB_PROPERTY_OF_RELATIONS.items()
    if value not in schemapropertyids and value not in emitted
)

dbp: 側の typo も「このリポジトリが実際にプロパティとして出した id」と突き合わされるので、schema.org 側と同じ強さで守られます。今やる必要は無く、その用途が出てきたときの選択肢としてどうぞ。

🔵 検査が「関係が出力されたか」を推移的にしか見ていません

キー検査は「キーがプロパティとして出た」ことを見ていて、そこから「getJsonld()rdf:Property 分岐が sub_property_of を出したはず」を推論しています。今のコードでは実際に成り立ちます(__init__SUB_PROPERTY_OF_RELATIONS.get(self.id) を引き、同じ分岐で必ず出力する)。ただ、直接見に行っても同じ長さです:

emitted = {node['@id'] for node in graph if 'rdfs:subPropertyOf' in node}

これなら getJsonld() の分岐構造がどう変わっても、「表に書いた関係が JSON-LD に載っている」という本来検証したい性質そのものを見ることになります(@type の絞り込みも兼ねます。rdfs:Class 分岐は rdfs:subPropertyOf を出さないので)。3 回連続でこの検査の穴を塞いでいるので、代理指標をやめると打ち止めにできると思います。

🔵 dbp_schema.sqlCompressionHint だけコメントの粒度が揃っていません

dbp_schema.sql:395-396rangeMin / rangeMax には継承の注記があるのに、同じテーブルの decimalPlaces:387)と precisionBytes:389)は無印のままです。今回 .proto 側で 4 つとも意味論を持つようになったので、SQL だけ 2 つが無言なのは中途半端に見えます。

ただし dbdiagram-oss_exported_data.json の埋め込み DBML も一緒に直す必要がある(前回同期させたばかりの箇所)ので、コスト対効果は微妙です。dbdiagram は ER 図の描画用で意味論の一次ソースではない、と割り切るなら現状のままで構わないと思います。


今回も確認できなかったこと

この実行環境では Python の実行が許可されておらず(Bash は git / grep / sed 相当の読み取りのみ)、ProtoToJsonld.py の再実行と負のプローブ 7 通りの再現は私の側では検証できていません。 そちらで実行された旨と、.jsonld の差分が申告どおり 4 行(dbp:precisionBytes / dbp:decimalPlacesrdfs:comment、英日 2 本ずつ)だけであること(これは確認済み)を根拠に、報告を妥当と判断しています。

.pb.go / src/dbp_schema.rs は引き続き未再生成です。PR 本文の見積もりは今回の変更を反映済みで、実際の差分と一致しています。


結論: .pyc の 1 件だけ取り除いて頂ければ、取り込んで良いと思います。 🔵 3 件はいずれも次の機会で構いません。merge 後の Go / Rust 再生成は引き続きお願いします。

@nagata-yoshiteru ご確認ください。

· branch claude/compression-hint-value-range-and-alias-alignment · View job

claude added 2 commits August 7, 2026 14:49
レビューの 🔴 指摘。`5235829` で `__pycache__/ProtoToJsonld.cpython-314.pyc`
(15,413 バイト)が混入していた。`ProtoToJsonld.py` をローカルで実行した副産物で、
意図的なものではない。

.gitignore には Rust / Cargo / RustRover の節しか無く Python の節が丸ごと無かったので、
放置すると生成器を回すたびに再発する。追跡中の Python は `ProtoToJsonld.py` と
`convert-jsonld-graph-to-ntriple.ipynb` の 2 つなので、`.ipynb_checkpoints/` も併せて
無視する。

バイトコードはインタプリタのバージョン(cpython-314)に紐づく生成物で、他の版で回す人には
無効なファイルが残るだけ。この PR がまさに「生成物と生成器の一致」を扱っている最中でもある。
レビューの 🔵 指摘。キー側の検査は「キーが rdf:Property として出た」ことだけを見て、
そこから「getJsonld() の rdf:Property 分岐が sub_property_of を出したはず」を推論していた。
今のコードでは実際に成り立つが、代理指標なので分岐の構造が変われば黙って外れる。

`'rdfs:subPropertyOf' in node`(dict のキーの有無)で出力そのものを読む形に変えた。
本来検証したい性質——表に書いた関係が JSON-LD に載っている——を直接見るので、
getJsonld() が次にどう変わっても成り立つ。@type の絞り込みも兼ねる
(rdfs:Class 分岐は rdfs:subPropertyOf を出さない)。エラー文言も
「プロパティとして出ていない」から「rdfs:subPropertyOf が届いていない」に合わせた。

検証: 再生成後の dbp-schema.jsonld / .ja.jsonld は md5 不変。負のプローブ 5 通り
(キーの綴り間違い / キーがクラスの id / 出力側が関係を落とす / 値のプレフィックス
typo / 値がクラス)すべて exit 1・commit 済み .jsonld は不変。3 つ目は旧実装では
exit 0 で通り、出力に rdfs:subPropertyOf のキーが 1 つも無いまま生成が完了していた
(=この commit が塞いだ穴)。rdfs:comment の文字列としての "rdfs:subPropertyOf"
(dbp-schema.jsonld:1317)は値なので偽陽性にならない。
@nagata-yoshiteru

Copy link
Copy Markdown
Member Author

追加レビューありがとうございます。🔴 の 1 件を取り除きました1e21a7e)。あわせて 🔵 のうち 1 件(代理指標の廃止)も入れています(5bb6540)。merge をお願いできる状態だと思います。

🔴 __pycache__/ProtoToJsonld.cpython-314.pyc → 削除しました(1e21a7e

ご指摘のとおり、ProtoToJsonld.py をローカルで回した副産物の混入で、意図的なものではありません。ファイルを削除し、.gitignore に頂いた 4 行をそのまま足しました:

# Python
__pycache__/
*.py[cod]
.ipynb_checkpoints/

git ls-files で、他に .pyc / __pycache__ / .ipynb_checkpoints が追跡されていないことも確認しています(この 1 ファイルだけでした)。履歴の書き換えは行っていません(force-push はしない方針のため。追跡から外れていれば以降の再発は止まります)。

🔵 検査が「関係が出力されたか」を推移的にしか見ていない → 直しました(5bb6540

「次の機会で構いません」と頂きましたが、3 回連続でこの検査の穴を塞いでいるので、代理指標をやめると打ち止めにできるというご指摘がそのとおりだと思ったので、頂いたコードのまま入れました:

with_sub_property_of = {
    node['@id'] for node in graph if 'rdfs:subPropertyOf' in node
}

(変数名だけ emitted から変えています。意味が「プロパティとして出た id」から「rdfs:subPropertyOf を実際に持つ id」に変わったので、名前を据え置くと読み違えるためです。)エラー文言も「プロパティとして出ていない」から「rdfs:subPropertyOf が届いていない」に合わせました。

rdfs:comment の中に文字列として出てくる "rdfs:subPropertyOf"dbp-schema.jsonld:1317dbp:rdfsSubPropertyOf の説明文)は 値であってキーではないので、in node は dict のキーを見る以上偽陽性になりません(下のプローブ 3 で、そのノードが残っていても検査が落ちることを実測しています)。

検証(venv に requests を入れて ProtoToJsonld.py を実際に回しています):

  • 再生成後の dbp-schema.jsonld / dbp-schema.ja.jsonldmd5 不変(意味論の変更ではないので当然ですが、念のため)。

  • 負のプローブ 5 通り、いずれも exit 1・原因を名指し・commit 済み .jsonld の md5 は不変(検査は open() の前):

    # 壊し方 結果
    1 キーの綴り間違い(dbp:aliasses exit 1 keys whose rdfs:subPropertyOf did not reach …: ['dbp:aliasses']
    2 キーがクラスの id(dbp:CompressionHint exit 1 同上
    3 出力側が関係を落とす(if self.sub_property_of is not None:if False: exit 1 … ['dbp:aliases']
    4 値のプレフィックス typo(shema:alternateName exit 1 values that are not schema.org properties
    5 値がクラス(schema:Thing exit 1 同上
  • 3 は旧実装では exit 0 で通ります(実測)。しかもそのとき生成された .jsonld には rdfs:subPropertyOfキーが 1 つも無く、残っているのは :1317 の説明文の文字列だけでした。これが今回塞いだ穴そのものです。

🔵 残り 2 件について

  • dbp → dbp の rdfs:subPropertyOf — 「今やる必要は無く、その用途が出てきたときの選択肢として」とのことでしたので、今回は入れていません。表が 1 件しか無いうちに使われない分岐を足すと、次に広げる人が「なぜこの形なのか」を読み解く材料が無い状態になるためです。ご提案のコードは、上の with_sub_property_of を値検査より前に持ち上げれば 1 行で足りるので、その用途が出た時点で表と一緒に広げます。
  • dbp_schema.sqlCompressionHint のコメント粒度 — ご自身で書かれていた「dbdiagram は ER 図の描画用で意味論の一次ソースではない」という割り切りを採り、現状のままにしていますdbdiagram-oss_exported_data.json の埋め込み DBML を再度同期させるコストに対して、.proto / JSON-LD / README という一次ソース 3 つが既に揃って同じことを言っている状態なので、得るものが小さいと判断しました。異論があればお知らせください。

今回も確認できていないこと

.pb.go / src/dbp_schema.rs は引き続き未再生成です(merge 後にお願いします)。PR 本文の「⚠️ 未実施」欄は、今回の変更が生成物に差分を出さない(md5 不変)ため更新していません。

ECC レビュー

code-reviewer / python-reviewer の 2 本とも CRITICAL / HIGH / MEDIUM 0 件で APPROVE でした。出た LOW 2 件はどちらも push 前に取り込んでいます:

  • emitted という変数名が新しい意味を表していない → with_sub_property_of に改名(上記)。
  • merge をふさいでいる 🔴 の修正と、後回しでよいと言われた 🔵 を同じ commit にまとめると、merge 直前に差分を広げることになる2 commit に分けました1e21a7e が 🔴 だけ、5bb6540 が 🔵 だけ)。🔵 のほうを落として取り込みたい場合は、1e21a7e だけで 🔴 の対応は完結します。

@nagata-yoshiteru ご確認をお願いします。

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nagata-yoshiteru's task —— View job


Claude finished @nagata-yoshiteru's task —— View job


追加レビュー(1e21a7e / 5bb6540

  • 🔴 .pyc の削除と .gitignore を確認
  • 🔵 with_sub_property_of への変更を検証
  • 生成物・他ファイルへの影響を確認
  • 所見の投稿

🔴 は解消、🔵 も入っていることを確認しました。取り込んで良い状態だと思います。 2 commit に分けた判断(1e21a7e だけで 🔴 が完結する)も、merge 直前の差分としては正しい形です。


検証できたこと

🔴 .pyc の除去(1e21a7e

  • __pycache__/ProtoToJsonld.cpython-314.pyc の削除を確認。git ls-files | grep -Ei 'pyc|__pycache__|ipynb' の結果は convert-jsonld-graph-to-ntriple.ipynb の 1 件のみで、他に取り残しはありません。作業ツリーにも __pycache__/ は残っていません。
  • .gitignore の追記(__pycache__/ / *.py[cod] / .ipynb_checkpoints/)は末尾の RustRover 節の後ろに独立した # Python 節として入っており、既存の節を壊していません。*.py[cod] が既存の追跡ファイルを覆う心配も無し(該当ゼロ)。
  • 履歴の書き換えをしていない点も方針どおりで正しいです(blob は履歴に残りますが、追跡から外れていれば再発は止まります。force-push しない方が重要)。

🔵 検査の直接化(5bb6540

  • ProtoToJsonld.py:361-363{node['@id'] for node in graph if 'rdfs:subPropertyOf' in node}偽陽性が起きないことを実データで確認しました: dbp-schema.jsonldrdfs:subPropertyOf が現れるのは 2 箇所だけで、:1317dbp:rdfsSubPropertyOf ノードの rdfs:comment:3076dbp:aliasesキーです。in node は dict のキーを見るので前者は拾いません(.ja.jsonld も同位置で同じ)。
  • 逆向き(表に無いのに rdfs:subPropertyOf が出る)も起こり得ません。sub_property_ofProtoToJsonld.py:124 で表からしか入らないためです。
  • 検査 2 本はどちらも open():373)より前のままで、commit 済みファイルは壊れません。
  • 生成物への影響ゼロを確認: 5235829..5bb6540 の差分は .gitignore / ProtoToJsonld.py / 削除された .pyc の 3 つだけで、.jsonld / .proto は 1 行も動いていません(git diff が空)。「md5 不変」の報告と一致します。

代理指標をやめた判断そのものについて — 「getJsonld() の分岐がどう変わっても成り立つ」というのは実際にそのとおりで、負のプローブ 3(if False: に差し替え)が旧実装で exit 0 だったという実測が、この置き換えの価値をそのまま示しています。


気付いた小さい点(いずれも今回は不要)

🔵 SUB_PROPERTY_OF_RELATIONS のコメントが検査の旧い姿を説明しています

ProtoToJsonld.py:84

WriteJsonld() raises on a key it did not emit

は、まさに今回やめた「出したかどうか」の言い方です。実際の検査は「関係が出力に載ったか」になったので、if False: のケース(キーは出ているが関係が落ちた)も落ちます。現状の文面はそれを言い切れておらず、検査より弱く読めます。直前の「キーは item.key == -1 フィルタを通る id であること」という制約の説明は今も正しいので、最後の 1 文だけの話です。

🔵 値側の検査だけ出力に依存していません

ProtoToJsonld.py:337-341itemsjsonldfile も見ない定数表だけの検査なので、WriteJsonld() が英日 2 回呼ばれると同じ判定を 2 回します(実害はありません。1 回目で落ちるので .jsonld は両方無傷)。キー側と並べて置いてある読みやすさとのトレードオフなので、現状のままで問題ないと思います。気になるなら表の定義の直後に一度だけ走らせる形もありますが、その場合は schemapropertyids の構築との順序に縛られます。

🔵 dbp:rdfsSubPropertyOfrdfs:subPropertyOf が同居しました

この PR で気付いた点として一応。この語彙には既に dbp_schema.proto:218RealWorldDataStructureProperty.rdfsSubPropertyOf、tag 4)があり、dbp-schema.jsonld:1315 に「schema.org 上の項目で対応するもの」を文字列で持つインスタンス側のフィールドとして出ています。今回そこに、語彙レベルの本物の rdfs:subPropertyOf トリプル(:3076)が加わりました。

  • dbp:rdfsSubPropertyOf — データ側で個々のプロパティが「schema.org の X 相当」と申告するための欄
  • rdfs:subPropertyOf — この語彙自身が dbp プロパティについて宣言する関係

用途は別物で衝突もしませんが、名前が 1 文字違いなので、README に 1 行あると後から来た人が迷わないかもしれません。今回の範囲外です。


今回も確認できていないこと

この実行環境では Python の実行が許可されておらず(Bash は git / grep / sed 相当の読み取りのみ)、ProtoToJsonld.py の再実行と負のプローブ 5 通りの再現は私の側では検証できていません。 ただし今回は「生成物に差分が出ない」ことが主張の中心で、それは git diff で直接確認できました.jsonld の差分ゼロ)。プローブの表は、コードを読む限り記載どおりの結果になるはずです(3 のみ旧実装で exit 0 になる、という点も emitted の定義から確かに導けます)。

dbp_schema.pb.go / src/dbp_schema.rs は引き続き未再生成です。PR 本文の「⚠️ 未実施」欄は 5235829 時点の内容で正しく、今回の 2 commit は生成物に差分を出さないので更新不要という判断に同意します。


結論: merge して良いと思います。 上の 🔵 3 件はいずれも次の機会で構いません。merge 後の Go / Rust 再生成(CompressionHint の tag 18/19 追加、RealWorldDataStructureProperty の tag 80〜83 の doc comment 変更、CompressionHint の tag 10/12 への doc comment 追加)は引き続きお願いします。

@nagata-yoshiteru ご確認ください。

· branch claude/compression-hint-value-range-and-alias-alignment · View job

@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nagata-yoshiteru's task —— View job


追加レビュー(1ea3cd2 — Go / Rust の再生成)

  • 1ea3cd2 の差分を確認
  • .proto との整合(新フィールド 18 / 19、tag 番号・型・synthetic oneof)を検証
  • doc comment の反映(tag 80〜83 / CompressionHint の 10・12)を検証
  • 無関係な差分・生成器バージョン起因の揺れが無いか確認
  • 所見の投稿

最後まで残っていた「⚠️ 未実施」が解消され、生成物が .proto と一致していることを確認しました。指摘はありません(🟠 が 1 件、PR 本文の記述だけ)。

git diff cc89244 HEAD.proto に入った変更は 7 箇所(コメント 6 本 + 新フィールド 2 つ)で、その すべてが .pb.go / src/dbp_schema.rs の両方に反映されています。逆に、それ以外の差分は 1 行もありません。


検証できたこと

1. descriptor のバイト列が計算と厳密に一致します

これが今回いちばん確度の高い確認でした。dbp_schema.pb.gofile_dbp_schema_proto_rawDesc で、CompressionHintDescriptorProto の長さ varint が

エンコード
変更前 \xc6\x06 838
変更後 \xa2\a 930

+92 バイトになっています。追加された中身を数えると:

  • FieldDescriptorProto × 2 — \x12\x1f (2) + 本体 31 バイト = 33 × 2 = 66
  • 合成 oneof (_rangeMin / _rangeMax) × 2 — B\v (2) + \n\t_rangeMin (11) = 13 × 2 = 26

66 + 26 = 92 で、長さ varint の増分とぴたり一致します。切り詰めや余りが無いことの機械的な裏付けになっています。

本体 31 バイトの中身も展開して確認しました:

\n\brangeMin   name = "rangeMin"
\x18\x12       number = 18            ← rangeMax は \x18\x13 = 19 ✓
 \x01          label = LABEL_OPTIONAL ✓
(\t            type  = TYPE_STRING ✓  (.proto の optional string と一致)
H\x0e          oneof_index = 14       ← rangeMax は \x0f = 15 ✓
R\brangeMin    json_name = "rangeMin" ✓
\x88\x01\x01   proto3_optional = true ✓

oneof_index14 / 15 は、既存の最後(_isMostlyIncremental = 13)の次で連番です。合成 oneof の宣言も B\x14\n\x14_isMostlyIncremental直後に同じ順で追加されており、proto3 optional の要求(合成 oneof は実 oneof の後ろ・フィールド宣言順)を満たしています。

2. .proto のコメントが両生成物に逐語で入っています

6 本すべて、末尾まで含めて文字列一致を確認しました(各コメントの末尾の一句が 3 ファイルで同数出現):

tag 末尾の一句 出現数(proto / pb.go / rs)
80 / 81 / 83 so consumers are the ones that have to check it 3 / 3 / 3
82 the range of the DataFieldType where it does not 1 / 1 / 1
83 it coarsens, never refines 1 / 1 / 1
CompressionHint 10 / 83 keep no more places than the DataFieldType does 2 / 2 / 2
CompressionHint 12 inherited from the DataFieldType otherwise 1 / 1 / 1
CompressionHint 18/19 consumers that derive precisionBytes are the ones that have to check it 1 / 1 / 1

これで PR 本文の「⚠️ 未実施」に挙がっていた 3 種類の差分がすべて実現していることになります(新フィールド 2 つ/tag 80〜83 の doc comment 変更/CompressionHint の tag 10・12 への doc comment 追加)。

コメントの配置も生成器の規約どおりです。RealWorldDataStructurePropertyrange_min/// Numeric range etc → 空行 → 本文(detached + trailing)、CompressionHintrange_min は 3 行の leading comment がそのまま連続する /// になっていて、decimal_places(tag 10)は detached + trailing。既存の他フィールドと同じ形です。

3. 生成器バージョンが動いていません

dbp_schema.pb.go:1-5 のヘッダ(protoc-gen-go v1.36.11 / protoc v7.35.1)は 1 文字も変わっていません。前回の b93d81e と同じツールチェーンで回っているので、当初懸念されていた「中途半端なバージョンで再生成して無関係な差分が大量に出る」状態にはなっていません。差分 45 行 / 18 行という規模も、.proto の変更量そのものです。

4. Go のアクセサ

GetRangeMin() / GetRangeMax()GetIsMostlyIncremental() の直後に、既存と同じ if x != nil && x.RangeMin != nil の形で追加されています。unknownFields / sizeCache の空白が動いているのは、新フィールド追加による gofmt の再整列で、意味の変更はありません。depIdxs / NumMessages は、追加がスカラー 2 本のみなので変わらないのが正しい挙動です。

5. 他の成果物への影響

この commit が触ったのは .pb.go.rs の 2 ファイルだけで、.jsonld / .sql / dbdiagram-oss_exported_data.json / README.md は 1 行も動いていません。今回は語彙の変更ではないので、これが正しい状態です(.jsonld5235829 時点で .proto のコメントを取り込み済み)。

6. 日英の .proto

dbp_schema.ja.protoCompressionHintrangeMin = 18 / rangeMax = 19 で番号が一致しています。こちらから生成される Go / Rust は無いので、追加の再生成は不要です。


🟠 PR 本文の「⚠️ 未実施」欄が古くなりました

内容の指摘ではなく、本文の記述だけの話です。冒頭の

⚠️ 未実施 — dbp_schema.pb.gosrc/dbp_schema.rs

この PR では Go / Rust の生成物を更新していません

1ea3cd2 で解消されました。merge 時のコミットメッセージにこの本文が入るので、「未実施」のまま残ると履歴を後から読む人が「Go / Rust はまだ古いはず」と誤解します。1ea3cd2 で再生成済み」に書き換えて頂くか、節ごと「実施済み」に差し替えるのが良いと思います(列挙されている 3 種類の差分の内訳自体は、実際に入ったものと一致しているので、そのまま残して見出しだけ変えるので足ります)。

🔵 継承元の DataFieldType 側には doc comment がありません(次の機会で)

今回で CompressionHint.rangeMinsrc/dbp_schema.rs:1150-1152)には「DataFieldType から継承する」と 3 行書かれましたが、その継承元である DataFieldType.rangeMin / rangeMax / decimalPlacesdbp_schema.proto:541-543、tag 32〜34)は無印のままです(src/dbp_schema.rs:1073-1075)。

JSON-LD では dbp:rangeMin が 1 ノードで、初出(tag 80)の rdfs:comment が代表になるので語彙としては問題ありません。困るのは .pb.go / .rs だけを読む人で、CompressionHint 側から「DataFieldType の値が適用される」と言われて DataFieldType を見に行くと何も書かれていない、という往復になります。この PR で入った状態ではなく元からの形なので、直すとしても別途で構わないと思います(1 行の逆向きの導線で足ります)。


今回確認できなかったこと

この実行環境には go / protoc / cargo がなく、.pb.go のコンパイルと cargo build は実行できていません。 ただし今回は生成物の検証なので、上記 1(descriptor のバイト列が独立に計算した値と一致)と 2(コメントの逐語一致)で、生成が実際に走った結果であることは十分に裏が取れていると考えています。

前回まで指摘していた「生成物と生成器の一致を機械的に確かめる手段が無い」件は変わらず残っていますが、この PR で置いていかれていたものは全部追いつきました。CI 化は別 PR という整理に引き続き同意します。


結論: merge して良い状態です。 残っているのは 🟠(PR 本文の「⚠️ 未実施」欄の書き換え)だけで、これはコードではなく merge コミットに残る文言の話です。🔵 は次の機会で構いません。

@nagata-yoshiteru ご確認ください。

· branch claude/compression-hint-value-range-and-alias-alignment · View job

@nagata-yoshiteru
nagata-yoshiteru merged commit 19fc035 into main Aug 8, 2026
1 check passed
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.

3 participants