Skip to content

Commit 7d76ee5

Browse files
ZviBaratzclaude
andauthored
fix(ego-lint): skip R-LOG-03 in resources/ and detect Promise-returning methods in catch-on-sync (#145)
## Summary - **R-LOG-03**: Add `exclude-dirs: ["resources"]` — standalone GJS scripts in `resources/` use `print()` correctly (tiling-shell FP) - **async/catch-on-sync**: Detect Promise-returning method bodies via brace-counted body extraction — `.catch()` on methods returning `new Promise()` is valid (gsconnect FP) - **hara-hachi-bu**: Mark 2 stale `fp` annotations as `resolved` — superseded by exact-ID `tp` entries - **Annotations/baselines**: Reclassify all resolved FPs across extensions and update baselines **Result: 0 known FPs across all 10 field-tested extensions.** ## Test plan - [x] `bash tests/run-tests.sh` — 760 pass, 0 fail - [x] New `log-resources-skip@test` fixture: R-LOG-03 does not fire on `resources/tool.js` - [x] Updated `catch-on-sync@test`: `_loadData()` (returns `new Promise()`) not flagged, `_doWork()` (returns scalar) still flagged - [ ] CI passes Closes #144 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 99c5903 commit 7d76ee5

25 files changed

+150
-177
lines changed

field-tests/annotations/appindicator.yaml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ findings:
2525
notes: "45-50 exceeds max 4 allowed"
2626
# FAILs — False Positives
2727
- id: "R-SLOP-16::GLib.file_get_contents"
28-
classification: fp
29-
notes: "Rule claims API doesn't exist in GJS, but it does — valid GI binding for g_file_get_contents()"
28+
classification: resolved
29+
notes: "Rule claims API doesn't exist in GJS, but it does — valid GI binding for g_file_get_contents(). Superseded: rule message updated; reclassified as tp advisory for synchronous blocking."
3030
- id: "R-VER46-01::add_actor runtime-guarded"
31-
classification: fp
32-
notes: "Code has if (obj.add_actor) guard — runtime feature detection. Fixed: guard-pattern."
31+
classification: resolved
32+
notes: "Code has if (obj.add_actor) guard — runtime feature detection. Fixed: guard-pattern. Finding no longer emitted."
3333
- id: "R-VER46-02::remove_actor runtime-guarded"
34-
classification: fp
35-
notes: "Same runtime guard pattern as add_actor. Fixed: guard-pattern."
34+
classification: resolved
35+
notes: "Same runtime guard pattern as add_actor. Fixed: guard-pattern. Finding no longer emitted."
3636
- id: "init/shell-modification::non-Extension constructors"
37-
classification: fp
38-
notes: "3 FPs — GLib.Error, Gio.Cancellable in constructors of runtime-only classes. Fixed: scoped to extension.js."
37+
classification: resolved
38+
notes: "3 FPs — GLib.Error, Gio.Cancellable in constructors of runtime-only classes. Fixed: scoped to extension.js. Finding no longer emitted."
3939
# WARNs — True Positives
4040
- id: "R-SEC-06::run_dispose"
4141
classification: tp
@@ -69,23 +69,23 @@ findings:
6969
notes: "File I/O not disclosed in metadata"
7070
# WARNs — False Positives
7171
- id: "R-SLOP-13::this instanceof in factory"
72-
classification: fp
73-
notes: "3 FPs — methods in MenuItemFactory bound to different shellItem types via connectSmart. Fixed: guard-pattern."
72+
classification: resolved
73+
notes: "3 FPs — methods in MenuItemFactory bound to different shellItem types via connectSmart. Fixed: guard-pattern. Finding no longer emitted."
7474
- id: "R-SLOP-35::Object.freeze enum"
75-
classification: fp
76-
notes: "3 FPs — standard JS enum pattern (SNICategory, SNIStatus, SNIconType). Fixed: guard-pattern."
75+
classification: resolved
76+
notes: "3 FPs — standard JS enum pattern (SNICategory, SNIStatus, SNIconType). Fixed: guard-pattern. Finding no longer emitted."
7777
- id: "R-SLOP-38::domain-specific identifiers"
7878
classification: resolved
7979
notes: "4 FPs — brightnessContrastEffect and similar are standard Clutter API names. Fixed: threshold raised."
8080
- id: "R-QUAL-31::_onDestroy signal handler"
81-
classification: fp
82-
notes: "7 FPs — _onDestroy is PanelMenu.Button signal handler convention. Fixed: guard-pattern."
81+
classification: resolved
82+
notes: "7 FPs — _onDestroy is PanelMenu.Button signal handler convention. Fixed: guard-pattern. Superseded by borderline entry with 3 remaining instances."
8383
- id: "lifecycle/connectObject-migration::connectSmart equivalent"
84-
classification: fp
85-
notes: "6 FPs — connectSmart provides equivalent auto-cleanup. Fixed: recognized in check-lifecycle.py."
84+
classification: resolved
85+
notes: "6 FPs — connectSmart provides equivalent auto-cleanup. Fixed: recognized in check-lifecycle.py. Finding no longer emitted."
8686
- id: "lifecycle/signal-balance::connectSmart not counted"
87-
classification: fp
88-
notes: "66 connects vs 18 disconnects — doesn't account for connectSmart auto-disconnect. Fixed."
87+
classification: resolved
88+
notes: "66 connects vs 18 disconnects — doesn't account for connectSmart auto-disconnect. Fixed. Finding no longer emitted."
8989
# WARNs — Mixed
9090
- id: "quality/constructor-resources::runtime-only constructors"
9191
classification: borderline

field-tests/annotations/clipboard-indicator.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@
33
findings:
44
# FAILs — Fixed False Positives
55
- id: "R-WEB-01::setTimeout"
6-
classification: fp
7-
notes: "GJS added native setTimeout in GNOME 45. Rule was unconditionally blocking. Fixed: max-version 44."
6+
classification: resolved
7+
notes: "GJS added native setTimeout in GNOME 45. Rule was unconditionally blocking. Fixed: max-version 44. Now SKIP for 45+ extensions."
88
- id: "R-WEB-02::setInterval"
9-
classification: fp
10-
notes: "Same as R-WEB-01. Fixed: max-version 44."
9+
classification: resolved
10+
notes: "Same as R-WEB-01. Fixed: max-version 44. Now SKIP for 45+ extensions."
1111
- id: "R-WEB-10::clearTimeout"
12-
classification: fp
13-
notes: "Same as R-WEB-01. Fixed: max-version 44."
12+
classification: resolved
13+
notes: "Same as R-WEB-01. Fixed: max-version 44. Now SKIP for 45+ extensions."
1414
- id: "R-WEB-11::clearInterval"
15-
classification: fp
16-
notes: "Same as R-WEB-01. Fixed: max-version 44."
15+
classification: resolved
16+
notes: "Same as R-WEB-01. Fixed: max-version 44. Now SKIP for 45+ extensions."
1717
- id: "license::LICENSE.rst not recognized"
18-
classification: fp
19-
notes: "License check only recognized LICENSE/COPYING, not .rst/.md/.txt variants. Fixed."
18+
classification: resolved
19+
notes: "License check only recognized LICENSE/COPYING, not .rst/.md/.txt variants. Fixed. Finding no longer emitted."
2020
- id: "metadata/uuid-matches-dir::cloned repo"
21-
classification: fp
22-
notes: "FAIL for cloned repos where directory != UUID. Fixed: downgraded to WARN."
21+
classification: resolved
22+
notes: "FAIL for cloned repos where directory != UUID. Fixed: downgraded to WARN. Superseded by expected WARN entry."
2323
# FAILs — True Positives
2424
- id: "css/shell-class-override::.popup-menu-item"
2525
classification: tp

field-tests/annotations/dash-to-panel.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ findings:
2525
notes: "extension.js:55 — Main.sessionMode.hasOverview in Extension constructor"
2626
# FAILs — False Positives
2727
- id: "R-DEPR-06::Tweener in comments"
28-
classification: fp
29-
notes: "utils.js — pattern matches Tweener in comments about migration from Tweener to Clutter. 2 instances."
28+
classification: resolved
29+
notes: "utils.js — pattern matches Tweener in comments about migration from Tweener to Clutter. 2 instances. Fixed: skip-comments. Finding no longer emitted."
3030
- id: "R-DEPR-05::commented-out code"
31-
classification: fp
32-
notes: "prefs.js:151 — commented-out line of old ExtensionUtils code"
31+
classification: tp
32+
notes: "desktopIconsIntegration.js:60,68,69actual import * as ExtensionUtils statements (GNOME 45+ target), not comments. Reclassified: originally thought commented-out, but these are real deprecated imports."
3333
- id: "R-VER48-02::PACKAGE_VERSION guard not recognized"
3434
classification: resolved
3535
notes: "Guard pattern already matches Config.PACKAGE_VERSION — resolved by replacement-pattern (PR #84) + guard-window increase to 10. Reclassified #122."
3636
- id: "init/shell-modification::constructor in enable() chain"
37-
classification: fp
38-
notes: "4 FPs — taskbar.js signal handlers and desktopIconsIntegration.js constructor, all called from enable()"
37+
classification: tp
38+
notes: "taskbar.js:46 and extension.js:55 — real module-scope Shell access (const SearchController = Main.overview.searchController) and Extension constructor Shell access. Reclassified: PR #140 fixed constructor scoping but these are different findings (module-scope assignments, not enable() chain)."
3939
# WARNs — True Positives
4040
- id: "lifecycle/prototype-override::extensive prototype patching"
4141
classification: tp

field-tests/annotations/gsconnect.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ findings:
300300
classification: tp
301301
notes: "No cancellation mechanism in disable() — async operations may outlive extension lifecycle"
302302
- id: "async/catch-on-sync::.catch() on non-async GetMimetypes() — verify method returns a Promise"
303-
classification: fp
304-
notes: "GetMimetypes() returns a Promise via new Promise() wrapper — not async-declared but does return a Promise"
303+
classification: resolved
304+
notes: "GetMimetypes() returns a Promise via new Promise() wrapper — not async-declared but does return a Promise. Fixed: check-async.py now detects Promise-returning method bodies. Finding no longer emitted."
305305
- id: "resource-tracking/destroy-not-called::shell/tooltip.js — parent does not call cleanup method on shell/tooltip.js"
306306
classification: tp
307307
notes: "11 tooltip instances created without parent calling cleanup — potential resource leak"

field-tests/annotations/hara-hachi-bu.yaml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,32 @@
44
# All findings below were false positives that were subsequently fixed.
55
findings:
66
- id: "R-SEC-07::St.Clipboard match"
7-
classification: fp
8-
notes: "F-001: R-SEC-07 fired even when disclosure was present; quality/clipboard-disclosure is a strict superset. Rule removed."
7+
classification: resolved
8+
notes: "F-001: R-SEC-07 fired even when disclosure was present; quality/clipboard-disclosure is a strict superset. Rule removed. Finding no longer emitted."
99
- id: "quality/gettext-pattern::use this.gettext()"
10-
classification: fp
11-
notes: "F-003: Fix message inaccurate — this.gettext() can't be used at module scope. Updated message text."
10+
classification: resolved
11+
notes: "F-003: Fix message inaccurate — this.gettext() can't be used at module scope. Updated message text. Finding no longer emitted."
1212
- id: "R-SEC-20::pkexec per-file"
13-
classification: fp
14-
notes: "F-004: Matched pkexec in all JS/shell files including string literals and comments. Only 1 of 5 files actually invoked pkexec."
13+
classification: resolved
14+
notes: "F-004: Per-file matching reduced but still matches pkexec in string literals/comments. Superseded by exact-ID annotations (tp). Finding no longer a false positive."
1515
- id: "quality/private-api::WARN count inflation"
16-
classification: fp
17-
notes: "F-005: Each location emitted a separate WARN line (up to 6 for one check). Consolidated to single WARN."
16+
classification: resolved
17+
notes: "F-005: Consolidated to single WARN but still lists multiple locations in detail. Superseded by exact-ID annotations (tp). Finding no longer a false positive."
1818
- id: "quality/module-state::only recognizes null reset"
19-
classification: fp
20-
notes: "F-006: Variables reset to 0, false, Promise.resolve() were not recognized as cleanup."
19+
classification: resolved
20+
notes: "F-006: Variables reset to 0, false, Promise.resolve() were not recognized as cleanup. Fixed: non-null reset values now recognized. Finding no longer emitted."
2121
- id: "R-PREFS-04b::widgets with no Adwaita equivalent"
22-
classification: fp
23-
notes: "F-007: Gtk.ListBox with boxed-list CSS, Gtk.ScrolledWindow for constrained height have no Adw replacement."
22+
classification: resolved
23+
notes: "F-007: Gtk.ListBox with boxed-list CSS, Gtk.ScrolledWindow for constrained height have no Adw replacement. Fixed: R-PREFS-04b now only flags widgets with Adw equivalents. Finding no longer emitted."
2424
- id: "quality/gettext-pattern::lib modules"
25-
classification: fp
26-
notes: "F-008: GLib.dgettext() is correct for library modules that can't access Extension base class."
25+
classification: resolved
26+
notes: "F-008: GLib.dgettext() is correct for library modules that can't access Extension base class. Fixed: gettext check now recognizes GLib.dgettext. Finding no longer emitted."
2727
- id: "quality/logging-volume::fixed threshold"
28-
classification: fp
29-
notes: "F-009: Fixed count threshold didn't scale with code size. ~1 log per 84 lines is reasonable density."
28+
classification: resolved
29+
notes: "F-009: Fixed count threshold didn't scale with code size. ~1 log per 84 lines is reasonable density. Fixed: density-based threshold. Finding no longer emitted."
3030
- id: "async/missing-cancellable::callback cancellation"
31-
classification: fp
32-
notes: "F-010: Check didn't recognize functions with isCancelled callback parameters providing equivalent cancellation."
31+
classification: resolved
32+
notes: "F-010: Check didn't recognize functions with isCancelled callback parameters providing equivalent cancellation. Fixed: callback cancellation pattern recognized. Finding no longer emitted."
3333
# Current remaining WARNs (all correct/expected)
3434
- id: "polkit-files::2 polkit files present"
3535
classification: tp

field-tests/annotations/tiling-shell.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ findings:
8989
classification: borderline
9090
notes: "manage_pr.sh is a dev tool, not part of extension runtime"
9191
- id: "R-LOG-03::print()/printerr() should not be used in production; use console.debug()"
92-
classification: fp
93-
notes: "monitorDescription.js is a standalone GJS script — print() is correct for stdout output"
92+
classification: resolved
93+
notes: "monitorDescription.js is a standalone GJS script in resources/ — print() is correct for stdout output. Fixed: R-LOG-03 now has exclude-dirs: [resources]. Finding no longer emitted."
9494
- id: "R-SLOP-03::version field is deprecated; EGO manages versions for GNOME 45+"
9595
classification: tp
9696
notes: "Version field in resources/metadata.json — standard advisory"

field-tests/annotations/v-shell.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33
findings:
44
# All 23 FAILs classified as FP — runtime-guarded version compat
55
- id: "R-VER44-02::Meta.later_remove runtime-guarded"
6-
classification: fp
7-
notes: "if (global.compositor) { ... } else { Meta.later_remove() } — old API only reached on GNOME <48"
6+
classification: resolved
7+
notes: "if (global.compositor) { ... } else { Meta.later_remove() } — old API only reached on GNOME <48. Fixed: guard-pattern + compat-downgrade. Finding no longer emitted."
88
- id: "R-VER46-07::Clutter.Container feature-flag"
9-
classification: fp
10-
notes: "const shellVersion46 = !Clutter.Container — used as boolean, not API call. 2 instances."
9+
classification: resolved
10+
notes: "const shellVersion46 = !Clutter.Container — used as boolean, not API call. 2 instances. Fixed: guard-pattern. Finding no longer emitted."
1111
- id: "R-VER48-02::Meta.disable_unredirect runtime-guarded"
12-
classification: fp
13-
notes: "if (Meta.disable_unredirect_for_display) ... else global.compositor — version-compat branch. 2 instances."
12+
classification: resolved
13+
notes: "if (Meta.disable_unredirect_for_display) ... else global.compositor — version-compat branch. 2 instances. Fixed: guard-pattern + replacement-pattern. Finding no longer emitted."
1414
- id: "R-VER49-02::Clutter.ClickAction runtime-guarded"
15-
classification: fp
16-
notes: "All 13 use Clutter.ClickAction || Clutter.ClickGesture fallback or if (Clutter.ClickAction) guards"
15+
classification: resolved
16+
notes: "All 13 use Clutter.ClickAction || Clutter.ClickGesture fallback or if (Clutter.ClickAction) guards. Fixed: guard-pattern. Finding no longer emitted."
1717
- id: "init/shell-modification::constructor called from enable"
18-
classification: fp
19-
notes: "3 FPs in overviewBackground.js, appDisplay.js — constructors called from _initModules() inside enable()"
18+
classification: resolved
19+
notes: "3 FPs in overviewBackground.js, appDisplay.js — constructors called from _initModules() inside enable(). Fixed: scoped to Extension class constructors (PR #140). Finding no longer emitted."
2020
# Key WARNs — True Positives
2121
- id: "quality/constructor-resources::connect in GObject constructors"
2222
classification: tp
@@ -198,8 +198,8 @@ findings:
198198
notes: "File I/O capability not disclosed in metadata description"
199199
# WARN findings — False Positives
200200
- id: "R-SLOP-13::this instanceof check inside a class method is always true"
201-
classification: fp
202-
notes: "2 hits — instanceof AppDisplay.FolderView in prototype-override method shared between subclasses; NOT always true"
201+
classification: resolved
202+
notes: "2 hits — instanceof AppDisplay.FolderView in prototype-override method shared between subclasses; NOT always true. Fixed: guard-pattern. Finding no longer emitted."
203203
# WARN findings — Borderline
204204
- id: "R-SLOP-38::Over-long identifier (>25 chars) is an AI verbosity indicator"
205205
classification: resolved

field-tests/baselines/appindicator.json

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"name": "appindicator",
33
"uuid": "appindicatorsupport@rgcjonas.gmail.com",
4-
"timestamp": "2026-03-10T22:10:59.527492+00:00",
5-
"ego_lint_version": "a441201",
4+
"timestamp": "2026-03-12T10:58:10.872002+00:00",
5+
"ego_lint_version": "1a58b06",
66
"ego_approved": true,
77
"exit_code": 1,
88
"counts": {
99
"pass": 189,
1010
"fail": 6,
11-
"warn": 60,
11+
"warn": 59,
1212
"skip": 14,
13-
"total": 269
13+
"total": 268
1414
},
1515
"metrics": {
1616
"js_files": 17,
@@ -170,13 +170,6 @@
170170
"detail": "statusNotifierWatcher.js:281: GObject.run_dispose() should not be used unless absolutely necessary",
171171
"fix": "Remove run_dispose() call. If genuinely needed, add a comment explaining why."
172172
},
173-
{
174-
"id": "R-LOG-03::print()/printerr() should not be used in production; use console.debug()",
175-
"status": "WARN",
176-
"check": "R-LOG-03",
177-
"detail": "appIndicator.js:1231: print()/printerr() should not be used in production; use console.debug()",
178-
"fix": "Replace print()/printerr() with console.debug() or console.error()."
179-
},
180173
{
181174
"id": "R-LOG-03::indicator-test-tool/testTool.js: print()/printerr() should not be used in production; use console.debug()",
182175
"status": "WARN",

field-tests/baselines/clipboard-indicator.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "clipboard-indicator",
33
"uuid": "clipboard-indicator@tudmotu.com",
4-
"timestamp": "2026-03-10T22:11:00.787905+00:00",
5-
"ego_lint_version": "a441201",
4+
"timestamp": "2026-03-12T10:58:11.682237+00:00",
5+
"ego_lint_version": "1a58b06",
66
"ego_approved": true,
77
"exit_code": 1,
88
"counts": {

field-tests/baselines/dash-to-panel.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "dash-to-panel",
33
"uuid": "dash-to-panel@jderose9.github.com",
4-
"timestamp": "2026-03-10T22:11:05.093467+00:00",
5-
"ego_lint_version": "a441201",
4+
"timestamp": "2026-03-12T10:58:14.418773+00:00",
5+
"ego_lint_version": "1a58b06",
66
"ego_approved": true,
77
"exit_code": 1,
88
"counts": {

0 commit comments

Comments
 (0)