From fe6051d591fab297619856b46af8a63628b9203b Mon Sep 17 00:00:00 2001 From: amaan-bhati Date: Tue, 14 Apr 2026 13:31:31 +0530 Subject: [PATCH 1/3] feat: automated ai powered qa agent Signed-off-by: amaan-bhati --- .github/workflows/qa-review.yml | 89 +++++++++ qa-agent/QA_GUIDELINES.md | 164 ++++++++++++++++ qa-agent/codebase_map.json | 71 +++++++ qa-agent/requirements.txt | 2 + qa-agent/scripts/qa_review.py | 328 ++++++++++++++++++++++++++++++++ 5 files changed, 654 insertions(+) create mode 100644 .github/workflows/qa-review.yml create mode 100644 qa-agent/QA_GUIDELINES.md create mode 100644 qa-agent/codebase_map.json create mode 100644 qa-agent/requirements.txt create mode 100644 qa-agent/scripts/qa_review.py diff --git a/.github/workflows/qa-review.yml b/.github/workflows/qa-review.yml new file mode 100644 index 000000000..b8dd81ced --- /dev/null +++ b/.github/workflows/qa-review.yml @@ -0,0 +1,89 @@ +name: QA Review Agent + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + + push: + branches-ignore: + - main + - master + + issue_comment: + types: [created] + + workflow_dispatch: + inputs: + pr-number: + description: "PR number to review" + required: true + review-mode: + description: "full (with second-order analysis) or fast" + required: false + default: "full" + +jobs: + # NOTE: update-codebase-map job which automatically commits back changes has been omitted + # to satisfy constraints regarding git commits to GitHub. We expect manual codebase map rebuilds. + + # --------------------------------------------------------------- + # the actual PR review + # --------------------------------------------------------------- + qa-review: + name: QA Review + runs-on: ubuntu-latest + + if: | + github.event_name == 'pull_request' || + github.event_name == 'workflow_dispatch' || + ( + github.event_name == 'issue_comment' && + github.event.issue.pull_request != null && + ( + contains(github.event.comment.body, '/qa-review') + ) + ) + + permissions: + pull-requests: write + contents: read + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install dependencies + run: pip install -r qa-agent/requirements.txt + + - name: Resolve PR number and review mode + id: context + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "pr_number=${{ github.event.inputs.pr-number }}" >> $GITHUB_OUTPUT + echo "mode=${{ github.event.inputs.review-mode }}" >> $GITHUB_OUTPUT + elif [ "${{ github.event_name }}" = "issue_comment" ]; then + echo "pr_number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT + # check if comment says /qa-review fast + if echo "${{ github.event.comment.body }}" | grep -q "fast"; then + echo "mode=fast" >> $GITHUB_OUTPUT + else + echo "mode=full" >> $GITHUB_OUTPUT + fi + else + echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT + echo "mode=full" >> $GITHUB_OUTPUT + fi + + - name: Run QA review agent + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ steps.context.outputs.pr_number }} + GITHUB_REPOSITORY: ${{ github.repository }} + REVIEW_MODE: ${{ steps.context.outputs.mode }} + run: python qa-agent/scripts/qa_review.py diff --git a/qa-agent/QA_GUIDELINES.md b/qa-agent/QA_GUIDELINES.md new file mode 100644 index 000000000..6289effc6 --- /dev/null +++ b/qa-agent/QA_GUIDELINES.md @@ -0,0 +1,164 @@ +# QA Guidelines +> Generated from codebase analysis on 2026-04-14 +> These rules are derived from actual patterns in this codebase. +> Update this file when the codebase conventions change — via PR, reviewed by the team. + +--- + +## Section 1 — Architecture rules + +Rules about how code is structured and where things belong. +Derived from: the component-driven Docusaurus structure of this codebase. + +### RULE-A-001: Component Colocation +**What**: React components must be placed in `src/components/` and not scattered across `docs/` or `src/pages/`. +**Why**: Ensures reusability across MDX pages. Mixing React logic inside `docs/` or `src/pages/` causes navigation bloat. +**How to check**: Look at new file additions. Anything ending in `.js` providing a UI fragment must be in `src/components/`. +**Example of violation**: +```diff ++ // docs/QuickStartWidget.js ++ export default function Widget() { return
Quickstart
; } +``` +**Example of compliance**: +```diff ++ // src/components/QuickStartWidget.js ++ export default function Widget() { return
Quickstart
; } +``` + +### RULE-A-002: Theme Customisation +**What**: Docusaurus default overrides must go entirely in `src/theme/`. +**Why**: Docusaurus relies on specific path resolutions for "swizzled" components (Navbar, Footer, etc.). Placing them anywhere else breaks the override mechanism. +**How to check**: If a component is named identically to a Docusaurus built-in (e.g., `DocItem`, `NavbarItem`), it must reside in `src/theme/`. + +--- + +## Section 2 — Type safety rules + +Rules about TypeScript / type usage derived from this codebase's type discipline. + +### RULE-T-001: Pure JavaScript over TypeScript +**What**: Avoid introducing `.ts` or `.tsx` files without a concerted architectural shift. +**Why**: This codebase is 100% JavaScript (uses `.js` extensively). The linter checks `.js` with `eslint-plugin-react`. Sneaking in `.ts` files may cause webpack loaders or linters to fail or result in inconsistent type disciplines. +**How to check**: Fail if `*.ts` or `*.tsx` extensions are added unless `tsconfig.json` changes accompany them. +**Example of violation**: +```diff ++ // src/components/Community.tsx +``` + +--- + +## Section 3 — Error handling rules + +Rules derived from how this codebase handles errors. + +### RULE-E-001: Component Fallbacks +**What**: Complex components (like filtering or routing logic) must wrap internal evaluation in basic try/catch if accessing browser APIs. +**Why**: Docusaurus pre-renders (SSR) static HTML. Accessing `window` or `document` unprotected breaks the `npm run build` process instantly. +**How to check**: Look for `window.` or `document.` accesses. They must be inside `useEffect()` hooks or `ExecutionEnvironment.canUseDOM` conditions. +**Example of violation**: +```javascript +const url = window.location.href; // Breaks Docusaurus SSR build +``` + +--- + +## Section 4 — API and data layer rules + +Rules about how routes are defined, validated, and how data is accessed. + +### RULE-D-001: No Server-Side Fetching in Components +**What**: Avoid complex fetching loops in components. +**Why**: Docusaurus generates a static site. Dynamic data fetching at runtime causes content shifting and defeats the purpose of SEO-optimized markdown documentation. +**How to check**: Flag usages of `fetch()` or `axios(...)` in components unless wrapped strictly with `useEffect()` for non-critical secondary info (like stars count). + +--- + +## Section 5 — Testing rules + +Rules about what must be tested, how tests must be structured in this codebase. + +**Minimum test requirements for a PR to pass**: +Currently, the codebase has 0% test coverage and uses NO testing framework, so there are no test requirements. + +- [ ] (INFO) Observe that no tests are required for now until a framework is established. If someone adds a test file, check if it's accompanied by `package.json` configurations (Jest, Vitest). + +--- + +## Section 6 — Naming and style rules + +Rules about naming derived from actual naming patterns in this codebase. + +### RULE-N-001: PascalCase for React Components +**What**: All components and their filenames must use `PascalCase`. +**Why**: This is the strict pattern in `src/components/` (e.g., `QuickStartFilter.js`, `GetStartedPaths.js`). It prevents case collision across case-sensitive file systems (Linux vs macOS). +**How to check**: Ensure `src/components/[file].js` starts with a capital letter. + +--- + +## Section 7 — Dependency rules + +Rules about adding, updating, or removing dependencies. + +### RULE-DEP-001: No Heavy UI Libraries +**What**: Do not add heavy UI component libraries (like Material UI or Ant Design). +**Why**: The project heavily utilizes TailwindCSS (`tailwindcss`) and custom styles in `src/css/styles.module.css`. Mixing CSS-in-JS abstractions bloats the bundle and creates clashing layouts. +**How to check**: Check `package.json` diff for adding new dependencies starting with `@mui`, `antd`, etc. Approved styling is TailwindCSS. + +--- + +## Section 8 — Breaking change detection rules + +THIS IS THE MOST IMPORTANT SECTION. + +### RULE-B-001: `src/components/Product.js` interface stability +**What this module provides**: The primary logic and layout for product description loops and UI structure on landing/docs. +**Files that depend on it**: Root pages, docs routing. +**What a change here can break**: The entire aesthetic of the landing pages and main documentation entry forms. +**What to check when this file is modified**: +- Ensure all tailwind classes added relate to valid defined `keploy` colors in `tailwind.config.js`. +- If prop types changed, ensure there's no runtime breakage. + +### RULE-B-002: `src/components/QuickStartFilter.js` and `QuickStartList.js` +**What this model represents**: Filter selection for multiple platforms and SDKs on quickstart pages. +**Files that use this model**: MDX docs relying on quickstart grids. +**What a change here can break**: Users are heavily reliant on Quickstart paths. Breaking this component means users cannot pick their platform (Linux, macOS, Windows). +**What to check when this file is modified**: +- Ensure the state toggle (`useState`) successfully maps to valid component returns. +- Flag changes to SDK names if they break hardcoded object lookups. + +### RULE-B-003: `docusaurus.config.js` and `sidebars.js` +**What this model represents**: Global configuration and navigation schema. +**Files that use this model**: Docusaurus router. +**What a change here can break**: The entire site build. Broken paths will throw "broken-links" errors in `docusaurus build`. +**What to check when this file is modified**: +- Check for trailing slashes matching previous patterns. +- Validate `url` or `href` objects inside navbar arrays. + +--- + +## Section 9 — PR checklist + +A mechanical checklist the agent runs on every PR regardless of what changed. + +- [ ] PR has a description (not empty) +- [ ] PR description explains WHY not just WHAT +- [ ] No files contain new TODO/FIXME without an associated issue number +- [ ] No `console.log` statements left in production code (unless inside a commented explanatory code block inside MDX). +- [ ] No commented-out large React UI blocks added. +- [ ] Diff does not include `yarn.lock` or `package-lock.json` changes without `package.json` changes. +- [ ] No `window.` DOM assignments in raw Component scope without SSR safety (`useEffect`). +- [ ] Tailwind class modifications use standard keys provided in `tailwind.config.js`. + +--- + +## Section 10 — Severity levels + +When the agent reports an issue, it must use one of these levels: + +**CRITICAL** — must be fixed before merge. Breaks existing functionality (SSR build issues), introduces security issue, or violates a rule with no safe exceptions. + +**WARNING** — should be fixed, but merge is not blocked. Inconsistent with conventions, reduces quality, or introduces technical debt. + +**INFO** — observation or suggestion. Improvement opportunity, not a violation. + +**QUESTION** — the agent cannot determine if this is correct without human context. Flags for reviewer attention. diff --git a/qa-agent/codebase_map.json b/qa-agent/codebase_map.json new file mode 100644 index 000000000..9e47940e2 --- /dev/null +++ b/qa-agent/codebase_map.json @@ -0,0 +1,71 @@ +{ + "src/components/responsive-player/ResponsivePlayer.js": [ + "src/components/index.js" + ], + "src/components/shared/Button.js": [ + "src/components/index.js" + ], + "src/components/KeployCloud.js": [ + "src/components/index.js" + ], + "src/components/Community.js": [ + "src/components/index.js" + ], + "src/components/Intro.js": [ + "src/components/index.js" + ], + "src/components/Resources.js": [ + "src/components/index.js" + ], + "src/components/QuickStart.js": [ + "src/components/index.js" + ], + "src/components/Hacktoberfest.js": [ + "src/components/index.js" + ], + "src/components/GetStartedPaths.js": [ + "src/components/index.js" + ], + "src/components/TestingCapabilities.js": [ + "src/components/index.js" + ], + "src/components/QuickStartTabs.js": [ + "src/components/index.js" + ], + "src/components/WhatIsKeploy.js": [ + "src/components/index.js" + ], + "src/components/EcosystemSupport.js": [ + "src/components/index.js" + ], + "src/components/DocHeaderChips.js": [ + "src/components/index.js" + ], + "src/components/SidebarBadge.js": [ + "src/components/index.js" + ], + "src/components/SidebarCategoryIcon.js": [ + "src/components/index.js" + ], + "src/components/TierCallout.js": [ + "src/components/index.js" + ], + "src/components/QuickStartList.js": [ + "src/components/QuickStartFilter.js" + ], + "versioned_docs/version-2.0.0/server/sdk-installation/index.md": [ + "versioned_docs/version-2.0.0/server/sdk-installation/go.md", + "versioned_docs/version-2.0.0/server/sdk-installation/java.md", + "versioned_docs/version-2.0.0/server/sdk-installation/javascript.md", + "versioned_docs/version-2.0.0/server/sdk-installation/python.md" + ], + "versioned_docs/version-1.0.0/go/supported-frameworks.md": [ + "versioned_docs/version-1.0.0/go/integration.md" + ], + "versioned_docs/version-1.0.0/go/integration-with-go-test.md": [ + "versioned_docs/version-1.0.0/go/replay.md" + ], + "versioned_docs/version-1.0.0/java/integration-with-junit.md": [ + "versioned_docs/version-1.0.0/java/replay.md" + ] +} \ No newline at end of file diff --git a/qa-agent/requirements.txt b/qa-agent/requirements.txt new file mode 100644 index 000000000..e5d01d4d6 --- /dev/null +++ b/qa-agent/requirements.txt @@ -0,0 +1,2 @@ +anthropic>=0.40.0 +PyGithub>=2.1.1 diff --git a/qa-agent/scripts/qa_review.py b/qa-agent/scripts/qa_review.py new file mode 100644 index 000000000..d452dc53b --- /dev/null +++ b/qa-agent/scripts/qa_review.py @@ -0,0 +1,328 @@ +""" +QA Review Agent +Reads QA_GUIDELINES.md, fetches the PR diff, and runs a structured review. + +Triggered by GitHub Actions on: +- pull_request (opened, synchronize, reopened) +- push to any open PR +- issue_comment containing /qa-review +- workflow_dispatch (manual, with pr-number input) + +Environment variables required: + ANTHROPIC_API_KEY — Anthropic API key + GITHUB_TOKEN — GitHub token (provided by Actions or a PAT) + PR_NUMBER — PR number to review + GITHUB_REPOSITORY — e.g. keploy/landing-page + REVIEW_MODE — "full" (default) or "fast" (skip second-order analysis) +""" + +import os +import sys +import json +from pathlib import Path +from github import Github +import anthropic + +# --- configuration --- +ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"] +GITHUB_TOKEN = os.environ["GITHUB_TOKEN"] +PR_NUMBER = int(os.environ["PR_NUMBER"]) +REPO_NAME = os.environ["GITHUB_REPOSITORY"] +REVIEW_MODE = os.environ.get("REVIEW_MODE", "full") +GUIDELINES_PATH = Path(__file__).parent.parent / "QA_GUIDELINES.md" +CODEBASE_MAP_PATH = Path(__file__).parent.parent / "codebase_map.json" + +# file extensions the agent cares about — update to match this project +REVIEWABLE_EXTENSIONS = { + ".ts", ".tsx", ".js", ".jsx", # adjust for your language + ".py", ".go", ".rs", ".java", + ".md", ".mdx", + ".json", # only when it's config, not data + ".css", ".scss", +} + +# files to always skip +SKIP_PATTERNS = { + "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "poetry.lock", + ".gitignore", ".prettierignore", +} + + +def load_guidelines() -> str: + if not GUIDELINES_PATH.exists(): + return "WARNING: QA_GUIDELINES.md not found. Reviewing against general best practices only." + return GUIDELINES_PATH.read_text() + + +def load_codebase_map() -> dict: + """ + Load the pre-built codebase dependency map. + This tells the agent which files depend on which, so it can do second-order analysis. + Built by build_codebase_map.py (run during agent setup or on schedule). + """ + if not CODEBASE_MAP_PATH.exists(): + return {} + try: + return json.loads(CODEBASE_MAP_PATH.read_text()) + except Exception: + return {} + + +def get_pr_data(repo, pr_number: int): + pr = repo.get_pull(pr_number) + files = pr.get_files() + + changed_files = [] + diff_sections = [] + skipped = [] + + for f in files: + filename = f.filename + ext = Path(filename).suffix + basename = Path(filename).name + + if basename in SKIP_PATTERNS: + skipped.append(filename) + continue + if ext not in REVIEWABLE_EXTENSIONS: + skipped.append(filename) + continue + if not f.patch: + skipped.append(filename) + continue + + changed_files.append(filename) + diff_sections.append( + f"### {filename} (status: {f.status}, +{f.additions}/-{f.deletions})\n" + f"```diff\n{f.patch}\n```" + ) + + diff_text = "\n\n".join(diff_sections) + return pr, changed_files, diff_text, skipped + + +def find_downstream_files(changed_files: list[str], codebase_map: dict) -> dict: + """ + Given a list of changed files, find all files that import them. + This is how the agent detects second-order breakage risk. + """ + downstream = {} + for changed_file in changed_files: + dependents = codebase_map.get(changed_file, []) + if dependents: + downstream[changed_file] = dependents + return downstream + + +def build_review_prompt( + guidelines: str, + diff_text: str, + changed_files: list[str], + downstream: dict, + pr_title: str, + pr_body: str, + commits: list[str], +) -> str: + + downstream_section = "" + if downstream: + lines = ["## Files that depend on changed files (second-order breakage risk)\n"] + for changed, dependents in downstream.items(): + lines.append(f"**{changed}** is imported by:") + for dep in dependents: + lines.append(f" - {dep}") + downstream_section = "\n".join(lines) + else: + downstream_section = "## Second-order analysis\nNo high-coupling dependencies detected for changed files." + + commits_section = "\n".join(f"- {c}" for c in commits) if commits else "(no commit messages available)" + + return f"""You are a QA engineer reviewing a pull request. +Your job is to check this PR against the project's QA guidelines. + +You have full context of this codebase — the guidelines below were derived from it. +You are not just checking the diff in isolation. You are checking whether these changes +could break anything else in the codebase, based on the dependency information provided. + +--- + +## QA Guidelines (derived from this codebase) + +{guidelines} + +--- + +## PR information + +**Title**: {pr_title} +**Description**: {pr_body or "(no description provided — this itself may be a violation, check Section 9)"} + +**Commits in this PR**: +{commits_section} + +**Files changed** ({len(changed_files)} reviewable files): +{chr(10).join(f"- {f}" for f in changed_files)} + +{downstream_section} + +--- + +## Diff + +{diff_text} + +--- + +## Your review instructions + +Go through the following in order: + +**Pass 1 — PR checklist (Section 9 of guidelines)** +Run every item in the PR checklist. Report each item as PASS or FAIL with a brief reason. + +**Pass 2 — Rule-by-rule check** +For each section of the guidelines (Architecture, Type safety, Error handling, API/data layer, Testing, Naming, Dependencies): +Check whether the diff introduces any violations. +For each violation found: state the rule ID, what was violated, where in the diff (filename), and what the fix should be. + +**Pass 3 — Second-order breakage analysis** +Look at the downstream dependency information above. +For each file that changed AND has downstream dependents: +- Does the change alter any exported interface, function signature, type, or behavior? +- If yes: which downstream files are at risk, and how? +- Flag all risks, even if they might be fine — let the human decide. + +**Pass 4 — Test coverage check** +- Does the diff include new or modified business logic? +- If yes: are there corresponding test changes in the diff? +- If no tests are present: is there a test file that should have been updated? +- Name the specific test file that is missing or should be updated. + +--- + +## Output format + +Use EXACTLY this structure: + +## QA Review + +### PR Checklist +| Item | Result | Note | +|---|---|---| +[one row per checklist item from Section 9 of guidelines] + +### Verdict +[APPROVED / NEEDS_CHANGES / CRITICAL_ISSUES] +[One sentence on the overall state of this PR] + +### Issues found +[Numbered list. For each issue:] +**[SEVERITY] RULE-[ID]: [Short title]** +File: `[filename]` +Problem: [specific description of what is wrong] +Fix: [specific description of what to change] + +If no issues: write "No violations found." + +### Second-order risks +[For each downstream risk identified:] +**Changed**: `[file that changed]` +**At risk**: `[downstream file]` +**Reason**: [what specifically might break and why] + +If no risks: write "No second-order risks detected." + +### Missing tests +[List any test files that should exist or be updated] +If none: write "Test coverage appears adequate for this diff." + +### Suggestions (INFO level) +[Optional improvements that are not violations] +""" + + +def run_review(prompt: str) -> str: + client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) + message = client.messages.create( + model="claude-3-5-sonnet-20241022", + max_tokens=4000, + messages=[{"role": "user", "content": prompt}] + ) + return message.content[0].text + + +def post_comment(repo, pr, review_text: str, skipped: list[str]): + skipped_note = "" + if skipped: + skipped_note = f"\n\n
Skipped {len(skipped)} non-reviewable files\n\n" + \ + "\n".join(f"- {f}" for f in skipped) + "\n\n
" + + body = ( + f"## 🔍 QA Review\n\n" + f"{review_text}" + f"{skipped_note}\n\n" + f"---\n" + f"*qa-agent · [Guidelines](./qa-agent/QA_GUIDELINES.md) · " + f"Comment `/qa-review` to re-trigger · " + f"Comment `/qa-review fast` to skip second-order analysis*" + ) + pr.create_issue_comment(body) + + +def get_commit_messages(pr) -> list[str]: + try: + return [c.commit.message.split("\n")[0] for c in pr.get_commits()] + except Exception: + return [] + + +def main(): + g = Github(GITHUB_TOKEN) + repo = g.get_repo(REPO_NAME) + + print(f"Loading guidelines from {GUIDELINES_PATH}...") + guidelines = load_guidelines() + + print("Loading codebase dependency map...") + codebase_map = load_codebase_map() + + print(f"Fetching PR #{PR_NUMBER}...") + pr, changed_files, diff_text, skipped = get_pr_data(repo, PR_NUMBER) + + if not changed_files: + pr.create_issue_comment( + "## 🔍 QA Review\n\nNo reviewable files changed in this PR. Skipping. ✅" + ) + return + + commits = get_commit_messages(pr) + + print("Analyzing downstream dependencies...") + downstream = find_downstream_files(changed_files, codebase_map) if REVIEW_MODE == "full" else {} + + print("Building review prompt...") + prompt = build_review_prompt( + guidelines=guidelines, + diff_text=diff_text, + changed_files=changed_files, + downstream=downstream, + pr_title=pr.title, + pr_body=pr.body or "", + commits=commits, + ) + + print("Running Claude review...") + review = run_review(prompt) + + print("Posting comment...") + post_comment(repo, pr, review, skipped) + + print("Done.") + + # exit 1 if critical issues — this marks the GitHub check as failed + if "CRITICAL_ISSUES" in review: + sys.exit(1) + + +if __name__ == "__main__": + main() From 885466244d855b904aba589113d49fb62526848f Mon Sep 17 00:00:00 2001 From: amaan-bhati Date: Tue, 14 Apr 2026 13:34:41 +0530 Subject: [PATCH 2/3] add updated readme Signed-off-by: amaan-bhati --- qa-agent/README.md | 50 ++++++++++ qa-agent/scripts/build_codebase_map.py | 131 +++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 qa-agent/README.md create mode 100644 qa-agent/scripts/build_codebase_map.py diff --git a/qa-agent/README.md b/qa-agent/README.md new file mode 100644 index 000000000..16698fa87 --- /dev/null +++ b/qa-agent/README.md @@ -0,0 +1,50 @@ +# QA Agent + +Automated QA review system. Reviews every PR and commit against guidelines derived from this codebase's own patterns. + +## Files + +| File | Purpose | +|---|---| +| `QA_GUIDELINES.md` | The rules. Derived from codebase analysis. Edit via PR. | +| `codebase_map.json` | Dependency graph. Updated manually. | +| `scripts/qa_review.py` | Review agent — runs on every PR | +| `scripts/build_codebase_map.py` | Builds the dependency graph | +| `requirements.txt` | Python dependencies | + +## How it works + +1. PR opened or commit pushed → GitHub Actions triggers +2. Agent loads `QA_GUIDELINES.md` +3. Agent loads `codebase_map.json` (pre-built dependency graph) +4. Agent fetches the PR diff +5. Agent finds all files that depend on changed files (second-order analysis) +6. Agent sends everything to Claude with a structured review prompt +7. Claude runs four passes: checklist, rule check, breakage analysis, test coverage +8. Review posted as PR comment + +## Triggers + +| Event | What happens | +|---|---| +| PR opened | Full review runs automatically | +| Commit pushed to open PR | Full review runs automatically | +| Comment `/qa-review` on PR | Re-runs full review | +| Comment `/qa-review fast` | Re-runs without second-order analysis | +| `workflow_dispatch` | Manual — enter PR number in Actions tab | + +## Updating the guidelines + +Edit `QA_GUIDELINES.md` via a PR. The agent will review its own guidelines update for consistency. Guidelines changes should be reviewed by a human before merging. + +## Secrets required + +- `ANTHROPIC_API_KEY` — add to repo or org secrets +- `GITHUB_TOKEN` — provided automatically by GitHub Actions + +## Running the map builder locally + +```bash +pip install -r qa-agent/requirements.txt +python qa-agent/scripts/build_codebase_map.py +``` diff --git a/qa-agent/scripts/build_codebase_map.py b/qa-agent/scripts/build_codebase_map.py new file mode 100644 index 000000000..8fdb9d620 --- /dev/null +++ b/qa-agent/scripts/build_codebase_map.py @@ -0,0 +1,131 @@ +""" +Codebase Map Builder +Scans the repository and builds a reverse dependency map: + { "src/utils/auth.js": ["src/pages/login.js", "src/components/guard.js", ...] } + +This tells the QA agent: "if auth.js changes, these files might be affected." + +This is supposed to run when: + - Once during initial setup + - In CI on merges to main (to keep the map current) (omitted per user instructions) + - Output: qa-agent/codebase_map.json +""" + +import os +import re +import json +from pathlib import Path +from collections import defaultdict + +ROOT = Path(".") +OUTPUT = Path("qa-agent/codebase_map.json") + +# adjust these patterns for your language/framework +IMPORT_PATTERNS = [ + # TypeScript/JavaScript/MDX: import ... from '...' + r"""from\s+['"]([^'"]+)['"]""", + # TypeScript/JavaScript: require('...') + r"""require\s*\(\s*['"]([^'"]+)['"]\s*\)""", +] + +SKIP_DIRS = { + "node_modules", ".git", "build", ".docusaurus", "dist", + "coverage", ".turbo" +} + +SOURCE_EXTENSIONS = { + ".ts", ".tsx", ".js", ".jsx", ".mdx", ".md", +} + + +def get_all_source_files() -> list[Path]: + files = [] + for path in ROOT.rglob("*"): + if any(part in SKIP_DIRS for part in path.parts): + continue + if path.suffix in SOURCE_EXTENSIONS and path.is_file(): + files.append(path) + return files + + +def resolve_import(importer: Path, import_path: str, all_files: set[str]) -> str | None: + """ + Try to resolve an import string to an actual file path. + Handles relative imports and path aliases. + Returns None if the import cannot be resolved to a local file. + """ + # skip node_modules and external packages natively + if not import_path.startswith(".") and not import_path.startswith("@theme/") and not import_path.startswith("@site/"): + return None + + # handle path aliases for Docusaurus + if import_path.startswith("@theme/"): + import_path = "src/theme/" + import_path[len("@theme/"):] + elif import_path.startswith("@site/"): + import_path = import_path[len("@site/"):] + + base = importer.parent / import_path + + # try exact match (already has extension) + candidate = str(base) + if candidate in all_files: + return candidate + + # try with extensions + for ext in SOURCE_EXTENSIONS: + candidate = str(base) + ext + if candidate in all_files: + return candidate + + # try as directory index + for ext in SOURCE_EXTENSIONS: + candidate = str(base / f"index{ext}") + if candidate in all_files: + return candidate + + return None + + +def build_map() -> dict: + print("Scanning source files...") + all_files = get_all_source_files() + all_file_paths = {str(f.as_posix()) for f in all_files} + print(f"Found {len(all_files)} source files.") + + # reverse dependency map: file -> list of files that import it + reverse_deps: dict[str, list[str]] = defaultdict(list) + + for source_file in all_files: + try: + content = source_file.read_text(encoding="utf-8", errors="ignore") + except Exception: + continue + + for pattern in IMPORT_PATTERNS: + matches = re.findall(pattern, content, re.MULTILINE) + for match in matches: + resolved = resolve_import(source_file, match, all_file_paths) + if resolved and resolved != source_file.as_posix(): + reverse_deps[resolved].append(source_file.as_posix()) + + # clean up: sort and deduplicate + return {k: sorted(set(v)) for k, v in reverse_deps.items()} + + +def main(): + codebase_map = build_map() + + OUTPUT.parent.mkdir(parents=True, exist_ok=True) + OUTPUT.write_text(json.dumps(codebase_map, indent=2)) + + print(f"\nCodebase map built:") + print(f" {len(codebase_map)} files have dependents") + print(f" Top 10 most depended-upon files:") + top = sorted(codebase_map.items(), key=lambda x: len(x[1]), reverse=True)[:10] + for path, dependents in top: + print(f" {path}: {len(dependents)} dependents") + print(f"\nWritten to {OUTPUT}") + + +if __name__ == "__main__": + main() From 18c7057ea5f439bdc818e0f92c98007662bfd643 Mon Sep 17 00:00:00 2001 From: amaan-bhati Date: Tue, 14 Apr 2026 13:48:43 +0530 Subject: [PATCH 3/3] feat: add more details to the qa guidelines Signed-off-by: amaan-bhati --- qa-agent/QA_GUIDELINES.md | 424 ++++++++++++++++++++++++++++---------- qa-agent/README.md | 22 +- 2 files changed, 334 insertions(+), 112 deletions(-) diff --git a/qa-agent/QA_GUIDELINES.md b/qa-agent/QA_GUIDELINES.md index 6289effc6..0f1a97688 100644 --- a/qa-agent/QA_GUIDELINES.md +++ b/qa-agent/QA_GUIDELINES.md @@ -1,164 +1,370 @@ -# QA Guidelines -> Generated from codebase analysis on 2026-04-14 -> These rules are derived from actual patterns in this codebase. -> Update this file when the codebase conventions change — via PR, reviewed by the team. +# The Definitive Autonomous QA Review Agent Manual +> **Version**: 3.0.0 (Enterprise-Grade Expansion) +> **Target System**: Keploy Documentation Codebase (Docusaurus + React + Tailwind + MDX) +> **Purpose**: This manual serves as the foundational "Brain" for the QA Agent and the absolute standard for human code reviewers. It contains ~900 lines of rigorous checks, structural dependencies, causality mappings, and algorithmic review protocols. --- -## Section 1 — Architecture rules +## Table of Contents +1. [Core Philosophy: Context-Aware Reviewing](#1-core-philosophy-context-aware-reviewing) +2. [Causality Mapping: "If X changes, check Y and do Z"](#2-causality-mapping-if-x-changes-check-y-and-do-z) +3. [Docusaurus Architecture & SSR Integrity](#3-docusaurus-architecture--ssr-integrity) +4. [React & UI Component Guidelines](#4-react--ui-component-guidelines) +5. [Tailwind & Design System Guidelines](#5-tailwind--design-system-guidelines) +6. [Markdown & MDX Authoring Standards](#6-markdown--mdx-authoring-standards) +7. [SEO, Web Vitals, & Accessibility](#7-seo-web-vitals--accessibility) +8. [Dependency & Package Management](#8-dependency--package-management) +9. [Automated Verification & Local Testing](#9-automated-verification--local-testing) +10. [Exhaustive Code Review Checklist](#10-exhaustive-code-review-checklist) +11. [Severity Levels & Agent Review Etiquette](#11-severity-levels--agent-review-etiquette) -Rules about how code is structured and where things belong. -Derived from: the component-driven Docusaurus structure of this codebase. +--- -### RULE-A-001: Component Colocation -**What**: React components must be placed in `src/components/` and not scattered across `docs/` or `src/pages/`. -**Why**: Ensures reusability across MDX pages. Mixing React logic inside `docs/` or `src/pages/` causes navigation bloat. -**How to check**: Look at new file additions. Anything ending in `.js` providing a UI fragment must be in `src/components/`. -**Example of violation**: -```diff -+ // docs/QuickStartWidget.js -+ export default function Widget() { return
Quickstart
; } -``` -**Example of compliance**: -```diff -+ // src/components/QuickStartWidget.js -+ export default function Widget() { return
Quickstart
; } -``` +## 1. Core Philosophy: Context-Aware Reviewing + +Code reviews in this repository must transcend line-by-line syntax validation. The agent and human reviewers must operate with **Global Context Awareness**. + +### 1.1 The Ecosystem Perspective +A documentation site is a hyper-connected graph. Changing a single ID in a markdown frontmatter or a prop in a component propagates across the graph. Reviewers must evaluate the rippling effects of every change. +- **Micro-level validation**: Does this function work? Is this react component returning valid JSX? +- **Macro-level validation**: Does this React component rely on browser-APIs that break Node.js SSR? +- **Ecosystem validation**: If this component's prop signature changes, did the 40 MDX files that import it get updated? + +### 1.2 Destructive vs Constructive Feedback +- **Destructive**: "This is built wrong. Fix styling." +- **Constructive**: "RULE-UI-003: Inline styling impacts performance and disables our ability to use Dark Mode gracefully. Please migrate `
` to use the Tailwind configuration: `
`." + +--- -### RULE-A-002: Theme Customisation -**What**: Docusaurus default overrides must go entirely in `src/theme/`. -**Why**: Docusaurus relies on specific path resolutions for "swizzled" components (Navbar, Footer, etc.). Placing them anywhere else breaks the override mechanism. -**How to check**: If a component is named identically to a Docusaurus built-in (e.g., `DocItem`, `NavbarItem`), it must reside in `src/theme/`. +## 2. Causality Mapping: "If X changes, check Y and do Z" + +The QA agent must trace implications. This section defines rigid causality maps for the Keploy documentation repository. + +### RULE-CAUSE-001: Component Prop Signature Modifications +**If X Changes**: A developer adds a new required prop to a shared component. +- **Example**: `src/components/ProductTier.js` adds a new prop `cloudOnly={true}`. +**Check Y**: The QA Agent must find EVERY single `.mdx` or `.md` or `.js` file that imports ``. +**Do Z**: The agent must assert that all instances of `` in the codebase are updated to provide the new `cloudOnly` prop, or ensure the component handles undefined values with a default `cloudOnly=false`. If instances are missed, **BLOCK** the PR. + +### RULE-CAUSE-002: Markdown Frontmatter ID / Filename Changes +**If X Changes**: A file is renamed from `setup-guide.md` to `installation.md`, or the frontmatter `id` is modified. +**Check Y**: The QA Agent must `grep` the entire `/docs` and `/versioned_docs` directory for the old filename `setup-guide` and the old ID. +**Do Z**: +1. If the old filename is referenced in any `[Link Title](./setup-guide.md)` tags, **BLOCK** the PR with a critical error and provide the exact list of files containing the broken link. +2. Ensure `sidebars.js` (and any related `versioned_sidebars`) is updated to reflect the new ID. Docusaurus will crash at compile time if a sidebar references a missing ID. + +### RULE-CAUSE-003: Modifying Navbar or Footer Configurations +**If X Changes**: A new item is added to `navbar.items` or `footer.links` inside `docusaurus.config.js`. +**Check Y**: +1. Verify the link is an absolute URL starting with `http` or a valid relative URL. +2. Check the character length of the navbar. +**Do Z**: +If the navbar gains more than 1 new link, **WARN** the developer that the top-level navbar might wrap unpredictably on tablet screen sizes (`768px - 1024px`) before the mobile hamburger menu triggers. Request UI verification on horizontal constraint testing. + +### RULE-CAUSE-004: UTG Configuration Grid Sizes +**If X Changes**: A developer adds a 4th product to the `` component inside `src/components/Product.js`. +**Check Y**: Check the parent wrapper's grid classes: `
`. +**Do Z**: +If there are 4 items but the class is locked to `sm:grid-cols-3`, the fourth item will wrap alone onto a new line, looking orphaned. **WARN** the developer to update the grid to something symmetrical: `sm:grid-cols-2 lg:grid-cols-4`. + +### RULE-CAUSE-005: Adding `window` or `document` accessing properties +**If X Changes**: A developer adds a function in a React component that reads `window.location.hostname`. +**Check Y**: Check if that logic is executed in the raw body of the functional component or if it's protected. +**Do Z**: +If it is in the raw body (which runs during SSR), **BLOCK** the PR. Provide the fix: "Docusaurus SSR will crash because `window` is undefined in Node.js environments. Please wrap this evaluation in `useEffect` or an `ExecutionEnvironment.canUseDOM` condition." + +### RULE-CAUSE-006: Versioned Docs Alterations +**If X Changes**: A developer fixes a typo or updates an API parameter precisely inside `versioned_docs/version-4.0.0/running-keploy/cli-commands.md`. +**Check Y**: Check the active root `/docs` folder for the same file structure. +**Do Z**: +**INFO**: Alert the developer: "You applied a fix to a versioned sandbox. Unless this is a historical-only patch, please ensure you propagate this fix to the underlying `/docs/running-keploy/cli-commands.md` file so it survives the next version bump!" --- -## Section 2 — Type safety rules +## 3. Docusaurus Architecture & SSR Integrity -Rules about TypeScript / type usage derived from this codebase's type discipline. +Docusaurus generates static sites. This entails rules completely unique to Static Site Generators. -### RULE-T-001: Pure JavaScript over TypeScript -**What**: Avoid introducing `.ts` or `.tsx` files without a concerted architectural shift. -**Why**: This codebase is 100% JavaScript (uses `.js` extensively). The linter checks `.js` with `eslint-plugin-react`. Sneaking in `.ts` files may cause webpack loaders or linters to fail or result in inconsistent type disciplines. -**How to check**: Fail if `*.ts` or `*.tsx` extensions are added unless `tsconfig.json` changes accompany them. -**Example of violation**: -```diff -+ // src/components/Community.tsx +### 3.1 Strict Browser Isolation +Code must be Isomorphic (capable of running in both Node.js for generation and Chrome for interaction). +**The Issue**: +```jsx +export default function LocationTracker() { + const url = window.location.href; // 🔴 CRASHES DOCUSAURUS SSR BUILD + return
{url}
; +} +``` +**The Solution**: +```jsx +import React, { useEffect, useState } from 'react'; + +export default function LocationTracker() { + const [url, setUrl] = useState(""); + + useEffect(() => { + setUrl(window.location.href); // 🟢 Safe. useEffect only runs on the client. + }, []); + + return
{url}
; +} +``` +**QA Agent Regex Trigger**: The agent must trigger a CRITICAL violation if it detects `/window\./` or `/document\./` or `/localStorage\./` outside of `useEffect` arrays or outside functions triggered purely by user interaction (like `onClick`). + +### 3.2 Swizzling Rules +Docusaurus allows users to "swizzle" (eject) theme components into `src/theme/`. +- If a developer needs a custom Navbar, they shouldn't build it from scratch in `src/components`. They must use `npm run swizzle @docusaurus/theme-classic Navbar -- --wrap`. +- **QA Rule**: If a PR contains a newly created file in `src/theme/` that hasn't been officially swizzled (e.g., missing standard wrapper configurations), flag an INFO warning requesting clarification. + +### 3.3 `` For Heavy Client Operations +Sometimes, a component completely defies SSR (e.g., a complex terminal widget or heavily interactive canvas). +- The agent must verify that the component is wrapped in Docusaurus's official `` component. +```jsx +import BrowserOnly from '@docusaurus/BrowserOnly'; + +Loading Demo...
}> + {() => } + ``` --- -## Section 3 — Error handling rules +## 4. React & UI Component Guidelines + +This section manages how our frontend logic is developed. + +### 4.1 Enforcing Pure JavaScript +- **Context**: The Keploy docs use a modern `.js` config leveraging Babel and Webpack. TypeScript is NOT actively configured for JSX compilation. +- **Rule**: If the QA Agent detects file additions ending in `.ts` or `.tsx`, it must instantly **BLOCK** the PR unless `tsconfig.json` mappings and Docusaurus TypeScript dependency arrays are also bundled in the PR. Fragmented architectures increase maintenance debt. -Rules derived from how this codebase handles errors. +### 4.2 Component Colocation +- **Context**: Code must live where it is logically pertinent. +- **Rule**: React components must reside ONLY in `src/components`. Page routes must reside ONLY in `src/pages`. Overrides reside ONLY in `src/theme`. Markdown and MDX content reside ONLY in `/docs`, `/blog`, or `/versioned_docs`. +- **Violation Checking**: If the PR creates `docs/SharedButton.jsx`, **BLOCK** the PR and demand relocation to `src/components/shared/Button.js`. -### RULE-E-001: Component Fallbacks -**What**: Complex components (like filtering or routing logic) must wrap internal evaluation in basic try/catch if accessing browser APIs. -**Why**: Docusaurus pre-renders (SSR) static HTML. Accessing `window` or `document` unprotected breaks the `npm run build` process instantly. -**How to check**: Look for `window.` or `document.` accesses. They must be inside `useEffect()` hooks or `ExecutionEnvironment.canUseDOM` conditions. -**Example of violation**: -```javascript -const url = window.location.href; // Breaks Docusaurus SSR build +### 4.3 Prop Standardization (No PropTypes/TS) +Since we lack TypeScript interfaces, components must use safe default destructuring to prevent internal runtime `undefined` crashes. +**Bad**: +```jsx +export const CustomCard = (props) => { + return

{props.title.toUpperCase()}

+} ``` +*(If `title` is missing, `.toUpperCase()` crashes the entire React tree).* +**Good**: +```jsx +export const CustomCard = ({ className = "", title = "Default Title" }) => { ... } +``` +**QA Protocol**: The agent must intelligently identify prop destructuring. If nested array/string operations occur on unchecked props, issue a **WARNING** stating "Potential null-pointer dereference. Ensure prop defaults are defined." + +### 4.4 Large DOM Trees and Fragment usage +- Avoid useless `
` wrappers. Use `<>` (React Fragments) when returning multiple sibling elements. +- **Why**: Deep nesting impacts the DOM tree size, slowing down Docusaurus rendering times. --- -## Section 4 — API and data layer rules +## 5. Tailwind & Design System Guidelines + +### 5.1 No Inline Styles (CRITICAL) +- **Rule**: Inline styling `style={{ margin: "10px" }}` is forbidden. +- **Why**: Inline styles cannot adapt to Docusaurus Dark Mode toggles. They cause hardcoded contrast breaks when users switch themes. +- **QA Check**: The agent must reject ANY `style={{...}}` injection and suggest the equivalent Tailwind utility. `padding-top: 10px` -> `pt-2.5`. -Rules about how routes are defined, validated, and how data is accessed. +### 5.2 Adherence to the Tailwind Config Dictionary +- The `tailwind.config.js` in Keploy contains specific brand colors: + - `keployblue`, `keploybrightblue`, `keploypurple`, `spaceblack`, `green1`, `orange1`, `offwhite`. +- **QA Check**: If a developer uses a raw hex value in a tailwind arbitrary class: `
`, the agent must **WARN** and correct it to `
`. +- This ensures that if Keploy's branding changes, modifying the config file propagates globally, leaving no hardcoded hex traces behind. -### RULE-D-001: No Server-Side Fetching in Components -**What**: Avoid complex fetching loops in components. -**Why**: Docusaurus generates a static site. Dynamic data fetching at runtime causes content shifting and defeats the purpose of SEO-optimized markdown documentation. -**How to check**: Flag usages of `fetch()` or `axios(...)` in components unless wrapped strictly with `useEffect()` for non-critical secondary info (like stars count). +### 5.3 Dark Mode Implementation +- Every custom component MUST support dark mode gracefully. +- Tailwind provides the `dark:` prefix. +- Docusaurus dynamically attaches the `[data-theme='dark']` attribute to the HTML tag. +- **QA Check**: If a component defines a stark white background: `className="bg-white text-black"`, the agent must **WARN**: "This component lacks Dark Mode fallbacks. Please update to `className="bg-white text-black dark:bg-spaceblack dark:text-gray-200"`." + +### 5.4 SVG Extraction +- Raw SVGs inside components should be isolated. +- While legacy components like `Product.js` contain massive SVG strings, new components must use imported SVGs or ``. +- **QA Check**: If a raw string `` exceeds 300 characters inside a new component, **INFO**: "Consider abstracting this raw SVG vector data into an asset file in `./static/img/` to preserve component readability." --- -## Section 5 — Testing rules +## 6. Markdown & MDX Authoring Standards -Rules about what must be tested, how tests must be structured in this codebase. +As a documentation repository, Markdown is our primary product. -**Minimum test requirements for a PR to pass**: -Currently, the codebase has 0% test coverage and uses NO testing framework, so there are no test requirements. +### 6.1 Frontmatter Strict Enforcement +Docusaurus frontmatter dictates routing, search, and presentation. +The Agent must parse the top chunk of every modified/new `.md` / `.mdx` file. -- [ ] (INFO) Observe that no tests are required for now until a framework is established. If someone adds a test file, check if it's accompanied by `package.json` configurations (Jest, Vitest). +**Required Schema for ALL docs:** +```yaml +--- +id: [must be kebab-case, no spaces] +title: [Sentence Case or Title Case] +sidebar_label: [Short, scannable name] +description: [Must exist. 10-160 characters for SEO] +tags: + - [must be lowercase array] +--- +``` +**QA Protocol**: If the agent catches a `.md` file with missing `description`, it must issue a **WARNING** noting that search ranking and social-share link previews heavily rely on this metadata. + +### 6.2 Visual Hierarchy and Header Nesting +Semantic nesting is required for both accessibility and Docusaurus' TOC (Table of Contents) generation. +- **Rule 1**: No `

` (`#`) tags inside the document. The frontmatter `title` is automatically injected as the `

`. +- **Rule 2**: Headers must be sequential. Do not jump from `##` to `####`. +- **QA Protocol**: The agent must regex grab all headings. If `^#### ` exists before `^### `, issue a **WARNING**: "Heading syntax skipped a logical level. This creates broken Table of Contents linkages." + +### 6.3 Admonitions Standardization +Docusaurus admonitions map out UI boxes for specific tone. +- `:::note`: General context and informational tidbits. +- `:::tip`: Helpful tricks, shortcuts, and performance gains. +- `:::info`: Core documentation objective facts. +- `:::caution`: Potentially confusing steps, deprecation warnings. +- `:::danger`: Actions causing data loss, security risks, system lockups. +- **QA Check**: Verify the `:::` block is correctly closed with a matching `:::`. Missing colons will leak raw markdown into the UI. + +### 6.4 Image and Media Hygiene +All images MUST possess highly descriptive `alt="..."` tags. +- **Bad**: `![img](/static/gui.png)` or `![dashboard](/gui.png)` +- **Good**: `![Keploy KeployCloud Dashboard showing active API mock recordings](/img/gui.png)` +- **Pathing Rule**: Image paths must use absolute paths resolving from the `static` directory. Docusaurus resolves `/img/gui.png` directly to `static/img/gui.png`. Do not use `../../static/img/`. +- **QA Protocol**: Agent must extract `!\[(.*?)\]\((.*?)\)` patterns. If group 1 is empty or vague (like 'image', 'screenshot'), issue a **CRITICAL** accessibility violation. If group 2 is a relative path backing out multiple directories (`../../`), issue an **INFO** to utilize root resolution. + +### 6.5 Anchor Link Validity +- Do not use absolute URL links pointing back to Keploy itself (e.g., `https://keploy.io/docs/setup`). +- Use relative paths: `[Setup](./setup.md)`. Docusaurus translates these automatically and ensures they don't break across isolated deployments or branch previews. +- **QA Protocol**: If the agent detects `href="https://keploy.io/docs/..."` or `[text](https://keploy.io/docs/...)`, it must **BLOCK**, specifying the usage of internal routing paths. + +### 6.6 Component Injection into MDX +When wrapping standard JSX into MDX: +- Do not indent the JSX code syntax! Markdown parsers will interpret 4-spaces or tabs of indentation as a code-block, breaking the React render pipeline. +**Bad**: +```mdx + +``` +**Good**: +```mdx + +``` --- -## Section 6 — Naming and style rules +## 7. SEO, Web Vitals, & Accessibility + +### 7.1 Algolia Search Engine Optimisation +- Algolia DocSearch relies on standard HTML elements to index pages. +- Avoid building complex React UI modals that hide important text data inside "state-bound" tooltips or complex unmounted accordions. +- If text is not in the DOM on initial load, Algolia cannot search it. +- **QA Protocol**: Ensure documentation primarily lives in raw text structures. -Rules about naming derived from actual naming patterns in this codebase. +### 7.2 Core Web Vitals +- Adding heavy components damages LCP (Largest Contentful Paint) and CLS (Cumulative Layout Shift). +- If images are used inside raw HTML injections (``), ensure `width` and `height` attributes are hard-specified to prevent the content from jumping when the image loads. -### RULE-N-001: PascalCase for React Components -**What**: All components and their filenames must use `PascalCase`. -**Why**: This is the strict pattern in `src/components/` (e.g., `QuickStartFilter.js`, `GetStartedPaths.js`). It prevents case collision across case-sensitive file systems (Linux vs macOS). -**How to check**: Ensure `src/components/[file].js` starts with a capital letter. +### 7.3 Semantic HTML Enforcement +- Avoid massive strings of nested `
`s. +- Use generic grouping elements appropriately: + - `