preview() 出镜前过 trace.RedactTextLimited(600 rune),覆盖失败日志的 chrome_output 与 withChromeOutput 追加给调用方的错误串;补凭据形状/原话可见/有界三条测试,删实现可打红。
依据 `DevDocs/reference/chromium-cdp/`(9 份实测+官方源码):旧姿势传 `--remote-debugging-port=0` 会被 Chromium 当成 ChromeDriver 式自动化启动 ⇒ 主动打开 `AutomationControlled` ⇒ `navigator.webdriver=true`;那个 bad-flag 是承重覆盖,但代价是**每次有头弹横幅**。 改用显式端口后 `webdriver` **本来就是 false** ⇒ flag 变纯冗余 ⇒ 去掉它,**两者兼得**。 - `launch.go`:`--remote-debugging-port=<我们选的端口>` 替掉 `=0`;**删掉** `--disable-blink-features=AutomationControlled`(注释写明理由)。 - 新增 `portrecord.go`:端口来源与落点的**唯一出处** —— 取空闲端口(`net.Listen` 取号后立刻关闭,**本进程不常驻监听**)、写/读/清**我们自己的记录** `<profile>/cyrene-debug-port`(选它与 Chrome 的 `DevToolsActivePort` 同目录: 天然按 profile 隔离、profile 换掉记录自动消失、内容只有端口号不含凭据); **兼容老记录**(换二进制时上一版起的浏览器可能还在跑 ⇒ 认不出会把"自己的浏览器" 误报成"profile 被别人占了");就绪判据换成「我们选的那个端口答得上 `/json/version`」; TOCTOU 处理 = 端口被占**换号重试一次**,重试仍失败则如实报错且不留记录。 - 三条认领路径(复用/清陈记录/如实报错保留现场)与三条失败分类(进程立刻退出 / 等端口超时 / 预算耗尽)**全部保留**;`ErrLaunch` + `errors.Is` 口径未变; **绝不杀进程**红线未变。 真机自证(子代理跑,默认 Skip 的 `realchrome_test.go`,`CYRENE_BROWSER_CDP_E2E=1` 开闸): `webdriver=false` · 命令行**无** flag/`--enable-automation`/`--headless` · UA 无 `HeadlessChrome`、`plugins=5`、`languages=zh-CN,zh`、`window.chrome` 在 · **UI Automation 控件树 17 个命名节点里没有「信息栏容器/信息栏」⇒ 无横幅** · 第二次 Dial **复用同端口、浏览器主进程仍是同一个 PID** · 收尾按 profile 路径筛残留 = 0。 验收(主会话复跑 + 亲自变异):整树 `go build ./...` + 两包 vet 绿;browser 包测试绿; 我用 -overlay 把该 flag 加回参数表 ⇒ `TestLaunchArgs_HeadfulCarriesNoAutomationTraces` 变红(逐字报"不许传的 flag")。 ⚠️ 未验(如实):无头档的横幅(无窗口判不了)、`chrome-headless-shell`、风控侧是否把 "端口写法"本身当信号、生产 profile 整链路(未碰)。
真机复现(我做的):同 profile 再起一次 chrome.exe ⇒ Chrome **把命令委托给已有 实例并 exit 0**,stderr 逐字「正在现有的浏览器会话中打开。」⇒ **不产生新的 DevToolsActivePort** ⇒ 我们的等待只能超时 ⇒ 浏览器降级档整体不可用。 修法:启动前加一跳**探测**,三档各自出路 —— - 端口记录缺席 / 端口没人听 ⇒ 正常启动(后者先把**陈记录**清掉:那是启动时写下 的记录、不是锁,删一条指向死端口的记录不会伤到任何活实例); - 端口在听 + `/json/version` 有合法响应 ⇒ **复用它**(INFO `browser debug endpoint reused`),**不再起第二个**; - 端口在听但握不上手 ⇒ **如实报错**(保留现场,既不起进程也不删记录); - 真被占用且拿不到端点 ⇒ 报错带 **Chrome 原话**(`withChromeOutput`)+ 可操作处置。 🔴 红线(写进错误文案与注释):**绝不杀别人的浏览器**、不发信号抢 profile、 不新开监听端口;`ErrLaunch` / `errors.Is` 口径未破。 验收(主会话复跑 + 亲自变异):browser 包与 plugins/tools/io 两包 build/vet/test 全绿;我用 -overlay 摘掉「复用」那一支 ⇒ TestLocalChromeAdoptsLiveEndpoint 与 TestDial_ReusesLiveEndpointAndDoesNotSpawnSecondProcess 变红。子代理另跑了真机 端到端(临时 profile):会话 1 拿端口 51732 → 裸起第二次 chrome(exit 0)→ 会话 2 **复用同一端口、未起第二个实例**。 ⚠️ 已知未修(如实):Chrome 那句委托提示是**控制台代码页(GBK)字节**,我们的 UTF-8 日志里会显示成乱码(字节保真、人看不了);彻底解决要引编码转换,另定。 ⚠️ 判据③的取舍:陈记录 +端口恰被别的程序复用时,会持续报错直到人工删 `DevToolsActivePort`(错误文案已写明处置);**未加"报错后自动清理重试"**。