from pathlib import Path import json,hashlib base=Path(__file__).resolve().parent folder=base.parent root=folder.parents[1] def sha(p):return hashlib.sha256(p.read_bytes()).hexdigest().upper() source=base/'pf-source-backups/20260924T041802Z/102.json' source_data=json.loads(source.read_text(encoding='utf-8'))['data'] empty=base/'backups/20260924T035000Z/102.json' assert json.loads(empty.read_text(encoding='utf-8'))['data']=={} manifest=dict(status='proposal-not-executed',api='http://s101.local:18080/',playerId='102',source=str(source.relative_to(root)).replace('\\','/'),sourceSha256=sha(source), emptyBaseline=str(empty.relative_to(root)).replace('\\','/'),emptyBaselineSha256=sha(empty), transformValues=False,writeCount=len(source_data),entries=[dict(key=k,before='absent',utf8Bytes=len(v.encode('utf-8')),valueSha256=hashlib.sha256(v.encode('utf-8')).hexdigest().upper()) for k,v in sorted(source_data.items())], restoreDeleteKeys=sorted(source_data),requireFreshEmptyGet=True,automaticRetry=False,restoreExecuted=False) (base/'102-import-proposal.json').write_text(json.dumps(manifest,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') review=json.loads((base/'checkpoint2-review-input-hashes.json').read_text(encoding='utf-8')) changes=[dict(path=x['path'],before=x['sha256'],after=sha(root/x['path'])) for x in review['files'] if sha(root/x['path'])!=x['sha256']] expected={'Client/Assets/Scripts/Stages/LoginStage.cs','Client/Assets/Scripts/Services/UserService.KVGameplayLoop.cs','Client/Assets/Editor/KVGameplayLoopSetup.cs','CodexOutput/upserver/KVGameplayLoopTests/Preflight/Program.cs'} assert {x['path'] for x in changes}==expected,changes (base/'supplement-source-audit.json').write_text(json.dumps(dict(changedReviewedInputs=changes,newPreflightHelper='Preflight/PFSourceBackup.cs',schemaUnchanged=True),ensure_ascii=False,indent=2)+'\n',encoding='utf-8') record=''' ## 补充检查点2:M24/V-1完成,102实际来源已查清 固定equipment-chain最终9组28断言通过(supplement-equipment-verified.json),正式请求0、finally恢复成功;M24试验的cfg.Tables前置与GContext抽象方法编译遗漏已修正,首败全部保留。原Unity B3A 34/B2-20 83断言及许可15断言通过。新增Schema只读预检后的最终编译0错误273警告;本轮无CLI安全级别变更、无PlayMode、无打包。对比81项旧受审输入,仅3个批准源码及Preflight/Program.cs改变;新加PFSourceBackup.cs只读工具。Schema、31模块算法和底层均未改。 选择102作为最小候选:PF源45键,源文件SHA256 827F36084648449CEFAFB96B3CE62093DF70B8A87E33A526DA5B03A9C135A377;有20001/30003两根已有鱼竿,当前装备20001。101源55键需3处兼容,102只需1处。只读预检报告102 M04字段5 Malformed,根因VIPAdPackData.cdTime为正常业务产生的JSON null,而Schema.Advert强制String。没有改原档、清字段或放宽Schema。 完整单方法修订设计及102原45键导入/Unknown核对/精确恢复方案已落盘《阶段4最小真实玩法闭环-102数据准备与cdTime最小兼容方案-待审-2026-09-24.md》;机器清单102-import-proposal.json包含每键字节数/摘要/前值缺失及精确恢复集合,尚未执行。新Schema差异不在R1当前白名单,送这一处必要独立补审;不重审M24,不称R1关闭。本轮新增PF身份+合并UserData只读请求2次;s101成功请求累计仍为4,KV/PF写均0。 ''' for name in ['阶段4最小真实玩法闭环实施记录-2026-09-24.md','开发日志.md']: with (folder/name).open('a',encoding='utf-8') as f:f.write(record) entry='''## 当前有效状态:M24与V-1已完成;102原档一处cdTime兼容方案待审(2026-09-24) 补充独立审查81项hash一致,主会话已[逐条裁决](阶段4最小真实玩法闭环补充审查裁决-2026-09-24.md)。M24按批准范围完成登录期注册;固定编译宿主9组28断言通过并恢复,原B3A/31模块Unity回归及许可测试通过,未改CLI Restricted。R1真实闭环尚未完成。 已按用户101/102授权只读备份PF源并检查,来源不再未决:**选102现有45键,已有20001/30003鱼竿;唯一Schema错误是合法cdTime:null被严格字符串校验拒绝。** 101需要额外两类兼容,暂不选择。原KV空档、PF源与摘要保留,PF/KV写均0。 - [x] R1-C0、M24/V-1:补充裁决、注册、固定宿主及合成验证完成;不必再次审M24。 - [x] R1-数据准备:两账号PF只读备份/Schema诊断;确定102候选,45键摘要及恢复删除集合已列为proposal。 - [ ] **当前评审侧**:审[102数据与cdTime最小兼容方案](阶段4最小真实玩法闭环-102数据准备与cdTime最小兼容方案-待审-2026-09-24.md)(§5提示词),只批准一个Schema方法及具体数据准备范围。尚未修改Schema或导入数据。 - [ ] 主会话随后核hash/逐条裁决→局部兼容修订/专项回归→102导入前重新确认空KV→逐值导入核验→真实装备/重启恢复。 - [ ] V-4/R1-C3:真实身份发布、初始化所有写、关闭、UI装备与原票据、新进程恢复、独立实施复核及关闭,均未完成。 本轮游戏行为仅补M24注册;其余新增为固定合成测试和只读源预检,没有重构业务。最终编译0错误273警告,不因增量日志把工程称为零警告。运行许可不存在、未PlayMode、未打包。正式s101地址http://s101.local:18080/固定;Unity CLI Loop,不用UnitySkills。4B1/4B2/4B3A已关闭,整体4B3/G4、4C、热换号和P2-α真实迁移仍未通过。 ### 以下为历史快照(当前以本节为准) ''' for name in ['接手入口.md','开发状态.md','TODO.md']: p=folder/name;old=p.read_text(encoding='utf-8');head,rest=old.split('\n',1) if name!='接手入口.md':head='# '+('开发状态' if name=='开发状态.md' else 'TODO')+':R1接线与102存档兼容' p.write_text(head+'\n\n'+entry+rest.lstrip(),encoding='utf-8') p=folder/'阶段4B3当前TodoItem-2026-09-24.json';d=json.loads(p.read_text(encoding='utf-8')) d.update(phase='R1-M24-V1-complete-102-cdTime-supplement-awaiting-review',nextResponsibleSide='independent-reviewer-cdTime-and-102-import-proposal',gameplayEnabled=False,formalRequests=4,pfReadOnlyLoginRequests=2,kvWrites=0,pfWrites=0) d['implementationScope']='Original R1 and M24/fixed-host implemented; one Schema compatibility method pending review; real loop not verified' for item in d['todoItem']: if item['id']=='R1-M24-supplement':item.update(status='completed',detail='81项hash、M24/V1-4裁决,注册及固定9组28断言通过') if item['id']=='R1-data-source':item.update(status='prepared-awaiting-compatibility-review',detail='已只读备份PF101/102,选102原45键;一处合法null解码兼容待审,尚未导入') if item['id']=='R1-C1-C2':item.update(status='partially-complete',detail='M24和V-1已通过;真实档Schema兼容、真实加载/保存验收仍缺') d['todoItem'].append(dict(id='R1-cdTime-compatibility',status='awaiting-independent-review',detail='仅Advert.cdTime显式JSON null保留;原字符串与其他类型检查不变,102原档不改值')) p.write_text(json.dumps(d,ensure_ascii=False,indent=2)+'\n',encoding='utf-8') paths={x['path'] for x in review['files']} for name in ['阶段4最小真实玩法闭环最小补充独立审查-2026-09-24.md','阶段4最小真实玩法闭环补充审查裁决-2026-09-24.md','阶段4最小真实玩法闭环-102数据准备与cdTime最小兼容方案-待审-2026-09-24.md']: paths.add('CodexOutput/upserver/'+name) for name in ['Preflight/PFSourceBackup.cs','102-import-proposal.json','supplement-source-audit.json','supplement-equipment-verified.json','pf-source-schema.json','pf-source-backups/20260924T041802Z/102.json','backups/20260924T035000Z/102.json','source-inspection-compile.log']: paths.add('CodexOutput/upserver/KVGameplayLoopTests/'+name) files=[dict(path=p,sha256=sha(root/p)) for p in sorted(paths)] (base/'102-compatibility-review-hashes.json').write_text(json.dumps(dict(scope='One Advert nullable field and 102 original 45-key proposal; no import executed',files=files),ensure_ascii=False,indent=2)+'\n',encoding='utf-8') print(json.dumps(dict(sourceKeys=len(source_data),changedReviewedInputs=len(changes),reviewHashes=len(files),proposalOnly=True),ensure_ascii=False))