feat(ai): ✨ add parity sampling for move validation
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
6a15d0a418
commit
88bb753876
1 changed files with 25 additions and 2 deletions
|
|
@ -271,6 +271,11 @@ static func _replay_learned_actions(action_log: Array, player: RefCounted) -> in
|
|||
var applied: int = 0
|
||||
var deferred_founds: int = 0
|
||||
var dropped_variants: Array[String] = []
|
||||
# Gate (b) instrumentation — record (intended_axial, resulting_gdscript_pos)
|
||||
# for the first few moves so the Inc-2 gate can prove the GDScript world
|
||||
# actually moved to the policy's chosen target. Capped to keep the log tight.
|
||||
var parity_samples: Array[String] = []
|
||||
const PARITY_SAMPLE_CAP: int = 6
|
||||
for entry: Dictionary in action_log:
|
||||
var kind: String = String(entry.get("kind", ""))
|
||||
match kind:
|
||||
|
|
@ -279,14 +284,24 @@ static func _replay_learned_actions(action_log: Array, player: RefCounted) -> in
|
|||
# the move-as-attack case at the target hex).
|
||||
var off: Vector2i = Vector2i(int(entry.get("to_col", 0)), int(entry.get("to_row", 0)))
|
||||
var ax: Vector2i = HexUtilsScript.offset_to_axial(off)
|
||||
var uid: int = int(entry.get("unit_id", -1))
|
||||
var move_json: String = JSON.stringify({
|
||||
"MoveUnit": {
|
||||
"unit_id": int(entry.get("unit_id", -1)),
|
||||
"unit_id": uid,
|
||||
"to_hex": [ax.x, ax.y],
|
||||
}
|
||||
})
|
||||
if DispatchScript.dispatch_action(move_json, player, index_maps, city_name):
|
||||
applied += 1
|
||||
# Position-parity proof: read the unit's resulting GDScript
|
||||
# position and compare to the intended axial target.
|
||||
if parity_samples.size() < PARITY_SAMPLE_CAP:
|
||||
var u: RefCounted = (index_maps.get("units", {}) as Dictionary).get(uid)
|
||||
if u != null:
|
||||
var match_str: String = "OK" if u.position == ax else "MISMATCH"
|
||||
parity_samples.append(
|
||||
"u%d→intended%s got%s [%s]" % [uid, str(ax), str(u.position), match_str]
|
||||
)
|
||||
"queue":
|
||||
var queue_json: String = JSON.stringify({
|
||||
"SetProduction": {
|
||||
|
|
@ -302,10 +317,18 @@ static func _replay_learned_actions(action_log: Array, player: RefCounted) -> in
|
|||
dropped_variants.append(String(entry.get("variant", "?")))
|
||||
_:
|
||||
dropped_variants.append(kind)
|
||||
print("[p1-29k] replay applied=%d (move/attack/queue dispatched into GDScript)" % applied)
|
||||
if not parity_samples.is_empty():
|
||||
print("[p1-29k] position_parity: %s" % str(parity_samples))
|
||||
if deferred_founds > 0:
|
||||
print("[p1-29k] DEFERRED %d FoundCity action(s) to Inc-3 (p1-29j boundary)" % deferred_founds)
|
||||
if not dropped_variants.is_empty():
|
||||
print("[p1-29k] dropped %d uncovered variant(s): %s" % [dropped_variants.size(), str(dropped_variants)])
|
||||
# Summarize dropped-variant counts rather than dumping the full toggle
|
||||
# storm (the policy oscillates Fortify↔Unfortify — see Inc-2 report).
|
||||
var dropped_counts: Dictionary = {}
|
||||
for v: String in dropped_variants:
|
||||
dropped_counts[v] = int(dropped_counts.get(v, 0)) + 1
|
||||
print("[p1-29k] dropped %d uncovered action(s): %s" % [dropped_variants.size(), str(dropped_counts)])
|
||||
return applied
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue