Skip to content

回归别再落到生产端口段;1999 那一项改打常规作战 - #11

Merged
qiyinxi merged 12 commits into
ModAVD:mainfrom
qiyinxi:fix/e2e-tools-038
Nov 6, 2026
Merged

qiyinxi merged 12 commits into
ModAVD:mainfrom
qiyinxi:fix/e2e-tools-038

Conversation

@qiyinxi

@qiyinxi qiyinxi commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

0.38 发版回归撞到的两件事(第 1、2 节),11-05 用户定的「只用 testbed」(第 3 节),11-06 在 testbed 的 flow-a 上实跑撞到的四处(第 4 节),以及审查后改的(第 5 节)。

1. 回归别再落到生产端口段

  • 管理器必须给:regress.ps1 不传 -Manager 时用了本机配置里留着的旧管理器(0.2.0,不认 portBase),测试根的 0 号实例开到了生产在用的 20000 段(同机生产实例占 20000–20049)。现在 -Manager 必须给,不再从本机配置取;单独跑某一项要先设 MODAVD_REGRESS_MANAGER(items\common.ps1 的 Get-ManagerDir,用到时才报错,不用管理器的项不受影响)。本机配置的 Manager 键删掉了。
  • 开机前核对 port_base:新函数 Assert-ManagerPortBase 跑 modavd --root <测试根> --json list(ModAVDManager 0.3.1 起带 port_base)。没有这个字段(旧版)、和 mas-avd.json 的 portBase 不一致、是 20000,都停下不开机,报出管理器路径、版本和看到的 port_base。Set-RootSdk(bridge、bridge-default、datadisk、yys 经它)和 Resolve-PortBase(upgrade、ime-pkg 经它)都调它;原来「这版 modavd 还不认 portBase,实例在 20000 段上」只记一笔的,现在直接停。
  • 星铁端口移出 20000 段:items\game-real.ps1 里星铁的控制台端口写死成 20040,改成 20120(0.38 回归 S7 / A9 就是在 20120 上跑的)。四个游戏的端口可以用本机配置 GamePorts(如 @{ sr = 20130 })覆盖;控制台端口和 +1、+2 落在 20000–20049,或碰 5037、20049、20050,就停(items\port-guard.ps1,-ReJudge 不查)。
  • README.md / README.en.md、local.example.psd1 跟着改。

2. 1999 那一项改打常规作战,没打到战斗就不算过

  • M9A 4.11.1 的「智能均衡刷材料」自己报错(KeyError 'name'),选不出关卡就「成功」退出;以前回归里「刷材料 0.6 分钟就结束」的那几次其实没打(0.38 回归查出来的)。
  • 驱动(维护者本机 Kit 里的 m9a_run411_load.py,不在本仓库)改打常规作战的资源本「尘埃运动 06」,选项和 0.38 回归测到战斗帧率的那次相同;点名要智能均衡刷材料时直接拒绝。
  • 判法:认「常规作战」那一行;不到 2 分钟就结束、又不是到时间停的,判成没打到战斗、不通过(0.38:没体力时 0.4–0.6 分钟,吃两次糖打完是 3.4 分钟)。
  • 吃糖原来在驱动里写死成不吃,改成参数:game-real.ps1 -M9ACandy <次数>(0–10,默认 0 不吃),传给驱动的 M9A_CANDY。套件里没改默认,要不要在发版回归里吃糖由维护者定。
  • -ReJudge 不再建指向 SDK 的目录联接(重判用不着,Linux 上也建不了)。

测试

  • 新加 tests/tooling-guards.ps1(33 项):没给 -Manager 时 regress.ps1 报错(环境变量和本机配置里放了也一样);Get-ManagerDir 没环境变量时报错;port_base 核对的四种情况(没字段 / 不一致 / 20000 / 正常)和 Resolve-PortBase;端口守卫拦住 20000、20040、20047–20050、5036、5037,放过 20051、20072、20096、20100、20120;Set-RootSdk、Resolve-PortBase、Sync-RootTools 确实调了核对。取 JSON 那一步换成假的,不调真的 modavd。
  • 新加 tests/m9a-verdict.ps1(18 项):用 -ReJudge 按造好的驱动输出重判,覆盖没体力 0.6 分钟、打完 3.4 分钟、到时间停(长短两种)、常规作战失败、旧任务的输出、启动游戏没成功。
  • 两个都加进了 CI;原有的 created-disk-usage(21 项)、upgrade-version(115 项)、qemu-ownership(481 项)都过;所有 .ps1 / .psd1 解析 0 错;改过的脚本查过没有只差大小写的变量名。
  • 变异检查:端口这一半 15 处(-Manager 和环境变量的两道 throw、20000 判断、不一致判断、$Want 判断、各处调用去掉、守卫上下界和 5037 / 20049 / 20050、去掉 +1 +2、星铁端口改回 20040、GamePorts 键名),1999 这一半 5 处(不拦不到 2 分钟的、到时间停也按时长判、还认旧任务、失败也当过、不传吃糖),都被测试抓住。
  • 驱动本身在本机用 M9A_PLAN_ONLY=1(只解析任务和选项,不连模拟器)跑过:不吃糖、吃 2 次糖两种选项解析和 0.38 那次一致;M9A_CANDY 写错、点名智能均衡刷材料都拒绝。实机跑一轮等这一批一起上机。

3. 只用 testbed 里已有的测试根,明确拒绝生产根目录(第四个提交)

11-05 用户定:testbed 里只有三组模拟器(开发 / 测试的 flow-a、flow-b,用户自己的一组),不可以去别的地方新建;生产在 D 盘、测试全在 E 盘,所以不再用「只许某个目录」的白名单,改成明确拒绝生产。

  • 拒绝生产:local.ps1 新加 Assert-NotProduction、Assert-NotProductionPort。生产根目录取本机配置 ProductionRoots(默认 D:\ModAVD;不分大小写,\ 和 / 都认,下面的目录也算),生产端口 5037、20049、20050。regress.ps1 的输出不再必须在 TempRoot 下,只是不能在生产根目录下;开跑前先核本机配置的 TestRoot / PackageRoot。
  • 只认已有的根目录:common.ps1 的 Resolve-TestRoot 要求有 mas-avd.json(没有就停,不新建),拒绝生产根目录和用生产端口的根。bridge、bridge-default、datadisk、yys 的 TestRoot 都经过它。
  • 装包类的项不再搭根:upgrade、ime-pkg 在 PackageRoot(新的本机配置键,没有就用 TestRoot)上先装包(升级先装回上一版),建临时实例(8、9 号,要空着、根下不能有在跑的模拟器),测完只删实例,根目录停在新包上,结论里写测之前、测之后各是哪一版。换包用新的 Install-Package:先删掉旧包清单里有、新包清单里没有的文件,再整个覆盖;avd、logs、mas-avd.json 不动;包没有清单时只覆盖。OfficialSdk 不再用到,从配置里拿掉。
  • created-disk-usage 的 Create 也改成在已有测试根里建测量实例(-Root,要求根目录已经是 -Package 那一版),不再复制包和 SDK 另搭根;docs/created-disk-usage.md 跟着改。

测试:新加 tests/root-guards.ps1(37 项,CI 里跑):生产根目录(各种写法)、ProductionRoots 可改、生产端口、没有 mas-avd.json 的目录不新建、测试根的 adb 端口是 20049 被拒、换包只删旧包独有的文件、不动实例和配置;upgrade、ime-pkg、created-disk-usage、bridge、datadisk 拿生产根目录当测试根时一开始就停、不建工作目录(这一段用临时目录里造的假生产根,绝不把真的 D:\ModAVD 传给脚本)。upgrade-version 测试改成传已有的测试根,24 个场景 115 项照旧全过;其余测试都过;解析 0 错,变量名无大小写撞名。变异检查(去掉各处守卫的 14 个变体)全部被抓住,见下面「测试碰到生产根目录」一节。

测试碰到生产根目录(11-05 22:07,已修)

  • 几点、碰了什么:11-05 22:07:50 给 tests/root-guards.ps1 做变异检查时,「created-disk-usage 不解析测试根」那个变体拿 D:\ModAVD 当测试根,跑了生产里的 modavd.exe --root D:\ModAVD --json list(只读查询,被 port_base 是 20000 那道核对拦住),更新了生产 avd\ 下 5 个 0 字节锁文件 .mas_0–.mas_4.bridge.lock 的修改时间。mas-avd.json、tools\、实例都没变,当时生产没有实例开着;那几个锁文件原样留着。
  • 为什么:测试的子进程那段把真的 D:\ModAVD 交给了被测脚本;守卫一被去掉,脚本就照常往下走,真去碰生产。
  • 怎么修的:测试里一律用临时目录。「默认是 D:\ModAVD」只比字符串、不读盘;其余凡是生产根目录都是临时目录里造的假根(用 ProductionRoots 指过去);管理器、随包脚本指到临时目录里不存在的路径,没有真程序可跑;最后核对假生产根里每个文件前后都没变。变异检查改在 worktree 的沙盒副本里改、在副本里跑:去掉守卫的 14 个变体全部被抓住,跑前跑后 D:\ModAVD\avd 的元数据完全相同。

4. 在 testbed 的根上实跑撞到的四处(11-06,后四个提交)

  • Set-RootSdk 认没有 sdkRoot 的根(0d4d013,开跑前读代码发现的):testbed 的根是整包装出来的,mas-avd.json 里没有 sdkRoot(用根下的 sdk\)。以前遇到这种根直接报「没有 sdkRoot」,bridge、bridge-default、datadisk、yys 在 testbed 上一开始就停。现在没有这个键时加在开头的 { 后面(换行、缩进跟着文件),返回 $null;换回时传 $null 整行删掉,管理器中途改写过、把它挪成最后一个键也认。原来就有的照旧只换值,原来是 "" 的换回 ""。参数不再是 [string](那样 $null 会变成 "",加的键就删不掉)。
    • 新测试 tests/root-sdk.ps1(35 项,CI 里跑):LF、CRLF、一行、空对象、管理器改写后在最后,换回后逐字节相同;中间状态用严格的 System.Text.Json 解析(管理器的 Go 不认多余的逗号,ConvertFrom-Json 认)。变异 12 处全抓住。
  • 游戏实例名可以改,实例目录不许在生产根目录下(b023ac2):testbed 的根里实例按编号叫 mas_<号>,game-real 写死的 mas_6 / mas_7 / gfx_t2 / endfield 对不上。本机配置新加 GameAvds(如 @{ r1999 = 'mas_1' }),名字只认字母、数字、_ . -。这一项绕过管理器直接用启动器开机,GameAvdHome / SrAvdHome 写错成生产的就会开到生产的实例,所以开机前核实例目录,在生产根目录下就停(-ReJudge 不查)。
    • root-guards 加两种(实例目录在假的生产根目录下、实例名带路径),都在建输出目录之前停,假生产根里的文件前后不变(现在 42 项);tooling-guards 核 game-real 读 GameAvds。变异 4 处全抓住。
  • 1999 那一项按打了几次判,不按时长(3c7ee91):第一次实跑体力 32、一次 25,M9A 复现 1 次(39 秒)就结束,常规作战 1.1 分钟,第 2 节「不到 2 分钟算没打」把它判成了没打到战斗,其实打了一次。驱动(本机 Kit,不在本仓库)现在从 M9A 自己的日志读打了几次,打出 combat rounds: N 和 stamina: 开始 -> 结束 (stage 一次);这里按次数判:0 次算没打(到时间停了也没打完一次的同样算),1 次以上算打了,结论里写次数和体力。旧驱动没有这一行、或驱动找不到 M9A 的日志(unknown)时才照旧按时长判。
    • m9a-verdict 加 6 种(只够打一次、0 次、0 次但用了 4 分钟、到时间停 0 次、到时间停打了 9 次、unknown),共 30 项;变异 7 处全抓住。
  • ime-pkg:测试根自己的 adb server 开着不算占端口(e7897c9):第 3 节改成在已有测试根上跑以后,ime-pkg 用的是测试根自己的 adb server 端口,开跑前的检查却还把这两个端口算进「被占用」。测试根的 adb server 只要前一项开过机就一直在,所以先跑 upgrade、再跑 ime-pkg 时必然停在「端口已被占用:31099」(实跑就是这样撞到的)。现在实例自己的三个端口照旧要空着;adb server 的两个端口只要是测试根自己的 sdk\platform-tools\adb.exe 占着就放过,别的程序(或取不到路径的)占着才停。判断写成纯函数 Get-PortConflicts(items\port-guard.ps1)。
    • tooling-guards 加 9 项(共 43 项):自己的 adb 不算(大小写、没规范化的路径也认)、别的根的 adb 算、取不到路径的算、实例端口谁占着都算、排序去重、范围外的不算、ime-pkg 真的调了它。变异 8 处全抓住。

5. 审查后改的(eb0f4f4、7623f20)

  • P2:ProductionRoots 在 D:\ModAVD 之外再加,不再替换它。 以前只写用户自己的根(比如 fsync-user)时,D:\ModAVD 就不在名单里了,生产反而没人拦。现在 D:\ModAVD 总是算;用户自己日常用的根也写进 ProductionRoots,local.example.psd1、README 写清。
  • 新的可选键 TestRoots:写了就只认列出来的测试根本身(Resolve-TestRoot、Install-Package、regress.ps1 开跑前都查),没写就和原来一样只拒绝生产。维护者机器上写 flow-a、flow-b。
  • P2:created-disk-usage 的 create 根本没跑。 Save-State Run-Modavd @('create', …) 两条语句并成了一行,PowerShell 把后一条当成 Save-State 的参数。拆开;ime-pkg、upgrade 末尾的 }$summary = … 也拆开。
  • P3:
    • Resolve-TestRoot 要求 mas-avd.json 写了 adbServerPort、scriptAdbServerPort:没写时管理器用生产的 20050 / 20049。
    • Install-Package 先核完整张要删的清单再删:带 ..、绝对路径、列了 avd\、logs\、mas-avd.json 的,一个文件都不删就停。
    • regress.ps1 开跑前也查 GameAvdHome、SrAvdHome、ImeAvdHome 不在生产根目录下;ime-reg.ps1 自己也查 ImeAvdHome 和 -Out。
  • 测试:
    • root-guards 42 → 90 项:
      • ProductionRoots 取并集,配了以后 D:\ModAVD 照样被拒(只比字符串),配进去的用户的根被拒,写成一个字符串也认;
      • TestRoots 列了的认,没列的、列了的根下面的目录都拒,不往没列的根装包;
      • 缺 adb 端口键的根被拒;清单写错的 8 种都不删文件就停;
      • 子进程名单加上 bridge-default、yys;upgrade、ime-pkg、fetch、created-disk-usage 的 -Work 和 ime-reg 的 -Out 落在假生产根下都停;ime-reg 的 ImeAvdHome 在假生产根下也停。
    • tooling-guards 43 → 50 项:
      • 端口加 19998、5035(只有 +2 会碰到);
      • regress.ps1 开跑前的几道核对,静态看:真跑要一个管理器目录,测试里不造假 exe;
      • 「两条语句并成一行」的检查:脚本自己的函数后面跟着另一个函数名当裸参数,或者 }$x = …。
    • 子进程报错按控制台宽度折行、带 ANSI 颜色码(Linux CI 上)时也认得出:root-guards 先去掉颜色码、把输出拼回一行再比,这个小工具本身也有 2 项测试(7623f20,eb0f4f4 的 CI 就是挂在这里)。
    • 其余 5 套测试照旧全过,解析 0 错。
  • 变异检查 24 处,全部抓住,每一处都核过是该拦的那一条检查失败的:
    • ProductionRoots 改回替换语义、去掉默认根;
    • TestRoots:不查、认根下面的目录、Resolve-TestRoot 不调、Install-Package 不调;
    • adb 端口键可以不写;
    • Install-Package:删 avd\、边核边删、不拦 ..;
    • regress.ps1:不查实例目录、不查 TestRoots、不查 -Out;
    • ime-reg:不查 ImeAvdHome、不查 -Out;
    • created-disk-usage、ime-pkg、upgrade 又并回一行;
    • 端口守卫去掉 +2;
    • bridge-default、yys 不经 Resolve-TestRoot;
    • upgrade、fetch、created-disk-usage 不查 -Work。
    • 都在去掉 .git 的副本里改、在副本里跑,跑前跑后 D:\ModAVD\avd 的元数据完全相同。

实跑(11-06,E:\testbed\flow-a,SDK 和管理器用 flow-a 自己的 0.38.1 / 0.4.1)

前三行同机另有一台测试模拟器(flow-b),后三行没有别的。

项 结果 看到的
regress.ps1 -Only bridge-default 通过(508 秒) -Manager 必须给、port_base 核对(flow-a 是 31000)、Resolve-TestRoot 都过;sdkRoot 临时加上、管理器照常读;新建有开机标记、第一次开机 34 秒装好桥、冷启动走 asg、modavd bridge 卸 / 装都对;临时实例删掉,flow-a 的 mas-avd.json 和跑之前逐字节相同
regress.ps1 -Only r1999(旧驱动、不吃糖) 不通过 常规作战「尘埃运动 06」复现 1 次、1.1 分钟结束,按时长误判成没打——就是上面第三处
game-real.ps1 -Game r1999 -M9ACandy 1 -Minutes 8(新驱动) 驱动判过;整项不通过 吃 1 次糖、combat rounds: 2、体力 9 → 19,判成「打了 2 次,1.7 分钟」(按旧判法同样会误判)。整项没过是帧率:47.0 比 0.37.0 基准 58.1 低 19%,但这一轮总共 2.9 分钟、大半是启动和菜单,基准是 15 分钟连续战斗,比不了
upgrade.ps1 -Prev 0.38.0 -Next 0.38.1(PackageRoot = flow-a) 通过(5.5 分钟) 按包根清单装回 0.38.0(删掉 0 个文件),临时 8 号用旧版建、开机、写标记;覆盖 0.38.1 后标记都在、64 GB 盘改大到 80 GB 扩满、升级后第一次开机自己装好桥、输入法和包里的逐字节相同;8 号删掉,flow-a 回到 0.38.1,mas-avd.json、原有两台实例的配置都没变
ime-pkg.ps1 -Package 0.38.1(紧接着 upgrade,3c7ee91) 不通过 开跑前停在「端口已被占用:31099」——占着的是 flow-a 自己的 adb server,就是上面第四处
ime-pkg.ps1 -Package 0.38.1(e7897c9) 通过(5.3 分钟) flow-a 自己的 adb server 照旧开着时放过;a 第一次开机 31 秒装上正式签名的输入法、设为默认、标记在;b 带窗口通道 20 项全过;c 换成开发签名的再开机换回正式签名,再开一次不变;9 号删掉,flow-a 还是 0.38.1
  • emu_monitor 新的三列(vram_adapter_mb、gpu_committed_mb、gpu_local_mb)两次实跑每行都有值。
  • 两处原来就这样、不是这次改出来的:采样脚本找不到启动器写的模拟器日志和 logcat(no-emu-log;game-real 自己另扫这两份日志,崩溃、vkerr 照样计);1999 是 x86_64 游戏,gltransport 是 pipe(11-05 和 0.38 回归一样)。
  • 体力只够打一两次时,这一项的帧率没有可比性;发版回归要不要默认吃糖(-M9ACandy)由维护者定。
  • 没实跑的:星铁(20120 端口、GamePorts)现在 testbed 里还没有星铁实例,只有单测;bridge、datadisk、yys 这次只多了 Resolve-TestRoot、工作目录的生产守卫,走的是和 bridge-default 同一个 Set-RootSdk,有单测,没另跑。

0.38 回归撞到两次:

- regress.ps1 不传 -Manager 时用了本机配置里留着的旧管理器(0.2.0,不认 portBase),
  测试根的实例开到了生产的 20000 段。现在 -Manager 必须给、不从本机配置取;单独跑某一项
  要设 MODAVD_REGRESS_MANAGER。开测试根的实例前用 modavd list --json 核对 port_base:
  没有这个字段(旧版)、和 mas-avd.json 的 portBase 不一致、是 20000,都停下不开机。
- game-real.ps1 把星铁的控制台端口写死成 20040(生产段)。改成 20120,四个游戏的端口
  可以用本机配置 GamePorts 覆盖;控制台端口和 +1、+2 落在 20000–20049 或碰 5037、
  20049、20050 就停。

tests/tooling-guards.ps1 覆盖这几道守卫,CI 里跑。
M9A 4.11.1 的「智能均衡刷材料」自己报错(KeyError 'name'),选不出关卡就「成功」退出,
以前回归里 0.6 分钟就结束的那几次其实没打。驱动(Kit 的 m9a_run411_load.py)改打常规作战的
资源本;常规作战不到 2 分钟就结束、又不是到时间停的,判成没打到战斗。体力不够时吃不吃糖由
-M9ACandy <次数> 定(传给驱动的 M9A_CANDY,默认 0 不吃)。-ReJudge 不再建指向 SDK 的目录联接。

tests/m9a-verdict.ps1 用 -ReJudge 按造好的驱动输出重判,CI 里跑。
GitHub 的 pwsh 步骤拿最后的 $LASTEXITCODE 当退出码,而 tooling-guards 最后调的是故意失败的
regress.ps1,33 项全过也被判失败。m9a-verdict 在 Linux 上跑 game-real -ReJudge,原来的
Join-Path $env:LOCALAPPDATA 碰到空值会停。
11-05 用户定:testbed 里只有三组模拟器,不可以去别的地方新建。生产在 D 盘、测试全在 E 盘,
所以不再用「只许某个目录」的白名单,改成明确拒绝生产。

- local.ps1:Assert-NotProduction / Assert-NotProductionPort。生产根目录取本机配置
  ProductionRoots(默认 D:\ModAVD,不分大小写、\ 和 / 都认),生产端口 5037、20049、20050。
- regress.ps1:输出不再必须在 TempRoot 下,只是不能在生产根目录下;开跑前先核本机配置的
  TestRoot / PackageRoot。
- common.ps1:Resolve-TestRoot 只认已有的根目录(有 mas-avd.json),拒绝生产根目录和生产端口;
  Install-Package 按两边的包根清单换包(先删旧包独有的文件再覆盖,avd、logs、mas-avd.json 不动)。
- bridge、bridge-default、datadisk、yys 的 TestRoot 都经过 Resolve-TestRoot。
- upgrade、ime-pkg 不再自己搭根目录:在 PackageRoot(没有就 TestRoot)上先装包(升级先装回上一版),
  建临时实例,测完只删实例,根目录停在新包上。created-disk-usage 的 Create 也改成在已有测试根里建实例。
- 新测试 tests/root-guards.ps1(37 项),CI 里跑;upgrade-version 测试改成传已有的测试根。
上一版把真的 D:\ModAVD 交给了被测脚本,变异检查去掉守卫时脚本跑了生产里的 modavd.exe list。
现在只在最前面拿 D:\ModAVD 比字符串;其余凡是生产根目录都是临时目录里造的假根(ProductionRoots
指过去),管理器、随包脚本指到不存在的路径,最后核对假生产根里的文件前后都没变。
- upgrade.ps1:说明用「在已有测试根上做」的版本,加上 ModAVD#10 的判法;ModAVD#10 的 SDK 模式代码照搬。
- upgrade-version 测试:ModAVD#10 的新场景照搬,调用改成传已有的测试根。
- 本机配置示例、README:去掉不再用到的 OfficialSdk,留下 ModAVD#12 的 ComponentCache;README 加上 fetch 那一行。
- fetch.ps1:工作目录也不能在生产根目录下。
testbed 的 flow-a / flow-b 是整包装出来的根目录,mas-avd.json 里没有 sdkRoot(用根目录下的 sdk\)。
Set-RootSdk 以前遇到这种根直接报「没有 sdkRoot」,bridge、bridge-default、datadisk、yys 在 testbed 上一开始就停。

现在没有这个键时在开头的「{」后面加上(换行和缩进跟着文件),返回 $null;换回时传 $null 把它整行删掉,
管理器中途改写过 mas-avd.json、把它挪成最后一个键也认。原来就有的照旧只换值,原来是 "" 的换回 ""。
各项把返回值原样传回去,参数不再是 [string](那样 $null 会变成 "",加的键就删不掉)。

新测试 tests/root-sdk.ps1(35 项,CI 里跑):LF / CRLF / 一行 / 空对象 / 管理器改写后在最后,
换回后逐字节相同,中间状态用严格的 JSON 解析(管理器的 Go 不认多余的逗号);变异 12 处全抓住。
testbed 的根里实例按编号叫 mas_<号>,game-real 写死的 mas_6 / mas_7 / gfx_t2 / endfield 对不上。
本机配置新加 GameAvds(比如 @{ r1999 = 'mas_1' }),只写要改的游戏;名字只认字母、数字、_ . -,带路径的就停。

这一项绕过管理器直接用启动器开机,GameAvdHome / SrAvdHome 以后指到 testbed,写错成生产的会开到生产的实例:
开机前用 Assert-NotProduction 核实例目录,在生产根目录下就停(-ReJudge 不查)。

测试:root-guards 加两种(实例目录在假的生产根目录下、实例名带路径),都在建输出目录之前停,
假生产根里的文件前后不变;tooling-guards 核 game-real 读 GameAvds。变异 4 处全抓住。
local.example.psd1、README 跟着改。
11-06 在 testbed 上实跑:体力 32、一次 25,M9A 复现 1 次(39 秒)就结束,常规作战 1.1 分钟,
按「不到 2 分钟算没打」判成了没打到战斗,其实打了一次。

驱动(维护者本机 Kit 的 m9a_run411_load.py,不在本仓库)11-06 起从 M9A 自己的日志里读打了几次,
打出「combat rounds: N」和「stamina: 开始 -> 结束 (stage 一次)」。这里按次数判:0 次算没打到战斗
(到时间停了也没打完一次的同样算),1 次以上算打了,结论里写次数和体力。
旧驱动没有这一行、或驱动找不到 M9A 的日志(unknown)时才照旧按时长判。

测试:m9a-verdict 加 6 种(只够打一次、0 次、0 次但用了 4 分钟、到时间停 0 次、到时间停打了 9 次、unknown),
共 30 项;变异 7 处全抓住。
改在已有的测试根上跑以后,ime-pkg 用的是测试根自己的 adb server 端口,开跑前的检查却还把这两个端口算进「被占用」。
测试根的 adb server 只要前一项开过机就一直在,发版回归里先跑 upgrade、再跑 ime-pkg 就必然停在「端口已被占用」。
11-06 在 testbed 上实跑 upgrade 后接着跑 ime-pkg 撞到。

现在实例自己的三个端口照旧要空着;adb server 的两个端口只要是测试根自己的 adb.exe 占着就放过,别的程序(或取不到路径的)
占着才停。判断写成纯函数 Get-PortConflicts(port-guard.ps1),tooling-guards 加 9 项。
审查意见(P2 两条,P3 一并改):

- ProductionRoots 改成在 D:\ModAVD 之外再加(取并集),不再替换它:以前只写用户自己的根(fsync-user)时,生产反而没人拦了。
  用户自己日常用的根也写进 ProductionRoots,local.example.psd1、README 写清。
- 新的可选键 TestRoots:写了就只认列出来的测试根本身(Resolve-TestRoot、Install-Package、regress.ps1 开跑前都查),
  没写就和原来一样只拒绝生产。
- created-disk-usage:`Save-State    Run-Modavd @('create', …)` 两条语句并成了一行,create 根本没跑(PowerShell 把后一条
  当成 Save-State 的参数),拆开。ime-pkg、upgrade 末尾的 `}$summary = …` 也拆开。
- Resolve-TestRoot 要求 mas-avd.json 写了 adbServerPort、scriptAdbServerPort(没写时管理器用生产的 20050 / 20049)。
- Install-Package 先核完整张要删的清单再删:带 ..、绝对路径、列了 avd\、logs\、mas-avd.json 的,一个文件都不删就停。
- regress.ps1 开跑前也查 GameAvdHome、SrAvdHome、ImeAvdHome 不在生产根目录下;ime-reg.ps1 自己也查 ImeAvdHome 和 -Out。

测试:
- root-guards 42 → 88 项:
  - 配了 ProductionRoots 以后 D:\ModAVD 照样被拒(只比字符串),配进去的用户的根被拒,写成一个字符串也认;
  - TestRoots 列了的认、没列的和列了的根下面的目录都拒、不往没列的根装包;
  - 缺 adb 端口键的根被拒;清单写错的 8 种都不删文件就停;
  - 子进程名单加上 bridge-default、yys;upgrade、ime-pkg、fetch、created-disk-usage 的 -Work 和 ime-reg 的 -Out 落在
    假生产根下都停;ime-reg 的 ImeAvdHome 在假生产根下也停。
- tooling-guards 43 → 50 项:
  - 端口加 19998、5035(只有 +2 会碰到);regress.ps1 开跑前的几道核对;
  - 两条语句并成一行的检查:脚本自己的函数后面跟着另一个函数名当裸参数,或者 `}$x = …`。
- 子进程报错按控制台宽度折行时也认得出(root-guards 先把输出拼回一行再比)。
@qiyinxi
qiyinxi merged commit 2afef64 into ModAVD:main Nov 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant