From fd643f55a271e63c554b94681454d357117c0678 Mon Sep 17 00:00:00 2001 From: Agent Control Runner Date: Wed, 14 Oct 2026 20:45:46 +0900 Subject: [PATCH] =?UTF-8?q?P08-03:=20=E9=85=8D=E7=BD=AE=E3=81=AE=E9=80=9A?= =?UTF-8?q?=E5=B8=B8=E6=93=8D=E4=BD=9C=E5=8F=97=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../completion_marker_contracts.json | 11 ++++ .../execution/p08-03/CONDITION_MATRIX.md | 24 ++++++++ .../execution/p08-03/implementation.json | 58 ++++++++++++++++++- scenes/main/main.gd | 14 ++++- scenes/main/world_preview.gd | 6 ++ tests/fixtures/p08-03/checker_fixture.py | 2 +- tests/fixtures/p08-03/placement.gd | 1 + tools/check_p08_normal_placement_evidence.py | 10 ++-- tools/test_p08_normal_placement_evidence.py | 21 ++++++- 9 files changed, 138 insertions(+), 9 deletions(-) diff --git a/docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json b/docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json index 3f1e39b..6539ba6 100644 --- a/docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json +++ b/docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json @@ -3690,6 +3690,17 @@ "path": "docs/spec/acceptance/P08-03.json", "scope": "normal placement; native and OS pending" } + }, + { + "test": "tests/transport/test_runtime_build_preview.gd", + "template": "Runtime build preview: checks, failures", + "required": true, + "fixed_check_count_used": false, + "source_sha256_at_schema_audit": "c881b60bce7276047884303a6823da9abfaaf8c1e85dbc5f2c0ff13f0d742449", + "authority": { + "path": "docs/spec/acceptance/P08-03.json", + "scope": "normal placement; native and OS pending" + } } ], "unknown_roster_suite_policy": "refuse, explicitly review its source/schema before accepting", diff --git a/docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md b/docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md index 62e00f8..a2cd7ee 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md +++ b/docs/plans/original-completion-2026-10-02/execution/p08-03/CONDITION_MATRIX.md @@ -500,3 +500,27 @@ A docs/plans/original-completion-2026-10-02/execution/p08-03/runtime-preview-pro A docs/plans/original-completion-2026-10-02/execution/p08-03/runtime-preview-proposal/runtime_preview.patch ``` Exact validation commands and initial/retry results are recorded in implementation.json repair17.validation. No Godot/native/full execution or recollection was performed. + +## Repair18 — submitted, no acceptance + +7297a4c050f0293df331c2c51bb32def248bcb6b + +['4775001', '127f22f'] + +dbf5cb8 / native source 12f04d6; target/stairs/construction/pointer passes; 8 unchanged state pairs; Opus pass; final-validation pass (historical support trace, no current applicability claimed) + +Every path in diff(M..worktree) must be inside allowed_paths; every path outside allowed_paths must equal its blob at 127f22f. Inherited Runtime is read-only. + +runtime_preview.patch was superseded by the integrated helper and was not applied; retained as history. + +to be bound by Runner + +(1) pending Root native/OS; (2)-(5) remain pending + +not claimed + +['Root freeze then normal OS and native recollection including changed preview and demolition UI', 'exactly one final all-suite regression on roster derived by Root', 'independent Opus review of all 5 conditions with raw-proof access', 'integration, current final verification and ledger', 'Windows same-distribution/device open; no Mac substitution'] + +R09 history and pins remain unrewritten. Low findings (empty cell, audio, idempotency, English Runtime messages) remain deferred. + +Repair18 local validation: python3 -B tools/test_p08_normal_placement_evidence.py ran 131 tests in 88.476s, exit 1: one existing R09 raw-proof read PermissionError; no weakening. py_compile initially failed on default cache permissions, then passed with PYTHONPYCACHEPREFIX inside allowed fixture scratch. JSON load and git diff --check passed. Scope adapter passed including boundary equality. Exact commands and source SHA256 are in implementation.json repair18. Root/Runner raw-proof access remains required. diff --git a/docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json b/docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json index b96cf5e..2d7dd5b 100644 --- a/docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json +++ b/docs/plans/original-completion-2026-10-02/execution/p08-03/implementation.json @@ -79,7 +79,7 @@ "actual_native_OS": "invalidated for changed demolition/support display; recollect after combined product fixes", "independent_review": "pending", "accepted": false, - "state": "blocked pending Root reconciliation and application of runtime_preview.patch; Main display premise gap recorded" + "state": "pending Root native/OS" }, "invalid_position_reason": { "implementation": "prepared", @@ -1898,5 +1898,61 @@ "18 focused tests: passed with one Root-positive skip before actual bytes were used", "18 focused tests: passed without skips after actual original hashes were used" ] + }, + "repair18": { + "input_M": "7297a4c050f0293df331c2c51bb32def248bcb6b", + "parents": [ + "4775001", + "127f22f" + ], + "support_trace": "dbf5cb8 / native source 12f04d6; target/stairs/construction/pointer passes; 8 unchanged state pairs; Opus pass; final-validation pass (historical support trace, no current applicability claimed)", + "adapter": "Every path in diff(M..worktree) must be inside allowed_paths; every path outside allowed_paths must equal its blob at 127f22f. Inherited Runtime is read-only.", + "proposal": "runtime_preview.patch was superseded by the integrated helper and was not applied; retained as history.", + "HEAD": "to be bound by Runner", + "conditions": "(1) pending Root native/OS; (2)-(5) remain pending", + "acceptance": "not claimed", + "pending": [ + "Root freeze then normal OS and native recollection including changed preview and demolition UI", + "exactly one final all-suite regression on roster derived by Root", + "independent Opus review of all 5 conditions with raw-proof access", + "integration, current final verification and ledger", + "Windows same-distribution/device open; no Mac substitution" + ], + "local_source_sha256": { + "scenes/main/main.gd": "92677e4ac57ed8d418a4a716bf0874cbbaea79cff893e5163c82ad1f75e7140a", + "scenes/main/world_preview.gd": "07e9a36baaa5d0904693f968164101a3938248cfd2cb65b600b64d10eca961d8", + "tools/check_p08_normal_placement_evidence.py": "926418042d4ae8c2afba2bd91799f5d32eac62c673ae83c332f3b2d12fcff90d", + "tools/test_p08_normal_placement_evidence.py": "b83f3c7d917d47d53007b25cb31f11011e2184f53ace3423f38a3007762b5675", + "tests/fixtures/p08-03/checker_fixture.py": "a9d376f0af35814b948347383edf11d299f2e78c3347161a49ae60e5a654ec24", + "tests/fixtures/p08-03/placement.gd": "c59f08fd232f73d0e06398cd3577aba8f5a5840d18c61ce5c88db9e7dba51923", + "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json": "560516247535ee55f3eebe22dec8f3c50ed02ad180b12a8a1f49169543a04562" + }, + "validation": [ + { + "command": "python3 -B tools/test_p08_normal_placement_evidence.py", + "result": "exit 1: 131 tests in 88.476s; one error in existing R09ImageTests.test_baseline_progressive_and_collection_positive: PermissionError reading /Users/korizatou114/Projects/とりにく工房ゲーム制作部/artifacts/original-completion-2026-10-02/p08-03-native-os-r09/index.json; no test weakened or evidence substituted." + }, + { + "command": "python3 -m py_compile tools/check_p08_normal_placement_evidence.py tools/test_p08_normal_placement_evidence.py tests/fixtures/p08-03/checker_fixture.py", + "result": "exit 1: PermissionError at default Python cache path" + }, + { + "command": "PYTHONPYCACHEPREFIX=tests/fixtures/p08-03/.scratch/repair18-pycache python3 -m py_compile tools/check_p08_normal_placement_evidence.py tools/test_p08_normal_placement_evidence.py tests/fixtures/p08-03/checker_fixture.py", + "result": "exit 0" + }, + { + "command": "python3 -c 'import json; from pathlib import Path; base=Path(\"docs/plans/original-completion-2026-10-02/execution\"); json.load((base/\"p08-03/implementation.json\").open()); json.load((base/\"completion_marker_contracts.json\").open()); print(\"JSON load OK\")'", + "result": "exit 0: JSON load OK" + }, + { + "command": "git diff --check", + "result": "exit 0" + }, + { + "command": "python3 -c 'import subprocess,fnmatch\nallowed=['\\''scenes/main/main.gd'\\'','\\''scenes/main/world_preview.gd'\\'','\\''tests/ui/test_p08_normal_placement_ops.gd'\\'','\\''tests/ui/test_p08_normal_placement_ops.gd.uid'\\'','\\''tests/fixtures/p08-03/**'\\'','\\''tools/run_p08_normal_placement.py'\\'','\\''tools/check_p08_normal_placement_evidence.py'\\'','\\''tools/test_p08_normal_placement_evidence.py'\\'','\\''tools/regression/suite-policy.json'\\'','\\''docs/plans/original-completion-2026-10-02/execution/p08-03/**'\\'','\\''docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'\\'']\npaths=subprocess.check_output(['\\''git'\\'','\\''diff'\\'','\\''--name-only'\\'','\\''7297a4c050f0293df331c2c51bb32def248bcb6b'\\''],text=True).splitlines()+subprocess.check_output(['\\''git'\\'','\\''ls-files'\\'','\\''--others'\\'','\\''--exclude-standard'\\''],text=True).splitlines()\nbad=[p for p in paths if not any(fnmatch.fnmatchcase(p,a) for a in allowed)]\nprint('\\''Scope checked paths:'\\'',len(paths));print('\\''Outside allowed_paths:'\\'',bad);assert not bad\nboundary=subprocess.check_output(['\\''git'\\'','\\''diff'\\'','\\''--name-only'\\'','\\''127f22f'\\''],text=True).splitlines()\nbad_boundary=[p for p in boundary if not any(fnmatch.fnmatchcase(p,a) for a in allowed)]\nprint('\\''Outside paths differing from boundary:'\\'',bad_boundary);assert not bad_boundary\n'", + "result": "exit 0: no outside allowed_paths; no outside paths differing from 127f22f" + } + ], + "context_gap": "R09 original raw-proof read access denied in this environment; Root/Runner must execute with required raw-proof access." } } diff --git a/scenes/main/main.gd b/scenes/main/main.gd index 1b89ddb..fff37f0 100644 --- a/scenes/main/main.gd +++ b/scenes/main/main.gd @@ -2124,7 +2124,19 @@ func _preview_failure_message(report: Dictionary) -> String: var codes_value: Variant = report.get(&"error_codes", []) if codes_value is Array and not codes_value.is_empty(): var code := String(codes_value[0]) - return "配置不可: %s" % PREVIEW_REASON_NAMES.get(code, code) + if PREVIEW_REASON_NAMES.has(code): + return "配置不可: %s" % PREVIEW_REASON_NAMES[code] + var code_reasons: Variant = report.get(&"reasons", []) + if code_reasons is Array and not code_reasons.is_empty(): + var reason: Variant = code_reasons[0] + for candidate: Variant in code_reasons: + if candidate is Dictionary and String(candidate.get(&"code", "")) == code: + reason = candidate + break + if reason is Dictionary: + var message := String(reason.get(&"message", "")) + if not message.is_empty(): + return "配置不可: %s" % message var reasons_value: Variant = report.get(&"reasons", []) if reasons_value is Array and not reasons_value.is_empty() and reasons_value[0] is Dictionary: return "配置不可: %s" % String(reasons_value[0].get(&"message", "条件を満たしていません")) diff --git a/scenes/main/world_preview.gd b/scenes/main/world_preview.gd index f69bba5..b6a87a2 100644 --- a/scenes/main/world_preview.gd +++ b/scenes/main/world_preview.gd @@ -202,6 +202,12 @@ func get_build_preview_report(cell: Variant = null) -> Dictionary: var target: Variant = _hovered_cell if cell == null else cell if build_definition == null or not target is Vector3i: return INVALID_PREVIEW.duplicate(true) + if _runtime != null and _runtime.has_method(&"preview_build_facility"): + var result: Dictionary = _runtime.call(&"preview_build_facility", build_definition.id, Vector3i(target.x, target.y, layer_mode), build_rotation) + result[&"connection"] = _build_connection_report( + _cells_from_serialized(result.get(&"cells", [])), + Vector3i(target.x, target.y, layer_mode)) + return result var construction: Variant = _service(&"construction_service") if construction != null and construction.has_method(&"validate_placement"): var report: Variant = construction.call( diff --git a/tests/fixtures/p08-03/checker_fixture.py b/tests/fixtures/p08-03/checker_fixture.py index 7c4ef11..d50b74b 100644 --- a/tests/fixtures/p08-03/checker_fixture.py +++ b/tests/fixtures/p08-03/checker_fixture.py @@ -240,7 +240,7 @@ def make(base, source, checker): elif label == 'missing_connection': row['expected'] = 'STAIR_LANDING_MISSING' report.update(can_build=False, error_codes=[row['expected']], reasons=[{'code':row['expected'], 'message':'先に階段の一つ下の階に通路を作ってください。', 'cells':[], 'details':{'reason':row['expected']}}]) - row['status'] = report['reasons'][0]['message'] + row['status'] = '配置不可: '+report['reasons'][0]['message'] elif label == 'cancel_demolition': row.update(kind='cancel', status='撤去を取り消しました。') elif label in ('demolition', 'refused_demolition'): diff --git a/tests/fixtures/p08-03/placement.gd b/tests/fixtures/p08-03/placement.gd index a7438f4..5364cac 100644 --- a/tests/fixtures/p08-03/placement.gd +++ b/tests/fixtures/p08-03/placement.gd @@ -123,6 +123,7 @@ func build(id: StringName, cell: Vector3i, label: String, expected: String = "") expect(not results.is_empty() and results.back().code == "OK", label + " accepted") elif expected == "STAIR_LANDING_MISSING": expect(not report.can_build and expected in report.error_codes and results.is_empty(), label + " preview refusal") + expect(status == "配置不可: " + String(report.reasons[0].message), label + " preview refusal status") else: expect(expected in report.error_codes and results.is_empty(), label + " preview refusal") var row := {"id": label, "kind": "build", "definition": String(id), "expected": expected, diff --git a/tools/check_p08_normal_placement_evidence.py b/tools/check_p08_normal_placement_evidence.py index c16adf7..20fc0f5 100644 --- a/tools/check_p08_normal_placement_evidence.py +++ b/tools/check_p08_normal_placement_evidence.py @@ -568,10 +568,13 @@ def action_gate(row, typed, root=HERE.parent): require(row['report']['error_codes'][0] == code and row['status'] == message, 'reason mismatch') require(not row['report']['can_build'] and not results, 'preview rejection bypassed') preserve(before, after, results) - elif label == 'missing_connection' and not results: + elif label == 'missing_connection': + require(not results, 'preview rejection bypassed') require(not row['report']['can_build'], 'preview/command disagreement') require('STAIR_LANDING_MISSING' in row['report']['error_codes'], 'preview reason differs from Runtime reason') - require(row['report']['reasons'] and row['status'] == row['report']['reasons'][0]['message'], 'connection reason mismatch') + reason = next((entry for entry in row['report'].get('reasons', []) if isinstance(entry, dict) and entry.get('code') == 'STAIR_LANDING_MISSING'), {}) + message = reason.get('message') + require(isinstance(message, str) and bool(message) and row['status'] == '配置不可: '+message and 'STAIR_LANDING_MISSING' not in row['status'], 'connection reason mismatch') preserve(before, after, []) elif kind == 'cancel': require(not results and row['status'] == '撤去を取り消しました。', 'cancel submitted command') @@ -622,9 +625,6 @@ def action_gate(row, typed, root=HERE.parent): require(set(resources_a) == set(resources_b) and all(resources_b[k] == v - cost.get(k, 0) for k, v in resources_a.items()), 'build cost mismatch') if label == 'supported_connected': require(row['report']['connection']['status'] == 'CONNECTED', 'positive connection absent') - if label == 'missing_connection': - require(row['status'] == '操作に失敗しました: '+result['message'], 'connection reason mismatch') - require(not row['report']['can_build'], 'preview/command disagreement') def check(project_root, evidence_dir): root, evidence = Path(project_root).resolve(), Path(evidence_dir).resolve() diff --git a/tools/test_p08_normal_placement_evidence.py b/tools/test_p08_normal_placement_evidence.py index 19a4b49..c05ffe8 100644 --- a/tools/test_p08_normal_placement_evidence.py +++ b/tools/test_p08_normal_placement_evidence.py @@ -116,9 +116,28 @@ class EvidenceTests(unittest.TestCase): def test_agreeing_preview_refusal(self): row = self.action_row('missing_connection') - self.assertEqual(row['status'], row['report']['reasons'][0]['message']) + self.assertEqual(row['status'], '配置不可: '+row['report']['reasons'][0]['message']) self.action_check(row) + def test_connection_status_corruptions(self): + for status in ('先に階段の一つ下の階に通路を作ってください。', '配置不可: STAIR_LANDING_MISSING', '配置不可: wrong message'): + with self.subTest(status=status): + row = self.action_row('missing_connection') + row['status'] = status + self.action_check(row, 'connection reason mismatch') + + def test_connection_reason_missing_or_empty(self): + for reasons in ([], [{'code':'OTHER', 'message':'other'}], [{'code':'STAIR_LANDING_MISSING', 'message':''}]): + with self.subTest(reasons=reasons): + row = self.action_row('missing_connection') + row['report']['reasons'] = reasons + self.action_check(row, 'connection reason mismatch') + + def test_connection_preview_rejection_bypassed(self): + row = self.action_row('missing_connection') + row['results'] = [{'code':'VALIDATION_FAILED', 'details':{'reason':'STAIR_LANDING_MISSING'}, 'message':row['status']}] + self.action_check(row, 'preview rejection bypassed') + def test_preview_command_disagreement(self): row = self.action_row('missing_connection') row['report']['can_build'] = True