Skip to content

AI front end code review guidelines and claude skills#1292

Open
labkey-martyp wants to merge 1 commit intodevelopfrom
fb_frontend_code_review_skills
Open

AI front end code review guidelines and claude skills#1292
labkey-martyp wants to merge 1 commit intodevelopfrom
fb_frontend_code_review_skills

Conversation

@labkey-martyp
Copy link
Contributor

@labkey-martyp labkey-martyp commented Feb 23, 2026

Rationale

This is a starting point for frontend ai code review guidelines. There are two code review checklists and claude skills, /code-review-react and /code-review-jest. The claude skills have two modes,

  1. Review only staged changes (changes not committed yet). ex. /code-review-react <directory or file path>
  2. Review full files or directories. ex /code-review-jest --full <directory or file path>
  • See .agents/common.md for review priority and format.
  • See the "Required output" section of the .claude/skills/<skill name>/skill.md for the expected output. Note: If there are more than 10 "suggested" changes (non-urgent), only the first 10 will be shown in each run.
  • See the files in .agents/review-checklists/<react or jest>/*.md for the code review checks.

It is recommended to run the code reviews multiple times until all the feedback is addressed.

These guidelines can be used by other ai agents as well, just point them to the directory.

Changes

  • .agents/review-checklists/jest code review checks
  • .agents/review-checklists/react code review checks
  • .agents/review-checkslists/common.md general code review guidelines
  • .claude/skill/<skill name>/skill.md define the claude skill using these guidelines

Copy link
Contributor

@labkey-jeckels labkey-jeckels left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have React or Jest changes handy to test this out, but the overall structure seems reasonable.

Others can better comment on whether these are the right items to highlight, but this might be best evaluated through actual testing.

I can see pulling some of this guidance into more general areas in the future. For example, the rules for code comments should be applicable to any language, not just React/TypeScript/JavaScript.

Copy link
Contributor

@cnathe cnathe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments but I agree that this will need to be treated as a working document as we use it and until we start using it, it is hard to know exactly what we all want here. Looks like a great starting point.

@@ -0,0 +1,123 @@
---
name: code-review-jest
description: "Trigger when the user requests a review of Jest test files (e.g., `.test.tsx`, `.spec.tsx`). Supports --full flag for complete file/directory review; defaults to staged changes when a path is provided."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove the .spec.tsx part right? those are dead tests that we need to convert. Instead maybe make the files target .test.tsx and .test.ts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, if anything we should probably have another skill for converting enzyme tests to RTL, but I also don't think it's high priority enough require it go in this PR.

# Jest Test Code Review

## Intent
Use this skill whenever the user asks to review Jest test code (especially `.test.tsx`, `.spec.tsx`, `.test.ts`, or `.spec.ts` files). Support three review modes:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here about spec files

4. Compose the review section per the template below. Group findings by **Urgency** section first (urgent issues, then suggestions). Within each section, order findings by the checklist primary category priority: **Correctness**, then **Maintainability**, then **Style**.

## Required output
When invoked, the response must exactly follow one of the two templates:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so much of the text / instructions above this line in this file are so close to a duplicate of the code-review-react/skill.md file. This likely makes sense as there might not be a good way to share that part of these instructions. I'm just a little worried about how we are goign to keep these things up to date and in sync.


### Confidence Threshold

Flag when the symbol is clearly unused in the file or when a mock setup is not consumed by behavior under test. If a mock or import may be used implicitly (module mocking side effects, global setup conventions), verify before commenting.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does "the symbol" mean in this sentence? do you mean variable?

6. **Unused parameters in callbacks must be prefixed with `_`.** If a callback parameter (e.g., in `.mockImplementation((unusedArg) => ...)`) is required for positional reasons but not used, prefix it with `_` to signal intent (e.g., `_unusedArg`).
7. **Unused `render` results must not be destructured.** If `render(<Component />)` is called and the return value is not used, do not destructure it. Write `render(<Component />);` instead of `const { container } = render(<Component />);` when `container` is never referenced.

### Examples
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great. I'd love to not have to manually check as a code reviewer if the import or variable is used!


> **Prerequisite:** Review and apply the common guidelines in [`common.md`](../common.md) before using this checklist.

## No redundant or near-duplicate tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious what AI would consider a near-duplicate test. I think using near duplicate tests is exactly how test cases often look when you are testing interactions of a sequence of parameters or properties (i.e. adjust prop1, then prop2, then prop3, etc. but the test is nearly the same).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, in those cases we should be using something like jest.each, where we have one shared test body, but you parametrize the test with an array of args. We don't do this a lot right now, but we should for sure be doing it more.


// ✅ Fallback for optional props
const [text, setText] = useState(props.initialText ?? '');
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great. these are always tough things to catch when manually scrolling through a large PR code change.

};
```

## Optional props that are always passed should be required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one has been debated a few times before by the Frontend group and I think people fall on different camps here. Seems fine to include as long as we are making an effort to be sure to update / adjust this set of rules as we work through usages.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this has been debated. I'm the one who has brought this to the group multiple times, basically anytime I've encountered an issue caused by this, or when I've done large refactors and discovered multiple type related issues, and I don't recall a time that I have gotten push back on this. The upside is that by following this rule your types are more correct, and it eliminates a whole class of bug, the downside is that it's slightly more verbose.

- **CSS Modules:** When using CSS Modules (`.module.css` / `.module.scss`), camelCase class names are standard since they become JS property names (e.g., `styles.searchForm`, `styles.activeItem`). Do not flag these as BEM violations.
- **Existing non-BEM code:** Class names in unchanged code that predate BEM adoption should not be flagged. Only apply BEM conventions to new or actively modified class names in the PR.

## No orphaned or unused CSS/SCSS rules
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be great if AI can help with this one! this is very tedious to track down manually

Copy link
Contributor

@labkey-alan labkey-alan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think overall these rules are fine. I did leave some feedback that you should review before merging. If you have follow up questions, or want to have a discussion, let me know.

My biggest issue with these rules at the moment is that I don't really think this is the appropriate place for them, as this keeps them scoped to LabKey server and modules defined within it, but it excludes their availability to our packages e.g. labkey-ui-components, labkey-ui-premium, which is where the majority of our react and jest code lives. I also don't really want a solution that involves duplicating these rules across every repo that needs them. That said, I think this is an acceptable place to put them for now, as it allows people to experiment with them today, albeit in a limited scope. We can always move these rules to a more ideal location later.

### Exceptions / False Positives

- Allow explicit smoke tests when the purpose is only to verify the component/function does not throw on render or initialization.
- Do not flag helper tests that intentionally validate test utilities/builders rather than product behavior, if the subject under test is the utility itself.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand this rule. Are we ever testing our test utilities?

expect(data[0].name).toBe('Alpha'); // This tests your test, not your code

// ✅ GOOD — asserts on rendered output from that input
const data = [{ name: 'Alpha', value: 10 }];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should encourage even more specific checks here. I think keeping this section is good, but maybe adding something that says "instead of looking for the existence of data anywhere, look for the existence of data where it is expected to be". Then provide an example of looking for "name" to be in the first column of the example Table component here, or something similar. Just generically looking for content to be on the page may be so overbroad that it is not useful.


- Do not flag short tests (roughly 3-5 lines) where Arrange/Act/Assert is obvious without comments.
- Do not require AAA comments in parameterized tests when added comments make the test harder to scan than the code itself.
- Prefer suggestions over high-severity findings unless the repository explicitly enforces AAA comment structure in tests.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is useful, since we don't have any repositories where AAA comments are explicitly enforced, and most of our existing tests do not follow this pattern.

- **Before:** `items.map((item, index) => <Row key={index} ... />)`
- **After:** `items.map(item => <Row key={item.id} ... />)`

If no natural unique key exists, consider whether the data model should include one. As a last resort, generate stable IDs when the data is first loaded.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line feels redundant given the (IMO) more thorough instructions in the Exceptions / False Positives section above.

{count > 0 && <Badge count={count} />}

// ✅ Or use a ternary
{count ? <Badge count={count} /> : null}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern is always worse IMO and I don't think we should offer it as an acceptable alternative. The count > 0 && solution above is less verbose and more explicit, which is better.


- Do not flag tiny local components with a single simple prop where an inline type is shorter and clearer.
- Do not require this pattern if the surrounding file consistently uses a different accepted convention and the PR is not refactoring style.
- If the project avoids `FC` entirely and types props on the function parameter instead, apply the spirit of the rule (named props type) rather than the exact syntax.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove this rule. We require components to be typed, so if someone made a component that was not labeled with FC I would consider that bad, and would request that is fixed prior to merging.

2. For each optional prop, verify whether any call site omits it
3. If all call sites provide the prop, flag it for conversion to required

**Scope note:** For widely-used shared components (5+ call sites), this check can be deferred to a separate audit. Focus on components with 1–3 usages where the call sites are visible in the current PR.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**Scope note:** For widely-used shared components (5+ call sites), this check can be deferred to a separate audit. Focus on components with 1–3 usages where the call sites are visible in the current PR.
**Scope note:** For widely-used shared components (5+ call sites), this check can be deferred to a separate audit. Focus on components with 1–4 usages where the call sites are visible in the current PR.


### Confidence Threshold

Flag only when the file/area already uses a class-name utility convention (for example, `classnames`, `clsx`, or local `cn`) and the inline conditional harms consistency/readability. For one-off simple cases in mixed-style files, prefer a suggestion.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only use classnames, and unless someone has a good reason to add a new dependency, I don't see that changing


### Confidence Threshold

Flag when the computation is non-trivial (for example, sorting/filtering large collections or repeated transformations) and can run frequently with unchanged inputs. For small arrays or infrequent renders, make this a suggestion only.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Flag when the computation is non-trivial (for example, sorting/filtering large collections or repeated transformations) and can run frequently with unchanged inputs. For small arrays or infrequent renders, make this a suggestion only.
Flag when the computation is non-trivial (for example, sorting/filtering large collections or repeated transformations) and can run frequently with unchanged inputs. For small arrays or infrequent renders, make this a suggestion only. If array size is not known, prefer memoization.


### Confidence Threshold

Flag as a high-severity finding when a nested function is used as a React component type (capitalized and rendered with JSX) inside a component body, causing remounts and state loss. Do not confuse this with render helpers that return JSX but are not treated as component types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should consider a rule that discourages render helpers. We have relied on them a ton in the past, but not in helpful ways. 99/100 render helpers at LabKey should be components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants