sbt と西部時代の山師たち
sbt という名の小さな村
僕は、有志で sbt と Zinc のメンテナをやっていて、それらは Scala という、マルチ・パラダイムかつ JVM、JS、ネイティブを対象とするマルチ・プラットフォームなプログラミング言語を駆動するツールチェインの一部を担っている。Scala 言語は 20年近く前からあるが、特に 2009年に Twitter社が採用して以降、Apache Spark、LinkedIn、Morgan Stanley、ING、Airbnb、Spotify、Netflix、国内だとリクルート、ドワンゴ、サイバーエージェント社などで採用事例があった。
経年の Scala の名声とは一歩おいて、sbt も Zinc も依然としてニッチなプロジェクトで、基本的には僕個人と Scala Center との協力、そして一部 Scala ユーザと EFPL、Lightbend/Akka社、JetBrains社、VirtusLab社、Databricks社、Gradle社などのツール担当の人たちから形成される内輪の人たちが送ってくれるコントリビューションで開発が行われていて、だいたいポーランドとかスイスの Scala カンファレンスに顔を出しているとお互い面識ができてくる。
金鉱山師たちが村にやってきた
2026年1月のある日、この状況は突然変化して、sbt/sbt に以前全く聞いたことが無い人たちからプルリクが送られてくるようになった。後になって徐々に分かったことは、sbt/sbt が、Gittensor という名前のクリプト通貨ベースのオープンソース懸賞プログラムに追加されたということだ。https://subnetalpha.ai/subnet/gittensor/ によると:
Gittensor は、デベロッパーがオープンソース・ソフトウェアに貢献することを奨励することに特化した Bittensor ネットワークのサブネットだ。簡単に言うと、デベロッパーが (山師として) 事前に選ばれたオープンソース・プロジェクトに (コードの改善やプルリクエストなど) 有意義なコントリビューションを行うとクリプト通貨を得られる仕組みを提供することで分散型「オープンソース労働力」を形成を目指す。
僕の限られた理解だと、ここで言う「サブネット」は Bittensor (TAO) というクリプト通貨の中での仮想ベンチャー企業で、アルファ・トークンが各ベンチャーの株式として機能する。Bittensor は、定期的にサブネットに投資を行って (これは「排出 (emission)」と呼ばれる)、山師たちにはアルファ・トークンで懸賞が渡され、これを TAO に払い戻し (unstake) して、さらに TAO は USD ドルに取引することができる。つまり、Bitcoin の全く無駄な「マイニング (発掘)」の代わりになんらかの有益な活動を行うというのが Bittensor のベンチャー企業の特徴のように思える。Bittensor (TAO) 本体に誰が投資しているのかは僕は知る由もないが、「コンピュータが協調して AI を開発する分散ネットワーク」を売り文句にしていて、ベンチャー・キャピタルだとは言っていない。
いずれにせよ、Gittensor は毎月 $116k USD (約1千800万円) の懸賞金のプールがあると言っている。彼らは毎日 41.38 TAO を受け取っていて、これは $9548 (約145万8000円) に当たり、そのうち 41% は「山師」に分配されると主張している。僕はこれらの数字の信憑性を確認する手段を持たないが、これが本当だと思っている集団がいる。便宜的に、プルリク当たり $100 (約1万5000円) の報酬があると仮定しよう。
最初の 1人のプルリクエストをマージすると、他にも次々と来るようになった。
GitHub 月間統計
GitHub のパルス によると、2025年12月25日から 2026年1月25日の一ヶ月で、23人のコントリビュータが 145本のプルリクエストを送って、132本がマージされ、194個のイッシューがクローズされた。この統計には、僕自身のプルリクエストも含まれるが、僕が 10年以上メンテナをやっていてずば抜けて活発な 1ヶ月だったと思う。
一般的なバグ懸賞プログラムと違って、Gittensor は「山師」がどの GitHub イッシューの作業をするかの制限が一切無い。スコアは、ドレークの方程式かのごとく複雑な scoring system によって計算される:
code_density = min(token_score / total_lines, 3.0) contribution_bonus = min(1.0, token_score / 2000) * 30 base_score = (30 × code_density) + contribution_bonus earned_score = base_score × repo_weight_multiplier × issue_multiplier × open_pr_spam_multiplier × time_decay_multiplier × repository_uniqueness_multiplier × credibility_multiplier final_score = max(0, total_earned_score - total_collateral_score)
イッシューの作業をしてもいいかと確認してくれる「山師」/コントリビュータの人もいれば、勝手にプルリクエストを送ってくる人たちもいる。これは、僕が古くて無用となったイッシューを先にクローズする動機付けとなった。これが、プルリクエストよりも多くイッシューが閉じられた理由だ。
結局プルリクの質はどうなのか
ここで、皆が気になっていると思うのは、結局プルリクの質はどうなのかということだと思う。僕が一つ言えるのは、Gittensor が質の低いプルリクを送ることを予防する様々な機構を設けているということだ。例えばベース・スコアは、Treesitter 経由で抽象構文木を分析して計算されるため、ただコメントを変えるだけのプルリクを送ったとしても「山師」はポイントを稼ぐことができない。また、マージされたプルリクと開いたプルリクの割合によって計算される信頼性係数も落ちるようになっている。そのため、僕の感覚だと「山師」たちは GitHub イッシューに取り組んでいると思う。
しかしながら、プルリクの実効性にかなりばらつきがあるのは想像に難くないだろう:
| イッシュー | ジュニア組 | シニア組 |
|---|---|---|
| 簡単なイッシュー | ⛅ | ☀️ |
| 複雑なイッシュー | ⛈️ | ⛅ |
僕の個人的な観測だと、「山師」/コントリビュータは 2つの集団に分かれる。便宜的に、ジュニア組とシニア組と呼ぶ。シニア組は、簡単なイッシューと複雑なイッシューの両方をバランス良く取り組むことができて、僕が長年配慮できてなかったイッシューを修正することができている。一方ジュニア組は、簡単なイッシューでも複数回のレビューを必要とし、複雑なイッシューだと苦戦する。これは、Scala メタプログラミング、GitHub Actions CI を通過できる Windows バッチなど特殊な知識を要求される sbt プロジェクトの特徴にもよるため、この人たちの一般的なスキルレベルの評価を云々しているわけでは無い。
以下は、今月コントリビュートされたプルリクから厳選してものだ:
- [2.x] test: Fix ParseKeySpec flaky test when task name matches project name #8454. これは key パーサーのプロパティー・ベーステストを修正するものだ。
- [2.x] ci: Upgrade launcher-package from sbt 0.13 to sbt 1.x
- [2.x] fix: Fix ProjectMatrix invalid project ID with CrossVersion.full. Scala 3 のマクロ関連の修正。
- [2.x] fix: Invalidate update cache across commands when dependencies change
- [2.x] feat: Add “3-latest.candidate” support for Scala 3 release candidates. これは Scala 3 チームがリクエストした機能の実装だ。
- [2.x] feat: Add dependency lock file support
- [2.x] feat: Support forked console. これは僕が冬休み中に作業した機能の引き継ぎで、僕が JLine の問題で行き止まってしてまったバグのパズルを解いてくれた。
他のプルリクの中には、生成AI で作られたり、コントリビュータがイッシューを再現したり動作を確認した痕跡が無い酷いものも多かった。
コントリビュータ・ガイドとコード・レビュー
プルリクとプルリク・コメントが相次ぐにつれ、良質なコントリビューションを受け取るのにコード・レビューの重要性がより明確になってきた。プルリクの実際の動作もそうだが、現状のコードベースの品質維持とセキュリティ脆弱性の予防という意味もある。
そのため、Contributor’s guide (CONTRIBUTING.md) を書き始めた。これは、コードを書き始める前にまず問題をテストすることをお願いするセクションなどを含む:
- プルリクエストの作業をする前に、報告された問題を GitHub Actions もしくは自分のコンピュータで必ず再現できることを確認すること。
- コードの変更を行った後、必ず変更点がコンパイルして、問題を修正することを確認すること。
こんなことは当たり前すぎて今まで書く必要も無いことだったが、昨今の生成AI 時代においては、コンパイルもせずに投機的にプルリクエストを送っている山師たちもいる疑っている。以下は、AIアシストのコントリビューションのガイドラインの全文だ:
AIアシストのコントリビューション
一般的に、以下のガイドラインに従う限りプルリクエストを作成する補助に AI ツールを使うことは認められている:
- AI によって生成されたプルリクエストは、人間によって (human-in-the-loop) 完全に確認されなければいけない。実際に sbt を走らせて、変更点をテストすること。
- いかなる形での AI の使用も公示する必要がある。プルリクエストの記述欄に AI ツールを使用したことを明記すること。
- 第三者の作成物がアウトプットに含まれないこと、もしくはアウトプットに含まれる作成物は Apache License と互換性のあるオープン・ソース・ライセンスに準拠すること。
- 自分のプルリクエストに取り込む前に AI ツールが作成した全てのコードをレビューして、理解し、無批判に生成されたコードを信頼しないこと。コードの最終責任はプルリクエストの作者にある。
- 無批判に AI ツールからコードをコピー・ペーストするのは、セキュリティ上の問題やプロジェクトの安定性のリスクとなるような変更点を導入する可能性があるため、有害である。
⚠️ 未テスト、説明不能な AI からコピー・ペーストされたプルリクエストをメンテナが発見した場合は、関連するプルリクエストは閉じられ、今後そのユーザがコントリビュータできないようにブロックを行う。 ⚠️
完璧な世界ならば、AI は高品質で正確なコードを毎回作成する。しかし、現状では、コードの品質は AI のドライバーに依存する。そして、AI ドライバーの多くはその水準に達していないのは現状だ。そのため、人か AI か、両者が改善するまでは、厳密なルールを設定してメンテナを保護する必要がある。
偶然同じ時期に AI に関する規定を定めてる Ghostty の AI Usage Policy から一部を借りてきた。
AI アシストのコントリビューションを禁止する明らかな機構は無いため、修正を証明するという、プルリクエストとして満たさなければいけない基準を明記するという方針を取った。
僕の予想だと、ジュニア組とシニア組の両者とも「山師」たちは AI アシストを使っているが、異なる結果にたどり着いている。生成 AI はトレーニング集合にあるコードのパターンを吐き出すだけで、魔法のようにプログラマをより良いプログラマに変えてくれる訳ではないということだろうか。喩えとしては、チェーンソーだと考えることができる。熟練した大工にチェーンソーを渡すと、いくつかの共通したたタスクを高速化することができる。素人にチェーンソーを渡しても、そもそも何を切っていいのかが分からず、切った後でカンナを当てることも知らず、怪我をするか、プロジェクトを傷つけてしまうのが関の山だろう。
送られてきたプルリクエストを慎重にレビューして、ローカル環境でテストを行い、未テスト、説明不能な AI からコピー・ペーストされたプルリクエストを閉じて、ユーザをブロックするという方策よりも良い方法があると思う人は僕に是非教えてほしい。
カオスな Tidelift
以前 Red Hat や Typesafe の起ち上げに関わっていた人たちが、2017年に Tidelift という会社を起業した。Tidelift は、セキュリティ・パッチやライセンスなどのメンテナンス業にフォーカスしたエンタープライズ向けのサブスク・モデルを提供する。Red Hat がその作業を行う人を雇ったのに対して、Tidelift はオープンソースのデベロッパに支払いを行うというのが新規性だった。
この Gittensor というのは、誰でもこのギグ経済に参加できるというカオスな Tidelift だと考えることができる。現状だと、オープンソースのコントリビューションとクリプトコインを受け取る「山師」を結ぶ市場として機能する。この方程式において、プロジェクトのメンテナが費やすエネルギーは外部性となっている (僕はクリプトコインに興味は無い) が、面白いプルリクエストを得られるという見返りもある。curl がバグ懸賞を止めるというニュースも最近あった:
2026年1月まで curl バグ懸賞は存在した。それはもう無い。
Gittensor の経営状態は僕の関与する所では無いが、Bittensor からの補助にのみ頼っているとしたらこの懸賞プログラムがいつまで持続可能なのかも疑問が残る。