P04-01: 同時発生の更新規約
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
# REPAIR40 implementation supersession; native evidence remains pending
|
||||
|
||||
The implementation-pending statements below are superseded only for S5A/S5B
|
||||
power, S5C command destruction, S5D automatic raid destruction, S5E paid midnight
|
||||
and S5F command/planned exit. The single CASE_TABLE now dispatches these cases.
|
||||
No case is relabelled as an executed proof. Root must establish every outcome
|
||||
from fresh Q raw; an unalignable raid or unsupported condition fails normally.
|
||||
|
||||
The S5 order adapter does not infer patience_release or paused_midnight.
|
||||
Fresh S3 can supply patience_release only from its own actually observed raw.
|
||||
The remaining frozen REQUIRED conditions, including shift_completion,
|
||||
same_minute_replay and paused_midnight, are not supplied by historical union.
|
||||
The final checker must remain failed if any required condition is missing.
|
||||
|
||||
The earlier text is retained as historical planning context:
|
||||
|
||||
# S5 — pending implementation, not a native run plan
|
||||
|
||||
No S5 executable driver or native receipt is supplied by this partial repair.
|
||||
|
||||
@@ -1,3 +1,73 @@
|
||||
# REPAIR40 A–F source batch — Root verification required
|
||||
|
||||
This section supersedes earlier implementation-pending directions below only
|
||||
for the code now supplied. It is not admission, a native result, original credit,
|
||||
or permission to repeat the once-only final full run.
|
||||
|
||||
Root order (unchanged):
|
||||
1. Affected pure controls. Keep every previous negative. Run full_suite_verifier.py
|
||||
--controls. New S5 typed mutation controls require actual fresh native raw;
|
||||
their positives remain unexecuted until that raw exists.
|
||||
2. Check-only S1–S5 plans on the final Q.
|
||||
3. One heavy lease: fresh native S1–S5, capacity/PID checks and verified complete
|
||||
Writer/Reader restore manifests. Within this step, evaluate the order adapter
|
||||
and its typed mutation controls against actual S5 raw when available.
|
||||
4. Fresh collect to a new exclusive audit-support/p04-raw-collect-q<N>.
|
||||
5. Full 184/329 once on final Q; derive actual roster/parse/source counts.
|
||||
6. Index.
|
||||
7. --verify-only.
|
||||
8. Independent review.
|
||||
9. Normal prepare/final and Root post-final normal_c_join.
|
||||
|
||||
Stage the complete unchanged directory hierarchy (including shared s5 wrapper,
|
||||
adapters and series dependencies) under BUILD/audit-support/p04-fresh-context.
|
||||
Stage the actual Q source there as well, preserving source bytes. Native outputs
|
||||
must be separate directories under BUILD, outside that context directory.
|
||||
Use --main M --submission S --tested-tree Qt --project-root <actual-Q> for every
|
||||
run_s*_native.py. No global monkeypatching is used to select Q.
|
||||
Historical --historical-r17 --check-only remains read-only. No historical native
|
||||
execution is admissible. All fresh plans/outputs are exclusive and must be absent.
|
||||
The single QA override and the selected source/UID/engine/ownership gates remain.
|
||||
|
||||
Before fresh collection Root writes audit-support/p04-fresh-runs.json from the
|
||||
actual receipts (no baked receipt SHA values):
|
||||
- protocol: p04-fresh-runs-v1
|
||||
- M, S, Q_tree: the actual full HEX40 inputs
|
||||
- collection: audit-support/p04-raw-collect-q<N>
|
||||
- series: exactly s1, s2a, s2b, s3, s4, s5; each entry has run (BUILD-relative)
|
||||
and byte/SHA descriptors named runner_input, runner_ended, raw_inventory,
|
||||
formal_relocation, read from the corresponding actual output files.
|
||||
- full_suite: run (BUILD-relative), runner_input and runner_ended descriptors
|
||||
from the final full run. These fields are consumed at index/checker time,
|
||||
so fresh collection precedes and does not depend on the full run.
|
||||
Use collect_p04_native.py --build <BUILD> --fresh q<N>.
|
||||
Never overwrite r22 and never merge its verified_conditions.
|
||||
|
||||
The full run uses the actual Q tools/run_all_tests.py standard schema and the
|
||||
Root finite-UID controller contract illustrated in the hash-verified context.
|
||||
Retain source-start.json, runner-input/ended, all-tests, parse-paths, every phase
|
||||
receipt/process/started/ended/log, UID plan/seals, retained stage and generated
|
||||
reports. full_suite_verifier imports that actual Q runner and marker/diagnostic
|
||||
modules. Its 15+EV entries explicitly distinguish suite applicability from
|
||||
boundary proof. test_required_kitchen is separately bound. It consumes no C,
|
||||
prepare/final or independent-review result; normal C remains Root's later join.
|
||||
|
||||
S5 has one CASE_TABLE for reserved counts, ordered labels and prepare/advance/
|
||||
stop/assert methods. S5A/B retain their original recovery and duplicate path.
|
||||
S5C–F use public commands and ordinary ticks. The automatic raid uses the
|
||||
autonomy fixture strengths with the service facility as OBJECTIVE; its queried
|
||||
earliest_minute must equal N. New cases replay independently after formal load.
|
||||
The adapter uses typed nodes, complete typed restore/replay equality and raw
|
||||
phase/receipt joins. It fails rather than fabricating an unavailable observation.
|
||||
The private receipt buffer is restored for C–F because their boundary already
|
||||
contains transactions; the A/B boundary receipt behavior is unchanged.
|
||||
|
||||
No worker engine, Git, Runner, native or controls run occurred. Only the recorded
|
||||
static checks were performed. r35/r36 remain FAILED; worker38/39 stops remain
|
||||
historical records; Q37 remains a local diagnostic. Original credit remains zero.
|
||||
|
||||
## Retained earlier directions
|
||||
|
||||
# Concrete32 power pair — unexecuted, not batch admission
|
||||
|
||||
`p04_s5_power_probe.gd` supplies S5A_PURE (paid public bath, genuine mana
|
||||
|
||||
+155
-18
@@ -1,7 +1,14 @@
|
||||
extends "res://tests/s3/test_runtime_actor_hardening.gd"
|
||||
|
||||
const CASES: Array[String] = ["S5A_PURE", "S5B_DEPENDENCY"]
|
||||
const SEEDS: Dictionary = {"S5A_PURE": 420550, "S5B_DEPENDENCY": 420551}
|
||||
const CASE_TABLE: Dictionary = {
|
||||
"S5A_PURE": {"expected_reserved_ids": 0, "labels": ["boundary", "held", "recovered", "duplicate_guard"], "prepare": "_prepare", "advance": "_advance", "stop": "_assert_stopped", "assert": "_assert_outcome"},
|
||||
"S5B_DEPENDENCY": {"expected_reserved_ids": 1, "labels": ["boundary", "held", "recovered", "duplicate_guard"], "prepare": "_prepare", "advance": "_advance", "stop": "_assert_stopped", "assert": "_assert_outcome"},
|
||||
"S5C_DESTRUCTION_COMMAND": {"expected_reserved_ids": 1, "labels": ["boundary", "held"], "prepare": "_prepare_order", "advance": "_advance_order", "stop": "_assert_order_stop", "assert": "_assert_order"},
|
||||
"S5D_DESTRUCTION_RAID": {"expected_reserved_ids": 1, "labels": ["boundary", "held"], "prepare": "_prepare_order", "advance": "_advance_order", "stop": "_assert_order_stop", "assert": "_assert_order"},
|
||||
"S5E_MIDNIGHT": {"expected_reserved_ids": 1, "labels": ["boundary", "recalled"], "prepare": "_prepare_order", "advance": "_advance_order", "stop": "_assert_order_stop", "assert": "_assert_order"},
|
||||
"S5F_EXIT": {"expected_reserved_ids": 1, "labels": ["boundary", "held"], "prepare": "_prepare_order", "advance": "_advance_order", "stop": "_assert_order_stop", "assert": "_assert_order"}
|
||||
}
|
||||
const SEEDS: Dictionary = {"S5A_PURE": 420550, "S5B_DEPENDENCY": 420551, "S5C_DESTRUCTION_COMMAND": 420552, "S5D_DESTRUCTION_RAID": 420553, "S5E_MIDNIGHT": 424242, "S5F_EXIT": 420555}
|
||||
const GUEST: StringName = &"p04.s5.guest.a"
|
||||
const REQUEST: StringName = &"p04.s5.request.a"
|
||||
const QUEUED_GUEST: StringName = &"p04.s5.guest.b"
|
||||
@@ -38,7 +45,7 @@ func _run() -> void:
|
||||
return
|
||||
_expect(DirAccess.make_dir_recursive_absolute(_evidence_dir) == OK, "external evidence directory")
|
||||
if _mode == "writer":
|
||||
for branch: String in CASES:
|
||||
for branch: String in CASE_TABLE:
|
||||
_case = branch
|
||||
_writer_case()
|
||||
else:
|
||||
@@ -92,7 +99,7 @@ func _queue(guest_id: StringName, request_id: StringName, exit_at: int) -> void:
|
||||
_expect(guest != null and request != null, "actual Guest and request exist")
|
||||
if guest == null or request == null: return
|
||||
_expect(guest.state == GuestRuntime.State.QUEUING and guest.queue_request_id == request_id, "actual queued ownership before advancing clock")
|
||||
_expect(request.quoted_price == _price and request.service_minutes == _duration and request.reserved_inventory_ids.size() == (1 if _case == "S5B_DEPENDENCY" else 0), "definition price/duration and one meal reservation")
|
||||
_expect(request.quoted_price == _price and request.service_minutes == _duration and request.reserved_inventory_ids.size() == CASE_TABLE[_case]["expected_reserved_ids"], "definition price/duration and one meal reservation")
|
||||
for id: StringName in request.reserved_inventory_ids:
|
||||
var reservation: InventoryReservation = _runtime.inventory_service.get_reservation(id)
|
||||
_expect(reservation != null and reservation.is_active() and reservation.requester_id == request_id, "public queue actually reserves meal")
|
||||
@@ -148,6 +155,128 @@ func _prepare() -> bool:
|
||||
_expect(_reserve > 0 and service.elapsed_minutes == _duration - 1, "positive reserve and duration-1 progress")
|
||||
return _clock.absolute_minute == _boundary - 1
|
||||
|
||||
func _prepare_order() -> bool:
|
||||
_fresh()
|
||||
var midnight: bool = _case == "S5E_MIDNIGHT"
|
||||
if midnight:
|
||||
_boundary = 1440
|
||||
var enabled: Dictionary = _runtime.enable_production_operations()
|
||||
_expect(bool(enabled.get(&"ok", false)), "S2a public operations path")
|
||||
if not bool(enabled.get(&"ok", false)): return false
|
||||
var facility: FacilityInstance = _build_cafeteria(true)
|
||||
if facility == null: return false
|
||||
_facility_id = facility.instance_id
|
||||
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(facility.definition_id)
|
||||
_price = definition.base_price
|
||||
_duration = definition.base_service_minutes
|
||||
_patience = _runtime.guest_service.get_definition(&"traveler").base_patience
|
||||
if midnight:
|
||||
_prepare_paid_reception()
|
||||
_cmd(&"set_staff_work_assignment", {&"staff_id": StringName("fixture.kitchen.worker.%s" % _facility_id), &"template_id": &"NIGHT", &"facility_id": facility.related_facility_id})
|
||||
var staff_ids: Array[StringName] = []
|
||||
for index: int in range(definition.staff_min):
|
||||
var id: StringName = StringName("p04.s5.staff.%d" % index)
|
||||
staff_ids.append(id)
|
||||
_cmd(&"register_staff", {&"staff_id": id, &"role_id": &"server", &"options": {&"state": StaffRuntime.State.OFF_DUTY, &"current_cell": Vector3i.ZERO}})
|
||||
_cmd(&"set_staff_work_assignment", {&"staff_id": id, &"template_id": &"NIGHT" if midnight else &"DAY", &"facility_id": _facility_id})
|
||||
var queue_at: int = _boundary - _duration - 1
|
||||
_expect(_price > 0 and _duration > 1 and queue_at > _clock.absolute_minute, "natural paid service before boundary")
|
||||
if queue_at <= _clock.absolute_minute or _duration <= 1: return false
|
||||
if _case == "S5D_DESTRUCTION_RAID":
|
||||
_expect(_duration > 5, "raid setup fits before natural completion")
|
||||
if _duration <= 5: return false
|
||||
_clock.advance_minutes(queue_at - _clock.absolute_minute)
|
||||
_expect(facility.active_staff_ids == staff_ids, "ordinary physical attendance")
|
||||
var second: bool = _case in ["S5D_DESTRUCTION_RAID", "S5F_EXIT"]
|
||||
_expect(_stock(facility.local_inventory_id, &"ingredient/basic_meal", 2 if second else 1, &"p04.s5.order.stock"), "actual reservable meals")
|
||||
_queue(GUEST, REQUEST, _boundary if _case == "S5F_EXIT" else _boundary + _duration + 1)
|
||||
_clock.advance_one_minute()
|
||||
var active: Array = _runtime.facility_service.get_active_services(_facility_id)
|
||||
_expect(active.size() == 1, "one natural primary service")
|
||||
if active.size() != 1: return false
|
||||
var service: ServiceInstance = active[0]
|
||||
_service_id = service.service_id
|
||||
_expect(service.started_at + _duration == _boundary, "natural N completion")
|
||||
if _case == "S5D_DESTRUCTION_RAID":
|
||||
_clock.advance_minutes(_boundary - 5 - _clock.absolute_minute)
|
||||
_prepare_breach()
|
||||
_clock.advance_minutes(_boundary - 2 - _clock.absolute_minute)
|
||||
_queue(QUEUED_GUEST, QUEUED_REQUEST, _boundary + _duration + 1)
|
||||
_clock.advance_minutes(_boundary - 1 - _clock.absolute_minute)
|
||||
if _case == "S5F_EXIT": _queue(QUEUED_GUEST, QUEUED_REQUEST, _boundary + _duration + 1)
|
||||
_reserve = _state.get_resource(&"mana")
|
||||
_recovery = {&"staff_ids": staff_ids, &"resume_minute": _boundary}
|
||||
_expect(service.elapsed_minutes == _duration - 1, "duration minus one at N-1")
|
||||
return _clock.absolute_minute == _boundary - 1
|
||||
|
||||
func _prepare_paid_reception() -> void:
|
||||
# S2a paid-midnight fixture, with catalog wages and ordinary assignments.
|
||||
var definition: FacilityDefinition = _runtime.definition_registry.get_facility(&"reception")
|
||||
_cmd(&"build_facility", {&"definition_id": &"reception", &"origin": Vector3i(2, 0, WorldService.LAYER_FRONT)})
|
||||
_clock.advance_minutes(definition.build_minutes)
|
||||
var reception_id: StringName = &""
|
||||
for instance: FacilityInstance in _runtime.facility_service.get_instances():
|
||||
if instance.definition_id == &"reception": reception_id = instance.instance_id
|
||||
_expect(not reception_id.is_empty(), "public paid reception completed")
|
||||
var catalog: Dictionary = JSON.parse_string(FileAccess.get_file_as_string("res://data/characters/mvp_staff_candidates.json"))
|
||||
for candidate_id: StringName in [&"staff_akane", &"staff_bardo"]:
|
||||
var wage: int = -1
|
||||
for row: Dictionary in catalog["entries"]:
|
||||
if StringName(row["id"]) == candidate_id: wage = int(row["daily_wage"])
|
||||
_cmd(&"hire_staff_candidate", {&"candidate_id": candidate_id})
|
||||
var worker: StaffRuntime = _runtime.staff_service.get_staff(candidate_id)
|
||||
_expect(worker != null and wage > 0 and worker.get_effective_daily_wage() == wage, "unchanged paid catalog wage")
|
||||
_cmd(&"set_staff_work_assignment", {&"staff_id": candidate_id, &"template_id": &"DAY" if candidate_id == &"staff_akane" else &"NIGHT", &"facility_id": reception_id})
|
||||
|
||||
func _prepare_breach() -> void:
|
||||
# Exact autonomy fixture strengths; the real service facility is the objective.
|
||||
_cmd(&"set_facility_conditions", {&"facility_id": _facility_id, &"conditions": {&"durability": 1}})
|
||||
_cmd(&"register_staff", {&"staff_id": &"p04.s5.guard", &"role_id": &"security", &"options": {&"state": StaffRuntime.State.AVAILABLE, &"health": 100, &"fatigue": 0, &"skills": {&"combat": 100}}})
|
||||
var wave: Dictionary = {&"wave_id": &"p04.s5.wave", &"threat_strength": 1000, &"retreat_threshold": 0, &"max_rounds": 1, &"entry_points": [&"gate.north"]}
|
||||
_cmd(&"create_defense_raid", {&"raid_id": &"p04.s5.raid", &"definition": {&"source_id": &"runtime_test", &"entry_points": [&"gate.north", &"gate.south"], &"objective_ids": [_facility_id], &"waves": [wave], &"round_minutes": 5, &"max_duration_minutes": 180, &"retreat_policy": &"HOLD", &"defender_retreat_threshold": 0}})
|
||||
_cmd(&"register_defense_combatant", {&"raid_id": &"p04.s5.raid", &"actor_id": &"p04.s5.guard", &"side": &"DEFENDER", &"combat": 0, &"max_health": 100, &"options": {&"armor": 2}})
|
||||
_cmd(&"register_defense_asset", {&"raid_id": &"p04.s5.raid", &"asset_id": _facility_id, &"kind": &"OBJECTIVE", &"max_integrity": 10000, &"defense": 0, &"options": {&"target_order": 1}})
|
||||
_cmd(&"register_defense_combatant", {&"raid_id": &"p04.s5.raid", &"actor_id": &"p04.s5.attacker", &"side": &"ATTACKER", &"combat": 1000, &"max_health": 100, &"options": {&"wave_id": &"p04.s5.wave", &"entry_point_id": &"gate.north"}})
|
||||
_cmd(&"start_defense_raid", {&"raid_id": &"p04.s5.raid"})
|
||||
var due: Array[Dictionary] = _runtime.defense_service.get_due_rounds(_boundary)
|
||||
_expect(due.size() == 1 and due[0][&"earliest_minute"] == _boundary and due[0][&"raid_id"] == &"p04.s5.raid", "automatic breach due at exactly N; no substitute")
|
||||
|
||||
func _advance_order(label: String) -> void:
|
||||
if label == "boundary":
|
||||
if _case == "S5C_DESTRUCTION_COMMAND": _cmd(&"set_facility_conditions", {&"facility_id": _facility_id, &"conditions": {&"durability": 0}}, _boundary)
|
||||
if _case == "S5F_EXIT": _cmd(&"leave_facility_queue", {&"facility_id": _facility_id, &"request_id": QUEUED_REQUEST}, _boundary)
|
||||
if label == "recalled":
|
||||
var before: Dictionary = _runtime.create_snapshot()
|
||||
var replay: CommandResult = _runtime.operations_coordinator.advance_to(_boundary)
|
||||
_expect(replay.is_success() and replay.is_replay, "same midnight is a replay")
|
||||
_expect(var_to_bytes(before) == var_to_bytes(_runtime.create_snapshot()), "same-minute replay changes no typed state")
|
||||
_recovery[&"midnight_replay"] = replay.to_dictionary()
|
||||
else:
|
||||
_clock.advance_one_minute()
|
||||
|
||||
func _assert_order_stop(point: Dictionary) -> void:
|
||||
if _case == "S5C_DESTRUCTION_COMMAND":
|
||||
_expect(point[&"service"][&"state"] == "FAILED" and point[&"service"][&"failure_reason"] == String(FacilityService.INTERRUPTION_BROKEN), "command destruction interrupts before payment")
|
||||
else:
|
||||
_expect(point[&"service"][&"state"] == "COMPLETED", "natural completion precedes later boundary effects")
|
||||
if _case in ["S5C_DESTRUCTION_COMMAND", "S5D_DESTRUCTION_RAID"]:
|
||||
_expect(point[&"facility"][&"durability"] == 0 and point[&"facility"][&"state"] == "BROKEN", "destroyed facility")
|
||||
if _case == "S5D_DESTRUCTION_RAID":
|
||||
_expect(point[&"facility"][&"suspension_reason"] == "DESTROYED", "automatic breach suspension")
|
||||
if _case == "S5E_MIDNIGHT":
|
||||
_expect(point[&"operations_enabled"] and not point[&"actual_coordinator_absent"], "operations-enabled midnight")
|
||||
|
||||
func _assert_order(before: Dictionary, point: Dictionary) -> void:
|
||||
_assert_order_stop(point)
|
||||
var paid: bool = _case != "S5C_DESTRUCTION_COMMAND"
|
||||
_expect(point[&"wallets"][String(GUEST)] == before[&"wallets"][String(GUEST)] - (_price if paid else 0), "exact primary wallet delta")
|
||||
_assert_reservation(before, point, REQUEST, "CONSUMED" if paid else "RELEASED", _boundary)
|
||||
if _case == "S5F_EXIT" or (_case == "S5D_DESTRUCTION_RAID" and point[&"minute"] > _boundary):
|
||||
_assert_reservation(before, point, QUEUED_REQUEST, "RELEASED", _boundary if _case == "S5F_EXIT" else _boundary + 1)
|
||||
_expect(point[&"wallets"][String(QUEUED_GUEST)] == before[&"wallets"][String(QUEUED_GUEST)], "secondary request never charged")
|
||||
if _case == "S5F_EXIT" and point[&"minute"] == _boundary:
|
||||
_expect(point[&"guests"][String(GUEST)][&"state"] == "LEAVING", "planned exit after completed service")
|
||||
|
||||
func _connect_observations() -> void:
|
||||
_runtime.economy_service.transaction_posted.connect(func(id: StringName, entries: Array) -> void:
|
||||
var rows: Array = []
|
||||
@@ -201,7 +330,10 @@ func _capture() -> Dictionary:
|
||||
&"actual_coordinator_absent": _runtime.operations_coordinator == null, &"unrelated_getters_called": false}
|
||||
|
||||
func _labels() -> Array[String]:
|
||||
return ["boundary", "held", "recovered"]
|
||||
var labels: Array[String] = []
|
||||
for label: String in CASE_TABLE[_case]["labels"]:
|
||||
if label != "duplicate_guard": labels.append(label)
|
||||
return labels
|
||||
|
||||
func _advance(label: String) -> void:
|
||||
if label == "boundary":
|
||||
@@ -250,20 +382,21 @@ func _advance(label: String) -> void:
|
||||
_clock.advance_one_minute()
|
||||
|
||||
func _writer_case() -> void:
|
||||
if not _prepare(): return
|
||||
if not Callable(self, CASE_TABLE[_case]["prepare"]).call(): return
|
||||
var before: Dictionary = _capture()
|
||||
_assert_before(before)
|
||||
if _case in ["S5A_PURE", "S5B_DEPENDENCY"]: _assert_before(before)
|
||||
_points["before"] = _write("before", before)
|
||||
_connect_observations()
|
||||
for label: String in _labels():
|
||||
_advance(label)
|
||||
Callable(self, CASE_TABLE[_case]["advance"]).call(label)
|
||||
var actual: Dictionary = _capture()
|
||||
_assert_outcome(before, actual)
|
||||
Callable(self, CASE_TABLE[_case]["assert"]).call(before, actual)
|
||||
_save_point(label, actual)
|
||||
_advance("duplicate_guard")
|
||||
var guard: Dictionary = _capture()
|
||||
_assert_outcome(before, guard)
|
||||
_points["duplicate_guard"] = _write("duplicate_guard", guard)
|
||||
if "duplicate_guard" in CASE_TABLE[_case]["labels"]:
|
||||
_advance("duplicate_guard")
|
||||
var guard: Dictionary = _capture()
|
||||
_assert_outcome(before, guard)
|
||||
_points["duplicate_guard"] = _write("duplicate_guard", guard)
|
||||
_branches[_case] = _write("case", {&"resource_replay": _replay_reference, &"points": _points.duplicate(true), &"phases": _phases.duplicate(true),
|
||||
&"commands": _write("commands", {&"submitted": _commands, &"completed_including_fixture": _results})})
|
||||
|
||||
@@ -410,6 +543,8 @@ func _load_point(path: String, expected: Dictionary) -> bool:
|
||||
var restored: bool = _runtime.restore_snapshot(loaded[&"snapshot"])
|
||||
_expect(restored, "public Runtime restore")
|
||||
_expect(var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(expected[&"snapshot"]), "all restored typed fields equal Writer")
|
||||
if _case not in ["S5A_PURE", "S5B_DEPENDENCY"]:
|
||||
_receipts = expected[&"receipts"].duplicate(true)
|
||||
return restored
|
||||
|
||||
func _is_replayed_phase(row: Dictionary) -> bool:
|
||||
@@ -418,6 +553,7 @@ func _is_replayed_phase(row: Dictionary) -> bool:
|
||||
func _assert_expected_phase_roster(references: Array) -> void:
|
||||
var expected_pairs: Array = []
|
||||
var end: int = int(_recovery[&"resume_minute"]) + 1
|
||||
if _case == "S5E_MIDNIGHT": end = _boundary
|
||||
for minute: int in range(_boundary, end):
|
||||
for phase: int in range(SimulationKernel.TickPhase.size()):
|
||||
expected_pairs.append([minute if phase == SimulationKernel.TickPhase.APPLY_COMMANDS else minute + 1, SimulationKernel.TickPhase.keys()[phase]])
|
||||
@@ -434,7 +570,7 @@ func _reader() -> void:
|
||||
var writer: Dictionary = JSON.parse_string(file.get_as_text())
|
||||
file.close()
|
||||
_expect(int(writer["pid"]) != OS.get_process_id() and writer["profile"] != OS.get_user_data_dir(), "independent Reader PID/profile")
|
||||
for branch: String in CASES:
|
||||
for branch: String in CASE_TABLE:
|
||||
_case = branch
|
||||
var writer_case: Dictionary = _read(writer["branches"][branch])
|
||||
var hashes: Dictionary = {}
|
||||
@@ -465,15 +601,16 @@ func _reader() -> void:
|
||||
var before: Dictionary = _read(writer_case[&"points"]["before"])
|
||||
var boundary: Dictionary = _read(writer_case[&"points"]["boundary"])
|
||||
if not _load_point(_slots[branch + "-boundary"], boundary): return
|
||||
_assert_stopped(_capture())
|
||||
Callable(self, CASE_TABLE[_case]["stop"]).call(_capture())
|
||||
_connect_observations()
|
||||
var replay_refs: Dictionary = {}
|
||||
for label: String in ["held", "recovered", "duplicate_guard"]:
|
||||
_advance(label)
|
||||
for label: String in CASE_TABLE[_case]["labels"]:
|
||||
if label == "boundary": continue
|
||||
Callable(self, CASE_TABLE[_case]["advance"]).call(label)
|
||||
var actual: Dictionary = _capture()
|
||||
var expected: Dictionary = _read(writer_case[&"points"][label])
|
||||
_expect(var_to_bytes(actual) == var_to_bytes(expected), "replay complete typed point including Runtime, inputs, receipts " + label)
|
||||
_assert_outcome(before, actual)
|
||||
Callable(self, CASE_TABLE[_case]["assert"]).call(before, actual)
|
||||
replay_refs[label] = _write(label + "-replay", actual)
|
||||
var expected_phases: Array = []
|
||||
for reference: Dictionary in writer_case[&"phases"]:
|
||||
|
||||
@@ -29,8 +29,23 @@ ENGINE_SHA256 = "c7cccbf8fb143e34e02fd6521e09be2c2b974f0d5db080b19071c9c570718cc
|
||||
MANIFEST = BUILD / "audit-support/p04-r17-full-inputs-r01/MANIFEST.json"
|
||||
MANIFEST_SHA = "a15f29fa12537f6d8aaf7cabea390922a9f16e3eb9c10981e5742aafc8c4c8a8"
|
||||
CONTRACTS = BUILD / "audit-support/p04-r17-full-inputs-r01/fixed/6ce6b28c5985e8a4f13b78bfeb1f1e09f6216d874fb01e0656ec1633bfa01cd7/completion_marker_contracts.json"
|
||||
CASES = ["S5A_PURE", "S5B_DEPENDENCY"]
|
||||
LABELS = {case: ["boundary", "held", "recovered"] for case in CASES}
|
||||
def case_table(path):
|
||||
matches = re.findall(r"^const CASE_TABLE: Dictionary = (\{.*?^\})", Path(path).read_text(), re.M | re.S)
|
||||
if len(matches) != 1:
|
||||
raise ValueError("exactly one literal CASE_TABLE required")
|
||||
table = json.loads(matches[0])
|
||||
for case, row in table.items():
|
||||
if (set(row) != {"expected_reserved_ids", "labels", "prepare", "advance", "stop", "assert"}
|
||||
or not row["labels"] or row["labels"][0] != "boundary"
|
||||
or len(row["labels"]) != len(set(row["labels"]))):
|
||||
raise ValueError("invalid case table: " + case)
|
||||
return table
|
||||
|
||||
|
||||
CASE_TABLE = case_table(QA)
|
||||
CASES = list(CASE_TABLE)
|
||||
LABELS = {case: [label for label in row["labels"] if label != "duplicate_guard"]
|
||||
for case, row in CASE_TABLE.items()}
|
||||
SLOTS = sorted(case + "-" + label for case in CASES for label in LABELS[case])
|
||||
MATERIALS = [MANIFEST, BUILD / "audit-support/p04-review-repair22-r01/ACTUAL_CURRENT_PUBLIC_POWER_FUNCTIONS.json"]
|
||||
|
||||
@@ -171,6 +186,27 @@ def engine_pin(path, expected=None):
|
||||
raise ValueError("engine identity changed")
|
||||
return value
|
||||
|
||||
|
||||
def mirror_formal(r, out, before):
|
||||
"""Mirror complete Writer and Reader packages, preserving original receipts."""
|
||||
relocated = {}
|
||||
for role in ("writer", "reader"):
|
||||
receipt = r.read(out / ("raw/" + role + ".json"))
|
||||
r.require(set(receipt["slots"]) == set(before), "formal slot roster")
|
||||
relocated[role] = {}
|
||||
for slot, original in receipt["slots"].items():
|
||||
r.require(Path(slot).name == slot and slot not in (".", ".."), "formal slot name")
|
||||
target = out / "formal" / role / slot
|
||||
target.mkdir(parents=True)
|
||||
members = r.inventory(Path(original))
|
||||
r.require(set(members) == {"journal.log", "manifest.json", "thumbnail.png", "world.bin"}
|
||||
and members == before[slot], "complete unchanged formal package")
|
||||
for member in members:
|
||||
shutil.copyfile(Path(original) / member, target / member)
|
||||
r.require(r.inventory(target) == members, "all copied formal hashes")
|
||||
relocated[role][slot] = dict(provenance=original, relative=str(target.relative_to(out)), members=members)
|
||||
r.write(out / "formal-relocation.json", relocated)
|
||||
|
||||
C_REL = "docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Typed S5 ordering derivations. Native provenance is verified separately."""
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
POWER_PATH = Path(__file__).with_name('s5_power_adapter.py')
|
||||
power = module('s5_order_power', POWER_PATH)
|
||||
Raw, staff_check, duplicate_check = power.Raw, power.staff_check, power.duplicate_check
|
||||
series, require = power.series, power.require
|
||||
DEPENDENCIES = {str(p): hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
for p in (POWER_PATH, power.SERIES_PATH)}
|
||||
GUEST, REQUEST = power.GUEST, power.REQUEST
|
||||
SECOND, SECOND_REQUEST = 'p04.s5.guest.b', 'p04.s5.request.b'
|
||||
|
||||
|
||||
def field(node, *keys):
|
||||
for key in keys:
|
||||
node = node.at(key)
|
||||
return node
|
||||
|
||||
|
||||
def scalar(node, *keys):
|
||||
node = field(node, *keys)
|
||||
require(node.kind in (1, 2, 4, 21), 'typed scalar required')
|
||||
return node.value
|
||||
|
||||
|
||||
def rows(node, *keys):
|
||||
node = field(node, *keys)
|
||||
require(node.kind == 28, 'typed array required')
|
||||
return node.value
|
||||
|
||||
|
||||
def phase(phases, name, minute):
|
||||
found = [p for p in phases if scalar(p, 'phase') == name and scalar(p, 'minute') == minute]
|
||||
require(len(found) == 1, 'one raw phase: ' + name)
|
||||
return found[0]
|
||||
|
||||
|
||||
def sales(point):
|
||||
return [r for r in rows(point, 'ledger') if scalar(r, 'category') == 'SERVICE_SALE'
|
||||
and scalar(r, 'credit_account') == 'GUEST_WALLET:' + GUEST]
|
||||
|
||||
|
||||
def release(before, after, request, minute):
|
||||
old = [r for r in rows(before, 'reservations') if scalar(r, 'requester_id') == request]
|
||||
new = [r for r in rows(after, 'reservations') if scalar(r, 'requester_id') == request]
|
||||
require(len(old) == len(new) == 1, 'one original reservation')
|
||||
ident = scalar(old[0], 'reservation_id')
|
||||
require(scalar(new[0], 'reservation_id') == ident and scalar(old[0], 'state') == 'ACTIVE'
|
||||
and scalar(new[0], 'state') == 'RELEASED' and scalar(new[0], 'terminal_at') == minute,
|
||||
'reservation release identity/state/time')
|
||||
operations = rows(after, 'snapshot', 'systems', 'runtime', 'inventory', 'idempotency_results')
|
||||
matches = [r for r in operations if scalar(r, 'action') == 'release'
|
||||
and scalar(r, 'result', 'reservation_id') == ident]
|
||||
require(len(matches) == 1 and scalar(matches[0], 'result', 'ok') is True,
|
||||
'exactly one successful release')
|
||||
require(field(after, 'requests', request).plain() == {}, 'no orphan request')
|
||||
return ident
|
||||
|
||||
|
||||
def payment(before, after, minute):
|
||||
sale = sales(after)
|
||||
require(not sales(before) and len(sale) == 1, 'exactly one new sale')
|
||||
price = scalar(before, 'inputs', 'price')
|
||||
require(price > 0 and scalar(sale[0], 'amount') == price
|
||||
and scalar(sale[0], 'absolute_minute') == minute
|
||||
and scalar(sale[0], 'source_entity_id') == scalar(after, 'inputs', 'facility_id'),
|
||||
'sale amount/time/facility')
|
||||
require(scalar(after, 'wallets', GUEST) == scalar(before, 'wallets', GUEST) - price,
|
||||
'single wallet debit')
|
||||
require(scalar(after, 'service', 'state') == 'COMPLETED'
|
||||
and scalar(after, 'service', 'completed_at') == minute, 'completed before payment')
|
||||
runtime = field(after, 'snapshot', 'systems', 'runtime')
|
||||
key = 'service.payment.' + scalar(after, 'service', 'service_id')
|
||||
idem = [r for r in rows(runtime, 'economy', 'idempotency') if scalar(r, 'key') == key]
|
||||
require(len(idem) == 1 and scalar(idem[0], 'transaction_id') == scalar(sale[0], 'transaction_id'),
|
||||
'independent service/payment idempotency join')
|
||||
receipt_entries = [r for receipt in rows(after, 'receipts') for r in rows(receipt, 'entries')]
|
||||
require(sum(r.raw == sale[0].raw for r in receipt_entries) == 1, 'sale bound to one typed receipt')
|
||||
return sale[0]
|
||||
|
||||
|
||||
def destruction_command(points, phases):
|
||||
before, end = points['before'], points['held']
|
||||
n = scalar(before, 'inputs', 'boundary')
|
||||
prior = phase(phases, 'FACILITY_COMPLETION', n)
|
||||
require(scalar(prior, 'facility', 'durability') == 0
|
||||
and scalar(prior, 'facility', 'state') == 'BROKEN', 'command destroys before completion')
|
||||
for p in (points['boundary'], end):
|
||||
require(scalar(p, 'service', 'state') == 'FAILED'
|
||||
and scalar(p, 'service', 'failure_reason') == 'BROKEN', 'INTERRUPTION_BROKEN')
|
||||
require(not sales(p) and scalar(p, 'wallets', GUEST) == scalar(before, 'wallets', GUEST),
|
||||
'zero destroyed charge')
|
||||
release(before, p, REQUEST, n)
|
||||
return {'destruction_stop': {'charges': 0}, 'command_destruction_before_completion': True}
|
||||
|
||||
|
||||
def destruction_raid(points, phases):
|
||||
before, end = points['before'], points['held']
|
||||
n = scalar(before, 'inputs', 'boundary')
|
||||
pre = phase(phases, 'INCIDENTS_AND_EVENTS', n)
|
||||
post = phase(phases, 'FACILITY_QUEUES', n)
|
||||
payment(before, phase(phases, 'VITALS_AND_ENVIRONMENT', n), n)
|
||||
payment(before, pre, n)
|
||||
require(scalar(pre, 'facility', 'durability') > 0 and scalar(post, 'facility', 'durability') == 0
|
||||
and scalar(post, 'facility', 'state') == 'BROKEN'
|
||||
and scalar(post, 'facility', 'suspension_reason') == 'DESTROYED', 'sale before automatic destruction')
|
||||
require(scalar(end, 'minute') == n + 1, 'unfinished failure at N+1')
|
||||
release(before, end, SECOND_REQUEST, n + 1)
|
||||
failed = [r for r in rows(end, 'snapshot', 'systems', 'runtime', 'facilities', 'service_history')
|
||||
if scalar(r, 'request_id') == SECOND_REQUEST]
|
||||
require(len(failed) == 1 and scalar(failed[0], 'state') == 'FAILED'
|
||||
and scalar(failed[0], 'failure_reason') == 'BROKEN', 'unfinished service failed by broken facility')
|
||||
require(scalar(end, 'wallets', SECOND) == scalar(before, 'wallets', SECOND), 'no unfinished charge')
|
||||
require([r.raw for r in sales(end)] == [r.raw for r in sales(pre)], 'no extra raid sale')
|
||||
return {'raid_sale_before_destruction': True, 'raid_unfinished_release': True}
|
||||
|
||||
|
||||
def midnight_day(points, phases):
|
||||
before, end, replay = points['before'], points['boundary'], points['recalled']
|
||||
n = scalar(before, 'inputs', 'boundary')
|
||||
require(n > 0 and n % 1440 == 0, 'midnight multiple')
|
||||
pre = phase(phases, 'FACILITY_COMPLETION', n)
|
||||
require(not sales(pre), 'settlement before sale')
|
||||
coordinator = field(pre, 'snapshot', 'systems', 'runtime', 'operations', 'coordinator')
|
||||
days = [r for r in rows(coordinator, 'day_summaries') if scalar(r, 'closed_at') == n]
|
||||
require(len(days) == 1 and scalar(days[0], 'period_end_minute_exclusive') == n,
|
||||
'one half-open DAILY_CLOSE at N')
|
||||
upkeep = [r for r in rows(pre, 'ledger') if scalar(r, 'category') == 'MAINTENANCE_PAYMENT'
|
||||
and scalar(r, 'absolute_minute') == n]
|
||||
require(upkeep and len({scalar(r, 'transaction_id') for r in upkeep}) == 1, 'a_upkeep before sale')
|
||||
mana = phase(phases, 'MANA', n)
|
||||
require(all(any(r.raw == u.raw for r in rows(mana, 'ledger')) for u in upkeep),
|
||||
'upkeep posted during TIME_BOUNDARIES')
|
||||
sale = payment(before, end, n)
|
||||
payment(before, phase(phases, 'VITALS_AND_ENVIRONMENT', n), n)
|
||||
require(n <= scalar(sale, 'absolute_minute') < n + 1440, 'new day sale')
|
||||
require(field(end, 'snapshot').raw == field(replay, 'snapshot').raw,
|
||||
'same-minute replay preserves every typed Runtime field')
|
||||
require(scalar(replay, 'inputs', 'recovery', 'midnight_replay', 'is_replay') is True,
|
||||
'same minute is_replay')
|
||||
def paid_view(point):
|
||||
value = point.plain()
|
||||
runtime = value['snapshot']['systems']['runtime']
|
||||
value.update(staff=runtime['staff'], payroll=runtime['staff']['payroll_settlements'],
|
||||
shifts=runtime['staff']['shifts'], operations=runtime['operations']['coordinator'],
|
||||
idempotency={'economy': runtime['economy']['idempotency']})
|
||||
return value
|
||||
# Reuse the unchanged paid-midnight ledger/duty joins after the typed order gates.
|
||||
series.settlement(paid_view(before), paid_view(end))
|
||||
return {'midnight_settlement': {'settlements': 1, 'sales_payments': 1, 'payroll_payments': 1,
|
||||
'upkeep_payments': 1, 'duty_payments': 1, 'nonzero_payroll': True},
|
||||
'midnight_replay': {'settlements': 1, 'same_minute_replayed': True, 'duplicate_payments': 0},
|
||||
'midnight_close_upkeep_before_sale': True, 'midnight_new_day_sale': True}
|
||||
|
||||
|
||||
def exit_order(points, phases):
|
||||
before = points['before']
|
||||
n = scalar(before, 'inputs', 'boundary')
|
||||
pre = phase(phases, 'FACILITY_COMPLETION', n)
|
||||
release(before, pre, SECOND_REQUEST, n)
|
||||
for p in [pre, points['boundary'], points['held']]:
|
||||
services = rows(p, 'snapshot', 'systems', 'runtime', 'facilities', 'service_history')
|
||||
services = services + [s for facility in rows(p, 'snapshot', 'systems', 'runtime', 'facilities', 'instances')
|
||||
for s in rows(facility, 'active_services')]
|
||||
require(not any(scalar(s, 'request_id') == SECOND_REQUEST for s in services), 'command exit before start')
|
||||
require(scalar(p, 'wallets', SECOND) == scalar(before, 'wallets', SECOND), 'command exit no charge')
|
||||
ai = phase(phases, 'AI_DECISIONS', n)
|
||||
published = phase(phases, 'PUBLISH_SNAPSHOT', n)
|
||||
payment(before, ai, n)
|
||||
payment(before, phase(phases, 'VITALS_AND_ENVIRONMENT', n), n)
|
||||
require(scalar(ai, 'guests', GUEST, 'state') == 'DECIDING'
|
||||
and scalar(ai, 'guests', GUEST, 'planned_exit_at') <= n
|
||||
and scalar(published, 'guests', GUEST, 'state') == 'LEAVING'
|
||||
and scalar(published, 'guests', GUEST, 'exit_reason') == 'PLANNED_EXIT',
|
||||
'AI exit only after DECIDING and paid completion')
|
||||
return {'exit_release': {'orphan_reservations': 0, 'released_once': True}, 'command_exit_before_start': True,
|
||||
'planned_exit_after_completion': True}
|
||||
|
||||
|
||||
DERIVERS = {'S5C_DESTRUCTION_COMMAND': destruction_command, 'S5D_DESTRUCTION_RAID': destruction_raid,
|
||||
'S5E_MIDNIGHT': midnight_day, 'S5F_EXIT': exit_order}
|
||||
|
||||
|
||||
def derive(root, writer_sha, reader_sha):
|
||||
root = Path(root)
|
||||
raw = Raw(root)
|
||||
writer = json.loads(raw.pin(root / 'writer.json', writer_sha), object_pairs_hook=power.unique)
|
||||
reader = json.loads(raw.pin(root / 'reader.json', reader_sha), object_pairs_hook=power.unique)
|
||||
require(writer['pid'] != reader['pid'] and writer['profile'] != reader['profile'], 'independent Reader')
|
||||
expected = set(DERIVERS) | set(power.CASES)
|
||||
require(set(writer['branches']) == set(reader['branches']) == expected, 'complete S5 roster')
|
||||
result = {}
|
||||
for case, function in DERIVERS.items():
|
||||
branch = raw.reference(writer['branches'][case])
|
||||
replay = raw.reference(reader['branches'][case])
|
||||
points = {k: raw.typed(v) for k, v in branch['points'].items()}
|
||||
phases = [raw.typed(r) for r in branch['phases']]
|
||||
raw.typed(branch['commands'])
|
||||
for p in points.values():
|
||||
staff_check(p, field(p, 'inputs', 'recovery'))
|
||||
result[case] = function(points, phases)
|
||||
for label, ref in replay['restored'].items():
|
||||
require(field(raw.typed(ref), 'snapshot').raw == field(points[label], 'snapshot').raw,
|
||||
'whole typed formal restore')
|
||||
require(set(replay['restored']) == set(points) - {'before'}, 'complete restore roster')
|
||||
require(set(replay['replay']) == set(points) - {'before', 'boundary'}, 'complete replay roster')
|
||||
for label, ref in replay['replay'].items():
|
||||
require(raw.typed(ref).raw == points[label].raw, 'whole typed independent replay')
|
||||
n = scalar(points['before'], 'inputs', 'boundary')
|
||||
expected_phases = [p.raw for p in phases if scalar(p, 'minute') > n or
|
||||
(scalar(p, 'minute') == n and scalar(p, 'phase') == 'APPLY_COMMANDS')]
|
||||
require([raw.typed(r).raw for r in replay['phases']] == expected_phases, 'complete phase replay')
|
||||
result[case]['formal_restore_verified'] = True
|
||||
if case == 'S5E_MIDNIGHT':
|
||||
result[case]['save_restore'] = {'settlements': 1, 'duplicate_payments': 0, 'formal_save_restored': True}
|
||||
return {'cases': result, 'dependency_sha256': DEPENDENCIES, 'raw_sha256': raw.hashes,
|
||||
'pending': ['patience_release', 'paused_midnight'], 'formal_acceptance': False}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Root-only typed mutations against fresh native S5 raw; never synthetic positives."""
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import struct
|
||||
import sys
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
import s5_order_adapter as a
|
||||
|
||||
mutation = a.module('order_typed_mutation', Path(__file__).with_name('s5_power_adapter_controls.py'))
|
||||
BUILD = Path('/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--raw-root', type=Path, required=True)
|
||||
parser.add_argument('--writer-sha256', required=True)
|
||||
parser.add_argument('--reader-sha256', required=True)
|
||||
parser.add_argument('--scratch', type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
scratch = args.scratch
|
||||
a.require(scratch.is_absolute() and not scratch.exists() and not scratch.is_symlink(), 'explicit absent scratch')
|
||||
a.require(scratch.parent.resolve(strict=True).is_relative_to(BUILD.resolve(strict=True)), 'scratch inside BUILD')
|
||||
a.require(not scratch.resolve().is_relative_to(args.raw_root.resolve()), 'scratch outside native raw')
|
||||
for parent in scratch.parents:
|
||||
a.require(not parent.is_symlink(), 'scratch ancestor symlink')
|
||||
positive = a.derive(args.raw_root, args.writer_sha256, args.reader_sha256)
|
||||
scratch.mkdir()
|
||||
raw = a.Raw(args.raw_root)
|
||||
writer = json.loads(raw.pin(args.raw_root / 'writer.json', args.writer_sha256))
|
||||
cases = {}
|
||||
for case in a.DERIVERS:
|
||||
branch = raw.reference(writer['branches'][case])
|
||||
cases[case] = ({k: raw.typed(v) for k, v in branch['points'].items()},
|
||||
[raw.typed(r) for r in branch['phases']])
|
||||
checks = []
|
||||
|
||||
def negative(label, case, owner, target, replacement):
|
||||
points, phases = cases[case]
|
||||
encoded = mutation.replace(owner, target, replacement)
|
||||
(scratch / (label + '.var')).write_bytes(encoded)
|
||||
changed = a.series.variant(encoded)
|
||||
changed_points = {k: changed if v is owner else v for k, v in points.items()}
|
||||
changed_phases = [changed if v is owner else v for v in phases]
|
||||
try:
|
||||
a.DERIVERS[case](changed_points, changed_phases)
|
||||
except ValueError:
|
||||
checks.append(label)
|
||||
return
|
||||
raise ValueError('mutation accepted: ' + label)
|
||||
|
||||
midnight = 'S5E_MIDNIGHT'
|
||||
points, phases = cases[midnight]
|
||||
n = a.scalar(points['before'], 'inputs', 'boundary')
|
||||
end = points['boundary']
|
||||
negative('sale-old-day', midnight, end, a.field(a.sales(end)[0], 'absolute_minute'), mutation.scalar(2, n - 1))
|
||||
pre = a.phase(phases, 'FACILITY_COMPLETION', n)
|
||||
days = a.field(pre, 'snapshot', 'systems', 'runtime', 'operations', 'coordinator', 'day_summaries')
|
||||
empty = days.raw[:-sum(len(r.raw) for r in days.value)] if days.value else days.raw
|
||||
# Preserve the original typed-array header and replace its element count.
|
||||
start = 12 if days.raw[:4] == struct.pack('<I', 28 | (1 << 16)) else 8
|
||||
empty = days.raw[:start-4] + struct.pack('<I', 0)
|
||||
negative('settlement-after-sale', midnight, pre, days, empty)
|
||||
raid = 'S5D_DESTRUCTION_RAID'
|
||||
points, phases = cases[raid]
|
||||
pre = a.phase(phases, 'INCIDENTS_AND_EVENTS', a.scalar(points['before'], 'inputs', 'boundary'))
|
||||
negative('raid-sale-missing', raid, pre, a.field(a.sales(pre)[0], 'category'), mutation.scalar(4, 'REMOVED_SALE'))
|
||||
command = 'S5C_DESTRUCTION_COMMAND'
|
||||
points, phases = cases[command]
|
||||
end = points['held']
|
||||
ops = a.field(end, 'snapshot', 'systems', 'runtime', 'inventory', 'idempotency_results')
|
||||
release = next(r for r in ops.value if a.scalar(r, 'action') == 'release')
|
||||
start = 12 if ops.raw[:4] == struct.pack('<I', 28 | (1 << 16)) else 8
|
||||
doubled = ops.raw[:start-4] + struct.pack('<I', len(ops.value) + 1) + ops.raw[start:] + release.raw
|
||||
negative('double-release', command, end, ops, doubled)
|
||||
exit_case = 'S5F_EXIT'
|
||||
points, phases = cases[exit_case]
|
||||
n = a.scalar(points['before'], 'inputs', 'boundary')
|
||||
ai = a.phase(phases, 'AI_DECISIONS', n)
|
||||
negative('ai-exit-during-service', exit_case, ai, a.field(ai, 'guests', a.GUEST, 'state'), mutation.scalar(4, 'RECEIVING_SERVICE'))
|
||||
pre = a.phase(phases, 'FACILITY_COMPLETION', n)
|
||||
reservation = next(r for r in a.rows(pre, 'reservations') if a.scalar(r, 'requester_id') == a.SECOND_REQUEST)
|
||||
negative('command-exit-after-start', exit_case, pre, a.field(reservation, 'terminal_at'), mutation.scalar(2, n + 1))
|
||||
print(json.dumps({'positive_cases': list(positive['cases']), 'negative_controls': checks,
|
||||
'formal_acceptance': False}, sort_keys=True))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -100,7 +100,9 @@ def derive(root, writer_sha, reader_sha):
|
||||
writer = json.loads(raw.pin(root / "writer.json", writer_sha), object_pairs_hook=unique)
|
||||
reader = json.loads(raw.pin(root / "reader.json", reader_sha), object_pairs_hook=unique)
|
||||
require(writer["pid"] != reader["pid"] and writer["profile"] != reader["profile"], "independent reader required")
|
||||
require(set(writer["branches"]) == set(reader["branches"]) == set(CASES), "exact case pair")
|
||||
expected = set(CASES) | {"S5C_DESTRUCTION_COMMAND", "S5D_DESTRUCTION_RAID", "S5E_MIDNIGHT", "S5F_EXIT"}
|
||||
require(set(writer["branches"]) == set(reader["branches"]) and
|
||||
set(writer["branches"]) in (set(CASES), expected), "exact pair or full case table roster")
|
||||
output = {}
|
||||
for case in CASES:
|
||||
branch = raw.reference(writer["branches"][case])
|
||||
|
||||
Reference in New Issue
Block a user