diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-01/REGISTRATION_PROPOSAL.json b/docs/plans/original-completion-2026-10-02/execution/p28-01/REGISTRATION_PROPOSAL.json new file mode 100644 index 0000000..00a5be7 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-01/REGISTRATION_PROPOSAL.json @@ -0,0 +1,159 @@ +{ + "status": "proposal for Root; nothing registered, prepared, dispatched or run by this Desktop session", + "assignment": { + "implementation": { + "worker": "codex", + "model": "gpt-6-astra", + "route": "complex", + "reason": "Godot windowed probe(GDScript)とPython collector(owned process・guard・stage照合)の複数領域にまたがり、段階0の停止判定など設計判断を含むためbounded(OpenCode)ではなくcomplex。UI実装ではないためAntigravityは使わない。" + }, + "independent_review": { + "model": "claude-opus-5-5", + "session": "独立一時セッション(実装・仕様作成と別)" + }, + "commander": "通常commander(Root経由)。この提案は契約案で、正式開始判断はcommanderの記録による。", + "measurement_execution": "Root(統合後、windowed実行のためGUIログインセッションのMacで、owned PID/guard/cleanup付き)", + "quota_fallback": "構造化providerエラーでquota確定時のみ同役割でAntigravity claude-opus-5-5-highへ1回。その他の失敗はblocked。" + }, + "register_project": { + "project": "the-tree-p28-01-perf-baseline", + "repo": "/Users/korizatou114/Projects/とりにく工房ゲーム制作部", + "worktrees": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p28-01-perf-baseline", + "baseline": [ + { + "id": "P28-01-C1", + "requirement_id": "P28-01", + "text": "速度は実UI/Clock経路(main.gd::_set_speed→SimulationKernel._process)のみで与え、直接advanceの値をx3 frameとしないことをchecker拒否試験で確認する。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C2", + "requirement_id": "P28-01", + "text": "元fixtureと各phase準備状態のSHA、sampleごとの登録総数・実稼働数・描画対象数を別欄に記録する。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C3", + "requirement_id": "P28-01", + "text": "seed実値(world_seed)とRNG stateを別欄にし、未取得はnullと理由にする。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C4", + "requirement_id": "P28-01", + "text": "GPU/描画時間の非対応・未取得はnullと理由にし、0や合格への補完をchecker が拒否する。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C5", + "requirement_id": "P28-01", + "text": "段階0(Operations ON限定動作・実数・完了時間)と外挿記録、phase上限1800s、超過時は原記録保存で停止を実装する。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C6", + "requirement_id": "P28-01", + "text": "private user://・owned PID/guard/cleanup・通常player保全・全rawログ/SHA結合をr02同等に保つ。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C7", + "requirement_id": "P28-01", + "text": "製品source mapが開始前後で不変であることを照合し、変化時は拒否する。", + "validation_ids": [ + "p28-01-collector-unit" + ] + }, + { + "id": "P28-01-C8", + "requirement_id": "P28-01", + "text": "機種・build・seed・速度・区間・平均・P95・最大の欄を全sampleに要求し、欠落・偽値をcheckerが拒否する。", + "validation_ids": [ + "p28-01-collector-unit" + ] + } + ], + "validations": { + "p28-01-collector-unit": { + "argv": [ + "{python}", + "docs/plans/original-completion-2026-10-02/execution/p28-01/collector/test_collect_p28_01.py" + ] + } + } + }, + "register_task_contract": { + "id": "P28-01-COLLECTOR", + "title": "現HEADの性能基準:windowed x1/x3・Operations ON collector", + "requirement_ids": [ + "P28-01" + ], + "acceptance_ids": [ + "P28-01-C1", + "P28-01-C2", + "P28-01-C3", + "P28-01-C4", + "P28-01-C5", + "P28-01-C6", + "P28-01-C7", + "P28-01-C8" + ], + "spec_ref": "docs/plans/original-completion-2026-10-02/execution/p28-01/SPEC.md", + "base_commit": "8c36c100b2073baf8a9c536528f319a5d0837a63", + "worker": "codex", + "allowed_paths": [ + "docs/plans/original-completion-2026-10-02/execution/p28-01/collector/**" + ], + "depends_on": [], + "resource_locks": [ + "p28-01-perf-collector" + ], + "validation_ids": [ + "p28-01-collector-unit" + ], + "max_repair_attempts": null + }, + "task_instructions": "docs/plans/original-completion-2026-10-02/execution/p28-01/TASK_INSTRUCTIONS.md", + "readonly_inputs_for_worker": { + "place_under": "build/p28-01-readonly/", + "copy_from": "artifacts/original-completion-2026-10-02/p14-03-representative-perf-r01", + "files": { + "collect_perf.py": "43f3e42900a670957a01cfcaca7e485809527b79912a358917c935c57ea9c063", + "measure.gd": "95e5967835cb05ad96e8e6f257689d0bd831792aa9c228c022e3af81448ff76a", + "PROCEDURE.md": "228eae9862f7a8ea49eb8c88456097023bf479f97da27e73e938bba33f15ba11", + "run-r02/profile_guard.gd": "597696c705cc8f0e79a35265ca3ef8df55f7fc3c4e0e5a2ce9a4e20e29e29a6f", + "run-r02/guarded.gd": "c9deebb39ee643d312a77bae64f74cf6851697bb31036fc56d67dd7c4037ee09", + "run-r02/execution.json": "553971f55635e529b48634ef86ad7d4198c8bafe04d5a6a5ef778a4de0439fc1", + "run-r02/after/evidence/report.json": "f1d447937158a884a1b287c3b5be38b6e73b73c5d748f9576401877402dabe1b" + }, + "note": "worker tree へcommitしない。fixture/engineはRootの実測時のみ使用。" + }, + "sequence": [ + "Root: register project/task(baseline・validation凍結)", + "Root: 通常commanderへこの契約を渡し正式開始判断を記録、Desktopへ読戻し", + "dispatch: codex実装→validate(unittest、engineなし)", + "独立Opus review", + "prepare-integration→final validate", + "Root: 統合済みcollectorで段階0→P1〜P4を実測(owned PID・raw保存)", + "証拠ゲート(receipt結合)通過後にのみ原P28-01を完了(22→23)" + ], + "credit": "この collector task 完了では原本加算0。", + "unchanged": [ + "予算値(performance_budget.gd:17-24)", + "原30/88・受入分母", + "製品source map 1407(正式192証拠を保持)", + "権限/政策/モデル/DB" + ] +} diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-01/SPEC.md b/docs/plans/original-completion-2026-10-02/execution/p28-01/SPEC.md new file mode 100644 index 0000000..58ecad7 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-01/SPEC.md @@ -0,0 +1,113 @@ +# P28-01 現HEADの性能基準:最小バッチ仕様 + +この文書は Runner の `spec_ref` です。work_packages.json 全体の代わりに、この対象に必要な原本定義だけを固定します。 + +## 1. 原本定義(変更しない) + +- 分母は原30パッケージ・88成果単位で、部分点はありません。開始時点の正式完了は22/88、完了パッケージは4/30です。 +- 成果単位 P28-01「現HEADの性能基準」(`work_packages.json` の P28.remaining_deliverables[0]) + - work: 実Runtimeの20,000マス・200客・50職員・150施設を基準にTick、経路、snapshot、描画、保存を測る。 + - acceptance: 機種、ビルド、シード、速度、測定区間、平均・P95・最大を残す。 +- パッケージ P28「性能・操作感・長期バランス」 + - requirement_ids: B-1.1, B-3.1a, B-4.3a, B-4.3c, B-11.1, B-12.1, B-14.4 + - decisions: D04, D08, D10 + - package acceptance(P28-01 の完了では満たしたことにしない): 既存性能予算と新しいWindows描画目標を満たす。到達不可能な収支/信仰/ランク条件なし。高速自動再生だけでプレイ時間・操作感を合格にしない。 +- P28 横断条件6件(各成果で適用し、適用外にするときは理由を記録する) + 1. 原本条件とUI操作が一致 + 2. Runtimeの実利用・会計・行動へ接続 + 3. 途中保存・再起動で再現 + 4. 異常/境界/中断を検証 + 5. 関連回帰PASS + 6. 要件別ログとソースハッシュを保存 + +## 2. 完全原本参照 + +`docs/traceability/original/BASELINE.txt`(SHA256 `75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a`)。行番号は `requirement_coverage.json` の source_lines です。 + +| ID | 行 | この対象での意味 | +|---|---|---| +| B-1.1 | 2–10 | PC (Windows)、想定プレイ時間 | +| B-3.1a | 58–60 | 現実10秒=ゲーム1時間、Pause/x1/x2/x3 | +| B-4.3a / B-4.3c | 84–87 | A*経路、EV待ち時間、渋滞時の50%減速 | +| B-11.1 | 213–216 | メイン画面、スクロール、ズーム、表と裏 | +| B-12.1 | 228–230 | ドット絵マップの描画 | +| B-14.4 | 258 | UIレスポンス向上 | + +既存の予算値は `scripts/core/performance_budget.gd:17-24` のとおりで、変更しません。x1 平均4 ms、x3 P95 12 ms、経路 P95 2 ms、main-thread stall の最大50 ms、保存5 s、読込8 s です。 + +## 3. 再利用する既存証拠(再生成しない) + +- **source**: main `8c36c100b2073baf8a9c536528f319a5d0837a63`。製品 source map は正式全回帰 `p14-03-formal-regression-83b170a-r01` と同じ1407件です。この対象では製品と source map の対象(autoload/scripts/scenes/data/tests/assets/tools と直下4ファイル)を変更しません。変更がなければ、正式192 suite の証拠はそのまま有効です。 +- **代表入力**: `artifacts/original-completion-2026-10-02/p28-current1299-runtime-scale-build-candidate-native-r01/fixture/reference.variant`(SHA `eb4f7700…f9bd`)。20,000/200/50/150、Operations OFF です。全生成はしません。 +- **engine**: `/Applications/Godot.app/Contents/MacOS/Godot`(SHA `c7cccbf8…8ccf`、4.7.2.stable.official.ed1daf0bf)。 +- **既存の headless 実測 r02**(`p14-03-representative-perf-r01/run-r02/execution.json` SHA `553971f5…9fc1`) + - 条件: Mac16,10・10コア・24 GB、Operations OFF、x1、300分 + - 1分 tick: 平均826.6 ms、P95 1702.7 ms、最大2918.1 ms + - 経路 cold: P95 0.61 ms + - snapshot: 平均77.6 ms + - 保存: manual 297 ms、autosave 327 ms + - 読込: 平均3193 ms、最大3368 ms + - これは x1 headless・Operations OFF の行としてそのまま採用し、再測定しません。 +- **collector の型**: `p14-03-representative-perf-r01/collect_perf.py`(SHA `43f3e429…c063`)と `measure.gd`(SHA `95e59678…f76a`)、`run-r02/profile_guard.gd`(SHA `597696c7…a6f`)。以下を引き継ぎます。 + - 私有の CoW stage、private user:// 保存 + - owned Popen による PID の捕捉、guard、cleanup + - 通常 player の保全 + - 全 raw stdout と SHA の結合 +- 上の artifacts/ は gitignore 対象のため、Root が worker へ build/ 配下の読取専用として渡します。 + +## 4. 不足を埋める測定(この対象の新規分) + +windowed(非headless)の main scene で、1回の collector 実行の中に次の4 phase を置きます。 + +| phase | Operations | 速度 | +|---|---|---| +| P1 | OFF | x1 | +| P2 | OFF | x3 | +| P3 | ON | x1 | +| P4 | ON | x3 | + +各 phase の区間は warm-up 30ゲーム分のあと、計測120ゲーム分です。 + +1. **実UIと同じ Clock 経路を使う。** 速度は `main.gd::_set_speed`(速度ボタンと同じ処理)で設定し、時間は `SimulationKernel._process → process_real_delta`(MAX_TICKS_PER_FRAME 8、MAX_BACKLOG 120)だけで進めます。`advance_minutes(3)` などを直接呼んで出した値を x3 frame とは呼びません。 +2. **SHA と実数を分けて残す。** 元 fixture の SHA と、各 phase の準備状態の SHA を記録します。数は sample ごとに3種類を区別して残します。 + - 登録総数(客・職員・施設) + - 実稼働数(在館で、退館中でない客、勤務中の職員、稼働中の施設) + - 描画対象の数(viewport 内で可視の node) + + warm-up で客が減った後の値を「200客の測定」とは呼ばず、実数を併記します。 +3. **seed と RNG state を別欄にする。** seed は restore 後の `SimulationRuntime.world_seed` の実値です。RNG state(`rng_streams`)は別欄に記録し、state を seed の名前で代用しません。 +4. **未取得は null と理由にする。** GPU 時間は `RenderingServer.viewport_set_measure_render_time` と `viewport_get_measured_render_time_gpu` で取得します。非対応・未取得なら null と理由を残し、0 や合格で補いません。CPU の描画時間、frame 時間、`Performance.TIME_PROCESS` も同じ扱いです。 +5. **段階を踏んで実行する。** + - 所要時間の見積り: 1分 tick 827 ms から、(30+120)分 × 4 phase = 約500 s の CPU 時間。起動と import は別。 + - 同じ collector の段階0として、Operations ON の限定動作を先に1回行います。enable の結果、10ゲーム分の1分ごとの時間、実数、完了時間を見ます。 + - 段階0の実測から P3・P4 の所要時間を外挿し、記録してから長い計測へ進みます。 + - 時間の超過(phase ごとに上限1800 s)や実数の不足があれば、その時点の原記録を保存して止めます。次の最小手順は判断担当が決めます。 +6. **各 sample に残すもの** + - 機種: hw.model、コア数、メモリ + - build: engine の文字列・hash・SHA、project の commit、source map の SHA + - seed と RNG state(3. のとおり別欄) + - 速度、区間(開始・終了のゲーム分と wall 時刻) + - frame 時間、1分 tick、stall(50 ms 超の frame の数と最大)、描画 CPU/GPU のそれぞれについて、平均・P95・最大・標本数 + - 予算は合否を生の値で並べるだけで、新しい許容値は作りません。 + +## 5. 対象外と非主張 + +- Windows 実機は未検証のまま残します(P02-03 / P28-03 の範囲)。 +- P28 パッケージの予算達成、P28-02、P28-03、長期バランス、プレイ時間は対象外です。 +- 4回分の全回帰と、fixture の全生成は行いません。 + +## 6. 完了の扱い + +- **この Runner task**: collector、probe、checker が下の C1〜C8 を満たし、Runner の validation、独立レビュー、integration、final を通ること。これで原本の加算は0です。 +- **原本 P28-01 の完了**: Root が統合済みの collector で実測し、その receipt を結合した後の証拠ゲートが通ったときに限ります。予算が未達でも、記録の項目がそろえば P28-01 の受入は成立します。未達の予算は P28 パッケージの未達として残します。 + +## 7. 登録条件(collector task の baseline) + +- **C1**: 速度は実UI/Clock の経路だけで与え、x3 を直接 advance の値で代用しないことを、checker が拒否試験で確認する。 +- **C2**: 元 fixture と各 phase の準備状態の SHA、および sample ごとの登録・稼働・描画の3種類の実数を、別々の欄に記録する。 +- **C3**: seed の実値と RNG state を別欄にし、取得できなければ null と理由にする。 +- **C4**: GPU や描画時間を取得できなければ null と理由にする。0 や合格への補完を checker が拒否する。 +- **C5**: 段階0(Operations ON の限定動作)と外挿の記録、phase ごとの上限、超過時に原記録を保存して止めることを実装する。 +- **C6**: private user://、owned PID・guard・cleanup・通常 player の保全・全 raw ログと SHA の結合を、r02 と同等に保つ。 +- **C7**: 製品 source map が変わらないことを開始前と終了後に照合する。変われば拒否する。 +- **C8**: 機種・build・seed・速度・区間・平均・P95・最大の各欄を全 sample に要求する。欠けた欄や偽の値は checker が拒否する。 diff --git a/docs/plans/original-completion-2026-10-02/execution/p28-01/TASK_INSTRUCTIONS.md b/docs/plans/original-completion-2026-10-02/execution/p28-01/TASK_INSTRUCTIONS.md new file mode 100644 index 0000000..eea3fb8 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p28-01/TASK_INSTRUCTIONS.md @@ -0,0 +1,44 @@ +# P28-01 collector task 指示(worker 向け) + +仕様は `SPEC.md`(同じディレクトリ)です。この指示と SPEC.md は変更しないでください。 + +## 作るもの(allowed_paths `docs/plans/original-completion-2026-10-02/execution/p28-01/collector/**` の中だけ) + +1. **`collect_p28_01.py`**: r02 の `collect_perf.py` を基にした外部 collector です。 + - 1版(main の現 source)だけを、私有の CoW stage に materialize します。 + - import は1回だけ行い、その後に段階0と P1〜P4 を1つずつ実行します。 + - `--check` は入力と予定の argv を検証して表示するだけで、stage も engine も作りません。 + - `--run` は実測します。Root が実行します。 +2. **`measure_p28_01.gd`**: windowed の main scene 用 probe です。 + - 代表入力の読込は r02 と同じく `FileAccess.get_var(false)`、`initialize`、`restore_snapshot` で行います。保存は private user:// だけです。 + - 速度は `main.gd::_set_speed` で設定し、`SimulationKernel._process` が進めるのを観測するだけにします。直接 advance を呼んではいけません。 + - 計測は frame ごとに行います。 + - stdout にちょうど1行 `P28_01_PERF_REPORT=` を出します。 +3. **`check_p28_01_report.py`**: report と収集結果の checker です。合格の条件と、拒否すべき偽の report は下に示します。 +4. **`test_collect_p28_01.py`**: 合成した入力だけで動く unittest です。engine も artifacts も不要にします。 + +## 必須事項 + +- SPEC.md の §4 と C1〜C8 を、そのとおりに実装します。 +- **checker が拒否すべきもの**(それぞれに対応する拒否試験を書く) + - x3 が直接 advance で作られている(Clock の速度と frame の記録が一致しない) + - 登録数を稼働数や描画数の欄に流用している + - seed の欄に RNG state が入っている + - GPU 時間が 0 で、理由がない + - 必須の欄が欠けている + - source map が変わっている + - raw stdout と report が一致しない + - PID が一致しない +- **製品 source map の対象には触れません。** autoload、scripts、scenes、data、tests、assets、tools と、`project.godot`、`export_presets.cfg`、`Makefile`、`AGENTS.md` です。 +- 予算の値、原30/88、受入分母は変えません。 +- 次のことはしません。 + - 全回帰 + - native engine の起動(実測は Root が統合後に行います) + - fixture の生成 + - P14 の再調査 +- 参照用の入力(r02 の `collect_perf.py`、`measure.gd`、`profile_guard.gd`、`run-r02/execution.json` と report)は、Root が `build/p28-01-readonly/` に読取専用で置きます。SHA は SPEC.md §3 のとおりです。それ以外の場所や、拒否されたパスにはアクセスしないでください。 +- commit はしません(Runner が submit します)。最終出力には変更したファイルと、試験の実行結果をそのまま出します。 + +## 検証 + +Runner の validation `p28-01-collector-unit` が `test_collect_p28_01.py` を実行します。そのあと、独立した Opus(claude-opus-5-5)が内容をレビューします。自己申告や終了コード0は、合格の証拠になりません。