Record P08 final native and normal OS migration evidence
This commit is contained in:
+4
@@ -1,3 +1,7 @@
|
||||
## 現在の優先対象(2026-10-13 更新)
|
||||
|
||||
現在はP08-02。候補d1c7ce27のnative全8実行と通常OS4操作の証拠取得済み。最終全174スイート回帰→登録検証→独立Opus→統合後確認の順に1件を閉じる。原30パッケージ/88成果単位・部分点なしを保持し、正式完了件数は増やさない。個別修正/累積推論回数と固定レビュー資料容量の旧上限はユーザー指示で撤廃済み。以下は過去の実行順序の履歴で、現在の停止条件ではない。
|
||||
|
||||
## 現在のRunner実行(2026-10-12)
|
||||
|
||||
ユーザーがmain更新を明示許可し、現成果と原契約入力をmainへ反映済み。元の1成果単位P06-01を範囲とするRunner登録、3CLIの制限下認証確認、Claudeのrun判断、Codex1担当の監査起動まで進んだ。現在の次対象はP06-01。P22-03は必要数量/見積未確定、P23-02の追加性能修正は保留。正式9/着手21/予定58、全体30/88・部分点なし。Runnerの0/1はこの1件だけの運用表示で、全ゲーム分母ではない。証拠検証器は未実装/未実行で未受入。以下の未登録/main接続未解決/P22優先の記述は変更前履歴として保持する。
|
||||
|
||||
+10
-2
@@ -1,8 +1,16 @@
|
||||
{
|
||||
"candidate": "d1c7ce27d21a77be87081e12d20e7c8dd6ffa353",
|
||||
"original_unit_completed": false,
|
||||
"next": "final native with first-writer semantic preflight, normal OS, final regression, independent Opus, integration",
|
||||
"next": "finish same full regression, bind registered evidence, validate, independent Opus, integration",
|
||||
"fixed_material_limit": null,
|
||||
"file_count_limit": null,
|
||||
"original_30_88_unchanged": true
|
||||
"original_30_88_unchanged": true,
|
||||
"native_final": "all8 PASS exact candidate",
|
||||
"normal_os": "preview,cancel,confirm,changed-source refusal recorded with preservation guards",
|
||||
"full_regression": {
|
||||
"state": "running",
|
||||
"session": 61113,
|
||||
"suites": 174,
|
||||
"directory": "artifacts/original-completion-2026-10-02/p08-02-final-full174-native-r01"
|
||||
}
|
||||
}
|
||||
|
||||
+20997
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"candidate": "d1c7ce27d21a77be87081e12d20e7c8dd6ffa353",
|
||||
"successful_native_os_run": "p08-02-native-os-r02",
|
||||
"input_pid": 20912,
|
||||
"ordinary_exit": 0,
|
||||
"candidate_source_guard": true,
|
||||
"stage_source_restored": true,
|
||||
"default_player_guard": true,
|
||||
"cleanup_errors": [],
|
||||
"failed_observer_run_retained": "p08-02-native-os-r01; not acceptance",
|
||||
"failed_reason": "QA recorder queried missing world_preview.modal_input_blocked property; repaired observer only",
|
||||
"six_original_facets": [
|
||||
"mixed_construction",
|
||||
"occupancy_change",
|
||||
"actual_actor_positions",
|
||||
"combined_rescue_logistics_ev",
|
||||
"no_overlap_orphan_loss",
|
||||
"unsolvable_preservation"
|
||||
],
|
||||
"remaining": [
|
||||
"full174 final regression completion",
|
||||
"registered verifier",
|
||||
"independent Opus game acceptance review",
|
||||
"integration and post-integration verification"
|
||||
],
|
||||
"formal_completion": false,
|
||||
"denominator": {
|
||||
"packages": 30,
|
||||
"units": 88,
|
||||
"completed": 10,
|
||||
"in_progress": 25,
|
||||
"planned": 53
|
||||
},
|
||||
"next_candidate_unit": "P08-03 pending P08-02 closure and actual Opus sequencing decision",
|
||||
"evidence_sha256": {
|
||||
"artifacts/original-completion-2026-10-02/p08-02-native-os-r02/proof.json": "274b1f2d63bb1146a9e597f87184a751873825c51b0da82c571c404802748dd4",
|
||||
"artifacts/original-completion-2026-10-02/p08-02-native-os-r02/ended.json": "d13b7b1ad230b51dae9bcba93cee1c8b3f27c9b92125dd87f9c6dffd56f39825",
|
||||
"artifacts/original-completion-2026-10-02/p08-02-native-os-r02/events.jsonl": "f6738a046770e96a76d00daf7f9fcf7631539151802d98ba9ea1d8ca4e1827a8"
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"commit": "d1c7ce27d21a77be87081e12d20e7c8dd6ffa353",
|
||||
"deficits": [
|
||||
"final regression: unsafe artifact path"
|
||||
],
|
||||
"original_unit_accepted": false
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+42
@@ -0,0 +1,42 @@
|
||||
import os,sys,uuid,json,hashlib,importlib.util,subprocess,time
|
||||
from pathlib import Path
|
||||
sys.dont_write_bytecode=True
|
||||
R=Path('/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-02/P08-02-implement')
|
||||
A=Path('/Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02')
|
||||
OUT=A/'p08-02-native-os-r02';stage=A/'p08-02-native-mixed-r06/stage'
|
||||
s=importlib.util.spec_from_file_location('p08_os_runner',R/'tools/run_all_tests.py');r=importlib.util.module_from_spec(s);s.loader.exec_module(r)
|
||||
outer=r.module('p08_os_owned',R/'tools/regression/owned_outer.py');r.require(not outer.native.helper['live_engines'](),'external engine present')
|
||||
r.require(r.read(stage.parent/'runner-ended.json')['error'] is None,'native final collection completed')
|
||||
r.require(subprocess.check_output(['git','rev-parse','HEAD'],cwd=R,text=True).strip()=='d1c7ce27d21a77be87081e12d20e7c8dd6ffa353','exact immutable candidate')
|
||||
r.require(not subprocess.check_output(['git','status','--porcelain'],cwd=R,text=True),'candidate clean')
|
||||
refs=r.source_refs(R);before=r.inventory(stage,stage=True);protected=r.default_player(R);public=(stage/'project.godot').read_bytes()
|
||||
for n,pin in refs.items():r.require(r.sha(stage/n)==pin['sha256'],'tested stage source exact '+n)
|
||||
nonce=uuid.uuid4().hex;profile_name='TheTree-PCK-tests-'+nonce+'-p08-os';profile=r.profile_path(profile_name);r.require(not profile.exists(),'fresh private profile');profile.mkdir()
|
||||
OUT.mkdir(exist_ok=False);__import__('shutil').copy2(Path(__file__).with_name('passive_os_migration_recorder.gd'),OUT/'passive_os.gd')
|
||||
formal=profile/'saves/manual_ui';formal.mkdir(parents=True)
|
||||
for source in (stage.parent/'pairs/off-positive/original/formal').iterdir():
|
||||
if source.is_file():
|
||||
__import__('shutil').copy2(source,formal/source.name);r.require(r.sha(source)==r.sha(formal/source.name),'formal fixture copy SHA')
|
||||
r.require(__import__('shutil').disk_usage(OUT).free>=500*1024*1024,'disk admission')
|
||||
base={'candidate':'d1c7ce27d21a77be87081e12d20e7c8dd6ffa353','source_map':{n:v['sha256'] for n,v in refs.items()},'stage':str(stage),'profile':str(profile),'owner_pid':os.getpid(),'default_before':protected,'source_before':refs,'formal_acceptance':False,'no_injected_gameplay_or_input':True,'controller_sha256':r.sha(Path(__file__)),'recorder_sha256':r.sha(OUT/'passive_os.gd')}
|
||||
r.write(OUT/'started.json',base);error=None;children=[];rows=[]
|
||||
try:
|
||||
(stage/'project.godot').write_bytes(r.private_project(public,profile_name));env=r.fresh_environment(dict(os.environ));env['P08_OS_OUTPUT']=str(OUT)
|
||||
argv=['/Applications/Godot.app/Contents/MacOS/Godot','--path',str(stage),'--script',str(OUT/'passive_os.gd')]
|
||||
with (OUT/'engine-native.log').open('w') as log:
|
||||
p=subprocess.Popen(argv,cwd=stage,env=env,stdout=log,stderr=subprocess.STDOUT);children.append(p)
|
||||
r.write(OUT/'process-started.json',dict(base,actual_pid=p.pid,command=argv,monotonic_ns=time.monotonic_ns()))
|
||||
print(json.dumps({'actual_pid':p.pid,'profile':str(profile),'events':str(OUT/'events.jsonl')}),flush=True)
|
||||
p.wait(timeout=900)
|
||||
r.require(p.returncode==0,'ordinary native exit0');raw=(OUT/'engine-native.log').read_text();r.require('ERROR:' not in raw and 'SCRIPT ERROR:' not in raw,'native diagnostics failed')
|
||||
rows.append({'actual_pid':p.pid,'exit_code':p.returncode,'engine_ended':True,'log_sha256':r.sha(OUT/'engine-native.log')})
|
||||
except BaseException as e:error=type(e).__name__+': '+str(e)
|
||||
finally:
|
||||
cleanup,cleanup_errors=outer.finish_captured(children);(stage/'project.godot').write_bytes(public)
|
||||
guards=[]
|
||||
try:
|
||||
r.require(r.source_refs(R)==refs,'candidate whole source unchanged');r.require(r.inventory(stage,stage=True)==before,'whole stage source unchanged');r.require(r.default_player(R)==protected,'default player unchanged')
|
||||
except BaseException as e:guards.append(type(e).__name__+': '+str(e))
|
||||
r.write(OUT/'ended.json',dict(base,rows=rows,error=error,guard_errors=guards,cleanup_errors=cleanup_errors,owned_cleanup=cleanup,passed=not(error or guards or cleanup_errors) and len(rows)==1,formal_acceptance=False))
|
||||
print(json.dumps({'ended':True,'error':error,'guards':guards,'rows':rows}),flush=True)
|
||||
sys.exit(1 if error or guards or cleanup_errors else 0)
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
extends SceneTree
|
||||
var main: Control
|
||||
var observer: Node
|
||||
func _initialize() -> void:
|
||||
call_deferred("_start")
|
||||
func _start() -> void:
|
||||
var scene: PackedScene = load("res://scenes/main/main.tscn")
|
||||
main = scene.instantiate()
|
||||
root.add_child(main)
|
||||
observer = PassiveRecorder.new()
|
||||
observer.main = main
|
||||
observer.out_dir = OS.get_environment("P08_OS_OUTPUT")
|
||||
root.add_child(observer)
|
||||
root.title = "The Tree P08-02 OS candidate d1c7ce2"
|
||||
|
||||
class PassiveRecorder extends Node:
|
||||
var main: Control
|
||||
var out_dir: String
|
||||
var log: FileAccess
|
||||
var previous: Dictionary = {}
|
||||
var elapsed := 0.0
|
||||
var rows := 0
|
||||
var runtime: Node
|
||||
var snapshot_count := 0
|
||||
var ui_count := 0
|
||||
var frame_count := 0
|
||||
var last_request := ""
|
||||
var latest_restore_snapshot: Dictionary = {}
|
||||
func _ready() -> void:
|
||||
log = FileAccess.open(out_dir.path_join("events.jsonl"), FileAccess.WRITE)
|
||||
runtime = main.get_node("/root/SimulationRuntime")
|
||||
var menu: MenuButton = main.find_child("SaveLoadMenu", true, false)
|
||||
menu.get_popup().id_pressed.connect(_on_menu_item)
|
||||
runtime.snapshot_published.connect(_on_snapshot_published)
|
||||
runtime.save_operation_completed.connect(_on_save_completed)
|
||||
_capture_ui.call_deferred("started_before_os")
|
||||
emit_record("started", {"pid": OS.get_process_id(), "platform": OS.get_name(), "candidate": "d1c7ce27d21a77be87081e12d20e7c8dd6ffa353", "source": "passive_root_normal_menu_observation_not_whole_acceptance"})
|
||||
func _on_menu_item(id: int) -> void:
|
||||
emit_record("actual_menu_item", {"id": id, "source": "production PopupMenu id_pressed; native input only"})
|
||||
_capture_ui("menu_%d" % id)
|
||||
func _capture_ui(reason: String) -> void:
|
||||
var snapshot: Dictionary = runtime.create_snapshot()
|
||||
var data := var_to_bytes(snapshot)
|
||||
var name := "ui-snapshot-%03d.bin" % ui_count
|
||||
var file := FileAccess.open(out_dir.path_join(name), FileAccess.WRITE)
|
||||
file.store_buffer(data)
|
||||
file.close()
|
||||
var json_name := "ui-snapshot-%03d.json" % ui_count
|
||||
var json_file := FileAccess.open(out_dir.path_join(json_name), FileAccess.WRITE)
|
||||
json_file.store_string(JSON.stringify(snapshot))
|
||||
json_file.close()
|
||||
var view: Node = main.get("world_preview")
|
||||
var definition: Variant = view.get("build_definition")
|
||||
var formal_name := "formal-%03d.json" % ui_count
|
||||
var formal := {}
|
||||
var base_path := ProjectSettings.globalize_path(String(main.get("manual_save_path")))
|
||||
for suffix: String in ["", SaveService.MIGRATION_BACKUP_SUFFIX]:
|
||||
for member: String in [SaveService.WORLD_FILE, SaveService.MANIFEST_FILE, SaveService.THUMBNAIL_FILE, SaveService.JOURNAL_FILE]:
|
||||
var path := (base_path + suffix).path_join(member)
|
||||
formal[suffix+"/"+member] = {"exists": FileAccess.file_exists(path), "sha256": FileAccess.get_sha256(path) if FileAccess.file_exists(path) else "", "bytes": FileAccess.get_file_as_bytes(path).size() if FileAccess.file_exists(path) else 0}
|
||||
var formal_file := FileAccess.open(out_dir.path_join(formal_name), FileAccess.WRITE)
|
||||
formal_file.store_string(JSON.stringify(formal)); formal_file.close()
|
||||
emit_record("ui_model_capture", {"formal_filename": formal_name, "reason": reason, "filename": name, "sha256": _sha(data), "json_filename": json_name, "json_sha256": _sha(FileAccess.get_file_as_bytes(out_dir.path_join(json_name))), "status_text": str(main.get("build_status_label").text), "build_definition_id": str(definition.id) if definition != null else "", "palette_open": bool(main.get("_build_palette_open")), "modal_blocked": (main.get("dimension_migration_dialog") != null and main.get("dimension_migration_dialog").visible), "save_path": str(main.get("manual_save_path"))})
|
||||
ui_count += 1
|
||||
_capture_frame.call_deferred(reason)
|
||||
func _capture_frame(reason: String) -> void:
|
||||
await RenderingServer.frame_post_draw
|
||||
var dialog: Window = main.get("dimension_migration_dialog")
|
||||
var target: Viewport = dialog if dialog != null and dialog.visible else get_tree().root
|
||||
var img := target.get_texture().get_image()
|
||||
if img == null or img.is_empty():
|
||||
emit_record("frame_capture_failed", {"reason": reason})
|
||||
return
|
||||
var name := "frame-%03d.png" % frame_count
|
||||
var error := img.save_png(out_dir.path_join(name))
|
||||
emit_record("frame_capture", {"reason": reason, "filename": name, "error": error, "sha256": _sha(FileAccess.get_file_as_bytes(out_dir.path_join(name))) if error == OK else "", "size": [img.get_width(), img.get_height()], "target": "dialog" if target == dialog else "root"})
|
||||
frame_count += 1
|
||||
func _sha(data: PackedByteArray) -> String:
|
||||
var context := HashingContext.new()
|
||||
context.start(HashingContext.HASH_SHA256)
|
||||
context.update(data)
|
||||
return context.finish().hex_encode()
|
||||
func _on_snapshot_published(_view: Dictionary, _digest: String) -> void:
|
||||
latest_restore_snapshot = runtime.create_snapshot()
|
||||
var data := var_to_bytes(latest_restore_snapshot)
|
||||
var filename := "snapshot-%03d.bin" % snapshot_count
|
||||
var file := FileAccess.open(out_dir.path_join(filename), FileAccess.WRITE)
|
||||
file.store_buffer(data)
|
||||
file.close()
|
||||
emit_record("snapshot_published_capture", {"filename": filename, "sha256": _sha(data), "absolute_minute": latest_restore_snapshot[&"clock"][&"absolute_minute"], "observer_reads_only": true})
|
||||
snapshot_count += 1
|
||||
func _on_save_completed(result: Dictionary) -> void:
|
||||
var path: String = str(result.get(&"save_path", ""))
|
||||
var operation: String = str(result.get(&"operation", ""))
|
||||
var receipt := {"path": path, "operation": operation, "ok": bool(result.get(&"ok", false)), "code": str(result.get(&"code", "")), "observer_reads_only": true}
|
||||
if bool(result.get(&"ok", false)) and operation in ["load", "recovery", "recovery_candidate"]:
|
||||
var disk := SaveService.inspect_snapshot(path)
|
||||
var stored: Dictionary = disk.get(&"snapshot", {})
|
||||
var observed := var_to_bytes(latest_restore_snapshot)
|
||||
var expected := var_to_bytes(stored)
|
||||
receipt["disk_read_only_ok"] = bool(disk.get(&"ok", false))
|
||||
receipt["latest_published_full_snapshot_semantic_equal"] = latest_restore_snapshot == stored
|
||||
receipt["observed_full_snapshot_sha256"] = _sha(observed)
|
||||
receipt["stored_full_snapshot_sha256"] = _sha(expected)
|
||||
receipt["snapshot_index"] = snapshot_count - 1
|
||||
var file := FileAccess.open(out_dir.path_join("loaded-stored-snapshot.bin"), FileAccess.WRITE)
|
||||
file.store_buffer(expected)
|
||||
file.close()
|
||||
receipt["restore_safety_report"] = result.get(&"restore_safety_report", {})
|
||||
emit_record("save_operation_completed", receipt)
|
||||
func emit_record(kind: String, value: Dictionary) -> void:
|
||||
if log == null:
|
||||
return
|
||||
var record := {"kind": kind, "pid": OS.get_process_id(), "ticks_msec": Time.get_ticks_msec(), "value": value}
|
||||
log.store_line(JSON.stringify(record))
|
||||
log.flush()
|
||||
rows += 1
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventKey:
|
||||
emit_record("key", {"keycode": event.keycode, "physical_keycode": event.physical_keycode, "unicode": event.unicode, "pressed": event.pressed, "echo": event.echo, "shift": event.shift_pressed, "ctrl": event.ctrl_pressed, "alt": event.alt_pressed, "meta": event.meta_pressed})
|
||||
elif event is InputEventMouseButton:
|
||||
if event.pressed:
|
||||
_capture_ui.call_deferred("native_mouse_after_dispatch")
|
||||
emit_record("mouse_button", {"button": event.button_index, "pressed": event.pressed, "position": [event.position.x, event.position.y]})
|
||||
func _process(delta: float) -> void:
|
||||
elapsed += delta
|
||||
if elapsed < 0.1:
|
||||
return
|
||||
elapsed = 0.0
|
||||
var request_path := out_dir.path_join("capture-request.json")
|
||||
if FileAccess.file_exists(request_path):
|
||||
var request: Variant = JSON.parse_string(FileAccess.get_file_as_string(request_path))
|
||||
if request is Dictionary and str(request.get("id","")) != last_request:
|
||||
last_request = str(request.get("id",""))
|
||||
_capture_ui("requested_"+last_request)
|
||||
var dialog: Variant = main.get("dimension_migration_dialog")
|
||||
var label: Variant = null
|
||||
var focus: Control = get_viewport().gui_get_focus_owner()
|
||||
var window: Window = get_tree().root
|
||||
var state := {"ime_text": DisplayServer.ime_get_text(), "ime_selection": [DisplayServer.ime_get_selection().x, DisplayServer.ime_get_selection().y], "label_text": String(label.text) if label != null else "", "label_rect": [label.get_global_rect().position.x, label.get_global_rect().position.y, label.size.x, label.size.y] if label != null else [], "label_focused": label.has_focus() if label != null else false, "dialog_visible": dialog.visible if dialog != null else false, "window_size": [window.size.x, window.size.y], "window_position": [window.position.x, window.position.y], "content_scale_factor": window.content_scale_factor, "screen_scale": DisplayServer.screen_get_scale(window.current_screen), "focus_name": String(focus.name) if focus != null else "", "save_path": String(main.get("manual_save_path")), "modal_input_blocked": (main.get("dimension_migration_dialog") != null and main.get("dimension_migration_dialog").visible)}
|
||||
if state != previous:
|
||||
emit_record("state", state)
|
||||
if state.get("dialog_visible") != previous.get("dialog_visible"):
|
||||
_capture_ui("dialog_visibility_%s" % str(state.get("dialog_visible")))
|
||||
previous = state.duplicate(true)
|
||||
func _exit_tree() -> void:
|
||||
if log != null:
|
||||
emit_record("observer_exit", {"rows": rows})
|
||||
log.close()
|
||||
Reference in New Issue
Block a user