name: ego-review description: >- Perform a manual code review of a GNOME Shell extension simulating what an EGO reviewer checks. Analyzes lifecycle correctness, signal disconnection, resource cleanup, async safety, security patterns, and code quality. Use before EGO submission, when reviewing GNOME extension code, or for pre-submission review.
ego-review
Simulated EGO reviewer code review for GNOME Shell extensions.
This skill guides a thorough manual code review that covers everything an extensions.gnome.org reviewer checks, plus common rejection patterns learned from real submissions.
Reviewer Context
Understanding the real EGO review process helps calibrate review severity:
- Primary reviewer processes 15,000+ lines of code per day across many extensions
- Review priority order: Security → Stability (resource leaks) → Code readability → Lifecycle correctness → API correctness → Metadata → AI pattern detection
- Lifecycle cleanup is the #1 rejection cause — not security, not metadata
- AI slop triggers deeper scrutiny: When a reviewer spots one AI-generated pattern, they examine the entire extension more carefully. A clean extension with one
pkexecusage gets more leeway than one withtypeof super.destroy === 'function'guards everywhere - The domino effect: Bad patterns in published extensions get copied. Reviewers are stricter on patterns they've seen spread (excessive try-catch, empty catches, TypeScript JSDoc)
- Developer understanding matters: When asked to explain code, developers who respond with more AI-generated text are immediately flagged. Extensions where the developer clearly understands the code get more benefit of the doubt
Phase 0: Automated Baseline
- Run ego-lint on the extension directory (invoke the ego-lint skill)
- Capture all FAIL/WARN/PASS results
- For each FAIL/WARN, note the check name — Phases 2-5 should NOT re-report issues already caught by ego-lint (avoid duplication)
- Focus manual review on issues ego-lint CANNOT detect (semantic, cross-file, design-level)
Phase 1: Discovery
- Read
metadata.json-- note UUID, shell-version, settings-schema, any session-modes - Glob all
.jsfiles -- identify extension.js, prefs.js, lib/ modules - Check for helper scripts, polkit rules, or other resources
- Note the extension's purpose and complexity level
Phase 1b: Licensing & Legal
Using licensing-checklist.md:
- Verify LICENSE/COPYING file exists and is GPL-compatible
- Check for code that appears borrowed from other extensions (attribution needed)
- Verify no copyrighted/trademarked content without permission
- Check extension name, description, and UI text for CoC compliance
Phase 2: Lifecycle Audit
Using lifecycle-checklist.md:
Read
extension.js— verify enable/disable symmetryCheck constructor constraints (no resource allocation in constructor)
Reference the resource-tracking findings from Phase 0 lint. ego-lint already ran
build-resource-graph.pyandcheck-resources.py. Use theresource-tracking/*findings from the lint results as the starting point. Do NOT re-runbuild-resource-graph.py.For each resource-tracking FAIL/WARN from lint: read the cited file:line to verify it's a true leak. Classify as: TRUE LEAK (blocking) | JUSTIFIED (note why) | FALSE POSITIVE (skip). For true leaks, include the fix in the report.
For ownership chains: if lint reports orphans, verify parent calls child's
destroy()in its owndisable()/destroy()and that destroy order is reverse of creation. If lint reports 0 orphans, do a brief spot-check of 1-2 ownership chains to verify graph accuracy, but do not perform a full ownership walk.Resource tracking table: if the report needs a resource tracking table, build it from the lint JSON's
resource-tracking/*findings rather than re-runningbuild-resource-graph.py --format=table.If the graph reports 0 orphans and complete ownership chains: abbreviate this phase — focus on async guards and cleanup ordering below
Async guard verification: For every
awaitin enable-path code, verify a_destroyedcheck follows the resume pointVerify cleanup ordering (reverse order of creation)
Check for _destroyed flag pattern in async operations
Verify session mode handling if applicable
Phase 3: Signal & Resource Audit
- Abbreviate this phase if Phase 2 found 0 orphans AND Phase 0 lint has
no
resource-tracking/*orlifecycle/*FAILs/WARNs. In this case, do a single spot-check: pick 1 resource entry from the graph and verify by reading the cited file:line that create/destroy are correctly paired. - Otherwise, for each resource-tracking or lifecycle FAIL/WARN from lint, verify by reading the cited code — focus on issues ego-lint cannot judge semantically (e.g., whether a cleanup pattern is architecturally correct).
- Check for resource types lint still misses: custom cleanup methods
(
_cleanup(),_teardown(),_clear()) not recognized by the resource graph. GSettings signal leaks and D-Bus connectSignal leaks are now automated — do not re-check manually. - Only do a full manual grep if lint reported orphans AND you suspect the graph missed resources after the spot-checks above.
Phase 4: Security Review
Using security-checklist.md:
- Check subprocess/command execution patterns
- Verify pkexec usage and helper script input validation
- Check clipboard operations and disclosure
- Check for network access
- Verify file path handling (no traversal)
- Check for telemetry/analytics patterns (banned by EGO)
- Check clipboard access and disclosure requirements
- Check for extension system interference (ExtensionManager usage)
Reviewer perspective notes:
- When a reviewer sees
pkexec, they immediately check the helper script for input validation - When a reviewer sees network access, they check if it's disclosed in the description
- When a reviewer sees clipboard access, they check if the user initiated it
Phase 4b: Accessibility (if extension adds UI)
Apply accessibility-checklist.md:
- Identify all custom UI elements added by the extension
- Check A1-A7 for each element
- Note: standard St.Button, PopupMenu, QuickToggle have built-in accessibility — only flag custom widgets
Phase 5: Code Quality
Using code-quality-checklist.md:
- Check for deprecated modules and APIs
- Check for web API usage (setTimeout, fetch, etc.)
- Look for AI code artifacts (imaginary APIs, hallucinated imports)
- Check for excessive logging
- Verify private API usage is documented
- Check error handling patterns
- Hallucinated API cross-reference: Verify that every API method called actually exists in the declared
shell-versionrange. Common hallucinations:Meta.Screen,St.Button.set_label(),GLib.source_remove(),Clutter.Actor.show_all() - GObject pattern verification: Check that
registerClasscalls haveGTypeName, thatdestroy()chains tosuper.destroy(), that GObject properties emitnotify - Prefs.js specific checks: Verify
fillPreferencesWindow()exists, GTK4/Adwaita patterns used correctly, no deprecated GTK3 patterns, no Shell imports - Check for
vardeclarations (should use const/let) - Check import ordering (GI → resource → extension)
- Check for
console.log()(banned — only debug/warn/error allowed)
Reviewer perspective notes:
- When a reviewer sees
console.log(), they think "developer forgot to clean up debug logging" - When a reviewer sees module-level
let, they think "will this persist across enable/disable cycles?" - When a reviewer sees
try { super.destroy() } catch, they think "AI-generated code"
Phase 5a: AI Pattern Analysis
Using ai-slop-checklist.md (46-item checklist):
- Split the 46 items by automation status:
- 1a. Automated items (24 of 46): Items 1-2, 4-5, 8, 11-12, 14-15, 18-26, 28, 34, 36, 41-42, 44. Pull the trigger count directly from Phase 0 lint — do NOT re-read descriptions or re-search the code.
- 1b. Manual-only items (15 of 46): Items 3, 7, 9, 13, 27, 31-32, 35, 37-40, 43, 45-46. Search extension source for each pattern — these require semantic judgment ego-lint cannot provide.
- 1c. Partial items (7 of 46): Items 6, 10, 16-17, 29-30, 33. Use ego-lint's result as a starting point, then apply manual judgment for aspects ego-lint cannot cover.
- 1d. Combine: automated triggered count + manual triggered count + partial triggered count = total score.
- Record whether it triggers, with file:line references
- Note whether the pattern is justified by context (check "NOT a signal" exceptions)
- Count JS files to determine threshold tier:
- <10 files: standard thresholds (4-6 BLOCKING)
- 10+ files: size-adjusted thresholds (5-8 BLOCKING)
- Check ego-lint's
quality/code-provenancescore — if provenance-score >= 3, apply +2 credit to BLOCKING threshold - Include count, category breakdown, threshold used, and assessment in the report
- When score reaches BLOCKING, provide specific file:line citations for each triggered item so the developer has an actionable fix list
AI Defense Report (for extensions with triggered AI patterns)
For each triggered AI pattern, include a Defense column in the analysis:
| # | Pattern | Triggered? | File:Line | Defense |
|---|---|---|---|---|
| 1 | Excessive try-catch | Yes | ext.js:45 | All try-catch wraps D-Bus calls (justified) |
| 8 | TypeScript JSDoc | Yes | lib/api.js:12 | Only on 2 exported functions (below threshold) |
Defense indicators to check for each triggered item:
- Is the pattern contextually justified? (try-catch around D-Bus, JSDoc on shared API)
- Does the code show domain knowledge that contradicts AI generation?
- Is there a consistent personal style across the file?
- Does the provenance score suggest genuine authorship?
If more triggered items have valid defenses than not, downgrade the verdict by one tier (BLOCKING → ADVISORY, ADVISORY → note only).
Output Format
## EGO Review Report — [Extension Name] v[version]
### Verdict: [LIKELY APPROVED | NEEDS REVISION | LIKELY REJECTED]
**Rejection Risk**: [LOW | MEDIUM | HIGH | VERY HIGH]
---
### Section 1: Blocking Issues (Must Fix)
#### [B1] Issue title (category)
**File**: path/to/file.js:line
**What**: Description of the issue
**Why reviewers reject this**: Explanation with reviewer perspective
**Fix**:
```js
// BEFORE
old code
// AFTER
fixed code
Section 2: Justification Required
Items that are acceptable IF properly documented:
[J1] pkexec usage
File: path/to/file.js:line Status: Requires reviewer justification Template: [Include pkexec justification template from security checklist]
Section 3: Advisory Issues (May Cause Questions)
[A1] Issue title
File: path/to/file.js:line What: Description Reviewer perspective: What the reviewer thinks when they see this Suggestion: How to fix
Section 4: Automated Check Summary (from ego-lint)
| Category | Pass | Fail | Warn |
|---|---|---|---|
| Metadata | N | N | N |
| Security | N | N | N |
| Lifecycle | N | N | N |
| Quality | N | N | N |
Section 5: AI Pattern Analysis
Score: N/46 triggered — [ADVISORY | BLOCKING] Triggered items: list with file:line Assessment: interpretation
Section 6: Submission Readiness
Ready to submit? [YES | NO] — N blocking issues remain
Action items (priority order):
- First thing to fix
- Second thing to fix
## Rejection-Risk Scoring Model
Calculate based on findings:
| Finding | Risk Points |
|---------|-------------|
| Each BLOCKING lifecycle issue | +3 |
| Each BLOCKING security issue | +4 |
| Each BLOCKING API hallucination | +5 (indicates AI) |
| AI slop score >= 3 | +5 |
| AI slop score >= 6 | +10 |
| Each ADVISORY issue | +1 |
| Justified advisory (with docs) | +0 |
**Verdict thresholds:**
- 0-2 points: **LIKELY APPROVED** — minor or no issues
- 3-6 points: **NEEDS REVISION** — fixable, resubmit after changes
- 7-12 points: **LIKELY REJECTED** — significant issues
- 13+ points: **LIKELY REJECTED** — fundamental problems or AI-generated
**Rough correspondence with ego-simulate scores:**
| ego-review risk | ego-simulate score | Interpretation |
|-----------------|-------------------|----------------|
| 0-2 | 0-4 | Likely to pass |
| 3-6 | 5-9 | May need revision |
| 7+ | 10+ | Likely rejected |
The scales use different inputs (ego-review: finding category points;
ego-simulate: taxonomy weights), so this mapping is approximate. When both
tools are run, prefer ego-review's assessment as the authoritative verdict.
## When to Use
- Before submitting to extensions.gnome.org
- After making significant changes to an extension
- When reviewing someone else's GNOME extension code
- As a learning tool for new extension developers