project-audit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Project audit — what is true of this project right now

Project audit — 这个项目此刻的真实状态

A gate asks whether an artifact is good. Acceptance asks whether anything on the list was lost. Neither asks what the project actually is today, and that is the only question an operator has when they open a repository they have not touched for a month.
This skill answers it from a cold start — no brief, no REQ table, no module map required — and leaves two artefacts: a page a person reads, and a sidecar the next audit reads.
门禁(gate)会问某个产物是否合格。验收(acceptance)会问清单上的任何东西是否丢失。两者都不会问项目今天实际上是什么,而当操作者打开一个一个月没碰过的代码仓库时,这恰恰是唯一的问题。
这个 skill 从冷启动(cold start)开始回答它——无需 brief、REQ 表格或模块地图——并留下两个产物:一页供人阅读的页面,以及下一次审计会读取的 sidecar。

Contents

目录

  • What this is not
  • The six phases
  • Three verdicts, and why the third one exists
  • The class that version checks cannot see
  • The two artefacts
  • What the script does and what you do
  • Exit criterion
  • Rationalizations
  • 这不是什么
  • 六个阶段
  • 三种结论,以及第三种为何存在
  • 版本检查看不到的类别
  • 两个产物
  • 脚本做什么、你做什么
  • 完成标准
  • 借口与现实

What this is not

这不是什么

OwnsReach for it when
references/portable-method.md
the method — the L0→L7 ladder, seams, axis rotationone deliverable is being walked inside a run
this skillthe procedure — cold start, probes, production, the reporta whole project is the subject
/skill-audit
(make-skill)
a skill's construction against the standardthe thing audited is a skill or plugin
/ux-audit
(super-ux)
code against documented scenariosthe question is user-facing behaviour
/seo-aeo-audit
(seo-aeo-audit)
a public surface's search and answer-engine visibilitythe question is whether a machine will find it
Read
references/portable-method.md
before phase 4.
It carries the standalone audit floor and needs neither a sibling skill nor network access. The companion task-pipeline audit, backlog and prioritisation references are optional deeper reading when installed; their absence never blocks this procedure.
负责内容何时使用
references/portable-method.md
方法——L0→L7 阶梯、seam、轴轮换单次运行中正在逐项检查一个交付物时
此 skill流程——冷启动、probe、生产环境、报告整个项目是审查对象时
/skill-audit
(make-skill)
按照标准检查 skill 的构建方式被审计对象是 skill 或 plugin 时
/ux-audit
(super-ux)
根据已记录的场景检查代码问题是面向用户的行为时
/seo-aeo-audit
(seo-aeo-audit)
检查对外公开内容在搜索和 answer engine 中的可见性问题是机器能否发现它时
在第 4 阶段之前阅读
references/portable-method.md
。
它包含独立审计的最低要求,既不需要同级 skill,也不需要网络访问。配套的 task-pipeline 审计、backlog 和优先级参考资料是可选的深入阅读材料;即使未安装,它们也绝不会阻碍本流程执行。

The six phases

六个阶段

Run them in order. Each writes into the same payload the report is rendered from.
按顺序运行。每个阶段都会写入同一份 payload,报告即由该 payload 渲染。

1. Discover — what this project IS, before anything is measured

1. 发现——在测量任何内容之前,先弄清这个项目是什么

scripts/audit.py
answers this mechanically: languages, package managers, monorepo shape, submodules, CI, deploy targets, declared telemetry, and the version the project states about itself. It reads committed state —
git ls-files
, never a directory walk — because a walk finds
node_modules
and build residue, and reports a project no clone would produce.
The output is a profile, and the profile chooses the probes. Skipping this and running a fixed checklist is how an audit produces the same nine findings on every repository it is ever pointed at.
scripts/audit.py
会机械地回答以下问题:使用的语言、package manager、monorepo 结构、submodule、CI、部署目标、声明的 telemetry,以及项目对外声明的版本。它读取的是已提交状态——使用
git ls-files
,绝不进行目录遍历——因为目录遍历会找到
node_modules
和构建残留,报告出一个全新 clone 根本不会产生的项目状态。
输出是一份项目画像,并由这份画像决定要选择哪些 probe。跳过这一步并运行固定检查清单,正是审计无论指向哪个仓库都产出相同九项发现的原因。

2. Probe — the registry, chosen from the profile

2. 探测——根据画像选择的 probe 注册表

Every probe declares what it needs (
git
,
gh
,
npm
,
network
, a connected MCP server). A need that is not met makes the probe blind, with the reason — never absent, and never clean. The catalogue by stack, and what to add for a project shape the script does not cover, is
references/probes.md
.
每个 probe 都会声明自身需要什么(
git
、
gh
、
npm
、网络、已连接的 MCP server)。需求未满足时,该 probe 会被标记为 blind 并附上原因——它绝不会缺席,也绝不会被视为 clean。按技术栈划分的 probe 目录,以及脚本尚未覆盖的项目形态应如何补充,见
references/probes.md
。

3. Prod — the evidence that only exists outside the tree

3. 生产环境——只存在于代码树之外的证据

This is the phase most audits skip, and the one that finds what the repository cannot admit about itself:
  • the published artefact against the source — see the next section;
  • CI history: not "is it green" but what share of release runs failed, and whether a failure was noticed.
    gh run list --limit 60 --json conclusion,name
    is one command and it is the closest thing to a production log a package has;
  • telemetry, present or absent. Absent is a finding only when something is deployed; for a library it is a design. Either way the report says which, because "no Sentry configured" and "no errors" must not render the same;
  • adoption, where a registry serves it — downloads make "is this in prod" a measurement rather than an opinion;
  • connected MCP servers — error trackers, analytics, hosting, databases. Ask what the project uses, use what is connected, and record the rest as blind. Read aggregates and pointers, never raw bodies (see The two artefacts).
Before ANY datastore read, in this order — a figure from the wrong database is worse than no figure, because it is quoted with the authority of a measurement:
  1. resolve the datastore from the platform's own attachment, not from a script in the repository and not from a name in the documentation;
  2. prove liveness with a freshest-write aggregate against a table the product writes constantly, and put that timestamp in the report beside every figure it underwrites;
  3. where more than one datastore is attached, name them all with their freshness — an audit that reads one and does not mention the other cannot be reproduced by its reader;
  4. the repository's connect helper is evidence about the repository, never about the platform. Where the two disagree that is a finding of its own, and it is the one this rule was written from.
这是大多数审计会跳过的阶段,也是能够发现代码仓库无法承认自身存在哪些问题的阶段:
  • 已发布产物与源码的对照——见下一节;
  • CI 历史:不只是看“是否为绿色”,而是查看发布运行中有多大比例失败,以及失败是否被发现。
    gh run list --limit 60 --json conclusion,name
    是一条命令,也是 package 最接近生产日志的东西;
  • telemetry 是否存在。 只有在确实有东西部署时,缺失才构成 finding;对于 library 而言,它可能是一种设计选择。无论属于哪种情况,报告都会明确说明,因为“未配置 Sentry”和“没有错误”绝不能呈现为同一种结果;
  • 采用情况——在 registry 提供服务的情况下,下载量可以让“这是否已投入生产”成为测量结果,而不是主观意见;
  • 已连接的 MCP server——错误追踪、分析、托管、数据库。询问项目使用了什么,使用已经连接的服务,并将其余部分记录为 blind。只读取聚合数据和指针,绝不读取原始正文(见“两个产物”)。
在读取任何 datastore 之前,严格按以下顺序执行——来自错误数据库的数字比没有数字更糟,因为人们会带着测量的权威性去引用它:
  1. 从平台自身绑定的 datastore 中解析目标,而不是依据仓库中的脚本,也不能依据文档中的名称;
  2. 使用针对产品持续写入的表所生成的最新写入聚合结果来证明 datastore 仍然存活,并把该时间戳放在报告中所支撑的每个数字旁边;
  3. 如果绑定了多个 datastore,则列出全部 datastore 及其新鲜度——只读取其中一个却不提及其他 datastore 的审计,读者无法复现;
  4. 仓库中的 connect helper 是关于仓库的证据,绝不是关于平台的证据。两者不一致时,这本身就是一项 finding,也是本条规则最初产生的原因。

4. Seams — hand off to the ladder

4. Seam——移交给阶梯

Now, and only now, walk the local portable method's ladder over the capabilities the discovery found. Bottom-up, seam-ordered. Absences found here are findings like any other.
此时,且仅此时,基于发现阶段找到的能力,按照本地 portable method 的阶梯逐层检查。自底向上,并按 seam 顺序排列。在这里发现的缺失,与其他 finding 没有区别。

5. Report — two files, one command

5. 报告——两个文件,一条命令

python3 scripts/audit.py --root <path>
writes the sidecar and prints a summary. Add
--report
for the HTML page, and
--no-open
beside it to write without opening. It is the same script the probes live in, so what the report claims and what ran are the same object.
python3 scripts/audit.py --root <path>
会写入 sidecar 并打印摘要。添加
--report
可生成 HTML 页面,再 alongside 使用
--no-open
则只写入而不打开页面。probe 也实现在同一个脚本中,因此报告所声称的内容与实际运行的内容属于同一个对象。

6. Propose — rows, not edits

6. 提议——只给条目,不做编辑

This skill commits nothing. Findings leave as board rows in the project's own vocabulary, priced with the board header's declared formula — the shipped default is
Sev × Blast + age_bonus
(
references/portable-method.md
, the local priority contract) — and the operator accepts them. Effort never ranks inside an audit: what a fix costs is the fixer's decision, not the finder's (
references/portable-method.md
). An audit that edits while it reads cannot be re-run to check itself. In
task-pipeline
's wave mode these rows and the JSON sidecar are wave 0's input: they join its inventory by id.
此 skill 不会提交任何内容。 finding 会以项目自身使用的术语写成看板条目,并按照看板表头声明的公式定级——随附的默认公式是
Sev × Blast + age_bonus
(
references/portable-method.md
,即本地优先级约定)——最终由操作者接受。
审计内部绝不会使用工作量进行排序:修复成本应由修复者决定,而不是发现者(
references/portable-method.md
)。一边读取一边编辑的审计无法重新运行并验证自身。在
task-pipeline
的 wave 模式中,这些条目和 JSON sidecar 是 wave 0 的输入:它们会按 id 加入 inventory。

A finding keeps its axes apart, or it is a guess wearing a verdict

Finding 必须保持各轴彼此分离,否则它只是披着结论外衣的猜测

Mechanism status, exploit/reproduction, exposure, observed incidence and impact uncertainty are FIVE axes, not one. A row written from the mechanism alone is indistinguishable from a real finding until each axis says what it knows — and one audit had eight consecutive rows rewritten by measurement, two of which would have destroyed inventory if remedied as written, because both read an absence of sales as an absence of demand. But the correction cuts both ways:
  • A proven defect may have incidence UNKNOWN. An auth bypass or a race reproduced locally is a code defect BEFORE any incident — the reproduction is the proof, and no production log is needed to license the row. A confirmed local crash with no production logs stays a code defect, external incidence UNKNOWN.
  • UNKNOWN ≠ 0. A zero sample is not zero risk; absent telemetry lowers what can be said about EXPOSURE, never the technical truth — and the row says which.
  • Unknown attacker control lowers exploitability CONFIDENCE, never the observed behaviour: what was watched happening stays written as watched.
  • A documented exception does not turn a failed invariant into PASS — decision status and technical validity are the separate axes of the section below.
The incidence axis is still asked: how often does the mechanism fire? A query, a log count, a telemetry read. Where the answer is never, keep the row priced as latent (the remedy weighed against zero); where the measurement is impossible, the INCIDENCE axis records
blind
— and the finding stands on its mechanism and reproduction axes. Each row records its observation scope and time, keeping code mechanism, deployment observation and assumptions apart —
templates/finding-evidence.json
in task-pipeline is the minimal schema, and the collector writes
mechanism
/
incidence
/
observed_scope
/
observed_at
into the sidecar. Ask an operator only when the unknown would change the action — an interview is not a prerequisite for a row.
Two rules follow from the same place:
  • Check a remedy against the population it would touch before proposing it. Two rows prescribed releasing an asset class; the measurement showed the asset class was the product's own inventory, deliberately held.
  • An absence is not evidence until the path that would produce the presence has been walked. Zero sales means no demand or no working path, and those two want opposite remedies.
mechanism status、exploit/reproduction、exposure、observed incidence 和 impact uncertainty 是五个独立的轴,而不是一个结论。 如果只根据 mechanism 撰写条目,那么在每个轴分别说明自身掌握的信息之前,该条目与真实 finding 无法区分。一次审计中曾有连续八条条目因测量结果而被重写,其中两条如果按照当时的描述接受修复,会摧毁 inventory,因为它们都把没有销售误读为没有需求。但这个修正同样适用于反方向:
  • 已证明的缺陷,其 incidence 仍可能是 UNKNOWN。 身份验证绕过或能够在本地复现的竞态,在任何事故发生之前就已经是代码缺陷——复现本身就是证明,不需要生产日志才能让条目成立。一个已确认但没有生产日志的本地崩溃仍然是代码缺陷,其外部 incidence 为 UNKNOWN。
  • UNKNOWN ≠ 0。 零样本不等于零风险;缺少 telemetry 只会降低对 EXPOSURE 可作出的判断,不会改变技术事实——条目必须明确说明是哪一种情况。
  • 攻击者控制情况未知,只会降低 exploitability CONFIDENCE,绝不会改变已经观察到的行为:实际观察到的事情仍然按原样记录。
  • 已记录的例外不会把失败的不变量变成 PASS——决策状态与技术有效性是下文各节相互独立的轴。
incidence 轴仍然需要回答:mechanism 多久触发一次? 可以通过查询、日志计数或 telemetry 读取来回答。如果答案是“从不”,则该条目仍应标为 latent(将补救方案与零发生率一同权衡);如果无法测量,则 INCIDENCE 轴记录为
blind
,而 finding 仍可根据 mechanism 和 reproduction 轴成立。每条条目都会记录观察范围和时间,并区分代码机制、部署观察与假设——task-pipeline 中的
templates/finding-evidence.json
是最小 schema,collector 会把
mechanism
、
incidence
、
observed_scope
和
observed_at
写入 sidecar。只有当未知信息会改变行动时才询问操作者——访谈并不是条目成立的前提。
由此得出两条规则:
  • 提出补救方案前,先对照它将影响的总体进行验证。 有两条条目建议释放某类资产;测量结果却显示,该类资产其实是产品有意持有的自有库存。
  • 在走过能够产生某种存在的路径之前,缺失不能算作证据。 零销售既可能意味着没有需求,也可能意味着没有正常工作的路径,而两者需要完全相反的补救方式。

Already decided is not a finding, and it is not nothing either

已决定的事项不是 finding,但也不能说它什么都不是

An audit that reads a module and not the places the module is used reports, as defects, the things the project has already decided — in the project's own words, because the decision is usually written a few lines from the code the finding cites. Five of eight rows in one run were that.
  • Read the call site, not only the definition. A finding about a module is not written until the places that use it have been read.
  • Every row states which of three it is: (a) undecided, (b) decided and documented right here, (c) decided elsewhere and not propagated. (a) and (c) are work — and so is a (b) that is still WRONG, because decision status and technical validity are DIFFERENT AXES. A documented decision can be mistaken, stale, or break an external contract; "it's by design" is not a proof of correctness. So a (b) splits:
    • accepted trade-off — a conscious limitation with a real, named cost the project chose to pay (single-browser support under a matching contract): mark it accepted limitation with its cost, not a defect.
    • documented violation — a decision that STILL breaks a security invariant, an external contract, or its own stated goal (an ADR that permits logging a refresh token): this REMAINS a
      finding
      , carrying the
      decision_id
      , the reason to revisit, and the counter-evidence. Recording a (b) the audit got wrong (a false positive) is worth more than deleting the row; but excluding every documented decision from findings is a systemic source of false NEGATIVES, which is the more expensive miss.
  • Where the verdict is (c), the remedy is a mechanical check, not an edit. A written rule nobody verifies reaches exactly as far as the place it was written; the durable fix in all five cases was a guard that asks the project's own instruction of every copy, not a patch to the copy that happened to be found.
如果审计只读取一个模块,而不读取使用该模块的位置,就会把项目已经决定的事项当作缺陷报告——而且应当使用项目自己的措辞,因为相关决定通常就写在 finding 所引用代码附近几行之处。某次运行中,八条条目里有五条属于这种情况。
  • 读取调用点,而不只是定义。 只有在读过模块的所有使用位置后,才能撰写有关该模块的 finding。
  • 每条条目都要说明属于以下哪一种:(a) 尚未决定,(b) 已决定且在此处有文档记录,(c) 已在别处决定但未传播。(a) 和 (c) 都是工作项,错误的 (b) 同样是工作项,因为决策状态与技术有效性是不同的轴。已记录的决定可能判断错误、内容过时,或破坏外部契约;“这是有意设计”并不能证明其正确性。因此,(b) 又分为:
    • accepted trade-off——项目有意识地接受了一项限制,并明确选择承担某种真实成本(例如在匹配契约下仅支持单一浏览器):将其标记为 accepted limitation 并记录成本,而不是缺陷。
    • documented violation——某项决定仍然破坏了安全不变量、外部契约或项目自身声明的目标(例如一份允许记录 refresh token 的 ADR):它仍然是
      finding
      ,并携带
      decision_id
      、重新审视的原因以及反证。记录一个审计误判的 (b)(false positive),比直接删除该条目更有价值;但把所有已记录决定都排除在 finding 之外,会系统性地产生 false NEGATIVES(漏报),而这种遗漏的代价更高。
  • 当结论为 (c) 时,补救措施应是机械化检查,而不是直接编辑。 无人验证的书面规则,作用范围恰好只到它被写下的位置;在这五个案例中,持久修复方案都是增加一个 guard,让每一份副本都接受项目自身规则的检查,而不是只修补恰好被发现的副本。

Three verdicts, and why the third one exists

三种结论,以及第三种为何存在

clean
·
finding
·
blind
. The vocabulary is closed; a fourth value is refused at construction.
blind
is the whole design.
Without it, a probe that could not look and a probe that found nothing produce the same empty section, and a reader takes the second meaning every time. This is the local method's silence is not a reading raised from a command to a probe: a zero exit with no output has not answered.
The page renders the blind list as a section of its own, never an appendix. An audit's blind spots are part of its result.
clean
·
finding
·
blind
。这是一个封闭的词汇集合;构建时会拒绝第四种取值。
blind
是整个设计的关键。
如果没有它,无法查看的 probe 与没有发现任何问题的 probe 会产生相同的空缺章节,而读者每次都会把后者理解成前者。这就是本地方法中“沉默不等于读取到结果”的原则从命令提升到 probe 后的表达:一个以零退出且没有输出的命令,并没有回答问题。
页面会把 blind 列表渲染为独立章节,绝不会放进 appendix。审计的盲区是其结果的一部分。

The class that version checks cannot see

版本检查看不到的那一类问题

One version string, more than one tree. A package's channels do not all serve the same thing: a registry serves the tag, while a plugin marketplace and a skills CLI serve the branch tip. When the branch has moved past the tag without a version bump, every channel answers the same number and ships different code.
Measured in this family on 2026-08-22: npm served one file at 4344 lines while the marketplace served it at 4575, and all three channels reported
1.15.0
. The pin checker was green throughout — correctly, because it compared the two strings.
So compare trees, never labels, and compare the pair that can actually disagree. The first draft of this probe compared the registry tarball against the tag and reported clean: those agree by construction, because the registry publishes from the tag. A tautology returning green is the false success shape — a mechanism trusted by its own reply.
Two more traps, both of which shipped in the first draft and are now fixtures:
  • A path in one channel and not the other is packaging, not divergence. A tarball ships what its
    files
    allowlist permits; counting
    .github/
    as a disagreement produced 22 findings where one file had moved.
  • Compare only when both sides claim the same version. A branch already bumped past its tag makes no common claim, and is
    blind
    , not
    clean
    .
一个版本字符串,却可能对应多棵代码树。 一个 package 的各个发布渠道并不都提供相同内容:registry 提供 tag,而 plugin marketplace 和 skills CLI 提供 branch tip。当 branch 已经超过 tag、却没有更新版本号时,所有渠道都会返回同一个版本号,却交付不同的代码。
该案例于 2026-08-22 实测:npm 提供的文件为 4344 行,而 marketplace 提供的同一文件为 4575 行,三个渠道却都报告
1.15.0
。整个过程中,版本固定检查器始终为绿色——它这样判断是正确的,因为它只比较了两个版本字符串。
因此,应比较代码树,绝不比较标签,并且必须比较真正可能不一致的一对对象。该 probe 的第一版曾将 registry tarball 与 tag 比较,并报告 clean:这两者按定义必然一致,因为 registry 本身就是从 tag 发布的。返回绿色的同义反复正是“假成功”的形态——一种机制盲信自己的回复。
另有两个陷阱,都在第一版中实际出现,如今已成为 fixture:
  • 一个渠道中存在而另一个渠道中不存在的路径,属于打包差异,不是代码分歧。 tarball 只包含其
    files
    allowlist 允许的内容;把
    .github/
    计入分歧,曾因一个文件发生移动而产生 22 条 finding。
  • 只有双方都声明相同版本时才能比较。 如果 branch 的版本已经超过 tag,双方就不存在共同的版本声明,此时应为
    blind
    ,而不是 clean。

The artefacts — the sidecar always, the page on request

两个产物——始终生成 sidecar,按需生成页面

docs/audit/<date>-audit.json
is written on every run. The HTML page is written only with
--report
.
Three output modes, and only one needs a browser: stdout (
--stdout
— the summary in the terminal, nothing written but the sidecar), json (the sidecar alone, the default — a machine reads it, no page and no browser), html (
--report
— the page too). A json-only or stdout run never opens a browser and never requires one; the browser is a concern of
--report
alone.
The split is not symmetry. The sidecar is what makes this a ratchet rather than a snapshot, and the next run reads it — skipping it would silently turn every future run into a first run. The page is a report, and a report is an artefact that outlives the conversation: one nobody asked for is a document nobody ordered and nobody maintains, sitting untracked under
docs/
one
git add -A
from the product's history. Answer in the conversation; write the page when somebody wants a page.
The page carries aggregates and pointers, never raw bodies. Counts, top classes, trends, and a link to the issue in its own system — never a stack trace, a log line or a row of data. The report is a file people forward, and a report that cannot be shared is one nobody writes twice.
A secret is reported by place and class, never by value.
file:line
, which credential it is, and the remedy. The value appears in neither artefact nor on stdout: an audit must not become the second place a credential leaks. Redaction is total rather than a prefix — half a credential plus its context is often enough to finish.
"Read-only" is about the TARGET, not the disk. The audit reads the project's source, data and production evidence and mutates NONE of it, and it commits nothing. It DOES write its own artefacts into its allowed output directory (
docs/audit/
by default,
--out-dir
to relocate) — the sidecar always, the page on
--report
. Writing the sidecar there is not a violation of read-only; writing into the target's source, or
git add
-ing anything, is.
The sidecar is what makes this a ratchet rather than a snapshot. Each finding carries an id derived from its probe and its place, so it survives a rewording; the next run prints what closed, what is new, and what has now survived three audits. That last number is itself a finding: a defect nobody picks up is a decision nobody wrote down.
每次运行都会写入
docs/audit/<date>-audit.json
。只有使用
--report
时才会写入 HTML 页面。
一共有三种输出模式,其中只有一种需要浏览器:
  • stdout(
    --stdout
    ——在终端打印摘要,除 sidecar 外不写入其他内容);
  • json(只生成 sidecar,默认模式——供机器读取,不生成页面,也不需要浏览器);
  • html(
    --report
    ——同时生成页面)。
仅 json 或 stdout 的运行绝不会打开浏览器,也绝不要求安装浏览器;浏览器只与
--report
有关。
这种拆分并非出于对称。sidecar 才是让审计成为棘轮式累积(ratchet)而非一次性快照的机制,下一次运行会读取它——如果跳过 sidecar,之后的每次运行都会在无声无息中退化成第一次运行。页面则是一份报告,而报告是一种会比对话更持久的产物:没人要求的页面,就是没人订购、也没人维护的文档,搁置在
docs/
下未纳入版本控制,距离被一次
git add -A
纳入产品历史只差一步。在对话中回答;只有当有人需要页面时,才写入页面。
页面只包含聚合数据和指针,绝不包含原始正文。 可以包含计数、主要类别、趋势,以及指向其自身系统中 issue 的链接——绝不包含 stack trace、日志行或数据行。报告是人们会转发的文件;无法分享的报告,也不会有人编写第二次。
Secret 只按位置和类别报告,绝不按值报告。 记录
file:line
、凭据类别以及补救措施。凭据值既不会出现在任何产物中,也不会出现在 stdout 中:审计绝不能成为凭据泄漏的第二个位置。脱敏必须是完全脱敏,而不只是隐藏前缀——半截凭据加上上下文,通常已经足以完成泄漏。
“只读”针对的是目标,而不是磁盘。 审计会读取项目的源码、数据和生产环境证据,却绝不修改其中任何内容,也不会提交任何内容。但它确实会把自身产物写入允许的输出目录(默认为
docs/audit/
,可通过
--out-dir
更改)——始终写入 sidecar,使用
--report
时再写入页面。向该目录写入 sidecar 不违反只读原则;写入目标源码或执行
git add
才违反。
sidecar 才是让审计成为棘轮式累积而非快照的关键。 每条 finding 都带有一个由 probe 和位置推导出的 id,因此能够在措辞变化后继续存在;下一次运行会打印哪些问题已经关闭、哪些是新问题,以及哪些问题已经连续三次审计仍然存在。最后这个数字本身就是一项 finding:一直无人处理的缺陷,意味着有人作出了决定,却没有把它写下来。

What the script does and what you do

脚本做什么、你做什么

The scriptYou
discovery, the registry, mechanical probes, the sidecar, the page on
--report
, the diff
the seam walk, MCP evidence, judgement about what a finding means
refuses a fourth verdict, redacts secrets, excludes its own outputdeciding severity and effort, writing the remedy that fits this project
The split is not tidiness. A judgement encoded in a script becomes a gate nobody agreed to; a mechanic left in prose becomes a step nobody runs. Both have shipped in this family and both are on its boards.
Run the script first, read its blind list, then spend your reading where it could not look.
脚本你
发现、注册表、机械 probe、sidecar、按
--report
生成页面、diff
seam 检查、MCP 证据、判断一条 finding 的含义
拒绝第四种结论、脱敏 secret、排除自身输出决定严重性和工作量、编写适合该项目的补救方案
这种拆分并非出于整洁。编码进脚本的判断会变成一道无人同意过的门禁;留在文字中的机械步骤会变成一个无人执行的步骤。 两者在这一系列中都曾实际出现,也都出现在其看板上。
先运行脚本,读取它的 blind 列表,然后把精力花在它无法查看的地方。

Exit criterion

完成标准

An audit is finished when — the criterion is CONDITIONAL on the deliverables requested, not a fixed page-and-browser:
  1. every probe has a verdict, and every
    blind
    one names why;
  2. the sidecar is written (always). On
    --report
    , and only then
    , the HTML page also exists, its internal links are safe and resolve, and its inspect/render status is recorded (opened, or
    --no-open
    noted) — WITHOUT
    --report
    no page is created and the run is still complete;
  3. every number in the report was produced by a command this run executed — a restated count is an assertion (
    evidence-docs
    );
  4. at least one figure was re-derived by a differently-shaped command and both were printed. Re-running the same command is a spell-check of the first run;
  5. the proposed rows are printed for the operator, with nothing written to the target.
审计在满足以下条件时即告完成——该标准要根据请求的交付物而定,而不是固定要求生成页面和打开浏览器:
  1. 每个 probe 都有结论,每个
    blind
    都说明原因;
  2. sidecar 已写入(始终需要)。仅在使用
    --report
    时
    ,HTML 页面也必须存在,其内部链接必须安全且能够解析,并且要记录检查/渲染状态(已打开,或注明使用了
    --no-open
    )——不使用
    --report
    时不创建页面,但运行仍视为完成;
  3. 报告中的每个数字都由本次运行实际执行的命令生成——重新陈述的计数属于断言(
    evidence-docs
    );
  4. 至少有一个数字通过采用不同形式的命令重新推导,并且两种结果都已打印。重复运行同一条命令,只是对第一次运行做拼写检查;
  5. 提议的条目已打印给操作者,且没有向目标写入任何内容。

Rationalizations

借口与现实

ExcuseReality
"The tests pass, so the project is healthy"Tests compare what somebody thought to write down. This phase 3 exists because the sharpest defect in this family was invisible to a green suite in every repository it touched.
"There's no Sentry, so there are no errors to report"Those are the same empty section and opposite facts. That is what
blind
is for.
"The versions match, so the channels agree"Measured: three channels, one version string, 231 lines of difference. Compare trees.
"I'll note the raw log lines so we have context"Then the report cannot be shared, and it will not be written again. Aggregate and point.
"I found a credential — I'll paste it so we can check it's live"The report becomes the second leak. Place and class; rotation is the remedy.
"Findings should just be fixed while I'm in there"An audit that edits while it reads cannot re-run to check itself, and the next run cannot tell a fix from a rewording.
"It's the same nine checks every time, so I can skip discovery"Then the instrument returns the same answer for every input, which is a fact about the instrument and not about the project.
"No findings — clean bill"Only against the probes that ran. Read the blind list before saying that sentence out loud.
借口现实
“测试通过了,所以项目是健康的”测试比较的只是有人认为应当写下来的东西。设置第 3 阶段,正是因为这一类问题中最严重的缺陷,在它触及的每个仓库里都对全绿的测试套件不可见。
“没有 Sentry,所以没有错误可报告”两者会呈现相同的空缺章节,却代表相反的事实。这正是
blind
的用途。
“版本一致,所以各渠道也一致”实测结果:三个渠道、同一个版本字符串,却相差 231 行。应比较代码树。
“我会记下原始日志行,这样就有上下文了”这样报告就无法分享,也不会再有人编写第二次。只保留聚合数据和指针。
“我发现了一个凭据——把它粘贴出来,就能检查它是否仍然有效”报告会成为第二次泄漏。只记录位置和类别;轮换凭据才是补救措施。
“既然已经来了,就应该在审计时直接修复 finding”一边读取一边编辑的审计无法重新运行并验证自身,下一次运行也无法区分真正修复与 merely 改写措辞。
“每次都是相同的九项检查,所以可以跳过发现阶段”这样工具对任何输入都会返回相同答案,而这是关于工具的事实,不是关于项目的事实。
“没有 finding——完全 clean”这一结论只对已经运行的 probe 有效。说出口之前,先阅读 blind 列表。

Triggers

触发条件

The description is the short form. The full trigger list it carried until 1.98.0, moved here verbatim, still routes to this skill:
"Use when someone asks what is actually true of a whole project right now — what is finished, what is half-built, what is broken, and what nobody has looked at. Walks a cold start: discover what the project is, run a registry of probes chosen from that, read production evidence (published artefact against source, CI history, telemetry present or absent), then leave a JSON sidecar so the next audit can say what moved, and a self-contained HTML report on request. Read-only: it proposes board rows and commits nothing. Triggers - 'project audit', 'audit the project', 'codebase audit', 'state of the project', 'what is unfinished', 'project health check', 'аудит проекта', 'проаудируй проект', 'состояние проекта', 'что не доделано', 'аудит кодовой базы'. Not for: auditing one deliverable inside a run (that is the pipeline's own ladder), reviewing a diff, or checking a skill's construction — say 'без диагностики' to opt out."
description 是简短形式。它截至 1.98.0 所携带的完整触发词列表现已逐字移至此处,但仍然会路由到此 skill:
“当有人询问整个项目当前究竟是什么状态——什么已经完成、什么只完成了一半、什么已经损坏、什么从未被检查过时使用。执行一次冷启动:先发现项目是什么,再运行据此选择的 probe 注册表,读取生产环境证据(已发布产物与源码的对照、CI 历史、telemetry 存在与否),随后留下 JSON sidecar,让下一次审计能够说明发生了什么变化,并可按需生成一份自包含的 HTML 报告。只读:提出看板条目,不提交任何内容。触发词 - 'project audit', 'audit the project', 'codebase audit', 'state of the project', 'what is unfinished', 'project health check', 'аудит проекта', 'проаудируй проект', 'состояние проекта', 'что не доделано', 'аудит кодовой базы'。不适用于:审计单次运行中的单个交付物(那属于 pipeline 自身的阶梯)、审查 diff,或检查 skill 的构建——说出 'без диагностики' 即可选择退出。”