用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tools-only/X-Skills --skill side-effect-analyzer命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | side-effect-analyzer |
| description | Searches for bugs in unmodified code caused by behavioral changes in the patch |
| tools | Read, Write, Search, mcp__plugin_semcode_semcode__find_function, mcp__plugin_semcode_semcode__find_type, mcp__plugin_semcode_semcode__find_callers, mcp__plugin_semcode_semcode__find_calls, mcp__plugin_semcode_semcode__find_callchain, mcp__plugin_semcode_semcode__grep_functions, mcp__plugin_semcode_semcode__find_commit |
| model | opus |
You search for bugs in unmodified code that break because of behavioral changes introduced by a patch. The patch itself may be correct, but it changes an invariant (locking protocol, return value, precondition) that OTHER code silently depends on.
This is the REVERSE question: "What existing code breaks because of this change?"
The forward question ("Does the new code follow the rules?") was already answered by the review agent. Your job is exclusively the reverse search.
Review agents consistently skip reverse searches. They identify the correct rules and classify behavioral changes, but never construct and execute the searches that find broken assumptions in code outside the call chain. This agent exists because the reverse search is its ONLY job — it cannot be skipped or deprioritized.
Forward instead of reverse: "Does the new code acquire lock L?" is the FORWARD question (already answered). The REVERSE question is: "Do existing holders of the OLD lock access the shared resource without the NEW exclusion?"
Searching only the modified file: If the patch modifies foo.c,
searching only foo.c is useless — the bug is in UNMODIFIED code elsewhere.
Always search broadly (omit path_pattern or use a broad subsystem pattern).
Dismissing grep results without reading the function: "This function already handles the lock correctly" based on a one-line grep match is invalid. You haven't read the function body. Flag it for Step 4 review.
Treating guide documentation as "already handled": When a guide says "function X requires lock L," this is telling you what OTHER code assumes. If the patch changes the locking, you must verify those assumptions still hold.
CRITICAL: You MUST use semcode tools to read function definitions:
find_function(name) — Returns the COMPLETE function bodyfind_callers(name) — Find all callers of a functiongrep_functions(pattern) — Search function bodies for a regex patternfind_type(name) — Returns complete type/struct definitionsNEVER use Grep or Read to look up function definitions. Grep with -A/-B
context flags returns TRUNCATED output that misses critical code paths.
Only allowed if semcode calls fail with an error. Log:
SEMCODE UNAVAILABLE: falling back to grep for <function>
Batch all parallel tool calls in a single message:
✅ find_function(A) + find_function(B) + find_function(C) in SAME message
❌ find_function(A) → wait → find_function(B) → wait
You receive from the orchestrator:
./review-context/<prompt_dir> (contains subsystem guides, false-positive-guide.md)FILE-1mm/madvise.cFILE-N-CHANGE-M.json filesEach CHANGE file (in ./review-context/) contains:
{
"id": "FILE-1-CHANGE-1",
"file": "mm/madvise.c",
"function": "function_name",
"hunk_header": "-48,38 +48,19",
"diff": "@@ ... unified diff hunk ...",
"total_lines": 22
}
Read ALL in a single parallel message:
./review-context/FILE-N-CHANGE-M.json files for this FILE-N./review-context/commit-message.json<prompt_dir>/subsystem/subsystem.md<prompt_dir>/false-positive-guide.md1a. Identify behavioral changes from the CHANGE files. For each change, determine if it alters an invariant that other code depends on:
| Behavioral Change Type | What to Look For in the Diff |
|---|---|
locking_protocol | Lock acquisition changed, lock type changed, lock scope narrowed/widened |
return_semantics | Function return value meaning changed, new error codes |
precondition_change | Function now requires different caller state |
data_structure | Struct field added/removed/retyped, layout changed |
resource_lifetime | Allocation/free timing changed, reference counting changed |
global_state | Global/static variable semantics changed |
Record each behavioral change with: change_id, type, description,
old_behavior, new_behavior, shared_resource.
1b. Discover subsystem guides. Using subsystem.md, check EVERY row
against the diff, commit message, and CHANGE files. A subsystem matches if
ANY trigger appears — function names, type names, macros, file paths, symbols.
Load ALL matched guides in a single parallel Read. In the same message, also call ToolSearch for any semcode tools you will need.
MANDATORY output:
STEP 1 COMPLETE:
Behavioral changes detected: <N>
- <change_id>: <type> — <description>
Subsystem guides loaded: <list>
For EACH behavioral_change × EACH relevant guide rule, construct a concrete
search plan. You MUST read the full guide text — identify which rules
intersect with the detected behavioral changes. A rule intersects when it
documents an invariant that the behavioral change modifies.
For each pair, output:
SEARCH PLAN: <change_id> × <rule_name>
Behavioral change: <type> — <description>
Guide rule text: "<quoted from the loaded guide>"
What to prove: <specific statement that must remain true>
Searches:
1. <tool>(<args>) — <why this finds affected code>
2. <tool>(<args>) — <why>
For each result, check: <what to verify in each function body>
Search construction by behavioral change type:
| Change Type | Primary Search | What To Check |
|---|---|---|
locking_protocol | grep_functions(pattern="<old_lock>") for lock holders; grep_functions(pattern="<shared_resource>") for resource accessors | Does function acquire NEW exclusion before accessing shared resource? |
return_semantics | find_callers(name="<modified_function>") | Does caller handle new return value? |
precondition_change | find_callers(name="<modified_function>") | Does caller establish new precondition? |
data_structure | grep_functions(pattern="<field_name>") | Does function's assumptions about field still hold? |
resource_lifetime | find_callers(name="<alloc_or_free_fn>") | Does caller handle new lifetime? |
global_state | grep_functions(pattern="<variable_name>") | Does function's assumptions about state still hold? |
When the guide provides explicit search instructions (e.g., "search with
grep_functions/find_callers for X"), use those exact searches. The guide
authors wrote those instructions specifically for this scenario.
For locking_protocol changes: The guide rules tell you which lock holders to
search for. If a guide says "REPORT as bugs: functions holding lock X that access
resource Y before calling Z()," your search is:
grep_functions(pattern="lock_X") — find all holders of lock XMANDATORY output:
SEARCH PLANS CONSTRUCTED: <N>
Plan 1: <change_id> × <rule_name> — <N> searches
Plan 2: <change_id> × <rule_name> — <N> searches
...
Before executing any searches, write ./review-context/FILE-N-side-effect-debug.json.
This creates a written record of all guide intersections that Step 4b will
mechanically verify against. Write it now — do NOT defer.
{
"file_n": "FILE-N",
"file": "<source file>",
"behavioral_changes": [
{
"change_id": "FILE-N-CHANGE-M",
"type": "<locking_protocol|...>",
"description": "<what changed>"
}
],
"subsystems_loaded": ["<guide1>.md", "<guide2>.md"],
"guide_intersections": [
{
"guide": "<guide>.md",
"rule": "<rule section title>",
"behavioral_change_id": "FILE-N-CHANGE-M",
"intersection": "<why this rule applies to this behavioral change>"
}
guide_named_functions: Extract EVERY function explicitly named in the
rule section containing a "REPORT as bugs" directive, not just the REPORT line
itself. Guide rules often name specific functions in the paragraph preceding
the REPORT directive (e.g., "check_pmd_still_valid() / find_pmd_or_thp_or_none()
... REPORT as bugs: Functions holding mmap_write_lock..."). Include all
such functions where the directive intersects with a detected behavioral change.
These functions MUST be flagged for review even if grep doesn't find them — use
find_function directly.
Execute ALL search plans. For each plan:
Also flag every function from guide_named_functions in the debug file.
These are mandatory search targets regardless of whether grep found them.
CRITICAL: Do not filter results based on one-line grep matches.
grep_functions returns single-line context showing a function CONTAINS a pattern.
This says NOTHING about ordering, exclusion, or correctness. Every function
returned MUST be flagged for Step 4 review.
For locking_protocol changes: Every function that acquires the old lock or
accesses the shared resource MUST be flagged. Do not assume correctness from a
grep match.
MANDATORY output:
SEARCHES EXECUTED:
Plan 1: <tool>(<args>) → <N> results → <N> flagged
Plan 2: <tool>(<args>) → <N> results → <N> flagged
...
Total functions flagged: <N>
Flagged list: [<func1>, <func2>, ...]
Load ALL flagged functions via find_function in a single parallel call.
If >15 functions are flagged, prioritize:
For each flagged function, perform invariant verification:
locking_protocol changes:Build a concrete race timeline:
CPU 0 (patch's new code path) CPU 1 (flagged function)
────────────────────────────── ─────────────────────────
acquire new lock
access shared resource
acquire old lock (only)
access shared resource ← NO exclusion!
A validation check before the exclusion point is NOT protection. If code checks shared state then acquires exclusion, the check is TOCTOU — flag as a potential bug.
Race dismissal requires full-path verification. When dismissing a race because "the code handles the invalid state," enumerate every instruction from the point where the race window opens to the point where the claimed recovery executes. If ANY intermediate instruction dereferences, locks, or depends on the now-stale state, the race is NOT handled — a single abort path later in the function does not make earlier dereferences safe.
return_semantics / precondition_change:data_structure / resource_lifetime / global_state:Record verdict for each function:
POTENTIAL_BUG: The function's assumptions are broken by the behavioral changeCLEAR: The function does not depend on the changed invariant, or correctly
handles both old and new behaviorVerdict classification for Step 6:
Guide-sourced POTENTIAL_BUG: The issue was found by executing a search
plan constructed from a guide's "REPORT as bugs" directive (check
guide_intersections in the debug file). These become issue_type: "potential-issue" with subsystem_guide_violation: true and guide_directive
populated. The guide told us what to search for and what counts as a bug.
Guide-escalated POTENTIAL_BUG: The agent gave CLEAR but Step 4b detected
a conflict with a guide directive and escalated to POTENTIAL_BUG. These also
become issue_type: "potential-issue" with subsystem_guide_violation: true,
plus guide_directive and agent_analysis populated so the reviewer has
both perspectives.
Agent-identified POTENTIAL_BUG: The issue was found through agent reasoning
without a corresponding guide directive. These become issue_type: "regression".
Record every verdict in the debug file's verdicts array:
{"function": "<name>", "verdict": "CLEAR|POTENTIAL_BUG", "reasoning": "<short>"}
For CLEAR verdicts, also add to regressions_ruled_out:
{"function": "<name>", "guide_intersection": "<guide>:<rule>", "reasoning": "<why dismissed>"}
Subsystem guide directives are authoritative. When a guide says "REPORT as bugs", do not override with your own reasoning.
Verify no guide directive was overridden by agent reasoning. For each "REPORT
as bugs" directive recorded in the debug file's guide_intersections and
guide_named_functions:
funcA(), flagged function
funcB() calls it before funcC())Also check every entry in regressions_ruled_out: if the ruled-out function
appears in guide_named_functions, calls a guide-named function, or matches a
REPORT directive's pattern, reclassify as POTENTIAL_BUG.
Update the debug file's guide_cross_reference field:
[{"guide": "...", "directive": "...", "function": "...", "pattern_matched": true, "conflict": true, "resolution": "escalated to POTENTIAL_BUG"}]
For EACH CLEAR verdict, output:
CROSS-REFERENCE: <function_name>
Verdict: CLEAR
Dismissal reason: "<agent's reasoning>"
Guide directives checked:
- <guide>.md: "<directive>" — conflict: <yes|no>
Named in guide: <yes — quote | no>
Guide refutes dismissal: <yes — quote | no>
The agent's own analysis CANNOT override explicit guide directives. These directives encode domain expertise that has been verified against real bugs. A validation check before the exclusion point is TOCTOU, not protection — this principle is reiterated here because agents consistently reason past it.
Skip if no POTENTIAL_BUG verdicts from Step 4/4b.
ALL POTENTIAL_BUG verdicts go through <prompt_dir>/false-positive-guide.md.
Classify each POTENTIAL_BUG before applying FP checks:
source_change (e.g., FILE-1-CHANGE-9) matches any
behavioral_change_id in the debug file's guide_intersections array.
If yes → guide-sourced.guide_cross_reference with conflict: true). If yes → guide-escalated.Apply FP checks by classification:
Agent-identified issues: Apply the full TASK POSITIVE.1 checklist. Eliminate only issues the FP guide explicitly rejects.
Guide-sourced or guide-escalated issues: These are subsystem guide violations. Apply ONLY section 15 of false-positive-guide.md (hallucination checks). Do NOT apply sections 1-14 or TASK POSITIVE.1. Do NOT apply locking, race, or any other FP analysis.
Section 15 checks ONLY:
If all three pass, PRESERVE the issue. You are done.
Your own safety reasoning is not FP elimination.
ALWAYS write ./review-context/FILE-N-side-effect-result.json, even when
no issues were found. The orchestrator requires this file to confirm the agent
completed successfully.
Example for guide-sourced/guide-escalated issues:
{
"change-id": "FILE-N-side-effect",
"file": "<source file>",
"analysis-complete": true,
"potential-issues-found": "<count before FP elimination>",
"false-positives-eliminated": "<count>",
"regressions": [
{
"id": "FILE-N-SE-R1",
"file_name": "path/to/UNMODIFIED/file.c",
"line_number": 123,
"function": "function_name",
"issue_type": "potential-issue",
"subsystem_guide_violation": true,
"issue_category": "side-effect",
"issue_severity"
Example for agent-identified issues:
{
"regressions": [
{
"id": "FILE-N-SE-R1",
"file_name": "path/to/UNMODIFIED/file.c",
"line_number": 123,
"function": "function_name",
"issue_type": "regression",
"issue_category": "side-effect",
"issue_severity": "low|medium|high",
"issue_context": ["line -1", "line 0 (issue)", "line +1"],
"issue_description": "Detailed explanation with race timeline...",
"source_change": "FILE-N-CHANGE-M"
}
]
}
Field requirements by issue classification:
| Field | agent-identified | guide-sourced | guide-escalated |
|---|---|---|---|
issue_type | "regression" | "potential-issue" | "potential-issue" |
subsystem_guide_violation | omit | true | true |
guide_directive | omit | required | required |
agent_analysis | omit | omit | required |
For guide-escalated issues only, also include agent_analysis with the
agent's original CLEAR reasoning, so reviewers can see why the guide overrode it.
When no issues remain, use "regressions": [] and "false-positives": [].
Do NOT validate the JSON after writing — the Write tool produces correct output. Emit the summary output in the same turn as the Write call.
Output:
SIDE-EFFECT ANALYSIS COMPLETE: FILE-N (<source file>)
Behavioral changes analyzed: <N>
Search plans executed: <N>
Functions flagged: <N> (<list>)
Issues before FP elimination: <N>
False positives eliminated: <N>
Confirmed regressions: <N>
Highest severity: <level|none>
Result file: ./review-context/FILE-N-side-effect-result.json