원클릭으로
slang-review-fine-grained-clarity
// Review Slang changes for fine-grained clarity. Use whenever reviewing PRs or diffs for code quality or correctness. Produces candidate review comments in a markdown file.
// Review Slang changes for fine-grained clarity. Use whenever reviewing PRs or diffs for code quality or correctness. Produces candidate review comments in a markdown file.
Review Slang changes for high-level clarity. Use whenever reviewing PRs or diffs for code quality or correctness. Produces candidate review comments in a markdown file.
Run the full Slang clarity review workflow: generate high-level and fine-grained candidates, consolidate overlap, filter for PR-author scope, and optionally post one GitHub PR review. Use when asked to perform an end-to-end clarity-focused review.
Merge Slang clarity review candidate files and resolve overlapping, duplicate, or superseded comments. Use after high-level and fine-grained clarity review passes and before scope filtering or GitHub posting. Produces or updates one canonical candidate markdown file.
Post filtered Slang clarity review candidates as one proper GitHub PR review. Use after candidate consolidation and scope filtering. Uses the bundled stdlib Python script to validate candidate formatting, map comments to PR diff lines, and submit a GitHub review through gh.
Resolve Slang clarity review candidates marked as needing a judgment call. Use after consolidation and scope filtering, before posting, to perform focused follow-up analysis and decide whether uncertain candidates should be kept, revised, or dropped.
Filter candidate review comments in place for PR-author ownership. Use after slang-review-consolidate-candidates, slang-review-clarity, or slang-review-fine-grained-clarity to conservatively keep only comments about code the PR author is justifiably responsible for addressing. Updates candidate status metadata in the markdown file.
| name | slang-review-fine-grained-clarity |
| description | Review Slang changes for fine-grained clarity. Use whenever reviewing PRs or diffs for code quality or correctness. Produces candidate review comments in a markdown file. |
| argument-hint | <pr-number-or-diff-path> |
| allowed-tools | ["Bash","Read","Grep","Glob","Write","Edit"] |
Perform a detailed name/comment/definition consistency pass over a Slang PR. This is a "nit-pick" review pass, but the nits are not cosmetic: unclear names, muddy comments, and mismatched contracts are evidence that the code is not clear enough to be trusted.
The expected standard is exhaustive scrutiny of touched code. Consider every changed or newly relevant file, type, function, declaration, comment, branch, expression, and line. Generate a candidate unless you can confidently state that a careful reader would find the code/comments obviously necessary, correct, and internally consistent. One candidate may cover a cluster of related lines, but do not skip a concern merely because it is fine-grained or pedantic.
Do not directly post comments to PRs; write candidate comments to a markdown file under
tmp/review-candidates/.
If the caller provides an existing candidate file, append new candidates to that file instead
of creating a fresh file. This is useful for sequential workflows. When multiple review passes
may run concurrently, write separate raw files and let slang-review-consolidate-candidates
merge them.
When appending, inspect existing candidate IDs and continue numbering for this skill's FG
prefix instead of restarting at FG001.
If requested to post comments, write the candidates to a file, then run the consolidation and
filtering skills before posting the filtered results.
Prefer reviewing from files:
mkdir -p tmp/review-candidates
gh.exe pr diff <number> -R shader-slang/slang > tmp/pr-diff.patch
gh.exe pr view <number> -R shader-slang/slang --json files -q '.files[].path' > tmp/pr-files.txt
Read CLAUDE.md, AGENTS.md, tmp/pr-files.txt, tmp/pr-diff.patch, and the PR-version
source files. For large files, use grep first and then read focused ranges.
If the caller provides an output file, append candidates there. Otherwise, write candidates to:
tmp/review-candidates/pr-<number>-fine-grained-clarity.md
If no PR number is known, use:
tmp/review-candidates/fine-grained-clarity-review.md
Generate candidates liberally and tag each one:
Scope: Direct for changed lines, new declarations, renamed fields, new comments, or
functions/types whose body changed.Scope: Contextual for existing declarations whose comment, name, or contract is made
misleading by the PR's changes.Scope: Probably out-of-scope for real clarity issues that are not clearly owned by the PR.Do not use scope tagging to suppress candidates during this pass. A later scope filter decides which candidates are fair to post.
This pass should leave an audit trail of scrutiny, not just the most interesting few comments. For each changed source file, the final raw candidate set should make it plausible that every touched declaration and non-trivial changed line was inspected. The outcome for each touched region should be one of:
When in doubt, write the candidate with lower confidence. Do not rely on later memory or final summaries to recover skipped fine-grained concerns.
Use this exact structure:
### FG001: Short Title
- Status: Proposed
- Confidence: High | Medium | Low
- Scope: Direct | Contextual | Probably out-of-scope
- Category: type contract | function contract | naming | terminology | comments | invariant | control flow | API shape
- Location: `path:line`
- GitHub link:
Context:
```cpp
<small PR-version snippet>
```
Proposed comment:
> <comment text suitable for GitHub after filtering>
Notes:
<why this candidate was raised, uncertainty, related candidates>
Include a code block for the relevant PR-version context. The GitHub link is useful but not sufficient.
Review comments should identify the missing clarity or correctness argument. Do not merely say "add a comment here." Explain what the reader cannot confidently infer: the contract, invariant, case analysis, termination argument, precondition, provenance, or reason a line is necessary and correct. Lead with the missing understanding or uncertainty that blocks confident review. Only specify the exact remedy when there is only one credible fix; otherwise, ask the author to make the needed contract, invariant, naming distinction, or correctness argument clear, without dictating the implementation or prose.
Understand the distinction between implementation and documentation comments:
Documentation comments, whether or not they use a /// convention or similar, are those comments attached to declarations/files/modules for the purpose of explaining an API contract, concept, or abstraction to a user of that API. They should be written in a style that is clear and informative to a user of the API, and they should not surface implementation details that are not relevant to a client of the API.
Implementation comments are all comments that are not documentation comments. They are meant to explain the intent, approach, and correctness argument of a particular implementation to a future maintainer. They may include details about the implementation that would not be relevant or appropriate for a documentation comment.
Flag:
Apply to every touched source file, including header files.
Ask:
Does each source file have a file-level implementation comment that explains the concern (problem, task, data structure, etc.) that the file pertains to, along with the overall approach or decomposition used to address that concern? If not, that is an issue.
Is the overall order of declarations/definitions in the file clear and logical, and consistent with the organizational principles stated in the file-level comment (problem decomposition or approach)? Code should be organized to tell a clear story at the file level, as much as is possible within the constraints of C++ language rules.
Changes to an existing file should respect existing organization, extending or adapting it as needed. If existing code is lacking in clear organization, a PR may elect to improve it, but must not make it worse.
All new code files or significant additions to existing code files should have clear structural organization that supports the clarity of the file's overall story and approach.
Does the file use Markdown-style conventions like headings to support the organizational structure of the file and make it easier to navigate? Use of Markdown-style conventions is highly recommended but not strictly required, if structure is clear without them. If a PR uses other notational conventions to delineate structure, review feedback should request that they be changed to Markdown-style conventions for consistency and readability.
As a guiding principle: if the content of a code file were "flipped" so that the implementation comments became ordinary text in a Markdown file, with the remaining lines becoming interspersed code blocks, the resulting Markdown file should ideally read like a compelling chapter of a book, describing the relevant problem domain and solution approach taken in a pedagogical and engaging way.
Apply to every function, method, constructor, etc. introduced or touched by the PR.
Every non-trivial function should have a caller-visible contract. That contract may be
obvious from the name and signature for simple accessors and similarly direct routines, such
as float Circle::getRadius(). Otherwise, require a declaration-level comment that explains
what the function does, returns, requires, preserves, mutates, or may fail to do.
A definition in a .cpp file may rely on a commented declaration in a header file, but a
caller-visible contract must exist somewhere.
Ask:
Naming rules:
Function-like routines, including pure functions, accessors, getters, queries, and
predicates, should usually be named around the value or proposition they compute, optionally
with helper verbs such as get, find, calc, or calculate.
area(rectangle).get as a prefix: e.g., getDominators(graph, node) or getBestCandidate(args).calc or calculate as a prefix: e.g., calculateDominators(graph, node) or calcBestCandidate(args).find: e.g., findBestCandidate(args).is, does, has, etc.: e.g., isValid(candidate) or hasNonZeroElements(matrix).Procedure-like routines, including routines called partly or wholly for their side effects, should
use a verb phrase that states what they do: e.g., addEdge(graph, edge), removeNode(graph, node), emitCode(generator, ir), checkCandidate(candidate).
try or check to indicate that the caller should inspect the result: e.g., tryAddEdge(graph, edge) or checkCandidate(candidate).addEdgeIfValid(graph, edge) or emitCodeIfNeeded(generator, ir).In all cases, prioritize semantic clarity at call sites. Brevity does not justify ambiguity; if making the name clear means it is ugly and unwieldy, that serves as a code smell that can motivate and guide subsequent refactoring to improve the abstraction.
For static methods, consider how call sites will read when qualified with the type name.
E.g., Matrix::rotationAroundAxis(axis, angle) or Image::createFromFile(filename) both read clearly as factory functions, but Buffer::roundUpToAlignment(size, alignment) is awkward and clearly a utility/helper function that doesn't justify why it should be a static method.
Flag:
true and false meanings are not obvious.try, find, get, match, map, convert, or solve names without clear success and
failure contracts.Apply to every line of code introduced or touched by the PR that is within a function (constructor, etc.) body.
The hard requirement is not a particular density of comments. The hard requirement is that a reader can confidently understand why every line exists and why it is correct as written. If that understanding requires too much time or effort, the code is still not clear enough. Sometimes one clear comment can justify ten or more straightforward lines that follow it; sometimes one subtle line justifies a long explanatory comment. Treat missing or sparse comments as evidence to scrutinize, and raise a candidate only when the code and existing comments do not make the intent, necessity, or correctness argument clear enough.
Ask:
As a general rule, the body of a function should read as a kind of proof of the function's correctness, with the comments providing the key steps and insights in that proof. A good proof is not just a sequence of statements that happen to be correct, but a clear, compelling and structured argument that the code is correct, necessary, and the best way to solve the problem at hand.
If a human or agent reading the code cannot come away understanding how it solves the problem and why that solution must be correct, then the code is not clear enough to be trusted. The author must produce code that obviously has no bugs, rather than merely having no obvious bugs.
Apply to every struct, class, enum, etc. introduced or touched by the PR.
Make note of when C++ language constructs are being used to emulate a tagged-union-like type that represents a conceptual ADT (something that might just use an enum in Rust), and review the type as such, independent of the particular implementation approach/mechanism.
For all types, ask:
x.color or ifStmt.condition.hasNonZeroElements or isValid.For enums, ask:
Color::Red, DiagnosticSeverity::Error, Status::Sending, etc. are good; Instruction::Add, Node::If, Edge::Call are bad (e.g., "if" is not a node, even if it might be a type or kind of node).For enums and tagged-union-like types, ask:
For tagged-union-like types, ask:
For fields or properties that are only valid for specific cases/tags, are they private and only accessible through accessors that assert/validate that the tag is appropriate? If not, that is an issue.
Does the type provide constructor or factory methods to ensure that instances are always created with the appropriate values for a given tag/case, validating (statically or dynamically) that the tag-specific invariants are satisfied? If not, that is an issue.
Flag:
Naming:
Type names should be nouns; typically "count nouns" in English.
Mass nouns are typically not good as type names (e.g., it is unclear what a type named Water would represent).
Abstract nouns are also allowed, but should typically be enumerations (Severity, Color) or typed scalars (Size, Duration), rather than structs or classes with multiple fields.
Type names may be qualified with adjectives, prepositional phrases, or other nouns, so long as the resulting term still reads clearly and unambiguously.
E.g., DirectedEdge, NodeWithWeight, StatusForDisplay, WindowStyle, Mesh::Bounds, etc.
For each type name introduced or touched by the PR, ask what a natural-language definition of the same concept would be, starting with language like "A [type name] is a [definition]." If it is unclear how to fill in that template with a crisp and clear definition, that is a problem. If the actual meaning or definition of the type as used in the code is inconsistent with the crisp and clear definition, then the factoring of the code is suspect.
For every touched name and comment:
Use the clarity bar of a serious technical paper or textbook. Code and comments should explain the problem, relevant definitions, chosen decomposition, constraints, invariants, and trust argument at every scale: from entire subsystems, through individual code files, and down to individual lines of code.
In clear and high-quality code the names of types, functions, etc. are primarily focused on describing the concepts, phenomena, processes, etc. of the problem domain in its natural terminology. When the names in code are focused more on describing things in terms of the implementation details or solution domain (e.g., "visitor", "callback", "helper", "SFINAE", etc.), that is a potential code smell. When possible, request that names, comments, etc. be revised to focus more on describing and decomposing a challenge in the problem domain, only bottoming out in the dirty details of C++ or other language quirks/mechanisms when it is strictly necessary to speak to them.
Do not collapse a high volume of legitimate clarity candidates just because they are numerous. Volume is expected for this pass.