diff --git a/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch b/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch deleted file mode 100644 index 9b8e4e0..0000000 --- a/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch +++ /dev/null @@ -1,506 +0,0 @@ -diff --git a/autoload/simulation_runtime.gd b/autoload/simulation_runtime.gd -index 27bb139..82fa152 100644 ---- a/autoload/simulation_runtime.gd -+++ b/autoload/simulation_runtime.gd -@@ -1056,14 +1056,10 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo - return false - var restored_relationships := RelationshipService.new() - restored_relationships.configure_original_identity_validator( -- func(payload: Dictionary) -> bool: return _original_relationship_identities_valid(payload, restored_staff) -+ func(payload: Dictionary) -> bool: return _original_relationship_identities_valid(payload, restored_staff, restored_catalog) - ) - if not restored_relationships.restore_snapshot(runtime_data[&"relationships"]): - return false -- for relationship: RelationshipState in restored_relationships.get_relationships(): -- for actor_id: StringName in [relationship.actor_a_id, relationship.actor_b_id]: -- if actor_id != &"player" and not restored_staff.has_staff(actor_id) and not restored_guests.has_guest(actor_id): -- return false - var restored_events := EventService.new() - for raw_definition: Variant in runtime_data[&"event_definitions"]: - var definition := EventDefinition.from_variant(raw_definition) -@@ -5387,7 +5383,7 @@ func _configure_relationship_event_boundaries() -> void: - if relationship_service == null or event_service == null: - return - relationship_service.configure_original_identity_validator( -- func(payload: Dictionary) -> bool: return _original_relationship_identities_valid(payload, staff_service) -+ func(payload: Dictionary) -> bool: return _original_relationship_identities_valid(payload, staff_service, mvp_content_catalog) - ) - relationship_service.configure_candidate_callback( - Callable(self, "_on_relationship_threshold_candidate") -@@ -6770,15 +6766,15 @@ func _execute_progress_staff_task(command: SimulationCommand) -> CommandResult: - result.command_id = command.command_id - return result - --func _original_relationship_identities_valid(payload: Dictionary, staff_registry: StaffService) -> bool: -+func _original_relationship_identities_valid(payload: Dictionary, staff_registry: StaffService, catalog: MvpContentCatalog) -> bool: - if payload.get("protagonist_id") != "player" or staff_registry == null: - return false - var subject := StringName(payload.get("subject_id", "")) - var rival := StringName(payload.get("rival_id", "")) - if subject == &"player" or rival == &"player" or subject == rival or not staff_registry.has_staff(subject): - return false -- var heroine_definition := mvp_content_catalog.get_entry(&"unique_characters", subject) -- var rival_definition := mvp_content_catalog.get_entry(&"unique_characters", rival) -+ var heroine_definition := catalog.get_entry(&"unique_characters", subject) -+ var rival_definition := catalog.get_entry(&"unique_characters", rival) - var subject_staff := staff_registry.get_staff(subject) - return subject_staff.employment_kind == StaffRuntime.EmploymentKind.UNIQUE \ - and heroine_definition.get(&"role_id") == String(subject_staff.role_id) \ -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 5474439..6d5e0ae 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 -@@ -7,7 +7,7 @@ - "template": "Original relationship model: checks, failures", - "required": true, - "fixed_check_count_used": false, -- "source_sha256_at_schema_audit": "ad509f5fb67ab91e1d1d99a08af51e4695e411b9a2541ea63ee22b1555cb0924", -+ "source_sha256_at_schema_audit": "c74b243dbbb54dba9bbc165e29508cca910f0beb63e32d25ebbb8ea606dccce9", - "authority": { - "path": "docs/spec/acceptance/P18-01-code-r01.json", - "scope": "new backend suite marker; native execution pending" -@@ -18,7 +18,7 @@ - "template": "Original relationship runtime: checks, failures", - "required": true, - "fixed_check_count_used": false, -- "source_sha256_at_schema_audit": "374f3d31a65d2f2b62dfef29721c8c838575b856f4fa5a0bca31c6ba4c7e09dd", -+ "source_sha256_at_schema_audit": "349271cc8b8a4750ef339ecac6905852bd7a5d006cca68ee10d5d0c737f426de", - "authority": { - "path": "docs/spec/acceptance/P18-01-code-r01.json", - "scope": "new backend suite marker; native execution pending" -diff --git a/docs/plans/original-completion-2026-10-02/execution/p18-01-code/IMPLEMENTATION.md b/docs/plans/original-completion-2026-10-02/execution/p18-01-code/IMPLEMENTATION.md -index 453eeb2..efc5cea 100644 ---- a/docs/plans/original-completion-2026-10-02/execution/p18-01-code/IMPLEMENTATION.md -+++ b/docs/plans/original-completion-2026-10-02/execution/p18-01-code/IMPLEMENTATION.md -@@ -1,6 +1,53 @@ - # P18-01-CODE implementation handoff - --Status: submitted for Runner validation; no acceptance or unit completion claimed. -+Status: repair 4 implementation prepared for Runner; no acceptance or unit completion claimed. P02-01 representative inputs remain an unavailable context dependency, detailed below. -+ -+## Repair 3 historical failure (2026-10-15) -+ -+Historical record only: stopping independent repairs over decoder permissiveness was wrong. The commander producer-evidence interpretation supersedes this old policy concern; the following describes the failed repair-3 attempt, not the current policy. -+ -+Inspected baseline d2a1f80a613e7c77b02b941026bc49c2d85db863 using read-only git show. -+RelationshipState.from_snapshot delegates to configure; _value preserves canonical -+key precedence. Numeric fields use int(), with clampi/maxi where applicable. -+Thus finite fractional numbers are truncated as well as integral JSON floats; -+numeric strings such as metrics.affection = "42" are also converted. The baseline -+RelationshipService._parse_snapshot similarly converts version and candidate -+sequence with int(). These are broader than a finite-integral-float-only policy. -+No acceptance policy for these conflicting formats has been selected here. -+ -+Baseline normalization also replaces non-Dictionary metrics, action_counts, -+daily_metric_deltas, flags and crossed_thresholds with defaults, coerces flags -+with bool(), and ignores non-Array threshold collections. The immutable spec -+requires wrong types to reject, while the repair direction requires baseline -+legitimate acceptance without a new restriction or loosening. In particular, -+accepting or rejecting numeric strings cannot satisfy both without an explicit -+policy decision. Non-numeric/non-finite input, wrong containers, future versions, -+duplicates, invalid references, corrupt original records and projection mismatches -+remain required rejections under the spec; this report does not waive any. -+ -+Baseline Runtime restore delegates legacy relationships to RelationshipService -+without the added actor-existence loop. Baseline GuestService.despawn_guest retains -+the departed guest in persistent_records and removes it from active guests. -+The held actor loop is therefore still an unresolved repair item. Candidate -+catalog selection, lifecycle tests, mutation-through-alias tests, atomic rejection -+coverage and source-pin updates are also still outstanding. The numeric Reader -+helpers in SimulationSnapshot and SaveService accept bounded finite integral JSON -+floats for their own envelope fields; they do not establish a policy overriding -+RelationshipState's coercions. P02-01 representative-save applicability has not -+been established; no fixture acceptance claim is made. -+ -+Only this handoff and prepare-only evidence were changed. Production code, test -+sources and marker/policy pins were left untouched pending policy resolution. -+Prepare-only exited 0: 1,311 source files, 67,310,742 bytes; 3,384,279,040 free -+bytes; 381,883,542 conservative required bytes; capacity available. Seven suites: -+original_relationship_model, original_relationship_runtime, -+relationship_event_service, runtime_relationship_events, -+runtime_snapshot_serialization, runtime_save_lifecycle, staff_management. -+308 future parse paths and nine future native phases; engines/stages = 0, -+actual_checks = null, formal_acceptance = false. The first invocation omitted -+required --output and exited 2; the corrected invocation used the allowed -+p18-01-code/repair-3-prepare output path. Native checks were not run. -+P18-01 remains 30/88, in progress, with no partial credit. - - Scope: dedicated original relationship state, lossless legacy snapshot preservation, - Runtime registration and read projection, and the contract-listed tests and collector. -@@ -34,8 +81,8 @@ The acceptance specification without its final newline matches the contract SHA2 - catalog membership does not invent recruitment. No new original update policy, - contact, route, attack, threshold or duel behavior is defined. - - Snapshot restore validates candidates before replacing live services, then -- rebinds the identity validator to live staff. Existing legacy actor references -- must resolve against player, restored staff or restored guests. -+ rebinds the identity validator to live staff. Legacy relationships retain the original acceptance of departed guests; original -+ records separately validate staff/person/catalog references. - - Every staff-management row exposes `original_relationship`. Missing records - have `configured: false` and null values, distinct from explicit zero. Configured - projections are copies, so reads and caller edits cannot change service state. -@@ -77,3 +124,91 @@ in_progress: ordinary Japanese UI rendering/equality, approved production values - all-seven recruitment, final full required roster and applicable Windows final - acceptance remain outstanding. No git writes, other agents or Runner controls - were used by worker. -+ -+## Repair 4 producer interpretation and independent repairs -+ -+The unchanged wrong-types/valid-legacy contract follows legitimate producers, -+not corrupt-input coercions. RelationshipState.create_snapshot -+(scripts/relationship/relationship_state.gd:132-152) emits String ids/route, -+int numeric fields, named route_lock, Dictionary numeric/bool collections and -+Array thresholds. Its validity check (:99-101) requires int metrics. -+Read-only git log identifies 423fd6d as the only history entry for that file; -+git show of that producer (:132-152) also emits the enum NAME String, not int. -+ -+Actual writer scripts/core/save_service.gd:874-878 serializes the snapshot with -+var_to_bytes and ZSTD; Reader :1021-1028 uses bytes_to_var. Thus world numeric -+ints remain ints. JSON decoding (:970-978) applies to the manifest, not relationship -+payloads. Integral JSON floats are not an established relationship save format -+on this path. Accept int legacy values, named route_lock and producer collections. -+Reject numeric strings, null, bool-as-number, fractional/nonfinite numbers, float -+relationship numbers, int route_lock, wrong containers and invalid enum names. -+Unknown extensions remain opaque; canonical values precede aliases, and aliases, -+unknown facts and collection order remain raw retained facts. Neither old axis -+configures original Affection/Lust/Netorare. -+ -+relationship_service.gd _legacy_types_valid now also checks collection key types -+and restricts route_lock to producer enum names. The pre-existing int/container -+checks implement the producer policy. No conversion or rewrite of raw input occurs. -+Runtime candidate validation now takes restored_catalog; command/service binding -+uses the live catalog. Removed only the added active legacy actor loop. -+GuestService.despawn_guest (scripts/guest/guest_service.gd:954-978) retains the -+persistent record and removes the active guest, so that loop rejected valid saves. -+Original identity/person validation remains in place. -+Existing StaffService.remove_staff (:897-898) and retire_staff (:942-943) already -+refuse UNIQUE departures before changes; tests assert refusal and saved original -+record survival. No new departure rule or record deletion was added. -+ -+The two new suites now cover real Service and Runtime affection/dependence -+mutations from v1 affinity/obligation, canonical precedence, raw extensions and -+order, null original values, v2 restore/rebind, departed persistent guest acceptance, -+and atomic malformed candidates. Rejection checks retain service identity/state, -+whole Runtime bytes and caller input. The five existing suites remain unchanged. -+Fixtures are validation inputs, not production values or newly hired characters. -+ -+Collector derives every sorted .gd path from the exact shared.source_refs map. -+Verification binds parse-paths.json, the receipt count, the unique zero-failure -+FULL_DEPENDENCY_PARSE marker, actual_parse_checks and the whole retained stage -+to that same source map. No count-specific skips or other provenance changes. -+This frozen map has 308 paths; expanded maps must verify their own full count. -+ -+### Precise remaining context gap -+ -+The P02-01 input manifest referenced by -+docs/plans/original-completion-2026-10-02/execution/multi-agent-dev-handoff/delivery_contract_proposal.json:333 -+is absent at artifacts/original-completion-2026-10-02/p02-01-fixed-baseline-r01/input-manifest.json -+in this worktree. Reading the exact production-root counterpart returns -+Operation not permitted. Production-root listing/search is also denied. -+No representative save bytes or decoded fixture are available in this checkout; -+.review-material is absent. Accordingly their exact types/applicability have NOT -+been verified, no older conflicting producer shape is asserted, and no replacement -+representative fixture has been invented. Runner/owner must supply readable pinned -+manifest and applicable save members to finish that mandatory evidence and test. -+This gap did not stop the independent repairs. No native checks were executed. -+UI, values, routes, contacts and duel remain untouched. P18-01 remains 30/88, -+in progress. Native seven-suite frozen evidence, p18-model validation, separate -+Opus review, latest-main integration and fresh merged-source evidence remain -+Root/Runner work; no completion claim is made. -+ -+### Worker static/prepare evidence (repair 4) -+ -+Python AST parsed successfully. git diff --check passed. Both new suite SHA-256 -+pins match their final source in marker contracts and suite-policy; all other -+rows are unchanged. The five existing suite files are byte-identical to HEAD. -+No engine, native collector, default profile or full regression was run. -+ -+Prepare-only roster (seven): original_relationship_model, -+original_relationship_runtime, relationship_event_service, -+runtime_relationship_events, runtime_snapshot_serialization, -+runtime_save_lifecycle, staff_management. Full paths are the unchanged ROSTER in -+tools/run_p18_relationship_tests.py:17-25. -+Initial repair-4 preview: 1,311 files, 67,318,770 source bytes, -+3,388,039,168 free bytes, conservative single-set admission 381,891,570 bytes, -+308 parse paths, nine future phases, engines/stages zero, actual_checks null, -+formal_acceptance false. A final preview after final edits is retained separately -+as repair-4-prepare.json. No native pass is implied by this preview. -+ -+Using the supplied old output estimate conservatively as 474 MiB per full set -+(including 351 MiB engine), two fresh sets require 948 MiB = 994,050,048 bytes. -+They fit the observed ~3.39 GB free space, with ~2.39 GB left before other new -+consumers. This is capacity arithmetic, not a reservation or a measured new run; -+actual output growth remains Root's admission responsibility. -diff --git a/scripts/relationship/relationship_service.gd b/scripts/relationship/relationship_service.gd -index 35d4670..d4a49ef 100644 ---- a/scripts/relationship/relationship_service.gd -+++ b/scripts/relationship/relationship_service.gd -@@ -543,7 +543,7 @@ func _parse_snapshot(snapshot: Dictionary) -> Dictionary: - - static func _legacy_types_valid(raw: Dictionary) -> bool: - for key: String in ["relationship_id", "actor_a_id", "actor_b_id"]: -- if not (raw.get(key) is String or raw.get(key) is StringName): -+ if not raw.get(key) is String: - return false - for key: String in ["shield_max", "shield_current", "last_event_at", "daily_attack_count", "attack_day", "metric_delta_day"]: - if raw.has(key) and not raw[key] is int: -@@ -559,9 +559,9 @@ static func _legacy_types_valid(raw: Dictionary) -> bool: - for value: Variant in raw.get(key, {}).values(): - if not value is int: - return false -- for key: String in ["action_counts", "flags"]: -+ for key: String in ["metrics", "action_counts", "daily_metric_deltas", "flags", "crossed_thresholds"]: - for identity: Variant in raw.get(key, {}): -- if not (identity is String or identity is StringName): -+ if not identity is String: - return false - for value: Variant in raw.get("flags", {}).values(): - if not value is bool: -@@ -572,10 +572,11 @@ static func _legacy_types_valid(raw: Dictionary) -> bool: - for threshold: Variant in value: - if not threshold is int: - return false -- if raw.has("route_id") and not (raw["route_id"] is String or raw["route_id"] is StringName): -- return false -- if raw.has("route_lock") and not (raw["route_lock"] is int or raw["route_lock"] is String or raw["route_lock"] is StringName): -+ if raw.has("route_id") and not raw["route_id"] is String: - return false -+ if raw.has("route_lock"): -+ if not raw["route_lock"] is String or not RelationshipStateType.RouteLock.keys().has(raw["route_lock"]): -+ return false - return true - - -diff --git a/tests/s4/test_original_relationship_model.gd b/tests/s4/test_original_relationship_model.gd -index d2a2c81..1f24b4f 100644 ---- a/tests/s4/test_original_relationship_model.gd -+++ b/tests/s4/test_original_relationship_model.gd -@@ -30,7 +30,50 @@ func _service() -> RelationshipService: - ) - - -+static func legacy_fixture() -> Dictionary: -+ return {"version": 1, "relationships": [ -+ {"relationship_id": "aliases", "actor_a_id": "heroine_anri", "actor_b_id": "player", -+ "metrics": {"affinity": 41, "obligation": 19, "extension": {"opaque": [3, "keep"]}}, -+ "extra": ["raw", 2.5]}, -+ {"relationship_id": "second", "actor_a_id": "departed", "actor_b_id": "player", -+ "metrics": {"trust": 7}}], -+ "threshold_candidates": [], "next_candidate_sequence": 1, "extension": ["ordered", 7]} -+ -+ -+func _alias_mutations() -> void: -+ var service := _service() -+ var legacy := legacy_fixture() -+ var input := var_to_bytes(legacy) -+ _expect(service.restore_snapshot(legacy), "int v1 aliases accepted") -+ _expect(service.apply_value_change(&"aliases", &"affection", 2, 0).is_success(), "affection mutation through real service") -+ _expect(service.apply_value_change(&"aliases", &"dependence", 3, 0).is_success(), "dependence mutation through real service") -+ var saved := service.create_snapshot() -+ var raw: Dictionary = saved[&"legacy"]["relationships"][0] -+ _expect(raw["metrics"]["affection"] == 43 and raw["metrics"]["dependence"] == 22, "canonical changes merged") -+ _expect(raw["metrics"]["affinity"] == 41 and raw["metrics"]["obligation"] == 19, "aliases remain old facts") -+ _expect(raw["metrics"]["extension"] == legacy["relationships"][0]["metrics"]["extension"] and raw["extra"] == ["raw", 2.5], "unknown facts survive mutation") -+ _expect(saved[&"legacy"]["relationships"][1] == legacy["relationships"][1], "record order preserved") -+ var restored := _service() -+ _expect(restored.restore_snapshot(saved), "mutated v2 restores") -+ _expect(var_to_bytes(restored.create_snapshot()) == var_to_bytes(saved), "mutated v2 raw order and bytes preserved") -+ _expect(restored.get_relationship(&"aliases").get_metric(&"affection") == 43 and restored.get_relationship(&"aliases").get_metric(&"dependence") == 22, "canonical values take precedence over raw aliases") -+ for key: StringName in [&"affection", &"lust", &"netorare"]: -+ _expect(restored.get_original_relationship(&"heroine_anri")[key] == null, "old axes never configure original " + String(key)) -+ _expect(var_to_bytes(legacy) == input, "mutation never changes input bytes") -+ for value: Variant in ["50", null, true, 50.0, 1.5, INF, NAN]: -+ var bad := legacy_fixture() -+ bad["relationships"][0]["metrics"]["affinity"] = value -+ _rejected(restored, bad) -+ var bad := legacy_fixture() -+ bad["relationships"][0]["metrics"] = [] -+ _rejected(restored, bad) -+ bad = saved.duplicate(true) -+ bad[&"relationships"] = [] -+ _rejected(restored, bad) -+ -+ - func _run() -> void: -+ _alias_mutations() - var service := _service() - var before := var_to_bytes(service.create_snapshot()) - var unset := service.get_original_relationship(&"heroine_anri") -diff --git a/tests/s4/test_original_relationship_runtime.gd b/tests/s4/test_original_relationship_runtime.gd -index f2aa656..7029ce1 100644 ---- a/tests/s4/test_original_relationship_runtime.gd -+++ b/tests/s4/test_original_relationship_runtime.gd -@@ -71,8 +71,90 @@ func _run() -> void: - invalid["rival_id"] = "missing" - _expect(not runtime.relationship_service.register_original_relationship(invalid).is_success(), "restore rebind keeps identity validator") - _expect(runtime.relationship_service.register_original_relationship(fixture).is_success(), "restored service accepts correct identities") -+ _expect(not runtime.staff_service.remove_staff(&"heroine_anri").is_success(), "registered UNIQUE heroine removal refused") -+ _expect(not runtime.staff_service.retire_staff(&"heroine_anri").is_success(), "registered UNIQUE heroine retirement refused") -+ var retained: Dictionary = runtime.create_snapshot() -+ _expect(runtime.restore_snapshot(retained), "refused departures survive save and readback") -+ _expect(runtime.relationship_service.get_original_relationship(&"heroine_anri")[&"configured"], "departure never deletes original record") -+ _extra_coverage(runtime) - runtime.free() - clock.free() - state.free() - print("Original relationship runtime: %d checks, %d failures" % [_checks, _failures]) - quit(_failures) -+ -+ -+func _reject_runtime(runtime: Variant, candidate: Dictionary) -> void: -+ var before := var_to_bytes(runtime.create_snapshot()) -+ var service: Variant = runtime.relationship_service -+ var service_bytes := var_to_bytes(service.create_snapshot()) -+ var input := var_to_bytes(candidate) -+ _expect(not runtime.restore_snapshot(candidate), "malformed candidate rejected atomically") -+ _expect(runtime.relationship_service == service and var_to_bytes(service.create_snapshot()) == service_bytes, "rejection preserves prior service identity and bytes") -+ _expect(var_to_bytes(runtime.create_snapshot()) == before, "rejection preserves whole Runtime bytes") -+ _expect(var_to_bytes(candidate) == input, "rejection preserves all input bytes") -+ -+ -+func _extra_coverage(runtime: Variant) -> void: -+ var candidate: Dictionary = runtime.create_snapshot() -+ var legacy := Fixtures.legacy_fixture() -+ candidate[&"systems"][&"runtime"][&"relationships"] = legacy -+ # GuestService's legitimate departure representation, retained after active removal. -+ candidate[&"systems"][&"runtime"][&"guests"][&"persistent_records"].append({ -+ &"guest_id": "departed", &"guest_type_id": "traveler", &"debt_gold": 0, -+ &"unresolved_incident_ids": [], &"outstanding_reservation_ids": []}) -+ candidate[&"systems"][&"runtime"][&"progression"][&"metrics"][&"guest_lifetime"] += 1 -+ var input := var_to_bytes(candidate) -+ _expect(runtime.restore_snapshot(candidate), "int v1 and departed persistent guest relationships accepted") -+ _expect(var_to_bytes(candidate) == input, "accepted v1 Runtime input unchanged") -+ for change: Dictionary in [{&"metric_id": &"affection", &"delta": 2}, {&"metric_id": &"dependence", &"delta": 3}]: -+ change[&"relationship_id"] = &"aliases" -+ _expect(runtime.submit_command(&"change_relationship", change).is_success(), "alias changes use public Runtime command") -+ var saved: Dictionary = runtime.create_snapshot() -+ var raw: Dictionary = saved[&"systems"][&"runtime"][&"relationships"][&"legacy"]["relationships"][0] -+ _expect(raw["metrics"]["affection"] == 43 and raw["metrics"]["dependence"] == 22, "Runtime merges canonical mutations") -+ _expect(raw["metrics"]["affinity"] == 41 and raw["metrics"]["obligation"] == 19, "Runtime keeps raw aliases") -+ _expect(raw["extra"] == ["raw", 2.5] and raw["metrics"]["extension"] == {"opaque": [3, "keep"]}, "Runtime keeps unknown facts") -+ var saved_bytes := var_to_bytes(saved) -+ _expect(runtime.restore_snapshot(saved), "mutated v2 Runtime restores and rebinds") -+ _expect(var_to_bytes(runtime.create_snapshot()) == saved_bytes, "v2 Runtime preserves raw bytes and order") -+ _expect(runtime.relationship_service.get_relationship(&"aliases").get_metric(&"affection") == 43 and runtime.relationship_service.get_relationship(&"aliases").get_metric(&"dependence") == 22, "Runtime canonical precedence survives rebind") -+ for key: StringName in [&"affection", &"lust", &"netorare"]: -+ _expect(runtime.relationship_service.get_original_relationship(&"heroine_anri")[key] == null, "Runtime old axes leave original unset") -+ _expect(runtime.relationship_service.register_original_relationship(Fixtures.fixture()).is_success(), "rebound service accepts original") -+ saved = runtime.create_snapshot() -+ for kind: String in ["numeric_string", "metrics_container", "duplicate", "version_type", "unknown_version", "projection", "non_heroine", "counterpart", "non_staff", "corrupt"]: -+ var bad := saved.duplicate(true) -+ var relationships: Dictionary = bad[&"systems"][&"runtime"][&"relationships"] -+ match kind: -+ "numeric_string", "metrics_container": -+ if kind == "numeric_string": -+ relationships[&"legacy"]["relationships"][0]["metrics"]["affection"] = "50" -+ else: -+ relationships[&"legacy"]["relationships"][0]["metrics"] = [] -+ relationships[&"relationships"] = relationships[&"legacy"]["relationships"].duplicate(true) -+ "duplicate": -+ relationships[&"original_relationships"].append(Fixtures.fixture()) -+ "version_type": -+ relationships[&"version"] = "2" -+ "unknown_version": -+ relationships[&"version"] = 3 -+ "projection": -+ relationships[&"relationships"] = [] -+ "non_heroine": -+ var rival_staff := StaffRuntime.new().configure(&"rival_rai", &"influencer", {&"employment_kind": &"UNIQUE"}) -+ _expect(rival_staff.is_valid(), "non-heroine rejection fixture is valid UNIQUE staff") -+ bad[&"systems"][&"runtime"][&"staff"][&"staff"].append(rival_staff.create_snapshot()) -+ relationships[&"original_relationships"][0]["subject_id"] = "rival_rai" -+ relationships[&"original_relationships"][0]["rival_id"] = "heroine_anri" -+ var registry := StaffService.new() -+ _expect(registry.register_staff(rival_staff).is_success(), "non-heroine UNIQUE exists in identity fixture registry") -+ _expect(Fixtures.Model.from_snapshot(relationships[&"original_relationships"][0]) != null, "non-heroine payload passes structural model validation") -+ _expect(not runtime._original_relationship_identities_valid(relationships[&"original_relationships"][0], registry, runtime.mvp_content_catalog), "catalog rejects non-heroine UNIQUE subject specifically") -+ "counterpart": -+ relationships[&"original_relationships"][0]["rival_id"] = "rival_other" -+ "non_staff": -+ relationships[&"original_relationships"][0]["subject_id"] = "departed" -+ "corrupt": -+ relationships[&"original_relationships"][0].erase("lust") -+ _reject_runtime(runtime, bad) -diff --git a/tools/regression/suite-policy.json b/tools/regression/suite-policy.json -index 63d34d8..6604a3d 100644 ---- a/tools/regression/suite-policy.json -+++ b/tools/regression/suite-policy.json -@@ -2,14 +2,14 @@ - "schema_version": 1, - "suite_policies": { - "tests/s4/test_original_relationship_model.gd": { -- "source_sha256": "ad509f5fb67ab91e1d1d99a08af51e4695e411b9a2541ea63ee22b1555cb0924", -+ "source_sha256": "c74b243dbbb54dba9bbc165e29508cca910f0beb63e32d25ebbb8ea606dccce9", - "ordinary_cleanup_prepared": false, - "ordinary_control_labels": [], - "old_bounded_teardown": false, - "new_audio_QA": false - }, - "tests/s4/test_original_relationship_runtime.gd": { -- "source_sha256": "374f3d31a65d2f2b62dfef29721c8c838575b856f4fa5a0bca31c6ba4c7e09dd", -+ "source_sha256": "349271cc8b8a4750ef339ecac6905852bd7a5d006cca68ee10d5d0c737f426de", - "ordinary_cleanup_prepared": false, - "ordinary_control_labels": [], - "old_bounded_teardown": false, -diff --git a/tools/run_p18_relationship_tests.py b/tools/run_p18_relationship_tests.py -index c520311..925ccca 100644 ---- a/tools/run_p18_relationship_tests.py -+++ b/tools/run_p18_relationship_tests.py -@@ -199,6 +199,7 @@ def seal(out, refs, engine, contract_sha): - source = content_map(refs) - shared.write(out / 'receipt.json', { - 'schema': 'guarded-p18-v2', 'source_map': source, -+ 'parse_checks': len([name for name in refs if name.endswith('.gd')]), - 'source_map_sha256': digest(source), - 'project_settings_sha256': source['project.godot']['sha256'], - 'marker_contract_sha256': contract_sha, -@@ -281,8 +282,10 @@ def verify(out, refs, markers, contracts, policy, contract_sha, parse_paths): - require(engine and shared.sha(engine) == start['engine_sha256'] - == manifest['engine_sha256'] == files['engine.bin']['sha256'], - 'current native engine and retained bytes pinned') -- require(read('parse-paths.json') == parse_paths and len(parse_paths) == 308, -- 'all 308 exact source parse paths') -+ derived_paths = ['res://' + name for name in sorted(refs) if name.endswith('.gd')] -+ require(read('parse-paths.json') == parse_paths == derived_paths -+ and manifest['parse_checks'] == len(derived_paths), -+ 'all exact source parse paths and receipt count') - require(end['passed'] is True and end['engine_ended'] is True and end['error'] is None - and end['cleanup_errors'] == [] and end['guard_errors'] == [], - 'finished successful collection without guard/cleanup error') -@@ -463,8 +466,9 @@ def verify(out, refs, markers, contracts, policy, contract_sha, parse_paths): - else: - require(row['controlled_environment'] == {}, 'fresh import environment') - if phase == 'parse': -- require(re.findall(r'(?m)^FULL_DEPENDENCY_PARSE checks=([0-9]+) failures=([0-9]+)\n', raw) -- == [('308', '0')] and row['actual_parse_checks'] == 308, 'unique all-script parse marker') -+ require(len(re.findall(r'(?m)^FULL_DEPENDENCY_PARSE\b', raw)) == 1 -+ and re.findall(r'(?m)^FULL_DEPENDENCY_PARSE checks=([0-9]+) failures=([0-9]+)\n', raw) -+ == [(str(len(parse_paths)), '0')] and row['actual_parse_checks'] == len(parse_paths), 'unique all-script parse marker') - if test: - parsed = markers.parse_raw(test, raw, contracts, source[test]['sha256']) - require(parsed['passed'] and row['completion'] == parsed -@@ -492,7 +496,7 @@ def verify(out, refs, markers, contracts, policy, contract_sha, parse_paths): - 'whole raw evidence unchanged during verification') - require(content_map(shared.source_refs(shared.HERE.parent)) == source, - 'whole current source unchanged during verification') -- print(json.dumps({'verified': True, 'actual_suites': 7, 'parse_checks': 308, -+ print(json.dumps({'verified': True, 'actual_suites': 7, 'parse_checks': len(parse_paths), - 'actual_checks': end['actual_all_roster_checks'], 'engines_started': 0, - 'formal_acceptance': False, 'original_unit_complete': False})) - return 0 -@@ -536,7 +540,6 @@ def main(argv=None): - require(contracts[test]['source_sha256_at_schema_audit'] == refs[test]['sha256'], - 'new strict source-hashed marker') - parse_paths = ['res://' + name for name in sorted(refs) if name.endswith('.gd')] -- require(len(parse_paths) == 308, 'exact expected parse count') - if args.prepare_only: - ancestor = out.parent - while not ancestor.exists(): -@@ -545,7 +548,7 @@ def main(argv=None): - size = sum(p['bytes'] for p in refs.values()) - print(json.dumps({'roster': ROSTER, 'source_files': len(refs), 'source_bytes': size, - 'free_bytes': free, 'conservative_required_bytes': size + shared.MIN_SPACE, -- 'capacity_available': free >= size + shared.MIN_SPACE, 'parse_paths': 308, -+ 'capacity_available': free >= size + shared.MIN_SPACE, 'parse_paths': len(parse_paths), - 'future_native_phases': 9, 'actual_checks': None, 'engines': 0, 'stages': 0, - 'formal_acceptance': False})) - return 0 diff --git a/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch.gz b/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch.gz new file mode 100644 index 0000000..5cafb44 Binary files /dev/null and b/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch.gz differ diff --git a/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF_REFERENCE.json b/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF_REFERENCE.json new file mode 100644 index 0000000..960aec6 --- /dev/null +++ b/docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF_REFERENCE.json @@ -0,0 +1,11 @@ +{ + "original_path": "docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch", + "original_bytes": 32892, + "original_sha256": "b4d570884c1d0eb90c6780c7346419cb7e3f43780ec590bb472822f087e3f72d", + "compressed_path": "docs/plans/original-completion-2026-10-02/execution/p18-01-resume-20261015/PRESERVED_REPAIR4_DIFF.patch.gz", + "compressed_bytes": 10186, + "compressed_sha256": "73f67bd136833919e20bbc6d3e0dc1c31524e8956eb71a75d3ceafc94e55a402", + "verified_content_preserved": true, + "raw_original_also_in_git_commit": "1a6cc43f2efe5c0128d7677c6ee5dd17dcb15ce2", + "reason": "Raw patch contains intentional diff context prefixes followed by tabs, which git diff --check misinterprets when patch is added as text. Preserve exact raw artifact in verified gzip, not whitespace-edit proof." +}