codependix-triage

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Acting on a codependix failure

处理 codependix 失败

Codependix reports a handful of distinct outcomes, and reading which one occurred is most of the work. Start by separating them: a boundary violation is a real edge in real code, a stale export is drift, a failure is a project that never got as far as producing one, and a run that wrote nothing at all is usually neither.
Codependix 会报告几种彼此不同的结果,而判断究竟发生了哪一种,就是这项工作的主要部分。先将它们区分开:**边界违规(boundary violation)**是实际代码中的实际边,**过期导出(stale export)**是漂移,**失败(failure)**是根本未走到生成导出这一步的项目,而完全没有写入任何内容的运行通常两者都不是。

A boundary violation

边界违规

--check boundaries
found an edge, or a cycle, that a declared rule condemns. Each violation names the graph level, the scope it was found in, the rule, both endpoints, and whatever the rule says about why it exists.
This is the one finding a re-run never fixes. Nothing is stale and nothing needs regenerating: the edge is in the code, and one of two things has to give.
  1. Remove the edge. Usually the right answer, and usually smaller than it looks — move a type into a
    *.types.ts
    file, invert a dependency, or lift a shared piece into a package both ends may reach.
  2. Change the rule, when the rule is what is wrong. That is a deliberate decision to write down in
    codependix.config.ts
    , with the reason, not a quiet widening of a selector until the run goes green.
Never narrow a selector, add an exclusion, or delete a rule purely to make a failing check pass. A gate loosened to pass is a gate that no longer protects anything, and the next reader has no way to tell it was ever meant to.
If the violation is at the
nx
level and mentions an edge with no import statement behind it, that is the point of the level: an
implicitDependencies
entry is a real project-graph edge, and
@nx/enforce-module-boundaries
cannot see it. Remove the entry, or the rule has to change.
--check boundaries
找到了一条被已声明规则判定为违规的边或一个环。每条违规都会指出图层级、发现违规的范围、规则、两个端点,以及规则对该边为何存在所作的说明。
**这是重新运行永远无法修复的一类发现。**这里没有 stale 内容,也不需要重新生成:边就在代码中,因此必须在以下两者之间作出调整。
  1. **移除该边。**通常这是正确做法,而且改动通常比看上去小——将某个 type 移入
    *.types.ts
    文件、反转依赖关系,或将共享部分提取到两端都可依赖的 package 中。
  2. 修改规则,如果错误的是规则本身。这应当是一个有意作出的决定,并将原因写入
    codependix.config.ts
    ,而不是悄悄扩大 selector,直到运行变绿。
绝不要仅仅为了让失败的检查通过,就缩小 selector、添加 exclusion 或删除规则。为通过检查而放宽的 gate 已经失去任何保护作用,而下一位读者也无从得知它原本是否用于守护某项约束。
如果违规位于
nx
层级,并且提到一条背后没有 import 语句的边,这恰恰说明了这个层级的用途:
implicitDependencies
条目是真实的 project-graph 边,而
@nx/enforce-module-boundaries
看不到它。请移除该条目,或者修改规则。

A stale
--check reports

过期的
--check reports

One or more configured exports disagree with a freshly built graph. The run names the projects.
Re-run
--write
. That is the entire fix.
The graphs move with the workspace they describe, so a project graph that changed makes every export that drew it stale — which is drift to refresh, not a defect to investigate.
Never hand-edit inside the anchor markers. The next
--write
replaces the block wholesale, so an edited diagram is a diff that silently disappears on the following run. The same goes for a standalone Markdown file: codependix owns its whole contents.
Two more things a stale check does not mean:
  • It is not a conformetry conformance difference. The
    codependix:start
    /
    codependix:end
    markers are codependix's own syntax and carry no dependency on any
    conformetry-*
    package. Running a conformance check, or reaching for a conformetry generator, fixes nothing here.
  • It is not evidence of a missing anchor. A project that has never been exported has no block to compare, and reports stale like any other drift.
一个或多个已配置的 export 与刚构建的图不一致。运行结果会列出相关项目。
**重新运行
--write
。这就是完整的修复方式。**图会随其描述的工作区一起变化,因此 project graph 的改变会让所有基于它绘制的 export 变为 stale——这属于应当刷新的漂移,而不是需要调查的缺陷。
**绝不要在 anchor 标记内手动编辑。**下一次
--write
会整体替换该块,因此手工编辑过的 diagram 只是一处 diff,会在后续运行中悄无声息地消失。独立的 Markdown 文件也一样:其全部内容完全由 codependix 管理。
stale 检查还 不 表示另外两件事:
  • 它不表示 conformetry 一致性差异。
    codependix:start
    /
    codependix:end
    标记是 codependix 自己的语法,不依赖任何
    conformetry-*
    package。运行 conformance check,或改用 conformetry generator,在这里都解决不了问题。
  • **它也不能证明缺少 anchor。**从未导出过的项目没有可比较的块,与其他漂移一样会报告为 stale。

A project that failed

失败的项目

A failure is collected per project and reported by name. One project failing does not stop the rest — every remaining project in that pass still runs, and all four graph-type passes are attempted regardless of whether an earlier one failed. So a run naming three failures is three things to fix, not one flaky run to retry.
失败信息会按项目收集并逐个报告。一个项目失败不会阻止其他项目运行——该轮中的其余项目仍会继续执行,而且无论前面的 graph type 是否失败,四种 graph type 任务都会全部尝试。因此,一次运行报告三个失败,就表示有三件事需要修复,而不是一次不稳定的运行需要重试。

The Markdown file does not exist

Markdown 文件不存在

The only anchor problem that fails outright. A missing anchor block is auto-created on
--write
; a missing file is not, because a project with no readme at all is a more serious problem than an unplaced block, and inventing the file would mean authoring a document nobody asked for.
Create the file — a project readme with at least a heading — and re-run.
这是唯一会直接导致失败的 anchor 问题。缺少 anchor 块时,
--write
会自动创建;缺少文件时则不会,因为一个完全没有 readme 的项目比未正确放置的块更严重,而擅自创建文件等于编写一份无人要求的文档。
创建该文件——项目 readme 至少包含一个 heading——然后重新运行。

A missing anchor block, on
--write

在
--write
时缺少 anchor 块

Not a failure.
--write
creates it, at one of exactly two safe places:
  • Appended to the end of the file as a new
    ## 🕸️ Codependix
    section, with an intro line and a
    ### <Subheading>
    for the graph type.
  • Inserted as a new
    ### <Subheading>
    at the end of an existing
    ## 🕸️ Codependix
    section, when an earlier graph type already created one.
It never places a block anywhere else in a document someone else is authoring, and never duplicates the heading. If the block landed somewhere you did not want it, move the whole marker pair by hand once and every later
--write
replaces the content in place.
这不是失败。
--write
会创建该块,并且只会将其放在两个安全位置之一:
  • 作为新的
    ## 🕸️ Codependix
    section 追加到文件末尾,其中包含一行引导内容,以及 graph type 对应的
    ### <Subheading>
    。
  • 当更早的 graph type 已创建
    ## 🕸️ Codependix
    section 时,作为新的
    ### <Subheading>
    插入现有 section 的末尾。
它绝不会把块放到他人正在编写的文档中的其他任何位置,也绝不会重复 heading。如果块出现在不希望它出现的位置,可以手动整体移动一次 marker 对,之后每次
--write
都会在原位替换其中的内容。

A NestJS project that failed to boot its container

启动容器失败的 NestJS 项目

The NestJS pass explores a project's container in preview mode, which registers every module and provider without instantiating any of them. A project building a
TypeOrmModule.forRootAsync
options factory never has a database contacted, so what breaks this pass is always something that throws while modules are being registered — a module whose static
forRoot
argument reads a variable that is absent, a top-level throw in a module file, or a project whose root module does not export what the pass expects. Look there.
An application is rooted in
src/main.module.ts
and its
MainModule
export; a library package with no such file is rooted in a synthetic module built from every
*.module.ts
it defines, so a module file that cannot be imported on its own fails a library that an application would not notice.
Two fixes that look plausible and are not: starting or seeding a database (the pass never contacts one), and building the project first (it imports the project's own TypeScript module sources directly).
If the CLI is being run from TypeScript sources through some other loader, check that decorator metadata survives it: NestJS constructor injection reads metadata that plain type-stripping erases, and the failure looks like a container that cannot resolve its own providers. The published
codependix
binary registers a decorator-preserving loader itself; a hand-rolled invocation has to do the same.
NestJS 任务会以预览模式探查项目的 container,期间会注册所有 module 和 provider,但不会实例化其中任何一个。即使项目构建了
TypeOrmModule.forRootAsync
options factory,该过程也绝不会连接数据库。因此,导致此任务出问题的始终是 module 在_注册_期间抛出的异常,例如某个 module 的 static
forRoot
参数读取了不存在的变量、module 文件顶层直接抛出异常,或者项目的 root module 未导出任务所期望的内容。应重点检查这些位置。
application 以
src/main.module.ts
及其
MainModule
export 为根;没有该文件的 library package 则以一个合成 module 为根,该 module 由它定义的所有
*.module.ts
构建。因此,一个无法单独导入的 module 文件会使 library 失败,而 application 可能根本注意不到。
有两种看似合理但实际无效的修复方式:启动或填充数据库(该任务绝不会连接数据库),以及先构建项目(它会直接导入项目自己的 TypeScript module 源码)。
如果 CLI 正通过其他 loader 从 TypeScript 源码运行,请检查 decorator metadata 能否在转换后保留:NestJS constructor injection 会读取 metadata,而仅剥离类型的转译流程会将其擦除;此时故障表现为 container 无法解析自己的 provider。已发布的
codependix
binary 会自行注册保留 decorator 的 loader;自行拼装的调用方式也必须做到这一点。

A rejected command line

被拒绝的命令行

--check
takes a comma-separated set drawn from
boundaries
and
reports
, and the whole command line is read before anything else happens:
  • --check needs a value
    — a bare
    --check
    , or one whose value is only separators. Name the set; do not drop the flag. Read as "gate nothing" it would be a gate that cannot fail.
  • --check does not accept "..."
    — a name from another tool.
    limits
    is codometer's and
    depth
    is callidescope's; only
    reports
    is shared.
  • --write cannot be combined with --check reports
    — an export cannot be stale in the run that just wrote it.
    --write --check boundaries
    is legal.
  • Naming neither
    --check
    nor
    --write
    is asked about at a terminal, and refused everywhere else — including any run an agent or a CI job makes, since neither has a terminal to answer on. Nothing is inferred and no default write happens.
Every mistake on one command line is collected before any is reported, so two complaints are two things to fix rather than two runs.
The command is
codependix map
, not bare
codependix
: a command line with no subcommand is rejected by the argument parser before any of this applies.
--check
接受一个逗号分隔的集合,其值只能是
boundaries
和
reports
。整个命令行会在执行其他操作之前被完整读取:
  • --check needs a value
    ——只写了一个裸
    --check
    ,或者它的值仅包含分隔符。请指定集合,不要删除该 flag。如果将其理解为“不对任何内容设置 gate”,那它就是一个永远不会失败的 gate。
  • --check does not accept "..."
    ——名称来自其他工具。
    limits
    属于 codometer,
    depth
    属于 callidescope;只有
    reports
    是共用的。
  • --write cannot be combined with --check reports
    ——刚完成写入的 export 不可能处于 stale 状态,因此不能同时使用这两个参数。
    --write --check boundaries
    是合法的。
  • 如果既未指定
    --check
    也未指定
    --write
    ,在终端中会就此询问,而在其他任何地方都会拒绝执行——包括 Agent 或 CI job 发起的任何运行,因为二者都没有终端可用来回答。系统不会推断任何选项,也不会默认执行 write。
同一条命令行中的所有错误都会在其他错误被报告前一次性收集,因此两条报错表示需要修复两个问题,而不是需要运行两次。
命令是
codependix map
,而不是裸
codependix
:没有指定 subcommand 的命令行会在上述规则生效前被参数解析器拒绝。

A
--write
that produced no files

未生成任何文件的
--write

The quietest outcome, and almost never a bug: the run exits 0, reports that every configured export is current, and writes nothing, because nothing was configured. Every unset
target
defaults to
"none"
, and a project resolving to
"none"
is left out of the results entirely rather than reported as up to date — so
0
projects in the report means codependix was configured to produce nothing.
Work down this list before suspecting the tool:
  1. Was a configuration file found at all? An absent one is legal and silent. Name it with
    --config
    to make its absence fail loudly instead.
  2. Is
    target
    set?
    A graph type carrying destinations but no
    target
    still resolves to
    "none"
    .
  3. Is the field spelled
    defaults
    ?
    default
    is stripped as an unknown key and has no effect.
  4. Does the configuration name an
    include
    at all?
    It defaults to nothing, so a configuration naming only
    defaults
    selects no project and exports nothing. The run warns —
    🕸️ Selected no project to export
    — and still exits zero, and
    --check boundaries
    stays green either way, because it judges every project regardless of
    include
    . Write
    include: ["**"]
    for whole-workspace coverage.
  5. Do the projects match
    include
    , and escape
    exclude
    ?
    Both match against a project's Nx name and its workspace-relative root.
  6. Is
    --directory
    the workspace root?
    It is what every project's path resolves against, not a subtree to scan — Nx resolves the graph itself from the process working directory. Pointed at a single project's folder, the run still reads the whole graph but resolves every project underneath that folder, so exports land somewhere unexpected or fail on a readme that is not there.
The
codependix-configure
skill covers each of those fields.
这是最不显眼的结果,而且几乎从来不是 bug:运行以 0 退出,报告所有已配置的 export 都是最新状态,却没有写入任何内容,因为根本没有配置任何输出目标。每个未设置的
target
都默认为
"none"
,而解析为
"none"
的项目会完全从结果中排除,不会被报告为最新状态——因此,报告中显示 0 个项目,意味着 codependix 被配置为不生成任何内容。
怀疑工具之前,请按以下列表逐项检查:
  1. **是否确实找到了配置文件?**配置文件不存在是合法且静默的。使用
    --config
    指定其路径,可以让缺失情况明确报错。
  2. **是否设置了
    target
    ?**一个带有 destinations、但没有
    target
    的 graph type 最终仍会解析为
    "none"
    。
  3. 字段是否拼写为
    defaults
    ?
    default
    会被当作未知 key 移除,因此不起作用。
  4. **配置中是否指定了
    include
    ?**它默认为空,因此只命名了
    defaults
    的配置不会选中任何项目,也不会导出任何内容。运行会发出警告——
    🕸️ Selected no project to export
    ——但仍以 0 退出;而且无论是否设置
    include
    ,
    --check boundaries
    都会保持绿色,因为它会判断每个项目。要覆盖整个工作区,请写入
    include: ["**"]
    。
  5. **项目是否匹配
    include
    ,并避开
    exclude
    ?**两者都会针对项目的 Nx name 和 workspace-relative root 进行匹配。
  6. **
    --directory
    是否指向工作区 root?**它是所有项目路径的解析基准,而不是用于扫描的 subtree——Nx 会根据进程工作目录解析 graph 本身。如果将它指向单个项目的文件夹,运行仍会读取整个 graph,但会把该文件夹下的每个项目都解析到这个路径基准上,导致 export 落在意外的位置,或因找不到 readme 而失败。
codependix-configure
skill 详细介绍了上述每个字段。

A configuration that was rejected

被拒绝的配置

Validation refuses two destination mismatches rather than silently exporting half of what was asked for: a
"both"
or
"json"
target with no
json
destination, and a
"both"
or
"markdown"
target with no
markdown
destination. A
markdown
destination naming neither an
anchor
nor a
path
is refused for the same reason — nothing would say where the export goes.
校验会拒绝两类 destination 不匹配,而不是只静默导出所要求内容的一半:target 为
"both"
或
"json"
,却没有
json
destination;target 为
"both"
或
"markdown"
,却没有
markdown
destination。出于同样的原因,如果
markdown
destination 既未指定
anchor
,也未指定
path
,校验也会拒绝,因为它无法确定 export 的写入位置。

Whose problem the graph is

图所反映的问题由谁负责

A finished export is a description, not a verdict — an export gates nothing about a codebase's shape, and only a declared boundary rule does. A diagram that shows something alarming (a cycle, a project depending on far more than expected) is a real finding about the code even when no rule condemns it, and the fix belongs in the code rather than in the configuration that exported it. Reach for the
codependix-navigate
skill to read what the graph is actually saying before changing anything.
完成的 export 是一份描述,不是一份裁决——export 不会针对代码库的结构设置任何 gate,只有已声明的 boundary rule 才会。即使没有任何规则判定某个 diagram 中的内容有问题,只要它显示了令人担忧的结构,例如环,或某个项目依赖了远超预期的其他项目,这仍然是关于代码的真实发现。修复应当落在代码中,而不是用于导出它的配置中。进行任何更改之前,请使用
codependix-navigate
skill 读懂 graph 实际表达的内容。