Skip to content

os doctor 不加载 .env*,读到的环境与 serve/dev/start 实际运行的不是同一份 —— 写在 .env 里的配置错误 doctor 一律看不见 #5387

Closed

Description

@baozhoutao

发现于 #5382(doctor 的 posture 报告,PR 见下)实施过程中的顺带核验;本单只记录,不在该 PR 里改(那单的文件面被限定为 packages/cli/src/commands/doctor.ts 的 posture 读取,而本单的修法会改变 doctor 每一项 env 派生检查所看到的输入,属于另一个决定)。

事实

serve / dev / start 三条命令都在 run() 早期用 dotenv-flow 载入 .env*:

  • packages/cli/src/commands/serve.ts:516 — dotenvFlow.config({ node_env: mode, silent: true })
  • packages/cli/src/commands/dev.ts:132 — dotenvFlow.config({ node_env: 'development', silent: true })
  • packages/cli/src/commands/start.ts:121 — dotenvFlow.config({ node_env: mode, silent: true })

doctor.ts 没有任何 dotenv 载入(grep -n dotenv packages/cli/src/commands/doctor.ts 无匹配),只看 process.env。

后果

诊断面读到的环境,和被诊断的那条命令实际运行时的环境,不是同一份。具体到 #5382 修完之后的那项检查:

# .env(提交进仓库,团队共享)
OS_TENANCY_POSTURE=isolatd

$ os doctor      # 看不到 .env,posture 解析成 single,报绿,exit 0
$ os serve       # 载入 .env,读到 isolatd,FATAL 拒绝启动(PR #5381 的闸门)

也就是说 #5382 修好的那条「doctor 与 serve 不一致」,在 .env 这条来源上仍然成立 —— 只是从「归因错误」缩小成了「完全看不见」。PR 里的文案已经如实写明这一点(「os doctor does not load .env* files, so a value set in one is not visible here」),不冒充检查过,但残留本身值得单独记一笔。

.env 恰恰是这个变量最常见的来源:PR #5381 把 serve 的闸门刻意放在 dotenv 载入之后,理由正是「该变量常常来自提交进仓库的 .env* 而不是 shell」。

为什么现在才成为问题

在 #5382 之前,doctor.ts 里 process.env 的直接读取是 0 处 —— 它此前根本没有 env 派生的检查,所以「不加载 .env」不产生可观察差异。#5382 给它加了第一项(posture),这条不一致才有了落点。任何后续想在 doctor 里检查 OS_* 配置的工作都会撞上同一堵墙。

需要决定的地方(所以没有顺手改)

在 doctor 里加一行 dotenvFlow.config() 表面上是一行,但它:

  1. 改变 doctor 每一项(现在的和将来的)env 派生检查的输入;
  2. 需要选一个 node_env —— serve 从 --dev / NODE_ENV 推导,start 用 mode,doctor 没有对应的旗标,选错会读到另一套 .env.<mode>;
  3. 会把 .env 里的值写进当前进程的 process.env,doctor 之后若还要报告「你的 shell 里设了什么」就分不清来源了 —— 可能需要把「从哪读到的」也报出来,而不是静默合并。

倾向:doctor 应当模拟 serve 的读取顺序并在报告里注明每个值的来源(shell / 哪个 .env 文件),而不是静默 merge —— 但这是诊断输出的契约变化,交维护者裁定。

现状证据

packages/cli 下没有任何测试钉 doctor 与 .env 的关系。


Context: #5382 / #5359 / PR #5381。与 #4801、cloud#1020 同属「诊断面与运行时不一致」家族。

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    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,并附 PM 裁定(留否决窗口 —— 维护者可否决,不等批准)。

    方向裁定:doctor 模拟 serve 的读取顺序,且按值注明来源,不静默 merge。 依据:

    1. 恢复既有不变量,非新决策 —— 「诊断面与运行时读同一份现实」是本仓付过两次账的规范(CLI 启动 banner 的 Tenancy: 读布尔 multiTenant,与 ADR-0105 D1 的权威 knob OS_TENANCY_POSTURE 对不上——isolated 会显示成 single-tenant #4801、cloud#1020),os doctor 对非法 OS_TENANCY_POSTURE 退出码 0 并报告「环境功能正常」—— 抛错被 config 分析的宽 catch 吞成一句「Could not load config」 #5382 修的正是它在 posture 上的一半;.env 这半边同属恢复一致性,方向已被规范决定。
    2. 两轴:长远轴 —— doctor 的价值就是回答「serve 将看到什么」,读取顺序对齐 serve(dotenv-flow,node_env 按 serve 同款推导:NODE_ENV || production,首版不新增旗标);防 AI 轴 —— **按值注明来源(shell / 哪个 .env 文件)**优于静默合并:静默 merge 正是 issue 第 3 点指出的「分不清来源」的温床,而带来源的报告让配置错误可归因。
    3. 实现机制(读文件不污染 process.env,还是先快照后对比)由 dev 按代码实况定;若发现必须引入新旗标或改变既有检查的判定结果超出预期面,按 needs_decision 停下报告。

    非 v17 窗口件,排本车道 v17 工作集之后;派发时范本引 PR #5381(serve 的 dotenv 时序论证)与 PR #5390(doctor 的 verdict 形态)。


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 5, 2026
  4. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    🔒 认领:PM 循环第 4 轮(cli 车道)
    会话:session_01VkPSGsX9o17MsGv3Lbxu2w
    分支:claude/issue-5387-doctor-dotenv-parity
    Worktree:objectstack-issue-5387
    域:domain:cli
    文件面:packages/cli/src/commands/doctor.ts + 测试 + changeset。⛔ 不动 serve.ts / dev.ts / start.ts / env.ts。与同批 #4633(packages/rest)、#5244(examples)不相交。

    执行口径按本单已留的 PM 裁定:模拟 serve 的读取顺序(dotenv-flow,node_env 按 serve 同款推导 NODE_ENV || production,首版不新增旗标),按值注明来源(shell / 哪个 .env 文件),不静默 merge 进 process.env;实现机制(独立读文件或先快照后对比)按代码实况定;若必须引入新旗标或改变既有检查判定超出预期,needs_decision 停下。范本:PR #5381(dotenv 时序论证)、PR #5390(doctor 的 verdict 形态,resolveTenancyPostureOrFinding 就在你要改的文件里 —— posture 检查的输入随本单变化,注意保持其测试绿)。in-process 测试一律显式 }, 60_000)。


    Generated by Claude Code

  5. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    ContributorAuthor

    ✅ 验收通过 —— PR #5398,转 ready 挂合并队列

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

    转 ready 挂 auto-merge,跟到 MERGED。


    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:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions