            current={r['serial']:r['owner'] for r in data['initial']};history=[{**r,'status':'active'} for r in data['initial']]
            def propose_replacement(ledger,old,new,owner):
                if ledger.get(old)!=owner:raise ValueError('old owner mismatch')
                if new in ledger:raise ValueError('new serial already assigned')
                candidate=copy.deepcopy(ledger);candidate.pop(old);candidate[new]=owner;return candidate
            for change in output['changes']:
                old,new,owner=change['old_serial'],change['new_serial'],change['owner'];check('旧设备归属匹配',current.get(old)==owner);check('新序列号当前无归属',new not in current)
                current=propose_replacement(current,old,new,owner)
                for row in history:
                    if row['serial']==old:row['status']='returned-review'
                history.append({'serial':new,'owner':owner,'status':'active'})
            check('SN-01历史保留而非删除',len(history)==3 and history[0]['status']=='returned-review');check('新SN-03当前归C1',current=={'SN-02':'C2','SN-03':'C1'})
            before=copy.deepcopy(current);rejected=False
            try:propose_replacement(current,'SN-03','SN-02','C1')
            except ValueError:rejected=True
            check('已分配SN-02的反例被拒且原归属不改',rejected and current==before);cout('device-history.csv',history);result={'current':current,'history':history}
