Skip to content

Development Guide ​

人間と AI のコントリビュータ向けの最小手順。設計は design.md、構造は architecture.md、未完了項目は roadmap.md を参照する。

初回セットアップ ​

ツールの版は mise と rust-toolchain.toml で固定する。 Node.js 22 は VitePress 2 でドキュメントをビルドするために必要。

bash
mise trust
mise install
mise run setup

setup は stdlib RBS の展開、npm 依存、Playwright browser を準備する。生成物の vendor/rbs/、target/、node_modules/ は source of truth ではない。

よく使うタスク ​

bash
mise tasks
mise run test
mise run check
mise run fmt
mise run clippy
mise run dev
mise run e2e
mise run build-pages

Rust の日常的な反復では、まず mise run check-quick(全targetの型確認)を使う。 実行可能な最適化バイナリが必要なときは mise run build-fast を使う。このタスクと ./scripts/check.sh は、実行性能を重視する release(thin LTO、codegen 1)ではなく、 LTOを無効にしてcodegenを並列化した release-fast を使う。配布物、性能計測、package workflowは引き続き release を使う。 ローカルの release-fast は増分コンパイルを有効にし、mise run build-fast などの反復時の 再ビルドを短くする。最終確認の ./scripts/check.sh とCIは CARGO_INCREMENTAL=0 と sccache を使い、増分なしのビルドを確認する。

./scripts/check.sh は lockfile に合わせた stdlib RBS の生成確認と、Rust の format、clippy、test、release-fast build をまとめて実行する。 mise run check はこれに加えて playground の typecheck、oxlint、oxfmt check も実行し、変更の完了条件とする。

クリーンなreleaseビルドやCI以外の再ビルドでは、任意でsccacheを使える。macOSは brew install sccache、その他の環境は各OSのパッケージまたは cargo install sccache --locked で導入し、次のように実行する。

bash
CARGO_INCREMENTAL=0 RUSTC_WRAPPER=sccache cargo build --release
sccache --show-stats

通常の cargo build / cargo check はincremental compilationが有効なdev profileのまま 使うほうが速い。sccacheはincrementalなRust crateをキャッシュしないため、常用する場合も このrelease/clean build用の指定に限定する。CIでは同じ設定を自動で適用し、GitHub Actions backendへコンパイラ成果物を保存する。

実験的な arity diagnostics は次で確認できる。

bash
TYDA_EXPERIMENTAL_CHECKS=1 cargo run -- --diagnostics <path>

RBS と parser ​

  • stdlib の RBS は Gemfile / Gemfile.lock の rbs gem から mise run vendor-rbs で生成する。 ./scripts/check.sh も生成 version marker を確認し、古い vendor/rbs/ を自動更新する。
  • crates/rbs-sys は公式 RBS C parser への薄い FFI。型定義の変換後に parser の構造体を保持しない。
  • Ruby runtime は build-time のみで、生成済み CLI / wasm の実行には不要。
  • RBS / RBI の import を変更したら、対応する scenario と外部型の unit test を更新する。

変更の進め方 ​

  1. 変更の user-facing な契約を scenario、CLI test、LSP test のいずれかで先に特定する。
  2. Ruby semantics / RBS に沿う一般規則を使い、既存の query backend / plugin / 宣言テーブルに合流する。
  3. 推論変更は最小例から段階的に検証する(testing.md、performance.md)。
  4. 実装、回帰テスト、対応する living document を同じ変更に含める。
  5. 変更後に pr-self-review を実行する。実装変更は mise run check、すべての変更は git diff --check を行う。

実装中に今回の変更と密接に関係する既存のアンチパターンを見つけたら、範囲を保って改善できる場合は 合わせて直す。無関係なリファクタへ広げない。

個別 repository の名前に依存する分岐や、一時的な debug API は追加しない。DSL が runtime に 登録されるだけで静的に証明できない場合は、外部 RBS / RBI の入力を選ぶ。

PR と依存 ​

一つの PR は一つの目的に絞り、その目的に必要な関連修正・テスト・文書をまとめる。説明は簡潔にし、 実装方針と検証結果を示す。公開出力の意図的な変更は scenario に残し、PR review で合意を得る。 依存追加は避け、必要な場合は理由と代替案を示して保守状況・ライセンス・性能影響を比較する。 ライセンスの適否は一律の許可リストを設けず、プロジェクトとの両立性をPRごとに判断する。

CI ​

  • PRのCIは .github/workflows/pull-request-ci.yml に集約し、test、performance、analysis-compatibility、pages、release-vscode、actionlint の6つの安定したgateを報告する。第1段階では Test、Pages、workflow lint と Analysis / Performance の比較用binary buildを並行実行する。Test gateの完了後、第2段階でAnalysisの11 subject、Performanceの10 subject、VS Codeの4 platformをすべて実行する。subject matrixは各7 job、VS Code matrixは4 jobまでに制限し、第2段階のmatrix legは最大18 jobを同時実行する。full CI対象のPRではsubjectやplatformの検証数を減らさない。新しいcommitが来たら、そのPRの古いCI run全体をcancelする。
  • PRでは親workflowが scripts/ci/classify-changed-paths.sh で変更範囲を分類し、再利用workflowへ結果を渡す。docs/** または playground/** だけの変更では汎用Rust・性能・VS Code CIをjob-levelでskipし、docs/** の変更ではPagesのドキュメント build、Playgroundのコード変更時は wasm build + E2Eを実行する。各aggregate gateは対象外のとき分類成功と依存jobの全skipを確認してsuccess、対象内jobの失敗・想定外skip・分類失敗はfailureとして報告する。matrix個別jobは結果とログのために残すが、required checkにはしない。approved-analysis-change ラベルを付けたときだけ、MaintainerまたはAdminが付けたことをGitHub APIで確認したうえで、解析出力・coverageの意図した差分を許可し、性能の実行時間・メモリ基準は引き続き適用する。新しいcommitが積まれた場合はラベルを自動削除し、再確認を要求する。
  • Test は Linux と Windows の Rust build / clippy / test を確認する。Windowsも全test targetを実行し、 unit、軽量integration、mutation、pathological、docのshardに分けて独立したrunnerで並列化する。 高コストなtest target同士を同じrunnerで競合させない。test gateはLinuxのformat / lint / test、Windowsの windows gate、VS Code checkの結果を集約し、windows gateはWindowsのformat / clippyと全shardの結果を集約する。 Rust compile jobは CARGO_INCREMENTAL=0 とsccacheのGitHub Actions backendを使い、rust-cacheはCargoの registry/gitだけを保存する(target directoryとの二重キャッシュを避ける)。
  • Pagesの再利用可能な pages-check workflowはPlaygroundの format:check、typecheck、oxlintを明示的に通した後、VitePressのドキュメント、wasm、RBS bundle、Playgroundをbuildして pages-dist/ に組み立て、/playground/ のPlaygroundに対してE2Eを実行する。PR側の pages gateが結果を集約し、Pages deploy権限はmain push用の pages.yml に分ける。
  • GitHub Pagesは main へのpush時だけ pages-dist/ を公開する。トップの紹介ページは docs/index.md から生成し、ドキュメントは /docs/、Playgroundは /playground/ で提供する。docs/README.md は /docs/ の索引として表示する。
  • /playground/ はVitePressのSPAルートではなく同じPages artifact内の静的アプリなので、トップとナビゲーションのリンクには target: "_self" を指定してフルページ遷移させる。
  • Pages のE2Eは pages-dist/ を /tyda/ 配下でも解決できるローカル静的サーバーで配信し、project siteの実URLに合わせてTop・Docs・Playgroundの遷移、reload、Back/Forward、hash復元を確認する。
  • Dependabot は Bundler、root / vscode/ の npm、Cargo、GitHub Actionsを週次で更新する。Major更新はPRを作るが自動mergeせず、Major以外のDependabot PRはGitHubのauto-mergeへ登録する。mergeはbranch protectionが要求する6つのCI gateの成功を待つが、PR branchを最新の main にする条件は設けないため、CI成功後に main が進んでもそのPRのCIを再実行せずmergeできる。手動作成のPRはWorkflowから自動mergeへ登録しない。必要ならMaintainer/Adminが内容とCIを確認してからGitHub上で明示的に設定する。workflowや scripts/** などCIポリシーを変更するPRは、auto-mergeを設定する前にMaintainer/Adminのレビューを行う。
  • 依存更新で脆弱性が見つかった場合は、direct / transitive、runtime / development-only、実際の到達経路と生成物へのバンドル有無を確認する。まず直接依存または親依存の正規の更新で修正版を取り込めるか検証し、解決できる場合だけ対応する。overrides や resolutions は使用しない。正規の更新で解決できない場合はライブラリ側の対応を待ち、脆弱性は無理に解消扱いにせずDependabot alertをopenのまま保持する。上流修正版がリリースされたら、通常の依存更新として再評価する。
  • release workflow は VSIX packaging と smoke test、main マージごとの platform gem packaging / smoke test / RubyGems Trusted Publishing を確認する。PRでは中央の pull-request-ci.yml が古いrunをcancelするが、tag pushとgem公開のmain workflowは公開途中の実行をcancelしない。gem 公開後は同じバージョンの v... tag と GitHub Release を作成し、前回 Release 以降のマージPRを自動生成ノートに記録する。RubyGems 側の pending trusted publisher を事前に設定する。Linux ARM64 はGitHub-hosted runnerの利用条件が整い次第追加する。
  • main の検証workflowはpush時にも変更範囲を分類し、READMEなどPagesに影響しないMarkdownだけならTest / Performance / VS Codeのfull CIを起動しない。docs/** や playground/** はPages buildを維持し、依存ファイル、Rust / Ruby / TypeScript、workflow、scripts/** の変更はfull CIを維持する。release-gem は現行の「main mergeごとに公開する」仕様のため、この分類ではskipしない。
  • Actions は commit SHA で固定し、Workflow lint の actionlint で workflow の構文・context を検査する。

main のbranch protectionでは、matrix個別jobではなく、常に報告される test、performance、analysis-compatibility、pages、release-vscode、actionlint のaggregate gateだけをrequiredにする。各gateは対象scopeでは全依存jobのsuccessを要求し、対象外scopeでは分類成功と依存jobの全skipを確認した場合だけsuccessとして扱う。Require branches to be up to date before merging は無効にし、必須gateをすべて通過したPRは最新の main を取り込まずにmergeできる。merge後の main で初めて分かる組み合わせ起因の回帰や性能低下は起こり得るため、merge後のCIも維持する。workflow変更をmainへ反映した後、required contextsもこの一覧へ更新する。Dependabot PRだけがauto-merge Workflowから自動登録される。手動PRでauto-mergeを使う場合は、Maintainer/Adminが内容とCIを確認したうえでGitHub上で明示的に設定する。解析結果を意図的に変更する場合は差分をJob Summaryとartifactで確認してから、MaintainerまたはAdminがラベルを付ける。

Windows のローカル開発は、現行の scripts/*.sh と mise task が Bash 前提のため Git Bash または WSL を使う。配布物はWindows x64をrelease workflowで検証する。

コーディング規約 ​

  • Rust、コメント、root の文書、commit は既存の英語規約に合わせる。docs/ の説明は日本語。
  • コメントは「何をするか」ではなく、コードから分からない理由だけを書く。
  • 型推論の不確実性は untyped / Unknown に倒し、誤った具体型を返さない。
  • 公開出力(RBS、diagnostics、LSP)の変更は byte / protocol 回帰を確認する。
  • docs は現在の状態だけを保つ。完了した作業履歴は追記しない。

VS Code / Cursor ​

Tyda は tyda --lsp が出力する TCP 接続情報で LSP server を提供する。TypeProf 拡張を使う 場合は typeprof.server.path に Tyda binary を指定する。protocol 起動と version 契約は LSP compatibility のため維持するが、推論結果を TypeProf と一致させるものではない。

bash
mise run vscode-deps
mise run vscode-build
mise run vscode-package

package task は platform binary と stdlib RBS を vscode/ に同梱して VSIX を作る。 生成物は commit しない。release version は tyda-version.txt と release workflow を正とする。