第 9 章 — 仕様を改善する
この章では、第 7 章で観測した結果から仕様のどこを直すかを決め、直した仕様をもう一度動かして確かめます。この章は演習だけからなります。
9.1 学ぶこと
- シミュレーション観察を使って どのつまみを回すか を同定する。
- 適切な層(deadline / monitor / lifecycle / actor / runtime)で仕様を調整する。
- 再実行で変更を検証する。
9.2 背景
どの症状をどの層で直すか
設計の各層に固有の修正方法があります:
| トレースで観察される症状 | 修正する層 | 例 |
|---|---|---|
| すべてのロボットで期限切れ | 仕様 — deadline を緩める | 5s → 7s |
| 1 体のロボットで monitor が頻発(偽陽性) | 仕様 — rule を厳しく | < 20 → < 15 |
| World モデルが間違っていてロボットが Violated になる | ランタイム — world snapshot のキーを修正 | update_instance_world 呼び出しを確認 |
| 報酬が支払われない | ランタイム — 報酬実行を実装 | engine.py を拡張 |
| すべて成功するが 集約 がおかしい(例:遅延) | 新 monitor または新契約 | FLEET_THROUGHPUT_SLA を追加 |
これは規範的 SoS 仕様における 不具合の小さな分類 です。
9.3 演習
演習 9.1 (★) — 1 つの失敗を診断する
目的: 第 7 章のトレースから 1 つ の違反を選ぶ。1 段落で説明:どの層を、どう変えるか。
提出: session5_diagnosis.md(1 ページ)。
演習 9.2 (★★) — 修正を適用する
目的: 5.1 の診断を実装する。修正後の仕様を my_delivery_v3.cadl として保存。
手順:
-
5.1 で診断した変更を実施。
-
演習 7.2 と同じ手順で、新しいファイルの IR を生成し、その IR に対してデモを再実行:
cd ~/program/cadl_repocadl sim-ir my_delivery_v3.cadl --format json > my_delivery_v3.ir.jsoncd ~/program/cadl-raspimouse-simulatorpython3 -m cadl.runtime.multi_robot_demo --ir ~/program/cadl_repo/my_delivery_v3.ir.json --summary -
修正したい違反が消え、かつ 他を壊していないことを確認。
提出: my_delivery_v3.cadl + v2 との diff。
演習 9.3 (★★★) — 報酬実行を実装
目的: 現在、報酬は仕様(incentives.rules)に 書かれている だけで 実行 されない。しかも、ルールの文字列はランタイムまで届いていない。仕様を IR に変換するとき(cadl_repo/src/cadl/sim/lower.py)、契約の governance に残るのは lambda と incentive_type だけで、rules のリストは落とされる。Python ランタイムにアクターごとの残高を持たせ、契約が Completed に到達したら報酬を加算する。
手順:
-
ContractRuntimeにbalances: dict[str, float]とアクセサruntime.balance(actor_id)を追加し、ルールを受け取る口を用意する(例:ContractRuntime(ir, log_path=None, reward_rules=[...]))。 -
ルールを取得する。IR には入っていないので、cadl のパーサで
.cadlソースから読み、別のスクリプトで JSON に書き出す(自分のファイルにincentives:ブロックがなければ、第 4 章のものを追加する):# dump_rules.py — cadl-lang をインストールした Python 環境で実行import json, sysfrom cadl.parser import parse_filesos = parse_file(sys.argv[1])rules = [{"contract": c.id, "rule": r.description}for c in sos.contracts if c.incentivesfor r in c.incentives.rules]json.dump(rules, open(sys.argv[2], "w"), indent=2)# python dump_rules.py my_delivery_v2.cadl rules.json# -> [{"contract": "DELIVERY_SLA", "rule": "reward(ROBOT[i], 10) when on_time_delivery"}]別スクリプトにするのは、シミュレータのリポジトリに独自のトップレベルパッケージ
cadl/があり、cadl-langを隠してしまうためです。ランタイムの中、そのテスト、あるいはシミュレータのルートからpython -mで実行するコードでは、from cadl.parser import parse_fileがNo module named 'cadl.parser'で失敗します。スクリプトは別のディレクトリで実行し、rules.jsonをデモに渡します(multi_robot_demoに--rewards rules.jsonオプションを追加する)。各ルールは元の文字列のままです。
reward(<actor_ref>, <amount>) when on_time_deliveryの形式を自分でパースし(正規表現で足りる)、それ以外は読み飛ばします(同梱の例にはpenalty(...)のルールもある)。発展版: ソースを読む代わりに、
lower.py(とsim/ir.pyのGovernanceParams)を拡張して IR にルールを載せる(例:governance.incentive_rules)。編集したチェックアウトのcadlを使い(pip install -e .。PyPI 版にはこのキーがない)、cadl sim-ir --format jsonの出力に現れることを確認したうえで、ランタイムが IR から読むようにする。 -
誰に支払うかを決める。ランタイムが知っているのはインスタンス ID(
robot-0-1)だけで、契約インスタンスにアクターのフィールドはない。インスタンスを開くときにアクターを渡し(例:open_instance(..., actors={"ROBOT": "robot-0"}))、ルールのROBOT[i]をそれに対応付ける。 -
終端状態に入ったときに加算する。インスタンスが閉じる箇所は 2 つある —
StateMachineEngine.fire_transition(completeを含む通常の遷移)とContractRuntime._fire_state_jump(期限とモニタによるジャンプ)— ので、両方にフックする。on_time_deliveryは「インスタンスがCompletedに入り、violationレコードがない」と自分で定義する。ランタイムの述語評価器は単独の識別子を真として扱うため、これを判定できない。 -
cadl/runtime/tests/test_rewards.pyを追加:- 配送
Completedで 10 ポイント獲得するテスト Violated配送では報酬が払われないテスト
- 配送
-
multi_robot_demo --summaryの出力に最終残高を追加。同梱のシナリオではrobot-0が 10、他の 4 台は 0 になる。
振り返り: CADL 仕様には既に reward(ROBOT[i], 10) when on_time_delivery と書かれていましたが、ここまでランタイムは無視してきました。IR にすら載っていませんでした。「仕様にそう書いてある」と「ランタイムが実際にそう動く」の境界線はどこですか?
演習 9.4 (★★★) — 最終レポート
目的: コース全体をカバーする 3 ページのレポート。
| ページ | 内容 |
|---|---|
| 1 | 初期 CADL モデル(v1)、モデルが問うている質問、v1 で欠けていたもの |
| 2 | シミュレーション結果 — ベースラインと修正後の比較。表と最低 1 枚の cadl-explorer スクリーンショット |
| 3 | 振り返り:規範を追加すること で何が得られたか? シミュレーションを動かすこと で仕様だけでは分からなかった何を学んだか? SoS-DSL の次の一手は? |
授業で使う場合
授業の前に。
- 第 4〜7 章のすべての提出物。
まとめと宿題。
最後の授業(第 9 章)の終わりまでに提出:
my_delivery_v1.cadl/v2.cadl/v3.cadlsession5_diagnosis.md+ 最終レポート(3 ページ)- (任意)
test_rewards.pyと修正版engine.py