"""Contract guards for timing, frozen-source coverage and production readiness.""" import sys from pathlib import Path import unittest ROOT=Path(__file__).resolve().parents[2] sys.path.insert(0,str(ROOT/'Tools')) from validate_skill_design import load,validate class SkillDesignTests(unittest.TestCase): def setUp(self): self.data=[load(ROOT/p) for p in ['Config/Combat/skill_system_v1.proposal.json', 'Config/Combat/skill_presentations_v1.proposal.json','Doc/Design/Sound/BattleSkills/manifest.json', 'Config/Gameplay/greenfield.json']] def test_covers_current_actors_without_claiming_runtime(self): r=validate(*self.data) self.assertEqual(r['skills'],len(self.data[3]['pets'])*2+len(self.data[3]['enemies'])) self.assertFalse(r['runtimeIntegrated']);self.assertFalse(r['generatedAudio']) def test_missing_actor_or_wrong_skill_kind_is_rejected(self): self.data[0]['skills'].pop() with self.assertRaisesRegex(ValueError,'coverage'):validate(*self.data) self.setUp();self.data[0]['skills'][1]['template']='ability_heal' with self.assertRaisesRegex(ValueError,'semantics'):validate(*self.data) def test_animation_and_cooldown_conflicts_are_rejected(self): skill=next(s for s in self.data[0]['skills'] if s['id']=='pet.1.basic') skill['timing']=dict(releaseTicks=11,recoveryTicks=11) with self.assertRaisesRegex(ValueError,'cooldown'):validate(*self.data) skill['timing']=dict(releaseTicks=2,recoveryTicks=16) with self.assertRaisesRegex(ValueError,'marker'):validate(*self.data) def test_missing_resource_cannot_claim_ready(self): asset=next(a for a in self.data[1]['assets'] if a['status']=='planned') asset['status']='existing' with self.assertRaisesRegex(ValueError,'missing'):validate(*self.data) def test_unresolved_cue_and_invalid_audio_request_are_rejected(self): self.data[1]['profiles'][0]['bindings']['HitResolved'][0]['asset']='missing' with self.assertRaisesRegex(ValueError,'Unresolved'):validate(*self.data) self.setUp();self.data[2]['items'][0]['duration']=.5 with self.assertRaisesRegex(ValueError,'1..30'):validate(*self.data) def test_actions_compose_but_cannot_repeat_an_action_id(self): t=self.data[0]['templates'][0] t['actions'].append({**t['actions'][0],'id':'additional_hit'}) validate(*self.data) t['actions'][1]['id']=t['actions'][0]['id'] with self.assertRaisesRegex(ValueError,'Duplicate logical action'):validate(*self.data) def test_model_forward_does_not_force_world_direction(self): self.data[1]['anchorPolicy']['worldFacing']='fixed_world_minus_z' with self.assertRaisesRegex(ValueError,'world facing'):validate(*self.data) if __name__=='__main__':unittest.main()