コンテンツにスキップ

ADR-30 — `rigor-ffi`プラグインの形状

ステータス: 提案済み、2026-05-25

ネイティブライブラリをffi gemでラップするRuby gemに共通のffiマシナリーをカバーするコアrigor-ffiプラグインと、ライブラリごとのサブプラグインファミリー(rigor-rbnaclrigor-ethonrigor-ffi-rzmqrigor-sassc)を出荷し、同じコアがtenderloveのffx gem(インストール時にCエクステンションにトランスパイルする厳格なFFIサブセット)をターゲットにするプロジェクトにも対応できる境界を設けるという決定を記録する。

根拠となるサーベイはdocs/notes/20260525-ffi-library-survey.mdにある(5つの実ffi消費者 + tenderloveの4リポジトリ補遺)。

ffi gem経由でネイティブライブラリをラップするRuby gemはRigorにとって繰り返す不透明性の壁を作る:

  • attach_function :name, [arg_types], ret_typeはロード時にモジュールメソッドを登録する。バインドされたメソッドは存在するが、そのRBS相当のシグネチャは呼び出しサイトでRubyのシンボル配列としてのみエンコードされている。
  • FFI::PointerFFI::MemoryPointerFFI::AutoPointerFFI::StructFFI::UnionFFI::Functionなどがクロスバウンダリのデータを運ぶ。これらはいずれも今日のRigorの語彙でファーストクラスの型ではない。
  • ethon(libcurl)、rbnacl(libsodium)、sassc-ruby(libsass)のようなgemのユーザー向けAPIは、attach_functionバインドされたプリミティブの上に構築されたRubyクラスレイヤーだ。バインディングシグネチャがなければ、高レベルメソッドはエンドツーエンドでDynamic[Top]として型付けされる。

5ライブラリサーベイ + tenderlove補遺が非自明な軸を特定した:

  1. バインディングスタイル分類。リテラルのattach_function(sassc-ruby、ethon、ffxターゲット)vsそれをラップするカスタムDSL(rbnaclのsodium_functionmodule_evalに補間)vs別gemで宣言されたバインディング(ffi-rzmq → ffi-rzmq-core)。
  2. ライブラリごとの生成サーフェス(surface)。ethonはオプションカタログを反復して各セッターをdefine_methodする;sassc-rubyはsass_プレフィックスを取り除くためにattach_functionをオーバーライドする。
  3. 名前付き不透明ポインタとしてのtypedef。sassc-rubyは10個のtypedef :pointer, :sass_*_ptrエイリアスを宣言する;それらを別個のNominal型として扱うと実際のクロスコンテキスト誤用を捕捉できるが、常にnominalにするとドキュメント目的だけのtypedefを使うgemで偽陽性が出るリスクがある。
  4. ffxターゲット。ffxはffi gemと同じDSLサーフェスを公開するが25シンボルのプリミティブ型セットのみを受け付ける(コールバック、struct、typedef、enum、varargs不可)。インストール時に本物のCエクステンションにトランスパイルし、ZJIT消費のため各トランポリンにFFI0マジックマークのメタデータブロブを埋め込む。
  5. Fiddleの隣接。RubyのStdlibのFiddleは並行するFFIメカニズム(sqliteffxがアウトパラメータ読み取りに使用)。そのバインディングサーフェスはffi gemのものとかなり異なる。
  6. 「FFIなし」の否定ケースchildprocessはFFIを一切使わない——RubyのProcess / IOに依存する。プラグインは検出されたFFIバインディングコードを根拠に有効化すべきで、「ローレベルに見える」ことを根拠にしてはならない。

補遺の主要な発見は本質的に好ニュース: ffxのDSLはffi gemのものとビット同一(かつ厳密に小さい)ので、ffi gemをカバーする認識器(recognizer)はffxターゲットコードを無料でカバーする——さらに、gem installビルドが失敗する前にffx非互換な宣言を静的診断として表面化できる機会もある。

正直な需要の絵は、エンジニアリングサーフェスが示唆するより弱い。sassc-rubyは事実上EOL(libsassが2020年に上流で廃止);typhoeus / ethonとrbnaclは実態があるが専門化したユーザーベース;ffi-rzmqはニッチ。4つの候補サブプラグインはどれも例えばrigor-activerecordのユーザー引力を持たない。実装の根拠は代わりに2つのゼロオーバーヘッドプロパティにある:

  • サブプラグインはplugins/に同梱され、解析されたプロジェクトの解決済み依存セットにマッチするgemが現れたときにのみ有効化される——非ユーザーはゼロのアナライザーコストを払う。
  • コアFFIキャリア(carrier)型(FFI::PointerFFI::MemoryPointerFFI::Struct)はサーベイコーパス全体で名前で参照されている;それらをコアrigor-ffiでモデル化することで、FFIに偶発的に触れるすべてのプロジェクト(4つの作業消費者だけでなく)を底上げする。

この組み合わせ——非ユーザーへのオーバーヘッドなしの付加的カバレッジ——は直接需要が弱いにもかかわらず積極的な実装を正当化する(WD9)。

コアrigor-ffiプラグイン + ライブラリごとのサブプラグインファミリーを出荷する。ADR-12 / ADR-25のパッケージング形状はdry-rbとRailsプラグインラインですでに実証済み。コアは共通のffiマシナリーをカバーし、ffi gemターゲットとffxターゲットの両プロジェクトを変更なしに対応する。ライブラリごとのサブプラグインはDSL認識器、オプションカタログ→セッターマッピング、高レベルAPI RBS精緻化を貢献する。

WD1 — プラグイン形状: コア + ライブラリごとのサブプラグイン

Section titled “WD1 — プラグイン形状: コア + ライブラリごとのサブプラグイン”

コアrigor-ffiプラグインが所有するもの:

  • extend FFI::Library認識(ホストモジュールがバインディングレジストリになる);
  • 25のプリミティブ型シンボル + :varargs + カスタムtypedef参照によるリテラルattach_functionウォーク;
  • callbacktypedefenumbitmask認識;
  • FFI::StructFFI::UnionFFI::ManagedStructlayoutウォーク;
  • FFI::PointerFFI::MemoryPointerFFI::BufferFFI::AutoPointerFFI::FunctionFFI::Structベース向けRBS;
  • 呼び出し境界でのString ↔ :pointer / :stringオートコーション(WD7);
  • typedef済みポインタのnominal型ヒューリスティック(WD4);
  • ffxターゲット診断ファミリー(WD5)と検出(WD6)。

ライブラリごとのサブプラグイン(rigor-rbnaclrigor-ethonrigor-ffi-rzmqrigor-sassc)が所有するもの:

  • 1つのgemに特有のDSL認識器(sodium_function、ethonのオプションカタログディスパッチ、sassc-rubyのプレフィックスストリップオーバーライド);
  • 高レベルAPI RBS精緻化(SecretBox#encrypt: (String, String) -> StringEasy#perform: () -> Integer);
  • クロスgemシグネチャ取得(ffi-rzmq → ffi-rzmq-core)。

却下された代替案。モノリシックな単一rigor-ffi(すべてのライブラリの認識器を常にロード)はRailsプラグインパッケージング規律のすでに支払われたコストを失い、非ユーザーにブートコストを強いる。コアなしの各gemフル自律形状は共通マシナリーのメンテナンスを分散させ、キャリアRBSを重複させる。

WD2 — DSL認識器の配置: コアの拡張ポイント

Section titled “WD2 — DSL認識器の配置: コアの拡張ポイント”

コアがPlugin::FFI::BindingRecognizer拡張ポイントを公開する。サブプラグインが認識器を登録し、その認識器はASTノードを受け取り、ゼロ個以上の合成されたattach_functionファクト(fact)を返す。コアはそれらのファクトをリテラルのattach_function呼び出しを処理するのと同じパイプラインで処理する——サブプラグインは並行した型付けパイプラインではなく認識器を貢献する。

フェーズ2(先送り): ADR-16 Tier Cが宣言的変換モードを出荷したら、sodium_function認識器はTier-Cマニフェスト宣言に移行する。拡張ポイントはTier Cにきれいに収まらない形状のために残る。

却下された代替案。コアがリテラルattach_functionのみを処理し、各サブプラグインが自分でASTをウォークする: 各サブプラグインがバインディングファクト放出のボイラープレートを再実装することになる。拡張ポイントを完全にスキップしてすべてのDSL認識をADR-16経由でルーティングする: Tier Cの先送りされた形状への依存を強制し、このADRの納品をADR-16に結合させる。

ffi-rzmqのattach_function呼び出しは別のffi-rzmq-core gemに存在する。解決パスはADR-10のオプトインの依存関係ソース推論: プロジェクトがffi-rzmqを使う場合、rigorは依存関係ソースティア下でffi-rzmq-coreのソースをウォークし、LibZMQ.*シグネチャを貢献する。

却下された代替案LibZMQ向けのプラグイン提供バンドルRBS(ADR-25)— FP規律の面で好ましいが、ffi-rzmq-coreに対して手書き + バージョンごとのメンテナンスが必要。ffi-rzmqは最も需要の低い作業消費者(WD9)でありADR-10が一般的な「FFIバインディングが兄弟gemにある」問題への長期的に正しい答えなので、ADR-10への先送りが安価なパス。ADR-10の進捗が止まりffi-rzmqサポートが具体的なユーザーの要求になった場合、ADR-25はフォールバックとして利用可能。

WD4 — typedef済み不透明ポインタ: 名前ヒューリスティックのnominal型

Section titled “WD4 — typedef済み不透明ポインタ: 名前ヒューリスティックのnominal型”

typedef :pointer, :alias_name呼び出しがNominal[<plugin>::<AliasName>]型を貢献するのはalias_nameが慣例的な不透明ポインタ命名パターン(エイリアスシンボルへの_ptr$ / _handle$ / Ptr$ / Handle$正規表現)にマッチするときのみ。そうでなければtypedefは:pointerの透明エイリアスとして扱われる。

nominalキャリアはロバストネス原則を尊重する:

  • 入力 — nominalエイリアスとして宣言されたパラメータはNominal[<alias>] | FFI::Pointer | Integer | nilを受け付ける(後2つはより広いFFIキャリア;IntegerはWD7に従いffxケースをカバー)。
  • 戻り値 — nominalエイリアスとして宣言された戻り型は厳密なNominal[<alias>]のまま。

プロジェクトごとの.rigor.yml例外リスト(rigor_ffi: { nominal_typedef_exceptions: ["log_target_ptr"] })でプロジェクトがヒューリスティックが誤発火した場合にtypedefを透明に戻せる。

却下された代替案。常にnominal: 精度最大だがドキュメントのみの目的でtypedefを使うgemでFP発生リスク。typedef呼び出し自体へのオプトインキーワード: ffi gemの呼び出し形状を変更する必要があり、それはrigorが越えられないAPI境界を越えることになる。

WD5 — ffxターゲット: 新しい診断ファミリーffx.unsupported-*

Section titled “WD5 — ffxターゲット: 新しい診断ファミリーffx.unsupported-*”

ffxターゲットが検出されたとき(WD6)、コアプラグインがffxがコンパイルを拒否するバインディング宣言の新しい診断ファミリーを表面化する:

  • ffx.unsupported-callbackcallback :foo, [...], :int
  • ffx.unsupported-structclass S < FFI::Struct
  • ffx.unsupported-typedeftypedef :pointer, :handle
  • ffx.unsupported-enum / -bitmaskenum :state, [...]
  • ffx.unsupported-varargsattach_function :printf, [:string, :varargs], :int
  • ffx.unsupported-type — ffx-25プリミティブセット外の型シンボル

この診断は構造上偽陽性がゼロ: それが表面化するすべての宣言は、ffxがgem installビルド時に翻訳に失敗するものだ。これはまさに偽陽性規律が明示的に招く種類の付加的ゼロFPリスク診断: ランタイムのビルド失敗を静的lintに移す。

重要度はデフォルト:error(ffxはビルドに失敗する);ffxターゲットかどうかが条件付きのデュアルターゲットバインディングファイルを意図的にメンテナンスするプロジェクトは宣言ごとに# rigor:disable ffx.unsupported-*で抑制できる。

WD6 — ffxターゲット検出: まずextconf.rbスキャン

Section titled “WD6 — ffxターゲット検出: まずextconf.rbスキャン”

ffx検出は3つのソースをトップダウンでカスケードする:

  1. プロジェクトextconf.rbスキャン。いずれかのext/**/extconf.rbにリテラルのFFX.create_makefile呼び出しが含まれれば、プロジェクトをffxターゲットとみなす。バンドラー依存なしの単一ファイルチェックで、標準的なsqliteffxパターンを処理する。
  2. Gemfile.lock依存スキャンffxが解決済み依存として現れれば、プロジェクトをffxターゲットとみなす。BundleSigDiscovery(v0.1.5)にすでに存在するバンドラー解析パスを再利用する。
  3. 明示的設定.rigor.ymlrigor_ffi: { target: ffx }を設定して検出を強制できる。最終手段、extconf.rbGemfile.lockも信頼できない環境のために存在する。

検出結果はプロジェクトコンテキストレベルでキャッシュされる(ADR-6のキャッシュ無効化ルールに従い、関連入力ファイルが変更されたときにクリアされる)。

却下された代替案。バンドラーファースト検出: 動作するがextconf.rbがすでにクリーンな答えを出すケースでバンドラー内部に結合する。明示的のみ: セットアップ摩擦が機会的検出のゼロFPコストを上回る。

WD7 — :pointerパラメータ入力セットを全面的に拡大

Section titled “WD7 — :pointerパラメータ入力セットを全面的に拡大”

attach_functionバインドされたメソッドの:pointer型パラメータはFFI::Pointer | FFI::MemoryPointer | FFI::AutoPointer | FFI::Buffer | Integer | String | nilを受け付ける、ターゲット(ffi gemまたはffx)に関係なく

根拠: サーベイコーパスはこれらのキャリアをそれぞれ渡す実世界の呼び出し元を示している——sqliteffxがInteger(Fiddle経由で読んだ生アドレス)を渡し、rbnaclがString(バイナリエンコードされたバッファ)を渡し、ethonがFFI::AutoPointer(ライフサイクル管理されたハンドル)を渡し、sassc-rubyがFFI::MemoryPointer.from_stringの結果を渡す。ロバストネス原則の「入力には寛容に」という行は、パラメータ型が実際の呼び出し元が渡すものの和集合であるべきと言う;実行時の拒否(ffi gemは生のIntegerを拒否する)はruntime concernであり、rigorのconcernではない。

戻り型はターゲット依存のまま: ffi gemターゲットはFFI::Pointer、ffxターゲットはInteger。戻り型は非対称の「出力は厳密に」サイド。

却下された代替案。ターゲット依存の入力ナローイング(narrowing)(ffi gem: FFI::Pointer | nil;ffx: Integer | nil): デュアルターゲットバインディングファイルがチェック不能になる;正当なクロスキャリアコードでFP。

以下は意図的にrigor-ffiから除外されている。各々に他の場所(既存または将来)に適した居場所がある。

項目理由
FFIハンドルのuse-after-free / double-free / リーク診断エフェクトトラッキング領域であり型の問題ではない。将来のrigor-resourceプラグイン(またはエンジン側のエフェクト解析)が適切な場所。
FFI::Structフィールドアクセスの境界チェック配列インデックスフロー解析はエンジン作業であり、FFI固有ではない。
ネイティブ側のコンパイル正確性(sassc-rubyのext/libsassビルド、ffxの生成C)Rigorはrubyを解析する;ネイティブビルドの正確性はgemの作者 / mkmfの問題。
fisk / aarch64 / JITBufferFFIバインディングサーフェスのない純Rubyの命令エンコーダー。エンドユーザーのコードはこれらのシンボルを参照しない。需要があれば将来のrigor-jit領域。
手書きCエクステンション(ext/*.c内のrb_define_methodRuby側の静的なハンドルなし。カバレッジには.soの解析が必要——ffxトランポリンFFI0ブロブ解析が着地するまでスコープ外。
Fiddle実質的に異なるDSLを持つ並行のStdlib FFIメカニズム。別途著作される兄弟rigor-fiddleプラグインに属する。

WD9 — 実装は非ユーザーへのゼロオーバーヘッドで正当化され、直接需要ではない

Section titled “WD9 — 実装は非ユーザーへのゼロオーバーヘッドで正当化され、直接需要ではない”

4つの候補サブプラグイン各々への直接ユーザー需要は正直に弱い。sassc-rubyは事実上EOL(libsassが2020年に上流で廃止);typhoeus / ethonは実態があるが低下傾向のHTTPクライアントシェア;rbnaclはクリプト重視のスタックに専門化;ffi-rzmqはニッチ。いずれもRailsティアプラグインのユーザーベーススケールには達しない。

それでも実装を進める理由:

  • 非ユーザーごとのコストはゼロ。サブプラグインは解決済み依存セットにマッチするgemが現れたときにのみ有効化される;rbnaclを一度もrequireしないプロジェクトはrigor-rbnaclの認識器のアナライザーコストを払わない。
  • コアrigor-ffiはすべての偶発的FFIユーザーを底上げする。コアでFFI::PointerFFI::MemoryPointerFFI::Structをモデル化することで、4つの作業消費者だけでなくFFIキャリアに触れるすべてのプロジェクトを助ける。コアの恩恵はサブプラグインの恩恵が狭くても広い。
  • 実装経験それ自体が出力。DSL認識器拡張ポイント(WD2)、typedef-nominalヒューリスティック(WD4)、ffx診断ファミリー(WD5/6)はどれもプラグイン契約(contract)の新しい形状だ。実際の作業消費者がv0.2.0に向けて契約サーフェスが安定する前にストレステストする。

これはdry-rbプラグインファミリーを現在の幅に正当化するのと同じ論理: 個別の需要が低く、非ユーザーへのオーバーヘッドなく、広いインフラ恩恵がある。

WD10 — カバレッジスコープ + 著作パス

Section titled “WD10 — カバレッジスコープ + 著作パス”

4つの作業消費者の先には2つの異なるgemポピュレーションが存在する: Rigorが対応すべき実世界のFFI gem、および外部ユーザーが著作するかもしれない内部 / プライベートFFI gem。このWDはコアrigor-ffiから何を得るかvsサブプラグインを必要とするものは何かを記録し、後者をADR-31で定義されたプロジェクト全体の貢献ポリシーを通じてルーティングする。

「バニラ」FFI gemに対するコアrigor-ffiのカバレッジスコープ

(a)自身のlib/でリテラルのattach_function呼び出しでバインディングを宣言し、(b)プリミティブ型シンボル + callback / typedef / enum / bitmask / FFI::Structを使用し、(c)バインドされたメソッドを薄いRubyクラスレイヤーでラップするFFI gemの場合、サブプラグインなしにコアが型付けサーフェスの大部分をカバーする:

サーフェスコアカバレッジ
attach_functionバインドメソッドシグネチャ完全(リテラルウォーク)
FFIキャリア型(Pointer / MemoryPointer / Struct / Function完全(コアのRBS)
layout経由のStructフィールドアクセス完全(リテラルウォーク)
Enum値セットとシンボル→整数マッピング完全(リテラルウォーク)
コールバックパラメータ / 戻り型完全(callback typedefウォーク)
typedef済み不透明ポインタエイリアスヒューリスティック(WD4);例外リスト利用可
FFIキャリアを返す薄いラッパークラスのdef完全(通常の推論がキャリアを伝播)
FFIプリミティブの戻り型よりリッチなセマンティクスを持つラッパークラスメソッド非対応——サブプラグインのRBS精緻化が必要
attach_functionをラップするカスタムDSL(rbnacl形式のsodium_function非対応——WD2のBindingRecognizer登録が必要
兄弟gemで宣言されたバインディング(ffi-rzmq-coreスタイル)非対応——WD3(ADR-10)またはバンドルRBS(ADR-25)が必要
オプションカタログ駆動のdefine_method(ethon形式)非対応——ADR-16 Tier B/Cの認識が必要

具体的には: リテラルのattach_function :acme_open, [:string], :pointerを宣言してそれをclass MyCorp::Acme; def initialize(path); @handle = LibAcme.acme_open(path); end; endにラップする内部MyCorp::LibAcme gemはコアのみで完全な型付けを得る。プロジェクトの.rigor.ymlは依存関係ソース推論スコープ(ADR-10)内にバインディングファイルが入るようdependencies:下にgemを列挙するだけでよい。

「サブプラグインが必要な」ケースの著作パス

新しいSKILL — rigor-ffi-plugin-author.claude/skills/rigor-ffi-plugin-author/SKILL.mdに配置)— 著作者を以下のステップでガイドする:

  1. 上のテーブルに対するカバレッジ評価。gemが「バニラ」パターンにマッチすれば、SKILLは「プラグイン不要——依存関係を宣言して終わり」で終了する。これは重要: SKILLは、コアで十分なときはプラグインを著作しないようにユーザーを説得すべきで、プラグインエコシステムを健全に保つ。
  2. ADR-31に従った著作パス — ユーザー自身のリポジトリでサードパーティのrigor-<gem> gemとして著作し(ADR-31 WD4)、gemがWD3のコミュニティ認知閾値に達したらWD2の昇格ルートを通じてバンドルを任意で提案する。
  3. スキャフォールド — ディレクトリレイアウト + specレイアウト + CHANGELOGルールのための一般的なrigor-plugin-author SKILLを参照(手続き形状はgemタイプに依存しない)。
  4. FFI固有のビットPlugin::FFI::BindingRecognizer登録(WD2)、オプションの高レベルラッパーRBS、バインディング認識とラッパークラス型付けの両方を検証するデモフィクスチャ。ラップされたgemのバージョンレンジをプラグインのgemspecにピン留めする;新しいラップgemバージョンはリポジトリ内のプラグインを更新することで追跡する(孤立プラグインリスクはADR-31 WD4に従いプラグイン著作者の責任)。

SKILLの手続きFFI固有コンテンツ(ステップ4)は最初は概略で、スライス(slice)1(コアMVP)が出荷されてスライス2(sassc-ruby)が最初の具体的なリファレンス実装を提供するにつれて権威的になる。

配布ガバナンス: ADR-31を参照

プロジェクト全体のポリシーが適用される——マイナーな焦点を絞った変更(例: すでにバンドルされたFFIサブプラグインへのバグFix)はダイレクトPRとして歓迎(WD1ダイレクトPRパス);新しいバンドルFFIサブプラグインは広範な変更であり、issue-firstルート(WD1 + WD2)を経由し、チームで著作した実装にCo-authored-by:アトリビューションを付ける;サードパーティのrigor-<gem>プラグイン著作は著作者自身のリポジトリで歓迎(WD4);実証されたサードパーティプラグインのsubtreeマージはオプションパスとして予約(WD5)。このADRはポリシーを再述しない;FFIプラグインファミリーはそれが統治するいくつかのプラグインファミリーのひとつ。

6スライス、概略。このADRではいずれのスライスもスケジュールされていない。スライス順序は需要重み付けではなく工学的進行駆動(最も単純なケースからコアを検証)。

スライススコープ
1コアMVPextend FFI::Library認識。25のプリミティブ型シンボルによるリテラルattach_functionウォーク。ffi_libFFI::PointerFFI::MemoryPointerFFI::AutoPointerFFI::FunctionFFI::Structベース向けRBS。WD7のポインタパラメータ幅広げ。DSL認識器拡張ポイントはまだなし。
2rigor-sassc消費者(経験構築)。最初の実消費者。WD4のtypedef-nominalヒューリスティックを検証(sassc-rubyはコーパスの最も単純なケース)。FFI::Structlayoutウォーク(SassValueタグ付きユニオン)+ enum認識(SassOutputStyle)を実行。低実需認識(sassc-ruby EOL)——スライスの価値はコア検証であり、ユーザー影響ではない。
3rigor-ethon消費者。ADR-16フレーバーの作業への最初の接触: オプションカタログ(Curl::Options.easy_options)がdefine_method生成セッターを駆動する。カタログモジュール向けのTier Bトレイトインライニング + セッター形状のTier Cヘレドックテンプレートを消費する可能性が高い。ADR-16が実際のdefine_methodファームをどの程度クリーンにカバーするかをテストする。
4rigor-rbnacl消費者 + WD2拡張ポイントBindingRecognizer拡張ポイントがここで着地し、sodium_function認識(補間ヘレドック——コーパスで最も困難なバインディング回収形状)によって駆動される。
5WD5+WD6 ffxターゲットextconf.rb / Gemfile.lock検出。6つのffx.unsupported-*診断。sqliteffxを検証消費者として使用(sqliteffx.rb内のすべての宣言はffx互換;診断は構築した反例フィクスチャにのみ発火すべき)。
6rigor-ffi-rzmq消費者ADR-10の依存関係ソース推論がメソッドレベルシグネチャを貢献できることにゲートされる(呼び出しサイトごとの戻り型精度はADR-10の将来サイクルバックログ)。最低優先度——ADR-10が進展するか具体的なユーザー要求が現れるまで先送り。
  • コアはffxを無料で処理する。ffxのDSLはffi gemのものの厳密なサブセットなので、コアrigor-ffiはffxターゲットプロジェクトをffx固有の認識器なしでカバーする。ffx固有の作業は付加的なWD5+WD6診断ファミリーのみ。
  • Plugin::FFI::BindingRecognizerは負荷を担うアーキテクチャ上のコミットメント。この拡張ポイントはADR-13のTypeNodeリゾルバチェーンと同じ形状問題ファミリー——プラグイン提供認識器のレジストリで、その出力が共通エンジンパイプラインに流れる。個別のサブプラグインを出荷することよりもそのサーフェスを正しく取得することの方が重要。
  • 実装順序は工学的進行駆動。sassc-rubyが最初なのはそれが最も需要の高いgemだからではなく、最も単純なケースだから。「なぜEOLのgemを最初にモデル化しているのか」という批判への反論者にはWD9を指摘できる。
  • rigor-fiddleは別の取り組み。FiddleのDSLサーフェスは十分に異なる(extend FFI::Libraryなし、attach_functionなし;Fiddle::Function.newFiddle::Pointerdlopenを使用)ため、共有インフラが薄くなる。独立して著作された兄弟プラグインがより単純な形状。このADRでブロックされない。
  • 二次シグネチャソースとしてのFFI0トランポリンメタデータの解析。ffxは各生成トランポリンに(magic | param_count | type_bytes | function_name)を埋め込む。Rubyバインディングファイルが隠れている(ベンダーブロブ、カスタムラッパー)が.soが存在するインストール済みgemに対して、トランポリンの解析でバイナリからシグネチャが回収できる。初期プラグインのスコープ外(ELF / Mach-O / PE認識が必要)だが、具体的な消費者がそれを必要としたら再検討に値する。
  • デュアルターゲットgem。サーベイされたgemはffi-gemとffxコードパスを条件付きで出荷していない。実際のデュアルターゲットgemが現れた場合、WD5の宣言ごとの抑制をエルゴノミクスのためにレビューしなければならない(おそらく問題ない——# rigor:disableが既存の宣言ごとのメカニズム)。
  • ethonのeasy_setopt内の呼び出しサイトごとのvarargs型付け[:pointer, :easy_option, :varargs]シグネチャは外部のオプションカタログを通じてenum値でvarargs型をディスパッチする。現在の決定ではコアではなくサブプラグイン(スライス3)でこれをモデル化する——varargs-dispatched-by-enumはサブプラグインが存在する種類の形状。同じパターンを持つ2番目のgemがメカニズムをコアに昇格させることを正当化したら注目する。
  • ffx.unsupported-*の診断ID安定性。WD5の6つのIDがフロア。7番目の追加(例: ffx.unsupported-blocking-call)は付加的で安全;6つのいずれかの名前変更はベースライン(baseline)を持つプロジェクトにとって破壊的変更。最初のリリースで6つをロック。

© 2026 TypedDuck. Licensed under CC BY-SA 4.0.