P04-01: 同時発生の更新規約

This commit is contained in:
Agent Control Runner
2026-10-16 03:11:58 +09:00
parent 5475391647
commit 64617018ed
6 changed files with 910 additions and 15 deletions
@@ -1,5 +1,28 @@
# 初期監査の検証器
## repair7 定義(以前の版識別説明に優先)
registered は deb1bcb、execution_origin は 9767b0a、checker は実際に
実行したcheckerのcommitとbytes、product_target は
`{main_anchor, submitted, composed_tree}` とする。checkerのSHAを製品版に
代用しない。提出後にしか確定しない自己blob照合は未実施としてRootが検証する。
`duty_payments` は決算日のpayroll settlement取引のうち、
ShiftInstance.record_duty_minute の勤務recordとstaff_id/day単位で
結合できる取引の件数。期待値は1のまま。独立した通貨項目ではない。
collectorはpayroll行と勤務recordの実rawを結合し、結合不能なら失敗する。
融資の公開返済API `repay_loan_principal` とledger分類
`LOAN_PRINCIPAL_REPAID` / `financing_principal_outflows` は存在する。
自動返済や全UIの完成は主張しない。「融資機構がない」という説明は撤回する。
midnight_replayは同minuteの決算API再呼出しによる実測までpending。
1442完了やservice request再送を1440売上・決算API再呼出しの証明にしない。
shift_completionはapproved-shift-current-r01.gdの1080観測を使う。
D05のEV停止帰属、停電と休業の厳密な順序、費用時点の未確定部分はpending。
全case収集、登録validate、独立whole review、統合準備の順序を維持する。
本修理での試験・engine実行はworkerでは行わない。
## repair6 現在値(2026-10-16)
旧値: C全体は `native ordering bytes` によりblocked、実applicabilityは拒否、
@@ -0,0 +1,98 @@
# repair7 作業状態
状態: blocked(実装未完了)。whole合格、登録validate成功、実測成功を意味しない。
提出547のGit objectと既存C実装は保持。今回の変更は未コミット。
engine・全回帰・checker試験・登録validate・Runner操作は未実行。
原15条件+EV、7領域、3安全性結果、30/88、部分点0を維持する。
## 実装した部分と未検証部分
checkerに名前付きtargetの照合を追加した。main_anchorは
9694f50ee63750192376ca69bc7dda3f884784c5、submittedは提出後に確定する実commit。
composed_treeはRoot例の904bbbを固定せず、毎回merge-treeから再計算する。
実行時の一時object directoryとcanonical objectsのread-only alternateを使い、
canonical refs/HEAD/indexへの書込み命令を使わない。この実装はまだ実行していない。
全tree entryと選択sourceを区別し、1338件のpath/bytes/SHA256をGit blobと
runner-input.source_beforeで両方向比較する。source選択規則はmain_anchorの
tools/run_all_tests.pyのSHAに固定。追加選択pathはcheckerのみ。
3139件の変更されていない既存metadataを明示分類し、追加・変更・削除pathは
登録scope内のみ許す。submitted差分もregisteredから独立にscope検査する。
ORDER_FUNCTIONS、REACH_REFS、applicability_deltaはcomposed_treeのbytesを読む。
candidate_treeは実候補のtree OIDとし、composed_treeの全entryとの一致を要求する。
checker metadataだけのcommit SHA差はengine再実行の理由にしない。
checker source bytesはsubmitted/composed/checker commitと別々に比較する。
自己blob一致は提出前なので**未実施**。Rootが提出後に検証する。
## 新しい入力形式(未試験)
既存indexの条件・authority・domain・rawを省略する形式ではない。
- `candidate_commit`: 実際にcheckerを実行するcheckoutのHEAD。
- `candidate_tree`: 実際に検証する候補tree。登録時にも指定し、比較を省略しない。
- `product_binding.product_target`: main_anchor/submitted/composed_treeの完全OID。
- `product_binding.tested_product`: 実測製品commit。製品manifestをGitから再計算する。
- `product_binding.runner_inputs`: 実runner-inputファイルのdescriptor配列。
descriptorはpath/bytes/sha256に加えてmaterialsとwrapperを持つ。
materialsはnative固定input/QAの原pathから供給済み実ファイルdescriptorへのmap。
原pathは由来のみで、そこからファイルを開かない。wrapperも実ファイルdescriptor。
Cの3 runのrunner-inputを全て含める。各selected_source_mapの差分は宣言済みQA
override 1件だけに限定する。
- `versions`: registered、execution_origin、checker、testedの4役割。
checkerはcommit/sha256。testedはproduct_target/manifest_sha256。
manifest digestはpath→{bytes,sha256}をsort_keys=True、separators=(',', ':')の
JSON UTF-8で符号化したSHA256。checkerのSHAは製品digestに代用しない。
- `native_bundle`: 従来のmanifestキーからpath/bytes/sha256 descriptorへ変更。
OWNERSHIP_RAW_PROVENANCE.jsonの実ファイルを指定する。
descriptorの相対pathはp04-evidence配下。絶対pathはbuild_dir/audit-support配下の
p04-whole-closure-r01、native-first-current、p04-current-native-series-r01の3系統のみ。
ファイルを追加コピーせずその場で読む。symlink・欠落・SHA/bytes不一致は失敗する。
## 残作業(Rootのnative実行へ進める状態ではない)
1. S1/S2/S3のprobeと、import/parse各1回→実測→正式Writer→別PID Readerを
結合するwrapperは未実装。既存templateを読んだだけで完成とは扱わない。
2. 全条件のactor/service/予約/帳簿/同minute/正式保存rawを結合するcollectorは
未実装。既存verify_nativeの有限3条件を全条件collectorに代用できない。
verified_conditionsの全条件への動的導出も未実装。
3. 新しいtarget側のconfig/input/environment実体照合は未完了。
現在は固定input/QA/wrapperと既存environment pin検査があり、これだけで
engine環境を全runnerの実起動に結合したとは主張しない。
4. 新入力形式へのfixture更新・Runner正式試験・提出後自己blob検査は未実施。
既存repair6の試験結果を今回の変更の合格として転記しない。
実装残作業を仕様不足として偽装しない。原本の未確定D05部分は従来どおりpending。
新しい金額、費用帰属、EV停止規則を追加して残作業を埋めない。
## B/Cの確定事項と実体確認
main969のautoload/simulation_runtime.gdのrepay_loan_principal本体と
tests/mvp/test_original_midnight_settlement.gdの返済テストをGit objectから読んだ。
公開返済APIとledger分類は存在する。自動返済・全UI完成は主張しない。
duty_paymentsはstaff_id/dayで勤務recordに結合できるpayroll settlement取引数で、
期待値1のまま。実コードではWAGE行のsource_entity_idがpayroll settlement_id、
settlement.rowsがstaff_id/payment、ShiftInstance snapshotがstaff_id/start_dayと
worked_minutes/overtime_minutesを保持する。給与行の数や勤務分数をそのまま
duty_paymentsに代入してはならない。day基準と勤務の実測差分も照合対象。
具体的に読んだ追加rawは
`p04-current-native-series-r01/p04-paid-shift-midnight-native-r01/order-evidence/midnight-midnight.json`
のstaff/payroll/economy部分と
`p04-current-native-series-r01/p04-paid-shift-midnight-formal-native-r01/runner-input.json`
のsource_beforeサンプル・fixed_input_pins。これを39raw読了・採用とはしない。
加えてnative-first-currentのactual-native、dependency-midnight-native、
dependency-formal-native各runner-input.jsonのキーとQA/QA_overridesを読んだ。
前2件にはfixed_input_pinsがなく、formalのみ保存入力のpinを持つ。
midnight_replayは実際の同minute決算API再呼出しまでpending。
paid資料の1442完了は1440売上境界を証明せず、request再送は決算API再呼出しを
証明しない。shift_completionはROOT_APPROVED_SHIFT_CURRENT_RESULTと
approved-shift-current-r01.gdの1080系列を結合する必要がある。
順序はworker実装完了→Root資源確認→S1→S2→S3→collector→登録validate→
独立whole review→prepare-integration/final。全case収集前のwhole合格はない。
S1準備に移行、A未検証。repair8はs1/の3ファイルによるコード準備のみ。未実測・原P04 whole未達。
@@ -0,0 +1,90 @@
# S1 Root run(コード準備のみ)
S1コード準備完了・未実測・原P04 whole未達。D05 pending、A未検証。
engine起動・全回帰・コミットはworkerでは実施しない。
assertは各caseの停止中の課金行0、予約の孤立0、到着1回だけ。
費用帰属、金額、EV停止規則を決めない。remaining_minutes保持は生観測として保存する。
## Rootが実行するコマンド
以下はSource checkout外のtask buildにplan/cache/rawを保存する。
Rootは先に空き容量・他のengine・終了済cacheへのアクセスを確認する。
既存出力は削除しない。再試行する場合はplan/outputの両方に新しいr番号を指定する。
```sh
export PYTHONPYCACHEPREFIX='/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/s1-python-cache'
python3 '/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/P04-01-implement/docs/plans/original-completion-2026-10-02/execution/p04-01/s1/run_s1_native.py' --check-only --plan '/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/p04-s1-root-plan-r01.json' --output '/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/p04-s1-native-r01'
python3 '/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/P04-01-implement/docs/plans/original-completion-2026-10-02/execution/p04-01/s1/run_s1_native.py' --plan '/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/p04-s1-root-plan-r01.json' --output '/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/p04-s1-native-r01'
```
既定の製品sourceは
`/Users/korizatou114/Projects/とりにく工房ゲーム制作部`。
workerのprobeだけを `tests/s3/test_runtime_staff_assignment.gd` にQA overrideする。
製品sourceの全選択ファイルをpinし、終了済cacheのselected mapとの完全一致を実runで要求する。
sourceの役割変更や不一致を自動承認しない。
既定cache:
`/Users/korizatou114/Projects/TheTree-managed-worktrees/p18-01-model/.runtime/P18-01-CODE/build/p18-relationship-evidence`。
workerからreceiptの読取りはOSに拒否された。check-onlyはその具体的path/errorを
cache_accessに記録し、engineやdefault playerには触らない。
Rootのcheck-onlyでは読める必要がある。実runではreceiptがpassedであること、
cacheの存在・全hash・cp -cの別inodeを必須とする。アクセス権やRoot境界は変更しない。
## 実行順序とexit
source_refs → QA override 1件 → private stage → bootstrap → cache cp -c/別inode →
import 1回 → parse 1回 → writer → 別PID reader →
finally owned_outer.finish_captured → fixed_guard。
normal watchdogは既存1200秒、importは既存180秒で変更しない。
実runのdefault-player保護は既存runnerを使う。
check-onlyの期待exitは0。engine起動0で入力SHAとplanを出力する。
cache_accessが非nullならRoot確認が未完でありnative開始条件を満たさない。
実runの期待exitは0(4phase成功、Writer/Reader別PID/profile、6安全性checksずつ、
14保存pointの正式復元、Writer保存物不変、owned cleanupとsource/default-player guard成功)。
strict phase失敗またはguard失敗は1、native開始前の入力・資源不備は2。
最初の失敗で停止し、自動再試行しない。exit0でも原P04 whole合格ではない。
## 出力とraw一覧
出力root:
`/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build/p04-s1-native-r01/`
- source_before.json、source_after.json、selected-source-map.json、runner-input.json
- runner-started.json、runner-ended.json、execution.json、PID-set.json、outer-owned-finally.json、raw-inventory.json
- stage/(別inodeの製品source+QA、.godot clone)、starters/、bootstrap/
- cache-reuse.json(全cache hashと終了済receipt pin)、parse-paths.json、contracts.json
- import/、parse/、writer/、reader/のstdout.log、stderr.log、engine-native.log、
strict runner生成のprocess/profile/start/end/capture証拠。全フォルダを保存する
- 各phaseの*-receipt.json、*-actual-phase.json、writer-combined-raw.log、reader-combined-raw.log
- raw/writer.json、raw/reader.json(PID/profile、正式slot path、checks/errors)
- raw/{writer,reader}-observations.{json,var}
- raw/{writer,reader}-{landing,no-safe-landing}-observations.{json,var}
- raw/{writer,reader}-{landing,no-safe-landing}-{before,boarded,depleted,stopped,held,landing,recovered}.{json,var}
- phase receiptが指すuser://saves/p04_s1/の全正式package。
WriterとReader各14slot、各slotのjournal.log、manifest.json、thumbnail.png、world.binを保持する。
private startup/runtime profileのlog/lock等も既存runner方式で保持し削除しない
JSONは閲覧用でVariant型を落とすため、必ずtyped .varと対で読む。
case観測はseed、実task.required_items、予約配列、ledger全行、trip/elevator report、
domain event、facility/service ID、全Runtime snapshot、コマンド結果を含む。
割当時のreserved_before_travelはイベント内の生観測で、正式保存pointとは区別する。
Readerは正式4-member packageを自身のprivate profileへ全コピーしてpublic load/restore後、
tickせず観測しWriter typed snapshotとの完全一致を確認する。
到着イベント履歴はWriter採取rawであることをReader側にも明示する。
no-safe-landingの残り時間保持とclosureによるrelease時点はrawで確認する。
給電復帰後も対象clinicは直接休業のままにして追加の搬送を防ぐ。
S2/S3、collector、A仕上げ、登録validate、独立whole review、統合は後続であり本提出の範囲外。
## worker静的確認の適用範囲
製品rootのtools/run_all_tests.pyもworkerから読取り拒否されたため、workerのcheck-onlyは
--project-rootにSource checkoutを明示した。選択sourceは1300件であり、Rootのcurrent製品1338件の検証を代行しない。
Rootは上記既定product_rootで独自のfresh planを作る。worker planを実runに転用しない。
停電と着床を別規則に分離しない。reserveをpublic commandで0にし、同じ更新境界の前に
対象clinicへ直接休業commandを送り、通常tickによる停電・予約解放・安全到着の実順序を記録する。
着床不能caseの予約は乗車中保持され得るため、releaseの時点を予測しない。
strict runnerの同一test名logはphaseごとにcombined-rawとして退避し、actual-phase/executionの
logを退避pathへ結合する。元strict receiptは変更せずstrict_runner_log_pathも残す。
@@ -0,0 +1,257 @@
extends SceneTree
# S1 only; setup follows test_rescue_elevator and transport:94-149.
const SEED := 712
const TASK := &"s1_rescue_with_tool"
var runtime: Variant
var clock: Variant
var state: Variant
var folder := ""
var mode := ""
var clinic_id: StringName
var checks := 0
var failures := 0
var errors: Array = []
var slots: Dictionary = {}
var observations: Dictionary = {}
var commands: Array = []
var arrivals: Array = []
var pretravel: Dictionary = {}
func _initialize() -> void: call_deferred("run")
# Exactly three safety assertions per case; operational failures are separate.
func outcome(ok: bool, label: String) -> void:
checks += 1
if not ok:
failures += 1
push_error(label)
func io(ok: bool, label: String) -> bool:
if not ok:
errors.append(label)
push_error(label)
return ok
func raw(label: String, value: Variant) -> void:
var file := FileAccess.open(folder.path_join(mode + "-" + label + ".var"), FileAccess.WRITE)
if io(file != null, "typed output " + label):
file.store_buffer(var_to_bytes(value)); file.flush(); file.close()
file = FileAccess.open(folder.path_join(mode + "-" + label + ".json"), FileAccess.WRITE)
if io(file != null, "JSON output " + label):
file.store_string(JSON.stringify(value, "\t")); file.flush(); file.close()
func read_json(path: String) -> Dictionary:
var file := FileAccess.open(path, FileAccess.READ)
if not io(file != null, "read " + path): return {}
var value: Variant = JSON.parse_string(file.get_as_text()); file.close()
if not io(value is Dictionary, "dictionary " + path): return {}
return value
func typed(path: String) -> Dictionary:
var file := FileAccess.open(path, FileAccess.READ)
if not io(file != null, "read typed " + path): return {}
var value: Variant = bytes_to_var(file.get_buffer(file.get_length())); file.close()
if not io(value is Dictionary, "typed dictionary " + path): return {}
return value
func cleanup() -> void:
if runtime != null: runtime.free()
if clock != null: clock.free()
if state != null: state.free()
runtime = null; clock = null; state = null
func reset() -> bool:
cleanup(); commands = []; arrivals = []; pretravel = {}; clinic_id = &""
clock = load("res://autoload/game_clock.gd").new()
state = load("res://autoload/game_state.gd").new()
runtime = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0); state.reset()
var initialized: Dictionary = runtime.initialize(clock, state, SEED)
clock.set_paused(true)
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
runtime.domain_events.subscribe(&"ELEVATOR_ARRIVED", &"s1.raw", on_arrival)
runtime.domain_events.subscribe(&"STAFF_TASK_ASSIGNED", &"s1.reservation", on_assignment)
return io(bool(initialized.get(&"valid", false)), "runtime initialization")
func on_assignment(event: SimulationDomainEvent) -> void:
if TASK in event.entity_ids and pretravel.is_empty():
pretravel = capture()
pretravel[&"staff_cell"] = runtime.staff_service.get_staff(&"medic").current_cell
func on_arrival(event: SimulationDomainEvent) -> void:
arrivals.append(event.to_dictionary())
func cmd(kind: StringName, payload: Dictionary) -> bool:
var result: CommandResult = runtime.submit_command(kind, payload, &"player")
commands.append(result.to_dictionary())
return io(result.is_success(), "public command " + String(kind))
func capture() -> Dictionary:
var reservations: Array = []
for reservation: InventoryReservation in runtime.inventory_service.get_reservations():
reservations.append(reservation.create_snapshot())
var ledger: Array = []
for entry: LedgerEntry in runtime.economy_service.get_entries(): ledger.append(entry.to_dictionary())
var events: Array = []
for event: SimulationDomainEvent in runtime.domain_events.recent_events(): events.append(event.to_dictionary())
var services: Array = []
for facility: FacilityInstance in runtime.facility_service.get_instances():
services.append({&"facility_id": facility.instance_id, &"active_service_ids": facility.active_services.keys()})
var task: StaffTask = runtime.staff_service.get_task(TASK)
return {&"seed": SEED, &"minute": clock.absolute_minute, &"snapshot": runtime.create_snapshot(),
&"ledger": ledger, &"reservations": reservations, &"task": task.create_snapshot() if task != null else {},
&"trip": runtime.elevators.get_actor_trip(&"staff:medic"),
&"elevator_report": runtime.elevators.get_report(), &"domain_events": events,
&"arrivals": arrivals.duplicate(true), &"commands": commands.duplicate(true),
&"service_ids": services, &"staff_invariants": runtime.staff_service.validate_invariants()}
func construct() -> bool:
if not reset(): return false
for spec: Array in [[&"infirmary", Vector3i(-6,0,1)], [&"service_elevator", Vector3i(0,0,1)]]:
if not cmd(&"build_facility", {&"definition_id": spec[0], &"origin": spec[1]}): return false
clock.advance_minutes(400)
for facility: FacilityInstance in runtime.facility_service.get_instances():
if facility.definition_id == &"infirmary": clinic_id = facility.instance_id
if not io(not clinic_id.is_empty(), "constructed clinic"): return false
for id: StringName in [&"patient", &"medic"]:
if not cmd(&"register_staff", {&"staff_id": id, &"role_id": &"medic", &"options": {
&"current_cell": Vector3i(0,1,1) if id == &"patient" else Vector3i(5,0,1),
&"health": 0 if id == &"patient" else 100, &"state": StaffRuntime.State.AVAILABLE,
&"role_tags": [&"medic"], &"permitted_task_tags": [&"rescue"]}}): return false
# Actual task.required_items uses the ordinary Runtime reservation callback.
if not cmd(&"add_inventory_stack", {&"owner_inventory_id": &"staff.supplies", &"item_id": &"tool/cleaning_kit", &"quantity": 1}): return false
return cmd(&"create_staff_task", {&"task_id": TASK, &"task_type": &"rescue_pickup", &"priority": 95, &"options": {
&"target_entity_id": &"patient", &"target_cell": Vector3i(0,1,1),
&"required_role_tags": [&"medic"], &"task_tags": [&"rescue"],
&"required_items": {&"tool/cleaning_kit": 1}, &"estimated_minutes": 30,
&"interrupt_level": 0, &"emergency": true}})
func save_point(label: String) -> void:
# The raw snapshot is observed immediately before the official save.
var point := capture()
raw(label, point)
var path := "user://saves/p04_s1/" + label
var saved := SaveService.save_snapshot(path, point[&"snapshot"])
if not io(bool(saved.get(&"ok", false)), "formal save " + label): return
var inspected := SaveService.inspect_snapshot(path)
io(bool(inspected.get(&"ok", false)) and bool(inspected.get(&"read_only", false)) and var_to_bytes(inspected.get(&"snapshot", {})) == var_to_bytes(point[&"snapshot"]), "formal inspect " + label)
slots[label] = ProjectSettings.globalize_path(path)
func safety(row: Dictionary) -> void:
var charge_rows: int = row[&"held_after"][&"ledger"].size() - row[&"reserve_exhausted_before_tick"][&"ledger"].size()
outcome(charge_rows == 0, "停止中の課金行0")
var orphans := 0
# Check each observed boundary, both directions, using actual task ownership.
for point_name: StringName in [&"boarded", &"stopped", &"held_after", &"final"]:
var point: Dictionary = row[point_name]
var tasks: Array = point[&"snapshot"][&"systems"][&"runtime"][&"staff"][&"tasks"]
var active: Dictionary = {}
for reservation: Dictionary in point[&"reservations"]:
if int(reservation[&"state"]) != InventoryReservation.State.ACTIVE: continue
if String(reservation[&"purpose"]) != "staff_task": continue
active[String(reservation[&"reservation_id"])] = reservation
var linked := false
for task: Dictionary in tasks:
if String(task[&"task_id"]) == String(reservation[&"requester_id"]) and String(reservation[&"reservation_id"]) in task[&"reservation_ids"]: linked = true
if not linked: orphans += 1
for task: Dictionary in tasks:
for id: Variant in task[&"reservation_ids"]:
if not active.has(String(id)): orphans += 1
outcome(orphans == 0, "予約の孤立0")
var counts := {&"staff:medic": 0, &"staff:patient": 0}
var stops: Array = row[&"boarded"][&"elevator_report"][&"shafts"][0][&"stops"]
var requests: Dictionary = {}
for trip: Dictionary in row[&"boarded"][&"elevator_report"][&"trips"]: requests[trip[&"actor_id"]] = trip[&"request_id"]
for event: Dictionary in row[&"final"][&"arrivals"]:
var payload: Dictionary = event["payload"]
var actor := StringName(payload.get(&"actor_id", &""))
if counts.has(actor) and payload.get(&"request_id") == requests.get(actor) and payload.get(&"cell") in stops: counts[actor] += 1
outcome(counts[&"staff:medic"] == 1 and counts[&"staff:patient"] == 1, "到着1回")
row[&"safety_raw"] = {&"stopped_ledger_delta": charge_rows, &"orphans": orphans, &"arrivals_by_actor": counts}
func writer_case(label: String, blocked: bool) -> void:
if not construct(): return
var row := {&"seed": SEED, &"case": label, &"before": capture()}
save_point(label + "-before")
var reserved := false
for tick: int in 130:
clock.advance_one_minute()
var task: StaffTask = runtime.staff_service.get_task(TASK)
if not reserved and not task.reservation_ids.is_empty():
row[&"reserved_before_travel"] = pretravel.duplicate(true); reserved = true
if task.task_type == &"rescue_transport" and runtime.elevators.get_actor_trip(&"staff:patient").get(&"state") == PathService.ELEVATOR_REQUEST_BOARDED: break
if not io(reserved and not pretravel.is_empty() and pretravel.get(&"staff_cell") == Vector3i(5,0,1) and not pretravel[&"task"][&"reservation_ids"].is_empty() and runtime.elevators.get_actor_trip(&"staff:patient").get(&"state") == PathService.ELEVATOR_REQUEST_BOARDED, "real reserved task reaches boarded pair"): return
row[&"boarded"] = capture(); save_point(label + "-boarded")
var stops: Array = runtime.elevators.get_report()[&"shafts"][0][&"stops"]
# Public fixture API reused literally from transport test, not a private mutation.
if blocked:
for cell: Vector3i in stops: runtime.path_service.configure_cell_traffic(cell, 4, 0, true)
var reserve: int = state.get_resource(&"mana")
if not cmd(&"change_resources", {&"deltas": {&"mana": -reserve}}): return
row[&"reserve_exhausted_before_tick"] = capture()
if not cmd(&"set_facility_conditions", {&"facility_id": clinic_id, &"conditions": {&"operator_open": false}}): return
clock.advance_one_minute(); row[&"depleted"] = capture(); save_point(label + "-depleted")
clock.advance_one_minute(); row[&"stopped"] = capture(); save_point(label + "-stopped")
clock.advance_minutes(20); row[&"held_after"] = capture(); save_point(label + "-held")
row[&"remaining_minutes_before"] = row[&"stopped"][&"elevator_report"][&"shafts"][0][&"remaining_minutes"]
row[&"remaining_minutes_after"] = row[&"held_after"][&"elevator_report"][&"shafts"][0][&"remaining_minutes"]
row[&"held_remaining_unchanged"] = row[&"remaining_minutes_before"] == row[&"remaining_minutes_after"]
if blocked:
for cell: Vector3i in stops: runtime.path_service.configure_cell_traffic(cell)
clock.advance_one_minute()
row[&"landing"] = capture(); save_point(label + "-landing")
if not cmd(&"change_resources", {&"deltas": {&"mana": reserve}}): return
clock.advance_minutes(45 if blocked else 1)
row[&"final"] = capture(); save_point(label + "-recovered")
row[&"reservation_release_raw"] = runtime.staff_service.get_task(TASK).create_snapshot()
safety(row); observations[label] = row; raw(label + "-observations", row)
func reader() -> void:
var receipt := read_json(folder.path_join("writer.json"))
if not io(int(receipt.get("pid", 0)) != OS.get_process_id() and String(receipt.get("profile", "")) != OS.get_user_data_dir(), "distinct Reader PID/profile"): return
for label: String in receipt["slots"]:
if not reset(): return
var original := String(receipt["slots"][label])
var target := ProjectSettings.globalize_path("user://saves/p04_s1/" + label)
if not io(DirAccess.make_dir_recursive_absolute(target) == OK, "reader package directory"): return
var directory := DirAccess.open(original)
if not io(directory != null, "writer package exists"): return
var members := directory.get_files(); members.sort()
if not io(directory.get_directories().is_empty() and members == PackedStringArray(["journal.log", "manifest.json", "thumbnail.png", "world.bin"]), "complete formal package"): return
for member: String in members:
if not io(DirAccess.copy_absolute(original.path_join(member), target.path_join(member)) == OK and FileAccess.get_sha256(original.path_join(member)) == FileAccess.get_sha256(target.path_join(member)), "exact formal member"): return
var loaded := SaveService.load_snapshot(target)
if not io(bool(loaded.get(&"ok", false)), "formal Reader load"): return
if not io(runtime.restore_snapshot(loaded[&"snapshot"]), "public Reader restore"): return
var expected := typed(folder.path_join("writer-" + label + ".var"))
if not io(expected.has(&"snapshot"), "writer point exists"): return
io(var_to_bytes(runtime.create_snapshot()) == var_to_bytes(expected[&"snapshot"]), "Reader exact typed snapshot")
var point := capture() # No tick after formal restore.
point[&"writer_observation"] = expected
observations[label] = point; slots[label] = target; raw(label, point)
for label: String in ["landing", "no-safe-landing"]:
var row := typed(folder.path_join("writer-" + label + "-observations.var"))
if not io(not row.is_empty(), "writer case exists"): return
for pair: Array in [[&"boarded", "boarded"], [&"stopped", "stopped"], [&"held_after", "held"], [&"final", "recovered"]]:
var point: Dictionary = observations[label + "-" + pair[1]]
for key: StringName in [&"snapshot", &"ledger", &"reservations"]: row[pair[0]][key] = point[key]
# Arrival history is Writer raw; Reader proves restored state separately.
safety(row); raw(label + "-observations", row)
func run() -> void:
folder = OS.get_environment("THE_TREE_S1_EVIDENCE"); mode = OS.get_environment("THE_TREE_S1_MODE")
if folder.is_empty() or mode not in ["writer", "reader"]: quit(2); return
if not io(DirAccess.make_dir_recursive_absolute(folder) == OK, "evidence directory"): quit(2); return
if mode == "writer":
writer_case("landing", false); writer_case("no-safe-landing", true)
else: reader()
raw("observations", observations)
var receipt := {&"pid": OS.get_process_id(), &"profile": OS.get_user_data_dir(), &"slots": slots,
&"checks": checks, &"failures": failures, &"operational_errors": errors,
&"whole_goal_accepted": false, &"unit_accepted": false}
var file := FileAccess.open(folder.path_join(mode + ".json"), FileAccess.WRITE)
if io(file != null, "phase receipt"):
file.store_string(JSON.stringify(receipt, "\t")); file.flush(); file.close()
cleanup()
print("S1 EV power: %d checks, %d failures" % [checks, failures])
quit(1 if failures or not errors.is_empty() or checks != 6 else 0)
@@ -0,0 +1,253 @@
#!/usr/bin/env python3
"""S1-only native entry. --check-only never loads ownership helpers or starts Godot."""
from pathlib import Path
import argparse
import hashlib
import importlib.util
import json
import os
import shutil
import subprocess
import sys
sys.dont_write_bytecode = True
HERE = Path(__file__).resolve().parent
BUILD = Path("/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build")
PRODUCT = Path("/Users/korizatou114/Projects/とりにく工房ゲーム制作部")
CACHE_RUN = Path("/Users/korizatou114/Projects/TheTree-managed-worktrees/p18-01-model/.runtime/P18-01-CODE/build/p18-relationship-evidence")
TEST = "tests/s3/test_runtime_staff_assignment.gd"
QA = HERE / "p04_s1_ev_power_probe.gd"
ENGINE = Path("/Applications/Godot.app/Contents/MacOS/Godot")
MATERIALS = [
BUILD / "audit-support/p04-whole-closure-r01/current-patterns/p04-idempotency-paid-formal-native-r01.py",
BUILD / "audit-support/p04-whole-closure-r01/current-patterns/idempotency-paid-formal-r01.gd",
BUILD / "audit-support/p04-whole-closure-r01/SOURCE_MANIFEST.json",
BUILD / "audit-support/p04-native-existing-sources/p04-01-power-formal-recovery-r04.gd",
BUILD / "audit-support/p04-native-existing-sources/p04-01-power-formal-recovery-native-r04.py",
BUILD / "audit-support/p04-native-existing-sources/SOURCE_MANIFEST.json",
BUILD / "audit-support/native-first-current/SOURCE_MANIFEST.json",
BUILD / "audit-support/native-first-current/actual-native/runner-input.json",
BUILD / "audit-support/p04-current-native-series-r01/SOURCE_MANIFEST.json",
BUILD / "audit-support/p04-current-native-series-r01/p04-idempotency-paid-formal-native-r01/runner-input.json",
]
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
value = importlib.util.module_from_spec(spec)
spec.loader.exec_module(value)
return value
def pin(path):
path = Path(path)
if path.is_symlink() or not path.is_file():
raise ValueError("missing exact input: " + str(path))
data = path.read_bytes()
return dict(path=str(path), bytes=len(data), sha256=hashlib.sha256(data).hexdigest())
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--project-root", type=Path, default=PRODUCT)
parser.add_argument("--output", type=Path, default=BUILD / "p04-s1-native-r01")
parser.add_argument("--plan", type=Path, default=BUILD / "p04-s1-plan-r01.json")
parser.add_argument("--cache-run", type=Path, default=CACHE_RUN)
parser.add_argument("--godot", type=Path, default=ENGINE)
parser.add_argument("--check-only", action="store_true")
args = parser.parse_args()
root = args.project_root.resolve()
out = args.output.resolve()
r = module("s1_standard_runner", root / "tools/run_all_tests.py")
# Preserve the reviewed source_refs -> exactly one QA override order.
source_before = r.source_refs(root)
refs = dict(source_before)
refs[TEST] = pin(QA)
expected = {n: dict(bytes=p["bytes"], sha256=p["sha256"]) for n, p in refs.items()}
fixed = [pin(p) for p in MATERIALS + [
QA, Path(__file__), HERE / "S1_ROOT_RUN.md",
root / "tests/transport/test_runtime_transport.gd",
root / "tests/staff/test_rescue_elevator.gd",
root / "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json",
]]
selected = dict(root_before=source_before, map={n: p["sha256"] for n, p in refs.items()}, timeout=1200)
cache_note = None
cache_receipts = []
for leaf in ["runner-ended.json", "runner-input.json"]:
path = args.cache_run / leaf
try:
cache_receipts.append(pin(path))
except OSError as caught:
cache_note = dict(path=str(path), error=type(caught).__name__ + ": " + str(caught),
required_before_native=True)
break
plan = dict(protocol="p04-s1-preparation-v1", project_root=str(root), output=str(out),
source_before=source_before, selected_source_map=selected["map"],
QA_overrides=[TEST], fixed_input_pins=fixed, cache_run=str(args.cache_run),
cache_receipts=cache_receipts, cache_access=cache_note,
phases=["import", "parse", "writer", "reader"],
native_engine_launches=0, whole_goal_accepted=False, unit_accepted=False)
# Check-only only reads source/materials and writes the plan in task build.
# It deliberately does not read default-player data, inspect processes or stat Godot.
if args.check_only:
args.plan.parent.mkdir(parents=True, exist_ok=True)
if args.plan.exists():
r.require(r.read(args.plan) == plan, "existing plan differs; use a fresh plan path")
else:
r.write(args.plan, plan)
print(json.dumps(dict(check_only=True, engines=0, source_files=len(source_before),
QA_overrides=[TEST], fixed_pins=len(fixed), plan=str(args.plan),
plan_sha256=r.sha(args.plan), cache_access=cache_note), ensure_ascii=False))
return 0
r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first")
def fixed_guard():
for value in fixed + cache_receipts:
r.require(pin(value["path"]) == value, "fixed input changed: " + value["path"])
fixed_guard()
# Native admission is Root-only and fails closed on unreadable cache.
r.require(cache_note is None, "Root must read exact cache receipts: " + str(cache_note))
old = args.cache_run
r.require(r.read(old / "runner-ended.json")["passed"], "ended cache run must have passed")
old_map = r.read(old / "runner-input.json")["selected_source_map"]
current_map = {n: p["sha256"] for n, p in source_before.items()}
r.require(old_map == current_map, "ended cache selected source must equal current product")
protected = r.default_player(root)
outer = module("s1_owned_outer", r.SUPPORT / "owned_outer.py")
r.require(not outer.native.helper["live_engines"](), "another Godot owns CPU")
engine = args.godot.resolve()
r.require(engine.is_file(), "Root native Godot path")
r.require(shutil.disk_usage(out.parent).free >= 1024**3 + engine.stat().st_size + 136*1024**2,
"reviewed native disk admission")
r.require(not out.exists(), "fresh output required; preserve previous attempts")
out.mkdir()
stage = out / "stage"
stage.mkdir()
(out / "starters").mkdir()
(out / "bootstrap").mkdir()
phases = []
previous = {}
error = None
guards = []
cleanup = []
cleanup_errors = []
cache_before = None
formal_before = None
formal_after = None
original_phase = outer.run_phase
def run_phase(argv, folder, timeout, env, **kwargs):
env = dict(env)
if folder.name in ["writer", "reader"]:
env.update(THE_TREE_S1_EVIDENCE=str(out / "raw"), THE_TREE_S1_MODE=folder.name)
return original_phase(argv, folder, timeout, env, **kwargs)
outer.run_phase = run_phase
r.write(out / "runner-started.json", dict(started=r.now(), owner_runner_pid=os.getpid(),
plan=pin(args.plan), engines_launched=0))
try:
r.write(out / "source_before.json", source_before)
r.write(out / "selected-source-map.json", refs)
# Private source stage first, then literal reviewed bootstrap.
for name, value in refs.items():
target = stage / name
target.parent.mkdir(parents=True, exist_ok=True)
r.copy_source(Path(value["path"]), target)
r.require(r.inventory(stage, stage=True) == expected, "whole private source")
for name, value in r.read(r.SUPPORT / "bootstrap-scripts.json").items():
data = value["text"].encode()
r.require(hashlib.sha256(data).hexdigest() == value["sha256"], "bootstrap pin")
(out / "bootstrap" / name).write_bytes(data)
cache = old / "stage/.godot"
cache_before = r.inventory(cache)
r.require(bool(cache_before), "nonempty ended cache")
for name in cache_before:
src = cache / name
dst = stage / ".godot" / name
dst.parent.mkdir(parents=True, exist_ok=True)
subprocess.run(["/bin/cp", "-c", str(src), str(dst)], check=True)
r.require((src.stat().st_dev, src.stat().st_ino) != (dst.stat().st_dev, dst.stat().st_ino),
"cache clone is a separate inode")
r.require(r.inventory(stage / ".godot") == cache_before, "whole cache clone hashes")
r.write(out / "cache-reuse.json", dict(ended_run=str(old), receipts=cache_receipts,
whole_cache=cache_before, independent_inode=True,
ordinary_import_required=True, ordinary_parse_required=True))
paths = ["res://" + n for n in sorted(refs) if n.endswith(".gd")]
r.write(out / "parse-paths.json", paths)
markers = module("s1_markers", root / "tools/strict_test_markers.py")
contracts = markers.load_contracts(root / "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json")
contracts[TEST] = dict(test=TEST, template="S1 EV power: <checks> checks, <failures> failures", required=True)
policy = r.read(r.SUPPORT / "suite-policy.json")
r.require(TEST not in policy["suite_policies"], "no normal suite watchdog/policy override")
r.write(out / "contracts.json", contracts)
r.write(out / "runner-input.json", dict(plan, owner_runner_pid=os.getpid(),
wrapper_sha256=r.sha(__file__), QA=pin(QA), runner_sha256=r.sha(root / "tools/run_all_tests.py"),
default_player_before=protected, fixed_input_pins=fixed,
functional_watchdog_seconds=1200, source_adoption=False))
diagnostics = module("s1_diagnostics", r.SUPPORT / "diagnostic_gate.py")
owners = module("s1_owners", r.SUPPORT / "ordinary_proof_gate.py")
audio = module("s1_audio", r.SUPPORT / "audio_evidence_gate.py")
public = (stage / "project.godot").read_bytes()
for phase, test in [("import", None), ("parse", None), ("writer", TEST), ("reader", TEST)]:
if phase == "reader":
writer = r.read(out / "raw/writer.json")
formal_before = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(len(formal_before) == 14, "all fourteen formal writer points")
row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected,
previous, policy, contracts, paths, public, protected, root,
outer, markers, diagnostics, owners, audio)
phases.append(row)
# execute_phase uses the same test log name; retain each phase's exact log too.
if test and row.get("log"):
(out / (phase + "-combined-raw.log")).write_bytes((out / row["log"]).read_bytes())
row["strict_runner_log_path"] = row["log"]
row["log"] = phase + "-combined-raw.log"
r.write(out / (phase + "-actual-phase.json"), row)
print(json.dumps(dict(phase=phase, passed=row["passed"], error=row.get("validation_error"))), flush=True)
r.require(row["passed"], "first strict phase failure: " + phase)
if phase in ["writer", "reader"]:
receipt = r.read(out / ("raw/" + phase + ".json"))
r.require(receipt["checks"] == 6 and receipt["failures"] == 0 and not receipt["operational_errors"],
"exact S1 outcome/operational receipt")
r.require(receipt["pid"] == row["actual_pid"], "actual native PID/receipt")
writer = r.read(out / "raw/writer.json")
reader = r.read(out / "raw/reader.json")
r.require(writer["pid"] != reader["pid"] and writer["profile"] != reader["profile"], "distinct formal processes")
formal_after = {n: r.inventory(Path(p)) for n, p in writer["slots"].items()}
r.require(formal_before == formal_after, "Reader leaves Writer packages unchanged")
except BaseException as caught:
error = type(caught).__name__ + ": " + str(caught)
finally:
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
try:
r.write(out / "outer-owned-finally.json", dict(cleanup=cleanup, errors=cleanup_errors))
except BaseException as caught:
guards.append("finally receipt: " + type(caught).__name__ + ": " + str(caught))
# Fixed guard always follows ownership cleanup, even if setup or an engine failed.
try:
fixed_guard()
after = r.source_refs(root)
r.write(out / "source_after.json", after)
r.require(after == source_before, "whole product source unchanged")
r.require(r.default_player(root) == protected, "default player unchanged")
if (stage / "project.godot").exists():
r.require(r.inventory(stage, stage=True) == dict(expected, **previous), "whole private source unchanged")
if cache_before is not None:
r.require(r.inventory(old / "stage/.godot") == cache_before, "original cache unchanged")
except BaseException as caught:
guards.append(type(caught).__name__ + ": " + str(caught))
pids = [p.pid for p in outer.OWNED]
passed = (error is None and not guards and not cleanup_errors and len(phases) == 4
and all(p["passed"] for p in phases) and len(pids) == len(set(pids)) == 4
and all(p["engine_ended"] for p in cleanup))
execution = dict(passed=passed, error=error, guard_errors=guards, phases=phases,
actual_captured_PIDs=pids, cleanup=cleanup, cleanup_errors=cleanup_errors,
formal_before=formal_before, formal_after=formal_after,
whole_goal_accepted=False, unit_accepted=False)
r.write(out / "raw-inventory.json", r.inventory(out / "raw"))
r.write(out / "PID-set.json", dict(owner_runner_pid=os.getpid(), engine_PIDs=pids))
r.write(out / "execution.json", execution)
r.write(out / "runner-ended.json", dict(execution, ended=r.now()))
print(json.dumps(dict(passed=passed, error=error, guard_errors=guards, output=str(out))))
return 0 if passed else 1
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as caught:
print(type(caught).__name__ + ": " + str(caught), file=sys.stderr)
raise SystemExit(2)