Просмотр исходного кода

docs(testing): add CI test reliability skill

Yichen Jiang 4 недель назад
Родитель
Сommit
94c714d813

+ 6 - 0
.agents/notes/implemented/testing/2026-08-28-ci-test-reliability-skill.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write .agents/notes/implemented/testing/2026-08-28-ci-test-reliability-skill.md
+2026-08-28-ci-test-reliability-skill.md: 5edf2aa769047cb5d4052a1338f2cc3886d9e0f9
+2026-08-28-ci-test-reliability-skill.zh.md: fd1a6d584f3c4686761f8c94ba99ee0d1c9b0233

+ 41 - 0
.agents/notes/implemented/testing/2026-08-28-ci-test-reliability-skill.md

@@ -0,0 +1,41 @@
+# Agent Note: CI test reliability skill
+
+Status: implemented
+
+English | [中文](2026-08-28-ci-test-reliability-skill.zh.md)
+
+## Problem
+
+DeepSeek Harness runs tests across concurrent Vitest files, worker processes, repository gates, and Actions jobs. Process isolation does not isolate host ports, predictable paths, external namespaces, or inherited children, while process-global mutations and incomplete teardown can contaminate later tests. A test can select the correct tier and still pass only when it runs alone.
+
+The testing policy owns test tiers, defensive patterns own runtime lifecycle rules, pre-push guidance selects commands, and code review evaluates completed diffs. None of them gives an agent a focused workflow for designing resource-owning tests against the real CI topology or classifying an existing probabilistic failure before changing code.
+
+## Decision
+
+[dsh-ci-test-reliability](../../../skills/dsh-ci-test-reliability/SKILL.md) owns test isolation and CI-flake diagnosis guidance. It applies when tests or fixtures acquire host resources, mutate process-global state, depend on asynchronous readiness, own subprocesses or network listeners, or exhibit probabilistic CI failures.
+
+The skill requires agents to model concurrency beyond one Vitest process, allocate live resources atomically, separate stable fixture identities from ephemeral transport addresses, synchronize on observable state, restore global mutations exactly, and await teardown to quiescence. Regression evidence matches the owned risk: negative controls for guards, deterministic barriers for races, concurrent independent processes for host-resource isolation, and external observations instead of component self-reports.
+
+The diagnosis-only workflow lives in a separate reference so ordinary authoring does not load Actions triage procedure. It compares passing and failing evidence before classifying host collisions, incomplete lifecycle, global contamination, load-sensitive synchronization, platform or entry-path failures, product races, provider transience, or runner infrastructure.
+
+[dsh-pre-push-checks](../../../skills/dsh-pre-push-checks/SKILL.md) conditionally consults the reliability skill before selecting commands, while [dsh-code-review](../../../skills/dsh-code-review/SKILL.md) applies it when reviewing risky tests. Command selection and general PR review remain with those existing skills.
+
+This decision partially overlaps the [deterministic and stress testing proposal](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.md). The skill ships authoring and diagnosis guidance; it does not implement that proposal's lint rule, universal replay fixture, or nightly stress job, so the proposal remains active.
+
+## Alternatives considered
+
+**Expand dsh-pre-push-checks.** Pre-push guidance runs after test design and owns evidence selection. Making it also own resource allocation, synchronization, teardown, and CI diagnosis would mix two different decisions and load reliability procedure for ordinary pushes.
+
+**Expand dsh-code-review.** Review guidance can detect unreliable tests after a diff exists, but it cannot guide the agent while the fixture is being designed or while a failure is being diagnosed without a PR.
+
+**Put the complete workflow in the standing testing policy.** The testing policy must remain the concise authority for tiers and placement. Loading detailed Actions diagnosis and resource-specific procedure for every test task would duplicate situational guidance and make that policy harder to scan.
+
+**Add a generic stress runner or regex gate immediately.** Repeated green runs do not prove a race is controlled, and literal ports, paths, sleeps, and URLs can be valid parser inputs or expected values. A later high-signal defect class can justify a narrow executed check without making broad textual matches policy.
+
+## Consequences
+
+Agents receive the reliability rules while designing or diagnosing the tests that need them, and pre-push and review workflows share the same criteria without duplicating the procedure. Pure deterministic tests continue to use the normal focused evidence path.
+
+The skill is advisory, so it cannot mechanically prevent every resource collision. A repeated, statically identifiable defect can still justify an executed repository check. The repository also retains one additional active Skill and reference whose links and statements must remain current with the actual CI topology.
+
+The existing deterministic-and-stress proposal remains open, and this change does not audit or rewrite the current test corpus.

+ 41 - 0
.agents/notes/implemented/testing/2026-08-28-ci-test-reliability-skill.zh.md

@@ -0,0 +1,41 @@
+# Agent Note: CI 测试可靠性 Skill
+
+Status: implemented
+
+[English](2026-08-28-ci-test-reliability-skill.md) | 中文
+
+## 问题
+
+DeepSeek Harness 会在并发的 Vitest 文件、worker 进程、仓库 gate 与 Actions job 中运行测试。进程隔离不会隔离宿主机端口、可预测路径、外部命名空间或继承的子进程,而进程全局状态变更与未完成的 teardown 可能污染后续测试。即使测试选择了正确层级,也可能只在独占运行时通过。
+
+测试政策负责测试层级,防御性模式负责运行时生命周期规则,pre-push 指引负责选择命令,代码 review 负责检查已完成的 diff。它们都没有为 agent 提供一个聚焦流程,用于按照真实 CI 拓扑设计会占用资源的测试,或在修改代码前对已有概率性失败进行分类。
+
+## 决策
+
+[dsh-ci-test-reliability](../../../skills/dsh-ci-test-reliability/SKILL.md) 负责测试隔离与 CI 概率性失败诊断指引。测试或 fixture 占用宿主机资源、修改进程全局状态、依赖异步就绪、持有子进程或网络 listener,或出现概率性 CI 失败时,使用该 Skill。
+
+该 Skill 要求 agent 建模单个 Vitest 进程之外的并发,原子分配实时资源,把稳定 fixture 标识与临时传输地址分开,按可观察状态同步,精确恢复全局变更,并等待 teardown 达到静止状态。回归证据与所持有的风险匹配:guard 使用负向控制,竞态使用确定性 barrier,宿主机资源隔离使用并发独立进程,并以外部观察代替组件自述。
+
+仅用于诊断的流程放在单独 reference 中,因此普通编写任务不会加载 Actions 分诊步骤。它会先比较成功与失败证据,再对宿主机冲突、未完成生命周期、全局状态污染、负载敏感同步、平台或入口路径失败、产品竞态、provider 瞬时故障或 runner 基础设施进行分类。
+
+[dsh-pre-push-checks](../../../skills/dsh-pre-push-checks/SKILL.md) 在选择命令前按条件引用可靠性 Skill,[dsh-code-review](../../../skills/dsh-code-review/SKILL.md) 则在 review 高风险测试时应用它。命令选择与通用 PR review 仍由这些现有 Skill 负责。
+
+该决策与[确定性与压力测试提案](../../proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md)部分重合。该 Skill 交付测试编写与诊断指引,但没有实现提案中的 lint 规则、通用回放 fixture 或 nightly stress job,因此提案保持活跃。
+
+## 考虑过的替代方案
+
+**扩展 dsh-pre-push-checks。** Pre-push 指引在测试设计之后运行,负责选择证据。如果它还负责资源分配、同步、teardown 与 CI 诊断,就会混合两种不同决策,并让普通 push 也加载可靠性流程。
+
+**扩展 dsh-code-review。** Review 指引可以在 diff 已存在后发现不可靠测试,但无法在 fixture 设计过程中指导 agent,也无法在没有 PR 时指导故障诊断。
+
+**把完整流程放入常驻测试政策。** 测试政策需要保持为测试层级与放置规则的简洁权威来源。让每个测试任务都加载详细 Actions 诊断与资源专项流程,会重复情境性指引,也会降低政策的可扫描性。
+
+**立即增加通用 stress runner 或正则 gate。** 重复运行保持绿色不能证明竞态已受控,而字面端口、路径、sleep 与 URL 可能是合法的 parser 输入或期望值。未来若出现高信号缺陷类型,可以增加窄范围的可执行检查,而不必把宽泛文本匹配当成政策。
+
+## 后果
+
+Agent 在设计或诊断确实需要这些规则的测试时获得可靠性指引,pre-push 与 review 流程也能共用同一套标准而不复制步骤。纯确定性测试继续采用普通的聚焦证据路径。
+
+该 Skill 属于指导性规则,无法机械阻止所有资源冲突。如果某种缺陷反复出现且能被静态识别,仍可增加可执行的仓库检查。仓库也会多维护一个活跃 Skill 与 reference,其链接和陈述必须与真实 CI 拓扑保持一致。
+
+现有确定性与压力测试提案继续开放,本变更也不会审计或重写当前测试语料库。

+ 2 - 2
.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.md
-2026-06-11-deterministic-and-stress-testing.md: d9977be835af05f9ee303b63ec6015bc9e153170
-2026-06-11-deterministic-and-stress-testing.zh.md: 263e69f85a1cd8ee47da07210e513cab272d1a44
+2026-06-11-deterministic-and-stress-testing.md: fd69611a393e36df5c5707640175bfd85c8e77ea
+2026-06-11-deterministic-and-stress-testing.zh.md: 5ba8dbe4cf2a6c08bf1a3d68def9f801430b176a

+ 2 - 0
.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.md

@@ -4,6 +4,8 @@ Status: proposed
 
 English | [中文](2026-06-11-deterministic-and-stress-testing.zh.md)
 
+The [CI test reliability skill](../../implemented/testing/2026-08-28-ci-test-reliability-skill.md) provides current authoring and diagnosis guidance without implementing the lint rule, universal replay fixture, or nightly stress job proposed here. Those mechanisms remain proposed.
+
 ## Problem
 
 Several loop tests synchronize with `setTimeout(30)` sleeps — flakiness debt that wastes agent cycles on retries and can mask ordering bugs. Separately, our core architectural promise (any session log replays to identical derived history) is asserted in two tests but is cheap to assert *everywhere*. And the inbox wakeup race was verified by hand exactly once; nothing re-verifies it continuously.

+ 2 - 0
.agents/notes/proposed/testing/2026-06-11-deterministic-and-stress-testing.zh.md

@@ -4,6 +4,8 @@ Status: proposed
 
 [English](2026-06-11-deterministic-and-stress-testing.md) | 中文
 
+[CI 测试可靠性 Skill](../../implemented/testing/2026-08-28-ci-test-reliability-skill.zh.md) 提供当前的测试编写与诊断指引,但没有实现本提案中的 lint 规则、通用回放 fixture 或 nightly stress job。这些机制仍处于提案状态。
+
 ## 问题
 
 若干 agent loop(智能体循环)测试通过 `setTimeout(30)` 睡眠来同步——这是一笔不稳定性债务,浪费 agent 的重试周期,还可能掩盖时序 bug。另外,我们的核心架构承诺(任何会话日志回放后都能得到相同的派生历史)目前只在两个测试中断言,但在*所有*测试中断言的成本极低。此外,inbox 唤醒竞态只被手动验证过一次,没有任何机制持续复验。

+ 109 - 0
.agents/skills/dsh-ci-test-reliability/SKILL.md

@@ -0,0 +1,109 @@
+---
+name: dsh-ci-test-reliability
+description: Design, review, and diagnose DeepSeek Harness tests and fixtures that can fail nondeterministically under CI concurrency, shared host resources, clocks, process-global state, subprocesses, network listeners, or asynchronous teardown. Use when adding or changing tests with those risks, investigating flaky CI, or reviewing test isolation; use dsh-pre-push-checks separately to select outgoing commands.
+---
+
+# Reliable DSH CI tests
+
+Build tests that remain correct under the repository's real CI topology, not only when run alone on a quiet workstation. This skill owns isolation and reliability decisions; it does not replace the repository's test-tier policy or select every command for a push.
+
+## Read the owning rules
+
+- Use [the testing policy](../../../docs/testing.md) to select unit, coverage, expected-output, snapshot, browser, or real-API evidence.
+- Use [the defensive patterns](../../../docs/defensive-patterns.md) for lifecycle, subprocess, cancellation, and teardown behavior.
+- Read the active Vitest config and GitHub workflow when their worker or job topology affects the test.
+- For recorded-session scenarios, also follow [the snapshot instructions](../../../snapshots/AGENTS.md).
+- Use [dsh-pre-push-checks](../dsh-pre-push-checks/SKILL.md) after the test design is sound to select outgoing validation.
+
+## Model the execution topology
+
+Assume these layers can overlap unless the active configuration proves otherwise:
+
+1. Tests in one Vitest file.
+2. Separate Vitest files or worker processes.
+3. Independent Vitest or repository-gate processes in one job.
+4. Different Actions jobs whose runners share one host.
+
+Process isolation does not isolate host ports, predictable filesystem paths, external services, databases, sockets, or inherited child processes. For every acquired resource, identify its owner, atomic allocation mechanism, observable readiness signal, registered cleanup, and quiescent completion signal.
+
+Do not serialize an entire suite merely because one fixture lacks isolation. Narrow the exclusive scope or change the resource allocation first. A sequential Vitest block cannot protect a host resource from another file, process, job, or runner.
+
+## Allocate resources atomically
+
+Use the resource owner's allocator instead of checking availability and claiming it later.
+
+- Network fixtures bind loopback with `listen(0)` and read the assigned address only after the server reports that it is listening. Never scan for a free port and bind it later.
+- Create private per-test temporary roots with `mkdtemp`; do not acquire predictable shared paths.
+- Give shared databases, sockets, sessions, and output locations unique per-test namespaces.
+- Use exclusive creation where a path must not already exist.
+- Keep stable recorded identifiers separate from ephemeral transport addresses. Translate inside the fixture instead of forcing the live resource to use the recorded value.
+
+Literal paths and URLs used only as parser inputs or expected values are not acquired resources. Do not rewrite them merely because they look fixed.
+
+## Contain process-global state
+
+Treat `process.env`, `cwd`, fake timers, locale and timezone, module mocks, registries, console hooks, `globalThis`, and global `fetch` interception as exclusive mutable resources.
+
+Prefer an injected dependency or instance-local adapter. When mutation is required:
+
+- capture whether the original value was absent or present;
+- restore that exact state;
+- register restoration immediately;
+- use `try/finally` around the smallest mutation scope;
+- keep an `afterEach` fallback when failure before the local `finally` is plausible;
+- intercept the narrowest exact request or call that the fixture owns.
+
+## Synchronize on state
+
+A fixed sleep is not evidence that setup completed or cleanup settled.
+
+- Wait for an explicit readiness event, handshake, state transition, owned promise, or externally observable condition.
+- Use deferred promises or barriers to place a race at a deterministic point and prove the relevant operations overlap.
+- Use a timeout only to bound a wait, never as the condition that makes the assertion correct.
+- Do not assert scheduler-dependent ordering unless that ordering is the product behavior under test.
+- When time itself is the subject, inject or fake the clock and always restore real timers.
+
+## Dispose to quiescence
+
+Register cleanup immediately after acquisition so assertion failures also release the resource. Cleanup stops new callbacks or requests, detaches listeners, restores global hooks, terminates owned work, and awaits child exit, server close, worker termination, or the equivalent completion signal.
+
+Calling `abort()`, `close()`, or `kill()` without awaiting the owned completion signal is incomplete teardown. When late completion is possible, prove that disposal prevents it from mutating another test.
+
+## Prove the intended regression
+
+- Observe an ordinary regression fail before the fix when practical.
+- For a new static or corpus guard, temporarily introduce the rejected case and observe the intended failure.
+- For a race, use barriers to prove overlap; repeated execution alone is not a race test.
+- For ports, sockets, shared paths, subprocesses, or other host resources, run independent test processes concurrently when cross-process isolation is part of the fix.
+- Verify external state, events, files, logs, exits, or disposal instead of trusting the component's self-report.
+
+Stress runs supplement a deterministic regression; they do not replace one.
+
+## Reject flake-masking fixes
+
+Do not present these as root-cause fixes for deterministic local tests:
+
+- increasing a timeout without identifying the awaited state;
+- adding retries;
+- making all files serial;
+- swallowing an error or unhandled rejection;
+- weakening an assertion;
+- normalizing away unstable behavior;
+- adding a sleep before cleanup or assertion.
+
+Retries remain valid for documented transient external-provider tests under the real-API policy. Keep that exception at the external boundary.
+
+## Diagnose existing flakes
+
+For an existing probabilistic CI failure, read [the CI flake diagnosis workflow](references/ci-flake-diagnosis.md). A diagnosis-only request remains read-only: report the cause and evidence unless the user also asks for a fix.
+
+## Validate and report
+
+Run the smallest focused regression for the affected behavior. Add topology-specific evidence only when the change owns that risk:
+
+- global mutation needs restoration evidence;
+- lifecycle or subprocess work needs quiescent teardown evidence;
+- ports, sockets, or shared paths need concurrent independent-process evidence;
+- a new guard needs a negative control.
+
+Before a push, use [dsh-pre-push-checks](../dsh-pre-push-checks/SKILL.md). Report exact commands and observed results; do not describe retries, skipped tests, or pending CI as passing.

+ 58 - 0
.agents/skills/dsh-ci-test-reliability/references/ci-flake-diagnosis.md

@@ -0,0 +1,58 @@
+# CI flake diagnosis
+
+Use this workflow only when the task is to investigate an existing probabilistic test or CI failure. Preserve the requested read/write scope: diagnosis does not authorize a fix, workflow rerun, or CI configuration change.
+
+## Freeze the evidence
+
+Record the repository, workflow, job, commit SHA, runner labels, timestamps, exact failing test or command, and the first stable failure signature. Keep infrastructure messages separate from test output.
+
+Compare multiple failing and passing runs. Prefer runs of the same SHA; when that is impossible, verify that the relevant test and CI configuration are identical across the compared commits. One passing rerun does not prove an infrastructure fault, and one timeout does not prove a product race.
+
+Use Actions logs and metadata to establish whether failures overlap on one host or resource namespace. Preserve links to the supporting runs rather than pasting large logs.
+
+## Classify the failure
+
+Classify from recorded evidence, not from the eventual fix:
+
+- **Host-resource collision:** the same port, socket, database, predictable path, cache, or external namespace is acquired by independent processes or jobs.
+- **Incomplete lifecycle:** teardown returns before children, workers, streams, servers, or callbacks reach quiescence; later output or mutations appear in another test.
+- **Process-global contamination:** outcome depends on test order or leaked `process.env`, `cwd`, fake timers, globals, mocks, locale, or module state.
+- **Load-sensitive synchronization:** a sleep, polling interval, or assumed event-loop turn substitutes for observable readiness or completion.
+- **Platform or entry-path mismatch:** the failure consistently follows an operating system, shell, filesystem rule, source/build mode, or executable entry.
+- **Product concurrency defect:** the test controls its resources, reproduces deterministically with explicit overlap, and exposes a race in shipped behavior.
+- **External-provider transience:** the failure is owned by a live API or network boundary and matches its documented retry policy.
+- **Runner infrastructure:** checkout, dependency download, disk, host process, or runner service fails independently of the test command. Require direct runner evidence before assigning this class.
+
+If evidence supports more than one independent fact, report each one. Do not collapse a timeout, signal, exit code, and assertion into a single inferred outcome.
+
+## Reproduce the smallest relevant topology
+
+Start with the owning test file or focused test name. Increase concurrency only to the first topology that reproduces the signature:
+
+1. one test process;
+2. concurrent tests or files;
+3. multiple independent Vitest processes;
+4. the owning repository gate with its configured worker count;
+5. separate jobs or runner processes sharing the implicated host resource.
+
+Match the active Vitest config, environment knobs, source/build mode, and platform. Do not lower a production timeout or add random load merely to manufacture a different failure.
+
+For a suspected race, replace probabilistic timing with a barrier at the contested transition. For a suspected host collision, prove simultaneous acquisition of the same identifier or prove that atomic unique allocation removes the conflict.
+
+## Fix at the owner
+
+When implementation is authorized, fix the component that allocates, publishes readiness, mutates global state, or owns teardown. Do not hide the failure in a snapshot normalizer, retry wrapper, broader timeout, global serialization setting, or weaker assertion.
+
+Keep stable fixture data separate from live resource allocation. A recorded URL can remain stable while the fixture maps its transport to an OS-assigned port; a stable expected path can remain an assertion without becoming a shared writable directory.
+
+## Close the investigation
+
+The evidence is complete when:
+
+- the original signature has a supported classification;
+- the smallest relevant topology reproduces it, or the external evidence is sufficient and the reproduction limit is explicit;
+- an authorized fix fails under a negative control or pre-fix state and passes under the same topology afterward;
+- any concurrent-process, restoration, or quiescent-teardown proof required by the resource owner passes;
+- remaining Actions checks are reported as passing, pending, skipped, or failing from their observed state.
+
+Do not run until a test happens to pass and call that result stable. Stop after the selected evidence establishes the conclusion, or report the missing fact that blocks classification.

+ 2 - 1
.agents/skills/dsh-code-review/SKILL.md

@@ -13,6 +13,7 @@ description: Use when reviewing a pull request in the deepseek-harness repo —
 - [docs/defensive-patterns.md](../../../docs/defensive-patterns.md): subprocess, callback, async-state, and disposal bug classes.
 - [docs/AGENTS.md](../../../docs/AGENTS.md): documentation placement and prose discipline.
 - [dsh-prose-standard](../dsh-prose-standard/SKILL.md): required coverage and editorial judgment for comments, docs, prompts, and visible strings.
+- [dsh-ci-test-reliability](../dsh-ci-test-reliability/SKILL.md): isolation and regression-proof rules for resource-owning, asynchronous, or flaky tests and fixtures.
 - [docs/testing.md](../../../docs/testing.md) and the [quality-gates Agent Note](../../notes/implemented/process/2026-06-11-quality-gates.md): required test tiers and gates.
 - [Agent Notes](../../notes/README.md): design rationale. Treat disagreement with an Agent Note as a design discussion, not an automatic veto.
 - For bilingual changes, read [translation-rules.md](../../../docs/i18n/translation-rules.md) and [terminology.md](../../../docs/i18n/terminology.md); the extended translation skill is outside automatic review and runs only on explicit user invocation.
@@ -39,7 +40,7 @@ description: Use when reviewing a pull request in the deepseek-harness repo —
 - **Borrowed and derived state:** determine whether each retained value is borrowed or owned under the package contract, then trace notifications and every cache, prompt, UI echo, replay, and query view to the documented success point and authoritative source.
 - **Bounds cover the final operation:** locate the owner of the complete emitted or retained result, including wrappers and metadata. Probe tiny and exact limits, oversized single chunks, and multibyte text for byte limits.
 - **Real entry path:** tests exercise the shipped Loader, bin, worker, ACP bridge, or subprocess where relevant. A hand-mounted plugin does not catch invalid Loader exports; a function plugin must named-export its namespace and have no default export.
-- **Test strength:** assertions fail on the intended regression and verify external state, logs, events, or disposal rather than restating the implementation or trusting an agent's report. Coverage is necessary but not evidence that the scenario is correct.
+- **Test strength:** assertions fail on the intended regression and verify external state, logs, events, or disposal rather than restating the implementation or trusting an agent's report. For resource-owning, asynchronous, or flaky tests, apply [dsh-ci-test-reliability](../dsh-ci-test-reliability/SKILL.md) to the real worker/job topology, allocation, restoration, synchronization, and quiescent teardown. Coverage is necessary but not evidence that the scenario is correct.
 - **Invariant lifecycle and negative controls:** verify candidate observations are rejected before publication where possible, session-backed checks reconstruct durable history after late loading or HMR, and a deliberately invalid case fails through the real runner for the intended rule.
 - **Implemented Agent Notes match shipped reality:** when a PR implements a proposed Agent Note, move and rewrite it as present-tense shipped state in the same diff, then verify paths, names, and mechanisms against the implementation.
 - **Transcript changes:** editor-visible or model-visible changes update snapshots or explain why no snapshot applies. Review expected-output diffs as behavior changes, not formatting noise.

+ 2 - 0
.agents/skills/dsh-pre-push-checks/SKILL.md

@@ -28,6 +28,8 @@ The command never guesses or fetches a base. Supply the ref verified from curren
 
 There is no universal local baseline beyond the hooks. Every behavior change needs the narrowest available test or purpose-built check that would fail for its regression; add broader checks only for surfaces the diff actually reaches.
 
+When the outgoing change adds or changes a resource-owning or asynchronous test, fixture, helper, or CI execution path, use [dsh-ci-test-reliability](../dsh-ci-test-reliability/SKILL.md) first to decide whether restoration, negative-control, quiescent-teardown, or concurrent-process evidence applies. This skill still selects the commands and avoids repeating evidence that already passed.
+
 - **Package or script behavior:** run the owning Vitest file or focused test name. Add adjacent package tests when a shared contract changes; leave repository-wide coverage to CI unless the change is genuinely cross-cutting or the user requests it.
 - **Documentation, Agent Notes, catalogs, or doc-linked comments:** run `pnpm run doc-sync`; run full lint when the documentation workflow requires it.
 - **Model-, editor-, CLI-, or terminal-visible output:** run the focused keyless snapshot or real runnable-example scenario that owns the output.