baa-conductor

git clone 

commit
7b27e5a
parent
097621a
author
im_wower
date
2026-03-26 00:38:55 +0800 CST
merge: land T-S011 and T-S012
14 files changed,  +313, -27
M DESIGN.md
+2, -1
 1@@ -218,8 +218,9 @@
 2 
 3 ## 11. 当前已知残留
 4 
 5-- `conductor-daemon` 和 runtime 脚本仍使用 legacy 名字 `BAA_CONTROL_API_BASE` / `--control-api-base`
 6+- `conductor-daemon` 和 runtime 脚本已经有 canonical 名字 `BAA_CONDUCTOR_PUBLIC_API_BASE` / `--public-api-base`,但仍保留 legacy 别名 `BAA_CONTROL_API_BASE` / `--control-api-base`
 7 - `status-api` 仍是独立的本地只读观察面,是否并入 `conductor-daemon` 尚未定案
 8+- 根验证入口已经落到 `pnpm lint` / `pnpm test`,但 `status-api`、`worker-runner` 和 runtime / e2e 检查还没全部接进去
 9 - `conductor.makefile.so` 目前只回源 `conductor-daemon` 已有路由,尚未承接完整业务 API
10 - 线上和历史文档里仍可能残留 `control-api.makefile.so`、Cloudflare / D1 相关资产或表述
11 - 如果后续再次出现 app-server 未发出合法 `turn/completed` 就提前断流,应视为新的 child / transport 故障,而不是 reopen 已修复的 BUG-008 / BUG-010
M README.md
+4, -4
 1@@ -120,13 +120,13 @@ legacy 兼容说明:
 2 
 3 - 保持 `mini` launchd、自启动和本地探针稳定
 4 - 保持 `conductor.makefile.so -> 100.71.210.78:4317` 的链路稳定
 5-- 继续收掉剩余 legacy 配置名和兼容入口
 6-- 给仓库根补齐真实可跑的验证入口
 7+- 把剩余测试入口继续收口到仓库根
 8+- 清理 repo 里最后一批 legacy 模板和删旧残留
 9 
10 ## 当前已知 gap
11 
12-- `conductor-daemon`、launchd 安装/检查脚本仍用 legacy 名字 `BAA_CONTROL_API_BASE` / `--control-api-base` 表示 conductor upstream/public API base
13-- 仓库根 `pnpm lint` / `pnpm test` 还是占位脚本,缺少统一质量入口
14+- `status-api` 已有测试文件,但还没接入根 `pnpm test`
15+- repo 模板和辅助文件里还留着少量 legacy 残留,例如 `ops/launchd/` 模板、`install-mini.sh` 的旧 secrets fallback 文件名,以及 `pnpm-lock.yaml` 里的已删除 importer
16 - `status-api` 已经默认读取 `conductor-daemon` 的 `/v1/system/state`,但仍是单独的本地只读观察服务;是否继续保留还是并入主接口,仍待后续任务决定
17 
18 ## 本机能力层
M apps/status-api/package.json
+1, -0
1@@ -9,6 +9,7 @@
2   },
3   "scripts": {
4     "build": "pnpm exec tsc -p tsconfig.json && BAA_DIST_DIR=apps/status-api/dist BAA_DIST_ENTRY=apps/status-api/src/index.js BAA_FIX_RELATIVE_EXTENSIONS=true pnpm -C ../.. run build:runtime-postprocess",
5+    "test": "pnpm run build && node --test src/index.test.js",
6     "typecheck": "pnpm exec tsc --noEmit -p tsconfig.json",
7     "serve": "pnpm run build && node dist/index.js",
8     "start": "node dist/index.js",
M docs/ops/repo-verification.md
+3, -2
 1@@ -34,14 +34,15 @@
 2 - `@baa-conductor/host-ops`
 3 - `@baa-conductor/codex-app-server`
 4 - `@baa-conductor/codex-exec`
 5+- `@baa-conductor/status-api`
 6 - `@baa-conductor/conductor-daemon`
 7 - `@baa-conductor/codexd`
 8 
 9-脚本会按顺序执行每个包自己的 `pnpm --filter <pkg> test`,这样失败点能直接定位到具体包。
10+脚本会按顺序执行每个包自己的 `pnpm --filter <pkg> test`,这样失败点能直接定位到具体包。`@baa-conductor/status-api` 的包级 `test` 会先执行自身 `build`,再跑 `node --test src/index.test.js`,不依赖人工交互或线上环境。
11 
12 刻意不覆盖:
13 
14-- `apps/status-api`、`apps/worker-runner` 等当前没有稳定 `test` 脚本的工作区
15+- `@baa-conductor/worker-runner` 等当前没有稳定 `test` 脚本的工作区
16 - 包内 `smoke` 命令
17 - `scripts/runtime/*.sh`、`tests/**/*.mjs` 这类更慢或需要额外运行时条件的端到端检查
18 
M docs/runtime/launchd.md
+1, -1
1@@ -40,7 +40,7 @@
2 
3 - `~/.config/baa-conductor/runtime-secrets.env`
4 
5-里提取 `BAA_SHARED_TOKEN` 并生成它;如果新的 env 文件不存在,还会回退读取 legacy `control-api-worker.secrets.env` 这个迁移前文件名。
6+里提取 `BAA_SHARED_TOKEN` 并生成它;只有这个默认 env 文件不存在时,才会回退读取 legacy 的 `control-api-worker.secrets.env` 迁移前文件名。
7 
8 说明:
9 
M ops/launchd/so.makefile.baa-conductor.plist
+4, -2
 1@@ -6,8 +6,8 @@
 2   Use scripts/runtime/install-launchd.sh to render the actual install copy.
 3   Adjust BAA_SHARED_TOKEN, BAA_CODEXD_LOCAL_API_BASE, and the listen-related
 4   variables before loading if the mini node uses a non-default address.
 5-  BAA_CONTROL_API_BASE stays here because conductor-daemon still reads that
 6-  legacy env name for its upstream/public API base.
 7+  BAA_CONDUCTOR_PUBLIC_API_BASE is the canonical upstream/public API base.
 8+  BAA_CONTROL_API_BASE remains here only as a legacy compatibility fallback.
 9   If this file is installed under /Library/LaunchDaemons, add UserName and keep
10   every path absolute; launchd will not read shell rc files for you.
11 -->
12@@ -33,6 +33,8 @@
13       <string>mini</string>
14       <key>BAA_CONDUCTOR_ROLE</key>
15       <string>primary</string>
16+      <key>BAA_CONDUCTOR_PUBLIC_API_BASE</key>
17+      <string>https://conductor.makefile.so</string>
18       <key>BAA_CONTROL_API_BASE</key>
19       <string>https://conductor.makefile.so</string>
20       <key>BAA_CONDUCTOR_LOCAL_API</key>
M plans/STATUS_SUMMARY.md
+9, -6
 1@@ -2,14 +2,14 @@
 2 
 3 ## 当前时间
 4 
 5-- `2026-03-25`
 6+- `2026-03-26`
 7 
 8 ## 当前代码基线
 9 
10-- 主线基线:`main@d1c9090`
11+- 主线基线:`main@097621a`
12 - 任务文档已统一收口到 `tasks/`
13 - 当前活动任务见 `tasks/TASK_OVERVIEW.md`
14-- `T-S001` 到 `T-S008` 已经合入主线
15+- `T-S001` 到 `T-S010` 已经合入主线
16 
17 ## 当前状态
18 
19@@ -52,11 +52,13 @@
20 - `T-S006`:`tasks/`、`plans/`、`README` 与 `docs/api/**` / `docs/runtime/**` 已把 `control-api` 收口为 legacy 背景,不再写成当前默认入口
21 - `T-S007`:`ConductorRuntime.stop()` 已补专项测试,覆盖 listener 释放、Firefox bridge client 关闭和重复 stop 的幂等行为
22 - `T-S008`:`codexd` 现在会把“未收到合法 completed 就提前断流”单独归类成新的 child / transport 故障,并写入 reopen 规则
23+- `T-S009`:`conductor-daemon` 和 runtime 脚本已经引入 `BAA_CONDUCTOR_PUBLIC_API_BASE` / `--public-api-base`,legacy `BAA_CONTROL_API_BASE` / `--control-api-base` 降为兼容别名
24+- `T-S010`:仓库根 `pnpm lint` / `pnpm test` 已变成真实入口,并新增 repo verification 文档
25 
26 ## 下一步任务
27 
28-- `T-S009`:把 conductor upstream/public API base 从 legacy 名字里解耦
29-- `T-S010`:补仓库根验证入口
30+- `T-S011`:把 `status-api` 测试接入根验证入口
31+- `T-S012`:清理 repo 中最后一批 legacy 模板与残留 importer
32 
33 ## 当前仍需关注
34 
35@@ -65,4 +67,5 @@
36 - 仍保留的 `control-api` 命名已经限定在历史任务卡、legacy 测试路径、兼容变量名和外部残留资产说明里;如果未来要继续删旧,需要单独评估文件名和兼容面
37 - 如果未来新增 runtime 测试绕开 `withRuntimeFixture(...)`,同类 listener 泄漏仍可能重新出现
38 - 这次没有改 `ConductorRuntime.stop()` 内部逻辑;如果未来关闭路径本身阻塞,还需要单独补运行时层测试
39-- 仓库根 `pnpm lint` / `pnpm test` 仍不是可信入口;后续应把常用验证收口到根脚本
40+- 根 `pnpm test` 目前还没有覆盖 `status-api`、`worker-runner` 和 runtime / e2e 检查
41+- repo 模板和辅助文件里还留着少量删旧残留,例如 `ops/launchd/` 模板、`install-mini.sh` 的 legacy secrets fallback 和 `pnpm-lock.yaml` 里的已删除 importer
M pnpm-lock.yaml
+0, -2
1@@ -14,8 +14,6 @@ importers:
2 
3   apps/conductor-daemon: {}
4 
5-  apps/control-api-worker: {}
6-
7   apps/status-api: {}
8 
9   apps/worker-runner: {}
M scripts/runtime/install-mini.sh
+5, -3
 1@@ -15,9 +15,11 @@ Options:
 2   --home-dir PATH           HOME used for LaunchAgents and defaults.
 3   --install-dir PATH        Override launchd install directory.
 4   --shared-token-file PATH  Preferred shared token file. Defaults to ~/.config/baa-conductor/shared-token.txt
 5-  --secrets-env PATH        Fallback env file used to extract BAA_SHARED_TOKEN.
 6-                            Defaults to ~/.config/baa-conductor/runtime-secrets.env
 7-                            and then legacy control-api-worker.secrets.env.
 8+  --secrets-env PATH        Preferred env fallback used to extract BAA_SHARED_TOKEN.
 9+                            Defaults to ~/.config/baa-conductor/runtime-secrets.env.
10+                            Falls back to legacy
11+                            ~/.config/baa-conductor/control-api-worker.secrets.env
12+                            only if the default file is missing.
13   --skip-build              Skip pnpm build.
14   --skip-restart            Skip launchd restart.
15   --skip-check              Skip check-launchd/check-node verification.
M scripts/verify-workspace.mjs
+1, -0
1@@ -11,6 +11,7 @@ const testPackages = [
2   "@baa-conductor/host-ops",
3   "@baa-conductor/codex-app-server",
4   "@baa-conductor/codex-exec",
5+  "@baa-conductor/status-api",
6   "@baa-conductor/conductor-daemon",
7   "@baa-conductor/codexd"
8 ];
A tasks/T-S011.md
+117, -0
  1@@ -0,0 +1,117 @@
  2+# Task T-S011:把 `status-api` 测试接入根验证入口
  3+
  4+## 直接给对话的提示词
  5+
  6+读 `/Users/george/code/baa-conductor/tasks/T-S011.md` 任务文档,完成开发任务。
  7+
  8+如需补背景,再读:
  9+
 10+- `/Users/george/code/baa-conductor/apps/status-api/package.json`
 11+- `/Users/george/code/baa-conductor/apps/status-api/src/index.test.js`
 12+- `/Users/george/code/baa-conductor/package.json`
 13+- `/Users/george/code/baa-conductor/scripts/verify-workspace.mjs`
 14+- `/Users/george/code/baa-conductor/docs/ops/repo-verification.md`
 15+
 16+## 当前基线
 17+
 18+- 仓库:`/Users/george/code/baa-conductor`
 19+- 分支:`main`
 20+- 提交:`097621a`
 21+- 开工要求:不要从其他任务分支切出;如需新分支,从当前 `main` 新切
 22+
 23+## 建议分支名
 24+
 25+- `chore/add-status-api-root-test`
 26+
 27+## 目标
 28+
 29+给 `status-api` 补稳定的包级 `test` 入口,并把它纳入根 `pnpm test`。
 30+
 31+## 背景
 32+
 33+- `status-api` 已经有 `apps/status-api/src/index.test.js`。
 34+- 但包本身没有 `test` script,所以根验证入口刻意没有覆盖它。
 35+- 这导致“根验证已成型,但状态面仍游离在根测试矩阵之外”。
 36+
 37+## 涉及仓库
 38+
 39+- `/Users/george/code/baa-conductor`
 40+
 41+## 范围
 42+
 43+- 给 `@baa-conductor/status-api` 增加稳定 `test` 脚本
 44+- 把它接入根 `pnpm test`
 45+- 更新验证文档说明覆盖范围
 46+
 47+## 路径约束
 48+
 49+- 优先复用现有 `apps/status-api/src/index.test.js`
 50+- 不要把任务扩展成 `status-api` 架构重构
 51+- 不要顺手改 `conductor-daemon` 或 `codexd`
 52+
 53+## 推荐实现边界
 54+
 55+建议优先做:
 56+
 57+- 为 `apps/status-api/package.json` 增加 `test`
 58+- 如有需要,调整测试运行前置 build 方式
 59+- 更新根验证脚本和 repo verification 文档
 60+
 61+## 允许修改的目录
 62+
 63+- `/Users/george/code/baa-conductor/apps/status-api/`
 64+- `/Users/george/code/baa-conductor/package.json`
 65+- `/Users/george/code/baa-conductor/scripts/`
 66+- `/Users/george/code/baa-conductor/docs/ops/`
 67+- `/Users/george/code/baa-conductor/docs/runtime/README.md`
 68+
 69+## 尽量不要修改
 70+
 71+- `/Users/george/code/baa-conductor/apps/conductor-daemon/`
 72+- `/Users/george/code/baa-conductor/apps/codexd/`
 73+- `/Users/george/code/baa-conductor/tasks/`
 74+
 75+## 必须完成
 76+
 77+### 1. 给 `status-api` 增加稳定测试入口
 78+
 79+- 包级 `pnpm --filter @baa-conductor/status-api test` 应可执行
 80+- 测试不依赖人工交互或线上环境
 81+
 82+### 2. 纳入根测试矩阵
 83+
 84+- 根 `pnpm test` 应覆盖 `status-api`
 85+- 失败点仍要能定位到具体包
 86+
 87+### 3. 回写文档
 88+
 89+- 更新根验证文档的覆盖范围
 90+- 说明哪些检查仍未纳入根入口
 91+
 92+## 需要特别注意
 93+
 94+- 不要把根入口做成难以定位失败点的一串黑盒命令
 95+- 如果 `status-api` 测试仍需要 build 前置,文档里要说明
 96+- 与 repo residual 清理任务并行时,避免同时修改同一段总览文档
 97+
 98+## 验收标准
 99+
100+- `@baa-conductor/status-api` 有稳定 `test` 入口
101+- 根 `pnpm test` 覆盖 `status-api`
102+- 文档已同步更新
103+- `git diff --check` 通过
104+
105+## 推荐验证命令
106+
107+- `npx --yes pnpm -C /Users/george/code/baa-conductor -F @baa-conductor/status-api test`
108+- `npx --yes pnpm -C /Users/george/code/baa-conductor test`
109+- `git -C /Users/george/code/baa-conductor diff --check`
110+
111+## 交付要求
112+
113+完成后请说明:
114+
115+- 修改了哪些文件
116+- `status-api` 的测试入口最终怎么组织
117+- 根 `pnpm test` 现在新增覆盖了什么
118+- 还有哪些检查仍未被根入口覆盖
A tasks/T-S012.md
+122, -0
  1@@ -0,0 +1,122 @@
  2+# Task T-S012:清理 repo 中最后一批 legacy 模板与残留 importer
  3+
  4+## 直接给对话的提示词
  5+
  6+读 `/Users/george/code/baa-conductor/tasks/T-S012.md` 任务文档,完成开发任务。
  7+
  8+如需补背景,再读:
  9+
 10+- `/Users/george/code/baa-conductor/ops/launchd/so.makefile.baa-conductor.plist`
 11+- `/Users/george/code/baa-conductor/ops/launchd/so.makefile.baa-status-api.plist`
 12+- `/Users/george/code/baa-conductor/scripts/runtime/install-mini.sh`
 13+- `/Users/george/code/baa-conductor/pnpm-lock.yaml`
 14+- `/Users/george/code/baa-conductor/docs/runtime/launchd.md`
 15+- `/Users/george/code/baa-conductor/tests/control-api/control-api-smoke.test.mjs`
 16+
 17+## 当前基线
 18+
 19+- 仓库:`/Users/george/code/baa-conductor`
 20+- 分支:`main`
 21+- 提交:`097621a`
 22+- 开工要求:不要从其他任务分支切出;如需新分支,从当前 `main` 新切
 23+
 24+## 建议分支名
 25+
 26+- `chore/clean-runtime-legacy-residuals`
 27+
 28+## 目标
 29+
 30+清掉 repo 里最后一批已经不再代表当前主线的 legacy 模板和删旧残留,让仓库静态资产与当前运行口径一致。
 31+
 32+## 背景
 33+
 34+- 当前主线已经有 canonical `BAA_CONDUCTOR_PUBLIC_API_BASE` / `--public-api-base`。
 35+- 但 repo 内仍有一些静态残留没有同步:
 36+  - `ops/launchd/so.makefile.baa-conductor.plist` 还只写 legacy key 和旧注释
 37+  - `pnpm-lock.yaml` 还保留已删除的 `apps/control-api-worker` importer
 38+  - `install-mini.sh` 仍把 `control-api-worker.secrets.env` 当 fallback 文件名写在默认说明里
 39+- 这些不会立刻打坏主线,但会持续误导维护者。
 40+
 41+## 涉及仓库
 42+
 43+- `/Users/george/code/baa-conductor`
 44+
 45+## 范围
 46+
 47+- 清理 repo 模板和辅助脚本里的静态 legacy 残留
 48+- 让 lockfile / 模板 / 帮助文本与当前主线一致
 49+- 保留必要兼容时,要明确标成 legacy fallback
 50+
 51+## 路径约束
 52+
 53+- 这个任务以静态资产和辅助脚本为主
 54+- 不要改 `apps/conductor-daemon` 的运行时逻辑
 55+- 不要把任务扩展成新的部署方案设计
 56+
 57+## 推荐实现边界
 58+
 59+建议优先做:
 60+
 61+- 更新 repo 里的 launchd plist 模板
 62+- 清理 lockfile 里已删除 importer
 63+- 收口 `install-mini.sh` 对 legacy secrets fallback 的口径
 64+
 65+## 允许修改的目录
 66+
 67+- `/Users/george/code/baa-conductor/ops/launchd/`
 68+- `/Users/george/code/baa-conductor/scripts/runtime/`
 69+- `/Users/george/code/baa-conductor/docs/runtime/`
 70+- `/Users/george/code/baa-conductor/pnpm-lock.yaml`
 71+- `/Users/george/code/baa-conductor/docs/ops/`
 72+
 73+## 尽量不要修改
 74+
 75+- `/Users/george/code/baa-conductor/apps/conductor-daemon/`
 76+- `/Users/george/code/baa-conductor/apps/status-api/`
 77+- `/Users/george/code/baa-conductor/tasks/`
 78+
 79+## 必须完成
 80+
 81+### 1. 清理 launchd 模板残留
 82+
 83+- repo 模板应体现 canonical public API 配置名
 84+- 注释要明确哪些内容只是 legacy 兼容
 85+
 86+### 2. 清理删旧后的静态残留
 87+
 88+- 清掉 lockfile 里已删除 importer 等明显残留
 89+- 不要留下与当前仓库结构冲突的静态记录
 90+
 91+### 3. 收口 helper 脚本说明
 92+
 93+- `install-mini.sh` 的默认说明要和当前 secrets 口径一致
 94+- 如果保留 legacy fallback,必须明确它只是兼容兜底
 95+
 96+## 需要特别注意
 97+
 98+- 不要破坏 `install-mini.sh` 当前对老环境的兼容回退能力
 99+- 如需更新 lockfile,保持改动最小,不要顺手升级无关依赖
100+- 与 `status-api` 测试接入任务并行时,尽量不要同时修改同一段 runtime 文档
101+
102+## 验收标准
103+
104+- repo 模板和辅助脚本与当前主线口径一致
105+- 已删除 importer 等静态残留被清掉
106+- 兼容 fallback 若保留,文档和帮助文本说明清楚
107+- `git diff --check` 通过
108+
109+## 推荐验证命令
110+
111+- `bash -n /Users/george/code/baa-conductor/scripts/runtime/install-mini.sh`
112+- `bash -n /Users/george/code/baa-conductor/scripts/runtime/install-launchd.sh`
113+- `npx --yes pnpm -C /Users/george/code/baa-conductor lint`
114+- `git -C /Users/george/code/baa-conductor diff --check`
115+
116+## 交付要求
117+
118+完成后请说明:
119+
120+- 修改了哪些静态模板或辅助脚本
121+- 清掉了哪些残留
122+- 保留了哪些 legacy fallback
123+- 跑了哪些验证
M tasks/TASK_OVERVIEW.md
+7, -5
 1@@ -9,7 +9,7 @@
 2 - `control-api.makefile.so`、Cloudflare Worker、D1 只剩迁移期 legacy 兼容残留和依赖盘点用途
 3 - `baa-hand` / `baa-shell` 只保留为接口语义参考,不再作为主系统维护
 4 - 当前任务卡都放在本目录
 5-- 当前任务基线:`main@d1c9090`
 6+- 当前任务基线:`main@097621a`
 7 
 8 ## 最近完成任务
 9 
10@@ -23,6 +23,8 @@
11 6. [`T-S006.md`](./T-S006.md):清理历史 `control-api` 命名残留
12 7. [`T-S007.md`](./T-S007.md):补 `ConductorRuntime.stop()` 关闭路径专项测试
13 8. [`T-S008.md`](./T-S008.md):补 codexd child / transport 断流诊断与 reopen 规则
14+9. [`T-S009.md`](./T-S009.md):把 conductor upstream/public API base 从 legacy 名字里解耦
15+10. [`T-S010.md`](./T-S010.md):补仓库根验证入口
16 
17 说明:
18 
19@@ -32,13 +34,13 @@
20 
21 围绕剩余技术债,当前建议继续推进这 2 张任务卡:
22 
23-1. [`T-S009.md`](./T-S009.md):把 conductor upstream/public API base 从 legacy 名字里解耦
24-2. [`T-S010.md`](./T-S010.md):补仓库根验证入口
25+1. [`T-S011.md`](./T-S011.md):把 `status-api` 测试接入根验证入口
26+2. [`T-S012.md`](./T-S012.md):清理 repo 中最后一批 legacy 模板与残留 importer
27 
28 说明:
29 
30-- `T-S009` 主要改 `apps/conductor-daemon`、`scripts/runtime/**` 和 `docs/runtime/**`
31-- `T-S010` 主要改根 `package.json` 与新增的验证脚本;尽量不要和 `T-S009` 同时改同一批文档
32+- `T-S011` 主要改 `apps/status-api/`、根验证脚本和验证文档
33+- `T-S012` 主要改 `ops/launchd/`、`scripts/runtime/install-mini.sh`、`pnpm-lock.yaml` 和少量 runtime 文档
34 
35 ## 任务文档约定
36 
M tests/control-api/control-api-smoke.test.mjs
+37, -1
 1@@ -1,5 +1,5 @@
 2 import assert from "node:assert/strict";
 3-import { existsSync } from "node:fs";
 4+import { existsSync, readFileSync } from "node:fs";
 5 import path from "node:path";
 6 import test from "node:test";
 7 import { fileURLToPath } from "node:url";
 8@@ -52,3 +52,39 @@ test("legacy cloudflare and D1 helper entrypoints are removed with the worker",
 9     false
10   );
11 });
12+
13+test("lockfile no longer keeps the removed control-api worker importer", () => {
14+  const lockfile = readFileSync(repoPath("pnpm-lock.yaml"), "utf8");
15+
16+  assert.equal(lockfile.includes("apps/control-api-worker:"), false);
17+});
18+
19+test("runtime static assets keep canonical names and label legacy fallbacks", () => {
20+  const conductorTemplate = readFileSync(
21+    repoPath("ops", "launchd", "so.makefile.baa-conductor.plist"),
22+    "utf8"
23+  );
24+  const installMini = readFileSync(
25+    repoPath("scripts", "runtime", "install-mini.sh"),
26+    "utf8"
27+  );
28+
29+  const canonicalIndex = conductorTemplate.indexOf("BAA_CONDUCTOR_PUBLIC_API_BASE");
30+  const legacyIndex = conductorTemplate.indexOf("BAA_CONTROL_API_BASE");
31+
32+  assert.notEqual(canonicalIndex, -1);
33+  assert.notEqual(legacyIndex, -1);
34+  assert.ok(canonicalIndex < legacyIndex);
35+  assert.match(
36+    conductorTemplate,
37+    /legacy compatibility fallback/
38+  );
39+  assert.match(
40+    installMini,
41+    /Defaults to ~\/\.config\/baa-conductor\/runtime-secrets\.env\./
42+  );
43+  assert.match(
44+    installMini,
45+    /Falls back to legacy[\s\S]*control-api-worker\.secrets\.env[\s\S]*only if the default file is missing\./
46+  );
47+});