Skip to content

os doctor 载入 objectstack.config.ts 时不带 .env* overlay —— 配置文件自己读 process.env 时,doctor 报「Could not load config」而 os serve 同目录正常启动 #5397

Closed

Description

@baozhoutao

发现于 #5387(doctor 对齐 serve 的 .env* 读取顺序)实施过程中的顺带核验;本单只记录,不在该 PR 里改 —— 原因写在下面。

事实

#5387 之后,doctor 会按 os serve 的顺序读 .env*,但读到的值只在需要它的那一次读取周围临时生效(withDotenvOverlay),刻意不合并进整轮运行的 process.env。今天套上 overlay 的只有 env 派生检查(posture)那一处;loadConfig() 没有套。

两条命令的顺序因此仍然不同:

  • serve:dotenvFlow.config()(packages/cli/src/commands/serve.ts:520)→ 之后才 bundleRequire 载入用户的 objectstack.config.ts。配置文件顶层读到的 process.env 含 .env* 的值。
  • doctor:readDotenvFiles()(不写 process.env)→ loadConfig()(packages/cli/src/commands/doctor.ts 的 config 分析块)。配置文件顶层读到的 process.env 不含 .env* 的值。

后果

配置文件在顶层读环境变量是常见写法(数据源 URL、开关)。当变量只写在 .env 里时:

  1. 值不同 —— 依赖该值的结构(条件声明的 object / datasource)在 doctor 与 serve 眼里不是同一份,doctor 的 config 检查判定的是一份服务器不会运行的配置;

  2. 更响的一种 —— 配置在缺值时抛错(throw new Error('OS_DATABASE_URL is required') 之类),doctor 会落进 config 分析那个很宽的 try,打印

    ⚠ Could not load config for analysis (config checks skipped)
    

    记一个 warning、exit 0,而 os serve 在同一个目录正常启动。这句话正是 os doctor 对非法 OS_TENANCY_POSTURE 退出码 0 并报告「环境功能正常」—— 抛错被 config 分析的宽 catch 吞成一句「Could not load config」 #5382 判定为「归因错误」的那一句:配置本身没问题,问题是 doctor 没把 .env 交给它。

为什么没有顺手改

给 loadConfig() 套上 overlay 会改变既有 config 检查(circular deps / unused objects / orphan views / dashboard integrity / spec 版本)的输入,可能新增或消除 warning —— 属于诊断输出的另一处契约变化,超出 #5387 派发时被限定的判定面(该单的口径明确要求:若改变既有检查的判定超出预期就停下报告)。

需要决定的是同一个问题的另一半:doctor 的 config 分析应当在哪一份环境下进行 —— serve 的那份(overlay 覆盖 loadConfig(),与运行时一致,但既有检查的判定面会变),还是当前这份(只覆盖显式声明的 env 输入,判定面不变,但 config 那条路径与 serve 仍不一致)。

现状

零件已经就位,不需要新机制:readDotenvFiles() / withDotenvOverlay() 就在同一个文件里(#5387 引入,packages/cli/src/commands/doctor.ts),把 loadConfig() 的调用包进去即可。packages/cli 下没有任何测试钉 doctor 的 config 载入与 .env 的关系。

Depends-on: #5387(其 PR 引入的两个零件是本单的前置)。与 #4801、cloud#1020 同属「诊断面与运行时不一致」家族。


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    on Aug 5, 2026
  2. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    分诊(cli 车道 PM,session_01VkPSGsX9o17MsGv3Lbxu2w,2026-08-05):入队 pm:queue,并附方向裁定(留否决窗口)。本单是 #5387 同一不变量(诊断面与 serve 同见)的最后一块:loadConfig() 无 overlay,配置文件顶层读 process.env.X(X 仅在 .env)时 doctor 与 serve 仍见不同值,缺值抛错还会落回 #5382 修掉的那句错误归因。方向:给 loadConfig() 套用 #5398 已就位的 withDotenvOverlay,config 检查判定因此变化的部分如实呈现(这正是修复内容,不是副作用 —— 与 #5398 对 D5e 建议的处理同一姿态);来源行照 #5398 口径归因。派发时范本引 PR #5398。Depends-on: #5387 已由 PR #5398 落地解除。维护者可否决。


    Generated by Claude Code

  3. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    🔒 认领:PM 循环第 5 轮(cli 车道)
    会话:session_01VkPSGsX9o17MsGv3Lbxu2w
    分支:claude/issue-5397-doctor-config-env-overlay
    Worktree:objectstack-issue-5397
    域:domain:cli
    文件面:packages/cli/src/commands/doctor.ts + 测试 + changeset。⛔ 不动 serve/dev/start/env.ts。与同批 #5399(runtime/metadata/rest 注释 + runtime 测试)不相交。⚠️ 依赖 PR #5398(withDotenvOverlay 等零件)—— 其在合并队列中,派发词已要求 dev 从 origin/main 取到后再动手;若未合先等。

    执行口径见上一条分诊评论:loadConfig() 套 overlay,config 检查判定的变化如实呈现(是修复内容非副作用),来源行照 #5398 口径。范本 PR #5398。


    Generated by Claude Code

  4. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    ✅ 验收通过 —— PR #5402,转 ready 挂合并队列(CI 23 项已全绿)

    对实况复核(cli 车道 PM,session_01VkPSGsX9o17MsGv3Lbxu2w):

    • 裁定兑现:loadConfig() 套上 run() 顶部同一份 dotenvReading(一轮一次解析,两处共用,不产生可分歧的第二次读取);判定变化按裁定作为修复内容如实呈报(被跳过的 config 检查组开始运行、真坏配置照旧报警不被消音 —— 各有钉)。
    • withDotenvOverlayAsync 的必要性论证与验证俱全:config 顶层在 bundleRequire 动态 import() 内,同步版 finally 会在 promise pending 时摘除 overlay —— 静默失效;反向验证 B 实锤(换同步版的失败输出与完全不套逐字相同,这正是该变体承重的证明)。两 wrapper 共享同一套 apply/revert,策略只写一遍。
    • 来源纪律升级后仍守住:overlay 现在携带 config 想读的任意变量(不再限于声明子集),报告只报文件不报变量名(测试钉住);DOCTOR_ENV_INPUTS 漂移守卫绿(注释刻意不写具体变量名)。
    • 测试 10 新例(reject 时仍摘除是主线路径而非边角)、反向验证两方向预测逐条命中、整包 76 文件 / 715 用例绿、七道门 + eslint + 控制字符自查干净。
    • 衍生 os doctor 的 config 分析 catch 丢弃了 error 本身 —— 配置真坏掉时只说「载入不了」,不说为什么 #5403(config 分析 catch 丢弃 error、警告无因且 --verbose 展不开)已由 PM 分诊入队,留给下一任派发。

    转 ready 挂 auto-merge,跟到 MERGED。本单落地后「诊断面与 serve 同见」不变量三部曲(#5382 → #5387 → #5397)收官。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landpm:dispatched

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions