Skip to content

Latest commit

 

History

History
677 lines (514 loc) · 86.4 KB

File metadata and controls

677 lines (514 loc) · 86.4 KB

Tsumugi — ロードマップ

最終更新: 2026-09-07

現在の作業状況(サマリ)

このセクションは「今どこにいて、次に何をやるか」を1か所に集約した早見表である。詳細・根拠は各 AUD / REV 項目と設計正本を参照する。設計確定は実装完了ではない(受入gate未達なら未完了扱い)。open 項目を増減したらこの表も更新する。

現在地

  • フェーズ: 意味論基盤(下記「設計sliceに沿う推奨実装順」のステップ2)を進行中。ステップ2の完了済み項目は AUD-050/017・049・019・047・048・016・024・034。Phase 1(embedding)以降は未着手。
  • 仕様 revision: language-spec 0.16(実装版 package は 0.1.0。番号体系は別管理)。
  • 完了の中心: 2026-08-26 深層監査(AUD-001〜050)の大半は実装済み。残る open は下表のとおり。
  • 新規入力: 2026-09-07 詳細レビュー(REV-001〜025)は全件が実装バックログ(設計は6件が §17 で確定、他は既存正本を参照)。

次に着手すべき順(先頭ほど優先)

「設計sliceに沿う推奨実装順」の未完了部分を抜き出したもの。詳細は同節を参照。

  1. 境界挙動(意味論基盤の残り): AUD-036(checked変換・構造化Exited)→ AUD-018(CLI script引数)→ AUD-033(未完結REPL入力のEOF診断)。あわせて §17 の REV-003(数値厳密比較)で観測挙動を変える revision を上げる。
  2. bytecode検証・API封印(基盤・境界挙動より前に置く): REV-006(VerifiedChunk/verifier)と同一マイルストーンで REV-004(patch_jump fallible化)・REV-005(MakeClosure capture記述子化)・REV-018(internal module封印)。
  3. 包括budget(P0 基盤): REV-015(source/string/heap/I-O budget・deadline・cancel)に REV-001(共有DAGの指数時間/出力)の受入条件を含める。REV-023(exit()のprocess終了廃止)も同基盤。
  4. Phase 1 embedding: 組み込みAPI仕様 E1〜E6 → E8a。REV-007/008/011/013/014/020 はこの Phase 1〜2 で解消する。
  5. Phase 2 capability: E7 → E8b と Capability C1〜C10。REV-002/009/019/021/022 はこの capability 面で実装(sandbox の process-global を ExecutionContext へ移す)。

open 項目一覧(未完了のみ・優先度順)

未完了(🟡 部分実装 / ⬜ 未実装)だけを AUD・REV 横断で並べたもの。✅ 完了項目は各バックログ節を参照。

優先度 ID 概要 状態 詳細
P0 REV-001 共有DAGの比較・表示が指数時間/出力 REV表 P0
P0 REV-002 非UTF-8 canonical import pathでsandbox認可がすり替わる REV表 P0
P0 REV-006 未検証bytecodeでstep/call課金を迂回し無期限実行 REV表 P0
P0 REV-015 source/string/heap/I-O/bulk workが未有限化 REV表 P0
P0 REV-023 exit()がホストプロセスを終了する REV表 P0
P1 REV-003 Int–Float比較が2^53超で誤り、==が非推移的 REV表 P1(§17.1 設計確定)
P1 REV-004 公開Chunk::patch_jumpがpanic REV表 P1(§17.2 設計確定)
P1 REV-005 不正MakeClosure descriptorをNull captureで黙認 REV表 P1(§17.3 設計確定)
P1 REV-007 ExecutionContextがsession stateとrun meterを混在 REV表 P1
P1 REV-008 stable Engine::executeがtransactionでない 🟡 REV表 P1(REPLのみ実装)
P1 REV-011 revision・engine差・実装statusが文書drift REV表 P1
P1 REV-012 call評価順のstatus/doc drift(意味論正本はAUD-017) 🟡 REV表 P1(§17.5 設計確定)
P1 REV-013 args()がhost process argvを読む REV表 P1
P1 REV-014 sandbox/env/limits/stdio/clockがprocess-global REV表 P1
P1 REV-018 internal module/raw bytecode公開が安全境界を弱める REV表 P1
P1 REV-020 import先parse errorの原因を捨てる REV表 P1
P1 REV-021 remove_dirの再帰削除とcapabilityの不整合 REV表 P1(§17.6 設計確定)
P1 AUD-018 CLIからscript引数を渡せない 🟡 AUD crosswalk(Embedding E8a)
P1 AUD-021 language-spec/LANG_GUIDE/design drift継続 🟡 AUD P2表(意味論確定後に継続更新)
P2 REV-009 list_dirの部分失敗黙殺と非UTF-8名衝突 REV表 P2(§17.4 設計確定)
P2 REV-010 32-bitでi64 as usizeがwrap REV表 P2
P2 REV-016 Rc cycleと長寿命contextのheap残留 REV表 P2
P2 REV-017 表示・repr・sort orderの結合 REV表 P2
P2 REV-019 now()のepoch前/error 0化と未検査cast REV表 P2
P2 REV-022 EOF/I-O error/permissionをNull/falseへ畳む REV表 P2
P2 REV-024 CIがrolling stable・fuzz/stress/MSRVなし 🟡 REV表 P2
P2 REV-025 parse diagnostic件数に上限がない REV表 P2
P2 AUD-020 sandbox TOCTOU/path-handle未実装 🟡 AUD crosswalk
P2 AUD-022 fuzz/stress/matrix未実装 🟡 AUD crosswalk
P2 AUD-033 未完結REPL入力のEOF診断 🟡 AUD P2表(§8 設計確定)
P2 AUD-036 lossy数値・OS境界変換の検証 🟡 AUD crosswalk(§10 設計確定)
P2 AUD-045 MSRV/release/install/OCI未実装 🟡 AUD crosswalk

プロジェクトの方向性

Tsumugiは、学習用の言語処理系として得た知見を発展させ、実運用を見据えた、制御可能な組み込みスクリプト言語を目指す。価値基準と非目標の正本はTsumugi Manifestoとし、本ロードマップは現在地からその目標へ進む順序を管理する。

最短の実行時間よりホストの安定性を優先する。新しい言語機能を増やす前に、組み込み境界、明示的な権限、包括的な実行予算、規範意味論、監査可能性を整える。

マニフェスト実現ロードマップ

以下は目標アーキテクチャへの移行順序である。現行のstep上限、collection上限、深度制限、filesystem/env allow-list、構造化エラー、差分テストは土台として再利用するが、それだけで各phaseが完了したとはみなさない。

Phase 目的 設計正本 設計状態 実装状態 完了gate
0 保証範囲と脅威モデル 脅威モデル ✅ 確定済み 🟡 文書化は完了。OS隔離guideとrelease導線は未実装 第11節Phase 0、TM-AT-07・TM-AT-12(host部分)
1 安定した組み込みAPI 組み込みAPI仕様 ✅ 確定済み 🟡 tree向け最小facadeとCLI入口のみ部分実装。LinkedScript、最終terminal型、panic境界等は未実装 第14〜15節 E1〜E6・E8a、EMB-AT-01〜09・13・15〜17
2 deny-by-default capability Capability Model仕様組み込みAPI仕様 ✅ 確定済み ⬜ 未実装。現行sandbox/env allow-listはfail-openのdefense-in-depth Capability第18〜19節 C1〜C10・Phase 2 CAP-AT、Embedding E7・E8b
3 包括的な実行予算 実行予算・協調実行仕様 ✅ 確定済み 🟡 step・collection・AST/import/call深度のみ部分実装。総heap、全I/O/source/host budget、deadline、runtime cancel、transactionは未実装 第3〜8・10・15.1〜15.3・16節、EMB-AT-21
4 協調実行と負荷制御 実行予算・協調実行仕様 ✅ 確定済み ⬜ 未実装 第6.2・9・11〜12・15.3〜15.5・16節、EMB-AT-22
5 規範意味論と決定的境界 決定性・実行時監査仕様次期意味論・実装決定 ✅ 確定済み 🟡 paired testはあるが既知のbackend差とHostBoundary/FunctionId/record-replayが未実装 Determinism第2〜6・14節Slice 1〜4/6・15.1/15.2/15.5・16節
6 実行時監査 決定性・実行時監査仕様 ✅ 確定済み 🟡 構造化errorのみ。canonical 8 event、sink、sequence、redaction、bounded journal、fail-closedは未実装 第7〜12・14節Slice 5・15.3/15.4・16節、EMB-AT-23・CAP-AT-30
7 運用保証と検証 検証・リリース・運用設計 ✅ 確定済み 🟡 timeout・golden・scaling・defensive test、3 OS CI、coverage artifactのみ実装。MSRV/release/fuzz/stress/OCI/運用は未実装 第6節matrix、第17節VRO-AT-01〜15、第18節

長時間処理について「確実に終わる」とは、任意のscriptの成功を保証することではない。ホストを不安定にせず、完了、停止、または失敗を観測可能な結果として扱い、有限の処理を設定された負荷の中で着実に進められることを目標とする。

2026-08-26 深層監査バックログ

ツリーウォーク版とVM版を、REPL継続実行・失敗時状態・スコープ・クロージャ・import・全組み込み関数・資源上限・既存仕様の観点で横断監査した。既存テストは全件成功したが、REPL入力間の状態回復や実行系差を検出できない空白がある。優先度は、ホストプロセス停止/メモリ枯渇につながるものを P0、誤実行・状態漏洩・主要仕様差を P1、診断性・境界値・文書不整合を P2 とする。

追加監査では cargo fmt --checkcargo clippy -- -D warningscargo buildcargo test がすべて成功した状態から、隔離した最小入力で既存テスト外の不具合を再現した。再現済み項目は実装状況欄に明記し、Windows固有挙動やsymlink操作など実環境確認が必要な項目はコード監査結果として区別する。

状態の読み方: 以下のAUD表の最終列はコード・test・workflow・配布物の実装状況であり、設計状態ではない。次期設計正本で判断が確定済みでも、受入gateを満たす実装がなければ完了扱いにしない。

P0 — Critical

ID 項目 再現・影響 実装状況
AUD-001 VM REPLのコンパイル失敗をtransactionalにする ブロック内でlocal追加後にcompile error(当時は未解決index assignment target、現在はループ外break等)を置くと、Compilerだけが更新され、次入力のGetLocalでRustの範囲外panic。stale loopからJump(0)生成にも到達可能 ✅ 完了(REPL回帰テスト追加)
AUD-002 VM REPLの未捕捉runtime error後にstack/frame/handler/compilerを復元する 一時値・callee frame・未実行bindingが次入力へ残り、誤値参照、古い関数の再開、二次panicを起こす ✅ 完了(REPL回帰テスト追加)
AUD-003 コレクション上限を全生成経路へ一貫適用する VMのlist/dict literal、pushmap/filter、keys/values等でTSUMUGI_MAX_COLLECTION_SIZEを迂回でき、メモリDoS防止の完了記載と矛盾 ✅ 言語から到達する生成・拡張経路を修正。総heap quotaは対象外
AUD-026 format_timeの極端なtimestampを定数時間で処理する format_time(9223372036854775807, "%Y")は1970年から1年ずつ進むため実用上停止せず、step予算も消費しない。tree/VMとも2秒以内に完了せず、timeout(終了124)で強制停止 ✅ 完了(400年周期化・両engineのi64極値timeout回帰テスト追加)
AUD-027 parser・compiler・evaluatorの全再帰経路へ深度制限を適用する 10万個のnot連鎖で旧MAX_PARSE_DEPTHを迂回し、Rust stack overflowでabort(終了134)。elif直再帰や左深BinOp ASTにも同種の経路があった ✅ 完了(MAX_AST_DEPTH=256、生成時検査・子f-string深度継承・実行前の非再帰preflight)
AUD-028 非循環import chainの深度を制限する treeのimport実行とVMのinline compileが、旧実装では深い非循環chainでhost stack overflowに到達し得た ✅ 完了(rootを除くactive chainを128に制限、tree/VM共通エラー)
AUD-043 トップレベルreturnの文脈を検証する Parserが関数外のreturnを無条件に受理するため3つの症状になる。(1) VM REPLでtop-level変数がある状態でreturnを実行すると、ReturnValueがroot frameをpopしstackをbaseまで捨てる一方Compilerのlocalsは残るため、次入力のGetLocalが空stackを読みsrc/vm.rsの範囲外panicでhost abort(終了1)。try内・for内のreturnでも再現し、tree REPLは同入力で正常継続する。(2) file実行では両engineとも後続文を実行せず、エラーなしで終了コード0になる。(3) import先のトップレベルreturnは、treeがmodule実行だけ打ち切って呼び出し元を継続する一方、VMはinline展開されたReturnValueがroot script全体を終了させる。break / continueは両engineでエラー化されるがreturnだけ検査がない ✅ 完了(Parserに関数本体の深度を持たせ、関数外のreturnを両engine共通のパースエラーへ。parser単体・error fixture・tree/VM REPLの回帰テスト追加)

P1 — High

ID 項目 再現・影響 実装状況
AUD-004 VMのlocals_cellsをREPL入力・try unwindで正しく保存/復元する 入力ごとにtop-level cell対応が消え、closureと変数が別値になる。try内localのcellがcatch変数slotと衝突する ✅ 完了(cell同一性・catch回帰テスト追加)
AUD-005 treeのwhile/forでエラー時もscopeを必ず解放する ループ内エラーをcatchすると反復localが後続処理・次REPL入力から見える ✅ 完了(caught error回帰テスト追加)
AUD-006 import失敗時のbase_dir・loading/loaded marker・compiler状態を復元する 同一fileの再試行がsilent skip。VMでは次の相対import基準やlocalsも汚染する ✅ 失敗rollback完了。import・REPLの状態commit方針もAUD-024で完了(未捕捉errorで全language-stateをrollback、正常・catch済み完了はcommit)
AUD-007 非トップレベルimportの意味論を統一する VMはcompile-time inlineのためfalse branchでもloaded扱い、loopでは複数実行、関数内relative path/control-flowもtreeと異なる ✅ トップレベル限定として統一(全ネスト構文のparserテスト・tree/VM回帰テスト追加)
AUD-008 if / try / catchのscope仕様を確定し両engineを統一する treeではblock内letが外から可視、VMではcompile error。公開ガイドの「ifはscopeを作らない」とVMが不一致 ✅ 独立block scopeへ統一(shadowing・error/control-flow・closure・REPL回帰テスト追加)
AUD-009 tree REPLのstep予算を入力単位でresetする step数がセッション全体で累積し、一度上限に達すると以後の入力も失敗。VMと不一致 ✅ 完了(入力間回帰テスト追加)
AUD-010 for変数のclosure bindingを反復単位で統一する [1,2,3]で作ったclosureがtreeは1,2,3、VMは全て3 ✅ 反復ごとのfresh cellへ統一(closure・control-flow・REPL slot再利用回帰テスト追加)
AUD-011 VMのcompile-time name resolution差を仕様化/縮小する dead branchの未定義名、global forward reference、引数評価順がtreeと異なる ✅ call validation順とruntime global fallbackを統一(dead code・forward read/write・mutual recursion・REPL/import回帰テスト追加)
AUD-012 context依存builtinの契約を統一する input(side())等の不正arityでtreeは引数を評価せず、VMは副作用後に拒否する。push/popはupvalue・一時List・error kindにも差がある ✅ builtin選択後のarity・破壊対象を引数評価前に検査。一時List拒否、left-to-right snapshot/writeback、local/upvalue/runtime global更新、collection error kindをtree/VMで統一
AUD-013 VM index assignmentのupvalue対応と評価順を統一する captured listへ代入不可。object取得順の違いで副作用後に古いlistを書き戻す ✅ target解決→index→value→in-place更新へ統一。local/upvalue/runtime global対応、未定義targetの先行報告、共有assign_indexによるメッセージ・境界判定一致(golden pair・両engine REPL回帰テスト追加)
AUD-014 equality / relational comparisonの対象型を統一する List/Dict/Function/Error、Int×Floatでtreeはtype error、VMはboolを返す場合がある。486ケース(9型×9型×6演算子)の網羅比較で128件の差分を確認した ✅ 完了(等価比較を全型で成立させ、Int×Floatを数値比較、List/Dict/Errorを構造比較、関数値をRc::ptr_eqの同一性比較へ統一。大小比較は数値のみ(混在可)。判定をValue::PartialEqへ集約し、486ケースの差分が0件。付随して型エラーの種別をkind明示へ変え、被演算子の値による誤分類も解消。仕様revisionを0.9へ)。網羅行列は型の組み合わせを対象としたため、同一sourceから複数の関数値を作る形は含まれず、同一性の粒度差をAUD-048として後から検出した
AUD-029 複数行lambdaの終端endを必須検証する let f = fn(x)\n return xをtree/VMとも構文エラーにせず終了コード0で受理する。EOFをendとして無条件消費している ✅ ParserでEndを必須検証し、tree/VM共通でEOFを構文エラー化
AUD-030 top-level importの評価時点を統一/仕様化する print("BEFORE")後の失敗importでtreeだけ先行出力する。実行中に生成したmoduleもtreeだけimport可能で、VMのcompile-time inlineと観測可能な差がある。9ケースの検証で4つの観測差を確認した(失敗import前の副作用、構文エラーmodule、import前の実行時エラー、実行中に生成/削除したmodule) ✅ 完了(実行前解決へ統一。src/module.rsModuleLoaderへ解決処理を集約し、treeはrunでリンク、VMはリンク済みプログラムをcompileする。exec_import / compile_importを削除し、9ケースすべてで両engine一致。仕様revisionを0.10へ)
AUD-031 WindowsでTSUMUGI_*環境変数保護をcase-insensitiveにする Windowsの環境変数検索は大文字小文字を区別しないがprefix検査は区別するため、env("tsumugi_sandbox")等で保護値を読める可能性がある ✅ Unicode uppercase後のprefix保護を実装。tree/VM、allow-list未設定/全許可、ASCII大小文字・Unicode case alias・secret非漏洩をWindows実OS CIで確認
AUD-032 破壊的ファイル操作のfinal symlink意味論を修正する check_pathは最終symlinkまでcanonicalizeし、remove/remove_dir/renameがlink自体ではなくlink先を削除・移動していた ✅ 完了(中間componentのみ解決し、final directory entryを操作)
AUD-037 ローカル名前付き関数のself-bindingを両engineで統一する 関数内で定義した再帰関数がtreeでは自身を捕捉できず未定義の関数、VMでは正常完了する。factorial(5)相当でtree失敗/VM 120を再現 ✅ 呼び出し時self-bindingとuser binding優先のbuiltin fallbackをtree/VMで統一。匿名lambdaの内部slot名も非公開化

P2 — Medium / Quality

ID 項目 再現・影響 実装状況
AUD-015 callback内break/continueを通常関数と同じくエラー化する treeのmap/filter/eachだけbreakを暗黙nullとして扱い、VMはcompile error ✅ 完了(control-flow回帰テスト追加)
AUD-016 同一scopeのlet再宣言時のbinding identityを仕様化する 既存closureがtreeでは旧cell、VMでは更新済みcellを参照 ✅ 完了(VM CompilerのStmt::Let再宣言でのslot再利用を廃止し、全scopeで新slot(=新cell)を割り当て。treeの既存fresh-cell挙動を規範として統一。let/fn再宣言のtop-level/function/block scope・REPL入力間rollbackを両engineで固定するgolden fixture let_redeclaration_fresh_cellとREPL回帰テストを追加。観測挙動が変わるため仕様revisionを0.14へ)
AUD-017 call-depth境界を統一する 上限128にtop-level frameを含めるVMだけ、許容user frame数が1少ない ✅ 完了(AUD-050と一体で解消。VMをactive_user_frame_count() = frames.len() - 1によるroot除外計数へ変更し、tree/VMとも128 user frameを許可・129個目を拒否。境界値127/128/129・相互再帰・lambda・callbackの回帰テストと、両engine一致のstack overflow traceテストを追加)
AUD-018 CLIからscript引数を渡せるようにする args()を公開しているがCLIが2個目以降の非flag引数をusage errorにする 🟡 設計確定・未実装(同第6節、Embedding E8a。capability profile/optionsとsafe/legacy移行はE8bで別追跡)
AUD-019 engine固有error kind/messageを統一する iteration/index/callback等でkind・messageが異なる。push/pop/map/filter/eachの主要なkindはAUD-012で統一したが、callback messageやtrace差は残る。具体例として、コレクション以外へのindex(let n = 42 に対する n[0])はtreeがruntime / 「インデックスアクセスできません: Int(42)[Int(0)]」、VMがtype / 「型エラー: Int(42) に対して Int(0) でインデックスアクセスできません」になっていた ✅ 完了(src/error.rsにoperation別canonical constructorを新設し、tree/VM/compiler/module/builtin_coreの全runtime error生成をそれへ移行。値埋め込みを型名へ置換し、message文字列からのkind推測(classify_runtime_error)とruntime()を削除。n[0]は両engineともtype / 「インデックスアクセスできない型です: Int」に統一し、index_read_lowering.expected.vmを削除。tests/canonical_error_inventory.rsで28 operation行をtree/VM両engine実行し(kind, message, line)完全一致とRuntime catch-all非生成を検証。仕様revisionを0.12へ。traceのcanonical化はcall trace統一済みで、host adapter traceはPhase 2で別追跡)
AUD-020 sandboxの脅威モデルとTOCTOU制約を明記する checkとI/O間のsymlink race、sandbox検査前のcanonicalizeによる許可外path存在oracle、dangling final symlink経由の新規write/append、空設定のfail-open意味論が未整理 🟡 設計確定・部分実装(現行制約の文書化のみ完了。脅威モデル TM-002〜004とCapability Model仕様 CAP-AT-10〜14のpath-handle実装は未完了)
AUD-021 language-spec / LANG_GUIDE / designのdriftを解消する engine parity・Float完全一致・全module unit test・coverage/benchmark gate等の記載が現実装やAUD残件と矛盾する 🟡 規範仕様と既知非適合、VMの実験的位置付け、sandbox制約、予約語、循環参照を更新。意味論確定後の更新は継続
AUD-022 REPL・differential・limit境界・defensive VMテストを追加する subprocess timeoutなし、error goldenが部分一致、fixture登録が手動、tree/VMが固定/tmpを共有して並列raceする。厳密なstderr/stdout副作用比較も不足 🟡 設計確定・部分実装(harness、timeout、完全一致、temp分離は完了。検証・リリース・運用設計のmatrix/fuzz/stressは未実装)
AUD-023 VMのunchecked index/unwrap()を構造化internal errorへ置換する compiler/VM invariantが崩れるとhost panic。AUD-001/002でユーザー入力から到達可能だった。Vm::new / run_repl_chunkは任意のChunkを受け取るため、library利用では範囲外のslot・定数・upvalue・行番号表の不足・operandのunderflowでindex panicへ到達した ✅ 完了(frame/stack/upvalue/定数/命令参照を検査付きヘルパー経由にし、unreachable!も含め本番コードからunwrapを排除。公開APIだけで書いたtests/defensive_vm.rsで8ケースを固定し、修正前はindex panicで失敗することを確認)
AUD-024 import・REPLの状態commit方針を明文化する 未捕捉error前の代入/list mutation/upvalue更新を保持するかrollbackするか未定義。外部I/Oはrollback不能 ✅ 完了(tree/VMとも未捕捉errorで全language-state(binding・cell値・index代入・push/pop・import marker)を入力開始時点へrollback。正常完了とcatch済み完了はcommit。外部効果はrollbackしない。first-write undo logで実装し記録量は変更箇所数に比例。仕様revisionを0.15へ。deadline/budget/cancel由来のrollbackはPhase 3/4で別追跡)
AUD-025 VM REPL checkpointの複製コストを削減する 入力ごとのstack.clone()が保持中List/Dictをdeep cloneし、時間・一時メモリがREPL状態量に比例する ✅ 完了(stack全体cloneを初期長と変更済みslotのmutation logへ置換。通常入力は保持中List/Dictを複製せず、既存slotの書換・削除時だけrollback用の元値を記録して未捕捉エラー時に復元)
AUD-033 未完結REPL入力のEOFを診断する if true等の継続入力中にEOFを送ると、tree/VMとも構文エラーを出さずbufferを破棄して終了コード0になる 🟡 設計確定・未実装(両engineで再現済み。次期意味論・実装決定第8節)
AUD-034 path_joinの引数型契約を厳格化する path_join("a", 123, "b")が型エラーにならずa/bを返し、非文字列argumentを無言で欠落させる ✅ 完了(全引数を左から右へStr検査し、最初の非Strでbuiltin_type / 「path_join の第 {position} 引数は Str である必要があります: {型名}」を返し結合を開始しない。tree/VMはAUD-049の共有registry/handlerを使うため差はなく、tests/canonical_error_inventory.rsにtree/VM一致の非Strケースを追加。正常系はtests/path_join_contract.rsでOS依存の期待値をRust PathBufから構築して照合。観測挙動が変わるため仕様revisionを0.16へ)
AUD-035 CLI・標準I/Oのhost panic経路を構造化する REPLのthread spawn・stdout flush・stdin readにunwrap()があり、broken pipe/I/O障害でpanicする。printprintln!のためtsumugi script.tsg | head -1でpanicした。Unixの非UTF-8 argvはstd::env::args()でもpanicし得る ✅ 完了(ErrorKind::Ioを追加しprintの出力失敗を構造化エラーへ。CLIのbanner・prompt・stdin・spawn・argv検証は診断+終了コード1へ。パイプ切断と非UTF-8 argvの回帰テストを追加)
AUD-036 lossyな数値・OS境界変換を検証する exitのi64→i32、file_sizeのu64→i64、NaN/Infを含むto_int/floor/ceil/roundがwrap・飽和・0化し得る 🟡 設計確定・未実装(同第10節: checked変換と構造化Exited。境界回帰testも未実装)
AUD-038 benchmarkをparse / compile / executeへ分離しVM退行を調査する 現行Criterionは毎回parseし、VMはcompileも含む。aarch64 release実測でVMはfibが約2.77倍高速な一方、loop 5000回は約358倍低速で、単純な「VMは高速」という説明が成立しない ✅ 4フェーズへ分離し退行の原因を特定・修正(VMのforが反復ごとにコレクションを複製しO(n^2)だった)。確保量ベースのスケーリングゲートを追加。副産物としてAUD-040 / AUD-041を検出
AUD-039 binaryからlibrary moduleを利用して二重コンパイルを解消する main.rslib.rsと同じ16モジュールを再宣言し、use tsumugi::を一切使わないため、同一ソースがlib targetとbin targetで2回コンパイルされる。単体テストも両方に取り込まれ、cargo testが同じテストを2回実行する(2026-08-28時点で各152件)。ビルド時間・テスト件数の解釈を歪める ✅ 完了(binaryのローカルmodule宣言を削除し、tree-walk CLIをEngine facade、VM CLIをlibrary moduleの型へ移行。単体テストはlib targetで一度だけ実行)
AUD-040 treeの名前付き関数self-bindingでValue::Fnの複製を避ける AUD-037の呼び出し時self-bindingが毎回Value::Fn(body AST含む)をcloneし、呼び出しコストが関数body長に比例する。fib(22)で67.0ms(該当行を無効化すると42.2ms、約1.6倍) Value::FnRc<FnDef> + Rc<captured>へ変更(VmFnのRc<Chunk>と同じ方針)。同一条件A/Bでfib(22) 64.5ms→21.2ms、確保量の比 15.89→1.06。確保量ベースの回帰ゲートを追加
AUD-041 コレクション読み取りで全体複製を避ける GetLocalが値を複製するため、ループ内のd[k] / xs[i]読み取りがコレクション全体をコピーする。forループの反復自体はAUD-038で解消したが、一般のindex読み取り経路は残っていた。実測ではtreeのEnv::getも同じく全体を複製し、lenも同じ経路だった(確保量の比は両engineとも約4.0) ✅ 完了(副作用のないindex式に限り参照読みへ。VMはIndexLocal / LenLocalへlowering、treeは変数セルをborrow()して読む。比はxs[i]が3.98→1.99(tree)/3.99→1.79(VM)、d[k]が4.00→2.00/4.01→1.95、len(xs)が3.97→1.99/3.98→1.79。goldenフィクスチャとscalingゲートを追加)
AUD-047 コレクションをcopy-on-writeにして複製コストを構造的に下げる AUD-041は副作用のないindex式だけを参照読みにしたため、d[to_str(i)]のように関数呼び出しを含むindex式は評価前のコレクションを読む意味論を保つために複製が残る(確保量の比4.00)。Value::List / Value::DictRc<Vec> / Rc<BTreeMap>にして書き込み時に複製すれば、意味論を変えずに複製を減らせる。upvalue経由の読み取り(GetUpvalueのclone)も同時に解消できる ✅ 完了(Value::ListRc<Vec<Value>>Value::DictRc<BTreeMap<String, Value>>へ変更。全mutation(assign_index・push/pop/__pop_update・VMのListPush/DictInsert)をRc::make_mut経由にし、検査後にdetachする。cloneはハンドル共有O(1)で、書き込み時だけbackingを複製する。観測挙動は不変。alias分離・引数/返り値/ネスト/closure共有cell・equalityを両engineで固定するgolden fixture collection_cow_aliasと、d[to_str(i)]・upvalue経由xs[i]の確保量が線形に収まるscaling gate cow_read_allocation_stays_linear_in_both_enginesを追加)
AUD-042 treeのclosure捕捉範囲を自由変数へ絞る treeはcapture_all()で定義時に見える全bindingを捕捉するため、クロージャを保持するコンテナ(push(saved, fn ...)saved等)まで捕捉し、cell→list→closure→captured→cellの参照循環でメモリが解放されない。200回×200個で51.8MB(循環しない書き方では2.19MB)。VMは自由変数だけをupvalue化するため発生しない。捕捉範囲の統一は生成コストの削減にもなる ✅ 完了(本体で言及される名前だけを捕捉。生存量は400個で345,796→0バイト、定義コストは可視binding 100個で19,640,166→2,560,166バイト。生存量ベースと定義コストのscalingゲート、tree/VM両engineのfixtureを追加)
AUD-046 treeの関数呼び出しでglobal scopeの複製を避ける push_call_frameself.scopes[0].clone()でglobal scopeのHashMapを呼び出しごとに複製するため、呼び出しコストがtop-level bindingの数に比例していた。global 5個と100個で同じ関数を2,000回呼ぶと確保量の比が3.67(AUD-042前は7.66)。VMは同条件で1.03。cellはRc共有なので値は複製されないが、entry数ぶんのRc複製とHashMap確保が毎回発生していた ✅ 完了(スコープスタックを差し替えずframe_baseで探索範囲を限定。確保量は2,000回の呼び出しでglobal 100個のとき12,203,174→2,349,174バイト、比3.67→1.01。releaseの実時間はfib(22) 22→17 ms、global 100個×20,000回 56→8 ms。可視性の単体テストとscalingゲートを追加)
AUD-044 完了済み非適合と古い記述をREADME・規範仕様から除く 仕様revision表記の不一致(当時README.md 0.5 / language-spec.md 0.6)、完了済み非適合(captured collectionへのindex代入)の掲載、README.mdの構成図がlib.rs / builtin_core.rs / limits.rs / sandbox.rs / module.rs / tests/defensive_vm.rsを欠くこと、env.rsを「関数テーブル」と説明すること、examplesを3件中1件しか挙げないこと、CI手順が矢印区切りでコピー実行できずcargo clippy--を欠き3 OS matrixとcoverage jobを記載していないこと。組み込み関数53個とLICENSE(MIT)の記載は実測と一致する ✅ 完了(revision表記はAUD-043で揃え、以後0.10まで追随。完了済み非適合はlanguage-spec.mdから除去しID付きの表へ置換。構成図はsrc/*.rs 19件が実ファイルと1対1で一致することを確認し、examplesも3件掲載。CI手順は3ジョブの表とコピー可能なコマンド列へ置換)
AUD-045 配布・実行手順とtoolchainの下限を明示する READMEのクイックスタートはcargo build / cargo runだけだが、エラーメッセージの例は$ tsumugi file.tsgを使う。cargo install --path .やPATH設定、再導入手順の記載がない。Cargo.tomlはedition 2024を要求しながらrust-versionを宣言せず、rust-toolchain.tomlもないためCIはstable追従で、compiler版の下限を検証できない。release / install workflowとcommit SHA固定のaction参照もない 🟡 設計確定・未実装(検証・リリース・運用設計: MSRV Rust 1.97、install/release、artifact/OCI/運用gate。現行workflow・manifestは未変更)
AUD-048 捕捉のない関数値の同一性判定を統一する AUD-014は「関数値は同一の関数値とだけ等しい」を規範としたが、同一性の粒度がengine間で揃っていない。fn make() return fn(x) x end end に対する make() == make() がtreeでfalse、VMでtrueになる。捕捉なし名前付き関数の2回生成、ループ内で同じlambda式を2回評価した2値の比較でも同じ差が出る。原因はsrc/value.rsPartialEqで、treeのValue::Fnは定義式の評価ごとに新しいRc<FnDef>を作るのに対し、VMのValue::VmFnはcompile時に共有されるRc<Chunk>とupvalue cellで比較するため、upvaluesが空だとallが真になる。upvalueを持つ関数値、および別々に書いた同形lambdaの比較は両engineで一致する。AUD-014の486ケース網羅比較は型の組み合わせを対象としたため、同一sourceから複数インスタンスを作る形を含んでおらず検出できなかった ✅ 完了(src/value.rsFunctionId(u64)を新設し、Value::Fn / Value::VmFnidを追加、PartialEqをID比較だけに統一。treeはEvaluator、VMはVmに単調増加counterを持ち、FnDef/Lambda評価・MakeClosure実行のたびに発番する。VMは定数テーブルにid未確定のプロトタイプVmFnを置き、capture 0件でも必ずMakeClosureを通して実行時に一意IDを付与する。IDはrollbackしても再利用しない。make()==make()はtree/VMともfalseに統一し、backend別期待ファイルcomparison_semantics.expected.vmを削除。REPL跨ぎのID非再利用回帰テスト(tree/VM)とcounter overflowのfault injection unit test(tree/VM)を追加。仕様revisionを0.13へ)
AUD-049 builtin名一覧の3重管理を解消する スクリプトから呼べるbuiltin名が3か所に分散している。builtin_core.rsdispatch(46名。__pop_updateは内部専用)、builtin.rsmatch name(53名、_ => Ok(None)で終わる)、compiler.rsis_builtin()(52名。printは予約tokenのため別扱い)。現状は3リストが整合しているが、追加時に1か所でも漏らすと「treeでは呼べるがVMでは呼べない」状態になり、compile errorではなく実行時のnameエラーとして現れる。design.mdが「builtin_core.rs + dispatchへの登録のみで両engineに反映される」と書いていたのはこの構造と矛盾していた ✅ 完了(src/builtin_registry.rsに単一BuiltinSpec registry(PUBLIC_BUILTINS)を新設し、tree委譲判定・Compilerのis_builtin・context判定・VM dispatchをすべてregistryから導出。手書き名一覧を3か所とも除去。VM CallBuiltin opcodeを名前文字列からBuiltinIdへ変更しtypoをcompile時検出。内部__pop_updateはpublic registryから外しpop書き戻し専用のOpCode::PopUpdateへ隔離してsourceから到達不能化。registry内unit test 9件とtests/builtin_registry_contract.rs 3件で一意性・往復・tree/VM名前解決・__pop_update非到達を自動検査。HostFunction registry連携(Capability Model仕様)はPhase 2で別途)
AUD-050 MAX_CALL_DEPTHlimits.rsへ集約する 構造的上限のうちMAX_AST_DEPTHMAX_IMPORT_DEPTHsrc/limits.rsにあるが、MAX_CALL_DEPTH = 128だけeval.rsvm.rsに同じdoc commentで二重定義されている。値とエラー文面は一致しているが、境界の数え方が揃っておらず、tree(call_stackが空開始)とVM(frames: vec![frame]でtop-level込み)で到達できる再帰深度が1段ずれる(AUD-017)。定義が分かれていることがこのズレを見つけにくくしている ✅ 完了(MAX_USER_CALL_DEPTH = 128src/limits.rsへdoc contract付きで集約。eval.rs/builtin.rs/vm.rsのローカル定義を削除し共有定数を参照。VMはactive_user_frame_count()でroot frameを除いて数え、AUD-017の1段ズレも同時に解消)

2026-08-27 検証スナップショット

対象はcommit feb1cbd940b0243faaec91b1eb7cf017c43283ae、aarch64 Linux、rustc 1.97.1cargo fmt --check、Clippy -D warnings、全targetテスト、release build、tree/VMのhello smoke testはすべて成功した。単体テスト138件はlib/binで重複実行され、統合テストは150件。cargo llvm-covのline coverageは全体83.55%、vm.rs 71.23%、builtin.rs 56.54%だった。

Criterionの平均値は次のとおり。各iterationにparseを含み、VMはcompileも含むため、一回実行のend-to-end latencyであり純粋なdispatch速度ではない。最新の測定値は次節「フェーズ別ベンチマーク」を参照する(この表はAUD-038前の記録として残す)。

workload tree VM 相対結果
fib_20 14.982 ms 5.408 ms VMが約2.77倍高速
dict_500 9.410 ms 34.350 ms VMが約3.65倍低速
fstr_300 89.535 µs 1.047 ms VMが約11.7倍低速
loop_5000 762.89 µs 272.94 ms VMが約358倍低速
higher_order_200 110.71 µs 78.633 µs VMが約1.41倍高速

2026-08-27 フェーズ別ベンチマーク(AUD-038)

対象はcommit c0fd91f+AUD-038の変更、aarch64 Linux、rustc 1.97.1、Criterionの中央値。

parse は 1.85–4.19 µs、compile は 0.72–2.73 µs で、いずれも実行時間より3桁小さい。したがって旧スナップショットのend-to-end値は実質的に実行フェーズの値であり、engine差の原因はparse/compileではない。

workload(execute) tree VM 相対結果
fib_20 29.130 ms 6.158 ms VMが約4.7倍高速
dict_500 11.185 ms 10.759 ms ほぼ同等
fstr_300 99.77 µs 155.21 µs VMが約1.6倍低速
loop_5000 870.22 µs 1.490 ms VMが約1.7倍低速
while_5000 1.032 ms 1.159 ms VMが約1.1倍低速
higher_order_200 112.72 µs 81.49 µs VMが約1.4倍高速

loop_5000(コレクション反復)と while_5000(コレクションを介さない反復)を並べると、イテレーション処理の追加コストが分離できる。

旧スナップショットからのVM側の変化は次のとおり。原因はいずれもforループの反復ごとのコレクション複製で、AUD-038で解消した。

workload 旧VM 新VM
loop_5000 272.94 ms 1.392 ms
dict_500 34.350 ms 10.587 ms
fstr_300 1.047 ms 154.20 µs

tree側は旧スナップショットより遅くなっている(fib_20 14.982 ms → 28.349 ms)。原因はAUD-037の呼び出し時self-bindingによるValue::Fnの複製で、AUD-040で解消した(次節)。この表のtree列はAUD-040前の値である。

2026-08-27 AUD-040後の実行フェーズ

Value::FnをRc共有にした後のexecuteフェーズ(--sample-size 20 --measurement-time 2、上の表とは測定設定・マシン状態が異なるため直接比較しない)。

workload(execute) tree VM
fib_20 7.599 ms 4.995 ms
dict_500 9.030 ms 8.826 ms
fstr_300 84.79 µs 127.53 µs
loop_5000 799.14 µs 1.117 ms
while_5000 942.73 µs 922.95 µs
higher_order_200 103.66 µs 72.75 µs
closure_def_200 144.99 µs 112.19 µs

修正の効果は同一マシン・連続実行のA/Bで確認した(fib(22)を7回実行した最小値)。

workload 93b7606 AUD-040後
tree fib(22) 64.5 ms 21.2 ms 0.33
tree closureループ定義 10.0 ms 7.8 ms 0.78
VM fib(22) 14.1 ms 13.2 ms 0.94(誤差。Value::FnはVMでは未使用)

実時間はマシン状態に依存するため、確保バイト数も併記する。body 2文の関数を300回呼ぶと 909,821バイト → 452,645バイト、body 100文との比は 15.89 → 1.06 になった。

2026-08-28 追加監査スナップショット

対象はcommit 06dae8e、aarch64 Linux、rustc 1.97.1cargo fmt --check、Clippy --all-targets -- -D warningscargo testはすべて成功した。単体テスト139件はlib/binで重複実行され(AUD-039)、統合テストは156件、スケーリングテストは2件である。

この状態から、既存テストが捕捉していない不具合として AUD-043(トップレベルreturnの未検証)を最小入力で再現した。トップレベルreturnのfixtureもREPL回帰テストも存在しないため、緑のCIでは検出できない。break / continueの文脈エラーは両engineで期待どおり報告される。

文書照合では AUD-044 / AUD-045 を追加した。Kubernetes / Helm / Kustomize / Dockerの資材は存在せず、追跡対象の設定ファイルは.github/workflows/ci.ymlCargo.tomlだけである。Windows固有挙動とsymlinkのTOCTOUは、従来どおり実環境確認が必要な項目として据え置く。

2026-08-28 AUD-042の測定

対象はaarch64 Linux、rustc 1.97.1tests/scaling.rsのグローバルアロケータで、確保量と生存量(確保 - 解放)を測った。実時間ではないため測定は決定的である。

関数ローカルのリストへクロージャを溜めて関数を抜けた後の生存量。

クロージャ数 修正前 修正後 VM
200 173,596 バイト 0 バイト 0 バイト
400 345,796 バイト 0 バイト 0 バイト

クロージャを2,000回定義する際の確保量(定義のみ、呼び出しなし)。

可視binding 修正前 修正後
5個 2,774,064 バイト 2,538,064 バイト
100個 19,640,166 バイト 2,560,166 バイト
7.08 1.01

同じ関数を2,000回呼ぶ際の確保量は、global 5個と100個の比が7.66→3.67へ下がったが比例は残った。捕捉範囲ではなくpush_call_frameのglobal複製が原因で、AUD-046として分離し別途修正した(次節)。VMは同条件で1.02〜1.03と影響を受けない。

2026-08-28 AUD-046の測定

同条件での、同じ関数を2,000回呼ぶ際の確保量。

top-level binding 修正前 修正後
5個 3,321,072 バイト 2,327,072 バイト
100個 12,203,174 バイト 2,349,174 バイト
3.67 1.01

fib(20)の確保量は23,164,422→15,832,425バイト。releaseビルドの実時間(3回の最小値)はfib(22)が22→17 ms、global 100個で20,000回呼ぶ例が56→8 msだった。VMは確保量・比とも変化しない。

2026-08-28 ドキュメント整合監査

対象はcommit 4396ffa、aarch64 Linux。README.md / LANG_GUIDE.md / docs/*.md の記述を実装と実行結果に突き合わせた。テスト件数は次のとおりで、これ以前のスナップショットの件数は当時のcommitに対する記録として残す。

種別 件数
単体テスト(lib / bin でそれぞれ実行、AUD-039) 152
統合テスト(tests/integration.rs 172
防御的テスト(tests/defensive_vm.rs 8
スケーリングテスト(tests/scaling.rs 6

検出した記述の誤りは3種類に分かれた。

規範仕様に反するもの: LANG_GUIDE.mdのClosures節とdesign.mdの既知のトレードオフが、AUD-014で廃止した「関数値は常に等しくない」という旧方針を残していた。LANG_GUIDE.mdは同じファイルのOperators節と矛盾していた。README.mddesign.mdはengine差の残存領域として「比較・index代入・builtin・import」を挙げていたが、これらはAUD-014 / AUD-013 / AUD-012 / AUD-030で統一済みで、実際に残る差を1件も挙げていなかった。language-spec.mdの既知非適合にはAUD-017が載っていなかった。

実装に追随していないもの: design.mdenv.rs節がEnv::functions(廃止済み)とcapture_all(AUD-042でcapture_referencedへ置換)を残し、frame_base(AUD-046)に触れていなかった。ユニットテスト表は8モジュールのうち5つしか挙げず、存在しないget_mutを観点に挙げていた。スケーリングテスト節は6性質のうち2つしか説明していなかった(tests/scaling.rsのmodule docもAUD-041の1件を欠いていた)。builtin_core.rsの説明は「~45個の純粋関数」だが実数はbuiltin_*が47個で、うち15個はfilesystem・env・clockに触る。CI手順は3ジョブ・3 OS matrix・coverage jobを反映していなかった。

文書間で重複し乖離したもの: 形式文法がLANG_GUIDE.mddesign.mdに二重に置かれ、index_assign(両方がAUD-013前のpostfix)とdict_literalLANG_GUIDE.mdだけが実装と異なるSTRINGキー)で食い違っていた。文法はLANG_GUIDE.mdの1か所に集約し、design.mdはv0.3からの差分だけを残した。

この監査で新たに再現・記録した項目は AUD-048(捕捉のない関数値の同一性がengine間で異なる)、AUD-049(builtin名一覧の3重管理)、AUD-050MAX_CALL_DEPTHlimits.rs外に二重定義)である。AUD-048はgolden fixtureで差分を固定した。

仕様revisionは0.11へ上げた。0.9(AUD-014)と0.10(AUD-030)は観測挙動の変更に伴う更新だったが、今回は観測挙動を一切変えていない。それまで文書化していなかった制約(returnの式必須、辞書キーの順序、containsの辞書での対象、sliceの負値、has_keyのキー型、format_timeの型とUTC、to_intの文字列受付範囲)を規範仕様へ明記したため、規範として拘束する内容が増えたことを示す更新である。

language-spec.mdの組み込み関数表では、実行して確認した挙動と説明が食い違う箇所を修正した。containsが辞書ではキーを見ること、keys / values / forの辞書反復が「アルファベット順」ではなくコードポイント順("Z" < "a")であること、sliceの負値が0クランプでindexアクセスの末尾参照とは非対称であること、has_keyのキーがStr限定であること、format_timeがInt限定・UTC固定であること、to_int"3.5"" 42"を受けないこと、returnに式が必須であることを明記した。

2026-09-07 詳細レビューバックログ(REV)

commit 092da35d0a01c6e3f403123df8416ec0819746d7 を対象に、production source・test・全設計文書を横断した詳細レビューを実施し、25件の指摘を REV-001〜REV-025 として記録した。レビュー報告書の正本は semantic-review/Tsumugi-detailed-review-20260907.md である。

このレビューの環境では rustc / cargo が使えず、cargo build / cargo test / cargo clippy / fuzz / sanitizer は未実施である。「確認」とあるものは、明示しない限りコード経路を静的に追跡して成立を確認したものである。

指摘のうち、レビュー時点で設計が不足していた(設計欄が △ または ×)6件(REV-003 / 004 / 005 / 009 / 012 / 021)は、次期実装仕様を 次期意味論・実装決定第17節に追加済みである。残りの指摘は既存の各設計文書と該当節を正本とし、設計を新規追加せず実装バックログへ直結させる。REV-012 は既存の第5節(AUD-017)が正本であり、意味論変更ではなく status / doc drift の解消のみを扱う。

状態の読み方: 下表の最終列はコード・test・workflow・配布物の実装状況であり、設計状態ではない。設計正本で判断が確定していても、受入gateを満たす実装がなければ完了扱いにしない。REV は既存 AUD 番号を再割り当てせず、独立した追跡項目として扱う。

P0 — Critical

ID 項目 到達範囲 設計状態 実装状況
REV-001 共有DAGの構造比較・表示・join・sortが指数時間/指数出力になる。value graph traversalへnode/depth/fuel/bytes上限とvisited pair管理を導入し、表示をHumanDisplay/CanonicalRepr/TotalOrderKeyへ分離する 通常script 検討○・設計○(実行予算・協調実行、REV-015受入条件へ追加) ⬜ 未実装
REV-002 非UTF-8 canonical import pathが空文字へ変換され、sandbox認可対象とI/O対象が分離する。認可APIを&Path/認可済みhandleへ変更する Unix + import 設計○(次期path-handle方式、capability-model ⬜ 未実装
REV-006 未検証bytecodeのJump(0)等でstep課金を迂回し無期限実行できる。raw Callもcall課金を迂回する。VerifiedChunkとverifierで検証済みbytecodeだけをVMへ渡す 公開raw bytecode 設計○(verifier要件を報告書に記載) ⬜ 未実装
REV-015 source・string・heap・I/O・bulk workが包括的に有限化されていない。reserve-before-allocate等でsource/string/heap/I-O budgetとdeadline/cancelを実装する。REV-001のDAG増幅も受入条件へ含める 通常script 検討◎・設計◎(実行予算・協調実行capability-model ⬜ 未実装
REV-023 script exit()がホストプロセスを終了する。process-globalなexitをやめ、構造化Exited outcomeを返す embedding 検討◎・設計◎(実行予算・協調実行、AUD-036と同基盤) ⬜ 未実装

P1 — High

ID 項目 到達範囲 設計状態 実装状況
REV-003 Int–Float比較が2^53超で誤り、==が非推移的になる。整数を丸めずFloatのbit表現から数学的に正確に比較する共通NumericOrderを導入し、min/maxは選択したoperandを元の型で返す 通常script ✅ 確定済み(次期意味論・実装決定§17.1) ⬜ 未実装
REV-004 公開Chunk::patch_jumpが範囲外/非jump offsetでpanicする。patch_jumpをfallible化し、builderをpub(crate)/feature gateへ封印する 公開low-level API ✅ 確定済み(次期意味論・実装決定§17.2) ⬜ 未実装
REV-005 不正MakeClosure descriptorをNull captureとして黙認する。capture記述子を明示化し、不整合はinternal errorにする(REV-006と同一マイルストーン) 公開raw bytecode ✅ 確定済み(次期意味論・実装決定§17.3) ⬜ 未実装
REV-007 ExecutionContextがsession stateとrun meterを混在し、execute間でstepを累積する。meterをrequestごとに分離する stable facade 設計◎(実行予算・協調実行ExecutionRequest ⬜ 未実装
REV-008 通常Engine::executeがtransactionでなく、エラー前のstate mutationを保持する。全stable executionへtransactionを適用する(AUD-024はREPL限定で完了) stable facade 設計◎(組み込みAPI実行予算・協調実行、AUD-024) 🟡 REPLのみ実装。全execution transactionは未実装
REV-011 language revision・engine差・実装statusが複数文書でdriftしている。機械可読な単一正本(project-metadata)から生成し、CIでstale literalを検査する 文書・release 設計◎(報告書に受入条件、§17との連携) ⬜ 未実装
REV-012 call評価順が現行仕様・実装(callee評価前検査)と次期仕様・code comment(callee先行)で矛盾し、完了表示も不整合。意味論の正本は第5節(AUD-017)で、statusとdoc driftのみ解消する call semantics ✅ 確定済み(次期意味論・実装決定§17.5、第5節が正本) 🟡 depth-counting実装済み。callee-precedence切替は未実装
REV-013 args()がhost process argvを読み、tree/VMで解析規則も異なる。runtime coreからstd::env::args_os()を除去し、ExecutionRequest.argumentsのみを公開する embedding 設計◎(組み込みAPI、AUD-018) ⬜ 未実装
REV-014 sandbox/env/limits/stdio/clockがprocess-globalまたはfirst-use global。EngineConfigExecutionRequestへ移し、library coreがstd::env等を直接参照しないようにする embedding 設計◎(capability-model組み込みAPI、AUD-014と関連) ⬜ 未実装
REV-018 internal module/raw bytecodeの公開が安全境界とstable surfaceを弱める。stable rootをEngine等へ限定し、internalsをpub(crate)にする(REV-004〜006の根因) 公開API 設計◎(組み込みAPI、§17.2と共通の封印作業) ⬜ 未実装
REV-020 import先parse errorの原因を捨て、wrapper messageだけを返す。原因診断を保持する import diagnostics 設計○(組み込みAPI error契約) ⬜ 未実装
REV-021 現行remove_dirは再帰削除だが次期capabilityはEmptyDirectoryへ割当て。remove_dirを空のみへ変更し、再帰削除をremove_treeRecursiveDelete)へ分離する filesystem capability ✅ 確定済み(次期意味論・実装決定§17.6) ⬜ 未実装

P2 — Medium / Quality

ID 項目 到達範囲 設計状態 実装状況
REV-009 list_dirがentry errorを黙殺し、非UTF-8名をlossy変換して衝突させる。個別entry errorをstructured host errorにし、非UTF-8名をinvalid_encodingにする filesystem ✅ 確定済み(次期意味論・実装決定§17.4、capability-model ⬜ 未実装
REV-010 32-bit targetでi64 as usizeがwrapし、limit迂回・巨大collectを起こし得る。try_fromとchecked arithmeticへ置換する 32-bit target 設計○(実行予算・協調実行 budget受入) ⬜ 未実装
REV-016 scriptからRc cycleを作れ、context再利用で回収不能heapが累積する。baseline heap課金・clear_user_state()・tenant跨ぎ再利用禁止で近期対応し、中期はarena+GCを検討する(AUD-042は偶発cycle削減で完了済み) 長寿命context 検討◎・設計○(設計、AUD-042) ⬜ 未実装
REV-017 human Displayが非escapeで、sort key・repr・outputが同じ表現へ結合されている。HumanDisplay/CanonicalRepr/TotalOrderを分離する(REV-001と連動) 通常script 設計△(sort仕様は記載、分離設計は不足) ⬜ 未実装
REV-019 now()がepoch前/clock errorを0にし、u64 as i64も未検査。clock capabilityとchecked変換で扱う clock 設計◎(capability-model実行予算・協調実行 ⬜ 未実装
REV-022 EOF・I/O error・permission等をNull/falseへ畳み、原因とdenialを区別できない。safe profileでdenialとOS失敗を区別する I/O API 設計◎(capability-model組み込みAPI ⬜ 未実装
REV-024 現行CIはrolling stable・mutable action・--lockedなし・fuzz/stress/MSRVなし。MSRV固定・action pin・release/fuzz/stress gateを段階導入する CI/release 設計◎(検証・リリース・運用設計、AUD-024/045と関連) 🟡 3 OS CI・golden・scaling・defensive testのみ実装
REV-025 source/token制限に加え、parse diagnostic件数にも上限がない。診断件数上限を設ける compile 設計△(source/token上限は記載、diagnostic件数は未記載) ⬜ 未実装

REV 由来項目の実装順は、次期意味論・実装決定第17節「移行順」と、後述の「設計sliceに沿う推奨実装順」に統合済みである。REV-001 / 015(包括budget)と REV-002 / 006 / 018(bytecode検証・API封印)は基盤に属するため、境界挙動より前に置く。

設計決定crosswalk

次の表は、監査で未決定または未完了として記録された論点を、設計正本と現行実装へ対応付ける。設計状態が確定でも、実装状況が未実装・部分実装ならAUD完了ではない。

AUD 設計状態 決定概要 正本 実装状態
AUD-018 確定済み CLIはtsumugi [OPTIONS] [SCRIPT [ARGS...]]とし、script引数をExecutionRequest.arguments snapshotへ渡す。入口統合をE8a、profile/options移行をE8bに分離 次期意味論・実装決定第6節、組み込みAPI仕様第12・14〜16節 未実装。現行CLIは追加引数を拒否
AUD-019 確定済み operation別の単一constructorからcanonical kind/message/line/traceを生成し、backend固有診断とmessage推測を廃止 次期意味論・実装決定第3節 ✅ 完了(language core分)。operation別constructorへ全移行、classify_runtime_error削除、tree/VM完全一致をinventory/pairedテストで固定。host adapter error(HostErrorSpec)はPhase 2で別追跡
AUD-020 確定済み Tsumugi単体をsecurity boundaryとせず、filesystemはportable path-handleで認可と利用をbindし、TOCTOU・oracle・dangling symlinkを受入試験化 脅威モデル TM-002〜004・第11節、Capability Model仕様第8節・CAP-AT-10〜14 部分実装。現行制約の文書化のみ完了、path-handle未実装
AUD-022 確定済み timeout/golden/differential/limit/defensive matrixに加え、fuzz・stress・failure injection・資源制約gateを段階導入 検証・リリース・運用設計第4〜6・17節 部分実装。harness、timeout、完全一致、temp分離は完了。matrix/fuzz/stressは未実装
AUD-024 確定済み Completed / Exitedだけ全language-stateをcommitし、その他terminalはexecution開始時点へrollbackする。catch済みerror後に最終完了した実行はcommitする。stdout/filesystem/network/DB/host function等の完了済み外部効果はrollbackしない 次期意味論・実装決定第7節、実行予算・協調実行仕様第10節、組み込みAPI仕様第10節 ✅ 完了(REPL submissionの未捕捉errorで全language-stateをrollback、正常完了・catch済み完了はcommit、外部効果はrollbackしない。first-write undo logで記録量は変更箇所数に比例。deadline/budget/cancel terminalはPhase 3/4で別追跡)
AUD-034 確定済み path_joinは全argumentをStrとして検査し、非Strを無言で欠落させない 次期意味論・実装決定第9節 ✅ 完了(builtin_path_joinで全引数を左から右へStr検査し、最初の非Strでbuiltin_typeエラーを返す。tree/VMは共有handlerで一致。error inventoryとpath_join_contractテストを追加。仕様revision 0.16)
AUD-036 確定済み exit、file size、Float→Intのlossy変換を共通checked helperで拒否し、valid exitは構造化Exitedにする 次期意味論・実装決定第10節 未実装。なおloop変数をiterationごとのfresh cellにする意味論はAUD-010で実装・完了済み
AUD-045 確定済み MSRVをRust 1.97とし、stable/MSRV CI、install/release、6 platform artifact、署名・SBOM・OCI、参照用Kubernetes Jobの順序とgateを固定 検証・リリース・運用設計第3〜10・17〜18節 未実装。現行はrolling stable、release/install workflow・OCI・manifestなし
AUD-048 確定済み function/lambda式の動的評価ごとにfresh FunctionIdを発行し、clone/captureは同じIDを保持、rollback後もIDを再利用しない 次期意味論・実装決定第12節、決定性・実行時監査仕様第4.7節 ✅ 完了。tree/VMとも関数等価性をFunctionId比較へ統一。VMはcapture 0件でもMakeClosureで実行時発番し、backend別期待ファイルを削除。REPL rollback非再利用・overflow fault injectionのテストを追加
AUD-049 確定済み 単一BuiltinSpec / callable catalogからtree、VM、compiler、arity、context metadata、生成文書を導出。HostFunction registryは別registryだが共通resolverで衝突検査 次期意味論・実装決定第13節、Capability Model仕様第17節・CAP-AT-20 ✅ 完了(language core分。src/builtin_registry.rsPUBLIC_BUILTINSをtree/VM/compiler/arity/context metadataの正本にし、CallBuiltinをBuiltinId化、__pop_updateOpCode::PopUpdateへ隔離。HostFunction registryとの共通resolver衝突検査はPhase 2で別追跡)
AUD-050 確定済み MAX_USER_CALL_DEPTH = 128limits.rsへ集約し、root frameを数えずactive user call数で統一。128個目を許可し129個目の直前で拒否 次期意味論・実装決定第5節 ✅ 完了(AUD-017と一体)。limits.rsへ集約、VMはactive_user_frame_count()でroot除外計数。tree/VMとも128 user frameを許可し129個目を同じline/message/traceで拒否。境界値・相互再帰・lambda・callbackの回帰テスト追加

設計sliceに沿う推奨実装順

  1. 基準固定: 次期意味論・実装決定第17節の基準固定と、現行非適合fixtureを維持する。文書の設計確定を実装完了として扱わない。
  2. 意味論基盤: 内部refactor → AUD-050/017深度統合(✅ 完了) → AUD-049単一BuiltinSpec(✅ 完了) → AUD-019 canonical error(✅ 完了) → AUD-047 COW(✅ 完了)/AUD-048 FunctionId(✅ 完了) → AUD-016 binding(✅ 完了)/AUD-024 transaction(✅ 完了) → AUD-034 path_join(✅ 完了)/AUD-036/018/033境界挙動の順で進める。
  3. Phase 1 embedding: 組み込みAPI仕様 E1〜E6→E8a。最終terminal型のsubsetを使い、先行公開型を作らない。
  4. Phase 2 capability: E7→E8bとCapability Model仕様 C1→C2、C3/C4/C5/C7、C6、C8、最後にC9/C10。現行ambient accessを削除するまで完了扱いにしない。
  5. Phase 3/4 control: E11/C11で有限budget・transactionを完成し、その後E12/C12でcooperative state machine、yield/pause/resume、admission/backpressureを実装する。
  6. Phase 5/6 determinism/audit: Determinism Slice 1〜4→Audit Slice 5→VM conformance Slice 6。E13/C13はSlice 5へ統合し、別event実装を作らない。
  7. Phase 7 verification/release: VRO-AT-01〜15を満たし、MSRV、release/install、artifact、OCI、運用資材は前段Phaseの受入を再検証してから導入する。
  8. 将来機能: classは次期意味論・実装決定第15節で設計済み・低優先度。基盤と総heap budgetの後に扱う。HTTPは同第16節で**設計済み・着手禁止(具体ユースケース承認待ち)**であり、Phase 1〜6完了と着手gate承認後だけ別計画を作る。

初回監査の改修境界(記録)

ユーザー入力だけでホストpanic/状態破損へ到達していた AUD-001 / AUD-002 を最優先で解消した。同じ状態境界に属する AUD-004 / AUD-006、独立して安全に修正できた AUD-003(主要生成経路)/ AUD-005 / AUD-009 / AUD-012(一部)/ AUD-015 / AUD-022 までを回帰テスト付きで扱い、言語仕様の選択を伴う項目はバックログに残した。

実装済み

  • 基本型(Int, Float, Str, Bool, Null)
  • 変数宣言(let)と再代入
  • 四則演算 + 剰余演算子(%)
  • 比較演算・論理演算(and / or / not)
  • 条件分岐(if / elif / else / end)
  • while ループ
  • for ループ(リスト・辞書・文字列のイテレーション)
  • break / continue
  • 関数定義・呼び出し(fn / return / end)
  • 第一級関数(関数を変数に代入・引数として渡す)
  • 無名関数 / ラムダ(fn(x) expr end
  • クロージャ(変数セルの参照キャプチャ・状態共有)
  • リスト・辞書
  • インデックスアクセス・代入
  • 組み込み関数(print, len, push, pop, keys, type, slice, contains, split, join, to_int, to_str, range)
  • ファイルI/O(read_file, read_lines, write_file, append_file)
  • REPL(複数行入力対応)
  • 行番号付きエラーメッセージ
  • CI(fmt + clippy + test)
  • REPL の is_incomplete をレキサー経由に修正(文字列/コメント内の誤判定解消)
  • eval.rs の分割(組み込み関数を builtin.rs に切り出し)
  • エラー型の構造化(TsumugiError enum: Parse / Runtime)
  • builtin.rs のカテゴリ別分割(I/O・コレクション・文字列・数値・ファイル・パス・日時)
  • 高階関数(map / filter / each)
  • バイトコード VM: Phase 1(OpCode + Chunk + Compiler + VM + 算術 + Print)
  • バイトコード VM: Phase 2(変数 — let / 再代入 / GetLocal / SetLocal)
  • バイトコード VM: Phase 3(制御フロー — if/elif/else / while / for / break / continue / and / or)
  • バイトコード VM: Phase 4(関数 — FnDef / Call / ReturnValue / 再帰対応)
  • バイトコード VM: Phase 5(クロージャ — upvalue / MakeClosure / Lambda)
  • バイトコード VM: Phase 6(組み込み関数 — 53個対応)
  • バイトコード VM: Phase 7(互換性修正 — min/max Int×Float混合、remove ファイル/ディレクトリ判定、write_file/append_file 型変換)
  • スタックトレース(関数呼び出し経路のエラー表示、ツリーウォーク版/VM版両対応)
  • ステップ予算(ループ反復 + 関数呼び出しのカウント制限、無限ループ/無限再帰を防止)
  • ファイルI/Oサンドボックス(環境変数 TSUMUGI_SANDBOX でアクセス許可パスを制限)
  • モジュール / import(ファイル分割、循環import検出、ネストimport対応、実行前解決の共有ローダーでツリーウォーク版/VM版を統一)
  • エラー処理 / try/catch(ランタイムエラーの捕捉、ネスト対応、ツリーウォーク版/VM版両対応)
  • From<String> 廃止(全エラー生成箇所を TsumugiError::runtime() に統一、文字列再パース除去)
  • import のサンドボックス対応(TSUMUGI_SANDBOX 設定時に import 先パスも検証、ツリーウォーク版/VM版両対応)
  • 環境変数アクセス制御(TSUMUGI_ENV_ALLOW で env() の読み取り可能キーを許可リスト制限)
  • 浮動小数点 IEEE 754 の基本挙動(VMのFloatゼロ除算をinf/NaNに修正、ツリーウォークにFloat比較armを追加。異種型・複合値を含む比較parityはAUD-014で解消)
  • セキュリティ強化(コールフレーム深度制限 MAX_CALL_DEPTH=128、map/filter/each ステップカウント修正、TSUMUGI_* 環境変数ブロック)
  • f-string(文字列補間)— f"hello, {expr}" 構文。レキサー/パーサー/評価器/VM全対応
  • 構造化エラー — try/catch で Value::Error を返す。e["type"] / e["message"] / e["line"] でアクセス可能。既存の文字列結合との互換性を維持
  • 参照キャプチャ — クロージャが Rc<RefCell<Value>> で変数セルを共有。カウンターパターン(状態を保持するクロージャ)をサポート。ValuePartialEq/Debug を手動実装に移行。VM版は SetUpvalue オペコード + locals_cells でローカル変数のセル昇格を実装

設計方針: 言語中核とホスト機能の境界

目標: 小さな言語中核 + 明示的なhost capability

言語中核には、文字列、数値、List/Dict、型変換など、外部状態へ触れない純粋な計算を置く。 filesystem、環境変数、時刻、標準入出力、process、network、database、メール、業務操作などの外部効果は、原則としてホストが実行単位で明示的に付与するcapabilityまたはhost functionとして提供する。

「自プロセス + OSで完結するか」ではなく、「外部状態を観測・変更するか」「権限、予算、監査の対象になるか」を境界の判断基準とする。

現行実装からの移行

現行のbuiltinはCLI中心の学習用設計としてOS機能へ直接接続している。次の表は現在の挙動と目標を区別する。

カテゴリ 現在 目標
文字列・数値・List/Dict操作 core builtin core builtinを維持
filesystem std::fsへ直接接続 read/write/delete等を分離した実行単位capability
環境変数・引数 process環境・argvへ直接接続 hostが許可した値のsnapshotを注入
時刻 OS clockを直接参照 clock capabilityとして注入
stdin/stdout processのstreamへ直接接続 host提供のinput/outputと出力量予算を使用
exit host processを終了 processを終了せず構造化Outcomeを返す
HTTP・DB・メール 未実装 coreへ追加せずhost function/moduleとして提供
業務操作 登録手段なし host function registryから明示的に公開

この移行は、設計確定済みのstable embedding APIと実行contextを先に実装してから行う。既存builtinをただ削除するのではなく、CLIが必要なcapabilityを明示的に付与する構造へ変え、同じengineを組み込み用途でも利用できるようにする。

現行のimportはTsumugi sourceを読み込む機能であり、native host moduleやhost functionを登録する拡張境界ではない。host extension APIが成立するまで、「HTTPやDBを外部moduleで提供する器が完成した」とは扱わない。

この境界を採用する理由

  1. 最小権限 — scriptごとに必要な操作だけを付与し、ambient authorityを避けられる
  2. 資源制御 — host callの時間、入出力量、同時実行数を実行予算へ含められる
  3. 監査可能性 — 外部効果の許可、拒否、引数、結果をhost boundaryで観測できる
  4. 予測可能性 — clock、env、filesystem等を注入し、同じ入力に対する再現性を高められる
  5. 依存の分離 — HTTP clientやDB driverを言語本体へ固定せず、ホストが用途に応じて選べる
  6. テスト容易性 — 実OSや外部serviceを使わず、fake capabilityで境界動作を検証できる

外部機能を追加する順序

  1. 組み込みAPI仕様のE1〜E6・E8aでstable Engine入口を作る
  2. Capability Model仕様の単一callable catalog、host function registry、deny-by-default policyを実装する
  3. clock、env、stdio、filesystem、process操作をhost境界へ移し、E7・E8bでsafe/legacy profileを接続する
  4. 実行予算・協調実行仕様のbudget、deadline、cancellation、backpressureと、決定性・実行時監査仕様のauditをhost callへ伝播する
  5. HTTPは次期意味論・実装決定第16節の着手gateを満たし、具体的ユースケースが承認された場合だけhost adapterとして別計画を作る

次の候補(バイトコード VM)

Phase 内容 状態
0+1 OpCode + Chunk + Compiler + VM + 定数 + 算術 + Print ✅ 完了
2 変数(let / 再代入 / 参照) ✅ 完了
3 比較 + 条件ジャンプ(if / while / for) + break/continue ✅ 完了
4 関数定義・呼び出し(コールフレーム) ✅ 完了
5 クロージャ(upvalue) ✅ 完了
6 組み込み関数(len, push, pop 等) ✅ 完了
7 VM互換性修正 — min/max混合型・remove・write_file ✅ 完了
8 浮動小数点 IEEE 754 統一 — VMゼロ除算→inf/NaN、Float比較arm追加 ✅ 完了

次の候補(言語機能)

優先度 項目 メモ
クラス(継承なし) 次期意味論・実装決定第15節で設計済み。基盤と総heap budget後の低優先度実装候補

設計済み・低優先度: クラス

背景

クラスの規範的なgrammar、identity、construction、error、受入基準は次期意味論・実装決定第15節で確定済みである。以下は判断に至った背景と候補記録として残し、実装時は同正本を優先する。

方針: クラスは設計確定済みとし、継承は採用しない

  • クラス構文自体: 設計確定済み。class ... end でデータと操作をまとめる低優先度の実装候補とする
  • クラス継承(スーパークラス/サブクラス): 採用しない。理由は後述
  • 合成(composition): 採用する。部品を「持つ」方式でクラス間の機能共有を実現する

継承をスコープ外とする理由

  1. 認知負荷が高い — 多段継承・メソッドオーバーライドの挙動追跡はプログラミング経験が浅い人にとって大きなハードル。Tsumugi の「入り口レベルで学ぶ」目的と矛盾する
  2. 現代的な設計思想との整合 — Go は継承を意図的に持たない。Rust はトレイトで代替する。「継承より合成」が定石として定着している
  3. 一度入れたら抜けない — 継承のメソッド解決順序(MRO)は言語の根幹に影響する。後から設計を変えるのが極めて難しい

継承なしで困らない理由

合成パターンで大半のユースケースに対応できる:

# 部品
fn create_battery()
    return {"level": 100}
end

fn charge(battery)
    battery["level"] = 100
end

# ロボット犬 = 部品を組み合わせ
fn create_robot_dog(name)
    return {"name": name, "battery": create_battery()}
end

fn recharge(dog)
    charge(dog["battery"])
end

クラス構文を入れる場合も同様に「フィールドに別のオブジェクトを持つ」ことで機能を共有する:

# 設計確定済みクラス構文の非規範例
class RobotDog
    fn init(name)
        self.name = name
        self.battery = Battery()
    end

    fn recharge()
        self.battery.charge()
    end
end

この方針を見直すタイミング

  • 「継承がないと書けないプログラム」の具体的なユースケースが明確になったとき
  • ただしその場合もまずインターフェース(trait 的な仕組み)で代替可能か検討する

検討事項: 実行安全性(ステップ予算) — 実装済み

実装内容

  • カウント対象: ループ先頭への戻り(while/for)+ ユーザー定義関数呼び出し
  • デフォルト上限: 1,000,000(百万ステップ)
  • 上限変更: 環境変数 TSUMUGI_MAX_STEPS で指定(例: TSUMUGI_MAX_STEPS=5000000
  • 超過時: ランタイムエラー "ステップ上限に達しました (上限: N)" + スタックトレース
  • ツリーウォーク版・VM版の両方で同じ動作

背景

Tsumugi にはファイルI/O やサンドボックス機能が既に実装されているが、 信頼できないコードの暴走(無限ループ・無限再帰)を防ぐためにステップ予算を導入した。

案: ループ反復 + 関数呼び出しのカウント制限

  • while / for がループ先頭に戻るタイミングでカウント +1
  • 関数呼び出し時にカウント +1
  • ループ内の let / if / 代入はカウントしない
  • 上限(例: 1,000,000)に達したら強制停止

この方式の利点

  • ユーザーの感覚と一致する(「100万回ループしたら止まる」はわかりやすい)
  • ループ内の処理量に左右されない(if が何段あってもカウントに影響しない)
  • 書き方に制約を加えない(while true も書ける。止まるなら止まる)
  • 無限再帰も検知できる

解決済みの事項

  • 上限値: デフォルト 1,000,000(百万)。環境変数 TSUMUGI_MAX_STEPS で変更可能
  • カウント方式: ループ反復 + 関数呼び出しのみカウント(ユーザーにとって予測しやすい方式を採用)
  • 実装タイミング: ファイルI/O 実装と同時に導入済み

参考

  • Dhall: チューリング不完全にすることで全プログラムの停止を保証
  • Deno: 権限付与モデル(--allow-net 等)
  • Go/Rust Playground: タイムアウトによる暴走防止
  • Lua: debug.sethook による命令数コールバック

品質改善候補(機能追加ではなく処理改善)

既存の実装を壊さずに品質・堅牢性・開発体験を底上げする改善項目。

エラーメッセージの改善

項目 詳細 状態
整数リテラルのオーバーフロー検出 read_numberi64::MAX 超の入力がパニックする → パースエラーにする ✅ 完了
未閉じ文字列の明示エラー レキサーが \n や EOF で打ち切った未閉じ文字列を明示的にエラー報告する ✅ 完了
From<String> の段階的廃止 "N行目: ..." を再パースする脆い変換を構造化エラーに逐次移行 ✅ 完了
パースエラーの回復 最初の1エラーで停止する代わりに複数エラーをまとめて報告 ✅ 完了

VM 実行性能

項目 詳細 状態
OpCode::CallBuiltin の String 除去 関数名を定数テーブルへ移し、AUD-049 で CallBuiltin(BuiltinId, usize) へ更に前進(typo を compile 時に検出) ✅ 完了
dispatch の match 分割 算術・比較・制御フローをメソッドに分けて可読性向上 未着手
call_fn_value ループ統一 run_frames(stop_depth) を抽出し run() と共有、try/catch 対応を統一 ✅ 完了

レキサー / パーサーの堅牢性

項目 詳細 状態
Token::Unknown のエラーメッセージ改善 パーサーに流れた際に文字名を含む親切なメッセージにする ✅ 完了
! 単体の処理 再帰で不明文字が消える問題を修正 ✅ 完了

テスト品質

項目 詳細 状態
カバレッジ可視化 cargo llvm-cov で未到達パスを特定しテスト拡充 ✅ 完了
ベンチマーク criterion で parse / compile / execute / end_to_end を分離計測 ✅ 完了(AUD-038)
計算量オーダーの回帰ゲート tests/scaling.rs が確保バイト数で for の線形性(AUD-038)、呼び出しコストのbody長非依存(AUD-040)、クロージャ定義コストの可視binding非依存(AUD-042)、呼び出しコストのtop-level binding非依存(AUD-046)、コレクション読み取りの線形性(AUD-041)を検査し、生存量でクロージャの解放(AUD-042)を検査(実時間に依存しない) ✅ 完了

コード構造

項目 詳細 状態
eval.rsexec_stmt 分割 巨大 match を独立メソッドに分離 未着手
Env::functions の廃止 関数を変数として統合しスコープルールを一本化 ✅ 完了

実行安全性

項目 詳細 状態
ユーザー関数のコール深度制限 関数再帰を128フレームでRust実stack overflow前にエラー化。root除外のactive user frame数で数え、tree/VM境界を統一(MAX_USER_CALL_DEPTHlimits.rsへ集約) ✅ 完了(AUD-050 / AUD-017)
関数外 return の拒否 関数本体の外のreturnをパース時にエラー化し、VM REPLのhost panicと無言終了を防止 ✅ 完了(AUD-043)
構文・AST深度制限 Parser生成時とCompiler/Evaluator入口でAST深度256を検査。nested f-stringにも親深度を継承 ✅ 完了(AUD-027)
import chain深度制限 rootを除くactive import chainをtree/VMとも128に制限 ✅ 完了(AUD-028)
サンドボックスの OnceLock テスタビリティ テスト時に環境変数を切り替え可能な設計にする 未着手
サンドボックスの中間シンボリックリンク迂回修正 新規書き込み時に親ディレクトリを canonicalize() してからチェック ✅ 完了
整数オーバーフローのエラー化 checked_add 等に置き換え、release ビルドでもサイレントラップを防止 ✅ 完了
メモリ DoS 対策(コレクションサイズ上限) List/Dictの生成・拡張、List生成builtin、反復変換に上限ガード。TSUMUGI_MAX_COLLECTION_SIZE で変更可能 ✅ 完了(総heap quotaは別課題)
ファジングテスト導入 cargo-fuzz でレキサー/パーサー/評価器に無作為入力 未着手
VM の unwrap() 除去 コンパイラバグ時にパニックではなく構造化エラーを返す ✅ 完了(AUD-023)
エラー種別の enum 化 classify_runtime_error()contains() 判定を ErrorKind enum に移行 ✅ 完了

設計済み・着手禁止: HTTPアクセス機能

方針: 言語中核へ組み込まない

HTTP adapterの着手gate、capability、SSRF/DNS/TLS/redirect、budget、audit、error契約は次期意味論・実装決定第16節で設計済みである。ただしPhase 1〜6完了と具体的ユースケースの設計レビュー承認までは、依存追加・実装・DNS接続testを開始しない。

HTTPはnetwork access、DNS、TLS、認証、redirect、response size、timeoutなど、権限・資源・監査の境界を伴う。特定のHTTP clientをTsumugi中核へ組み込まず、host functionまたはhost moduleとして提供する。

例えばホストがhttp_getを公開する場合も、scriptから任意のnetwork accessを許可するのではなく、次をhost policyで制御する。

  • 接続先scheme・host・portのallow-list
  • request/response byte上限
  • connect/read/total deadline
  • redirect回数
  • 同時実行数とrate limit
  • cancellation
  • request開始、許可・拒否、終了理由のaudit event
  • credentialとresponse bodyのredaction

具体的なRust HTTP clientと認証方式はホストアプリケーションが選択する。これにより、HTTP dependencyの更新周期を言語本体から分離し、Tsumugiを利用しないホストへ不要な依存を持ち込まない。

実装タイミング

  • 着手禁止(具体ユースケース承認待ち)。Phase 1〜6の受入gateと次期意味論・実装決定第16.1節の全条件を満たすまで開始しない
  • 承認後もcore builtinではなくhost adapterとして別計画を作る
  • 具体的なRust HTTP clientと認証方式は承認ユースケースとhost責任に合わせて選び、coreへ固定しない