Skip to content

Commit e36f4ad

Browse files
ZviBaratzclaude
andcommitted
feat: add initial baselines and fix --json stdout
Generate golden baselines for all 10 field test extensions. Fix --json flag to redirect progress output to stderr so stdout contains only clean JSON. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0dbe7e8 commit e36f4ad

File tree

12 files changed

+4916
-1
lines changed

12 files changed

+4916
-1
lines changed

field-tests/baselines/appindicator.json

Lines changed: 550 additions & 0 deletions
Large diffs are not rendered by default.

field-tests/baselines/blur-my-shell.json

Lines changed: 415 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
{
2+
"name": "clipboard-indicator",
3+
"uuid": "clipboard-indicator@tudmotu.com",
4+
"timestamp": "2026-03-04T22:16:56.118064+00:00",
5+
"ego_lint_version": "0dbe7e8",
6+
"ego_approved": true,
7+
"exit_code": 1,
8+
"counts": {
9+
"pass": 192,
10+
"fail": 2,
11+
"warn": 24,
12+
"skip": 17,
13+
"total": 235
14+
},
15+
"metrics": {
16+
"js_files": 6,
17+
"total_lines": 2486,
18+
"largest_file": "extension.js (1430)",
19+
"css_lines": 75,
20+
"schema_keys": 31
21+
},
22+
"provenance_score": null,
23+
"findings": [
24+
{
25+
"id": "polkit/action-id-match::No polkit files found",
26+
"status": "SKIP",
27+
"check": "polkit/action-id-match",
28+
"detail": "No polkit files found"
29+
},
30+
{
31+
"id": "polkit/action-id-prefix::No polkit files found",
32+
"status": "SKIP",
33+
"check": "polkit/action-id-prefix",
34+
"detail": "No polkit files found"
35+
},
36+
{
37+
"id": "polkit/helper-exists::No polkit files found",
38+
"status": "SKIP",
39+
"check": "polkit/helper-exists",
40+
"detail": "No polkit files found"
41+
},
42+
{
43+
"id": "css/important::Found 1 !important usage(s) in stylesheet.css \u2014 !important overrides Shell theme; prefer higher specificity",
44+
"status": "WARN",
45+
"check": "css/important",
46+
"detail": "Found 1 !important usage(s) in stylesheet.css \u2014 !important overrides Shell theme; prefer higher specificity"
47+
},
48+
{
49+
"id": "css/shell-class-override::.popup-menu-item: overrides GNOME Shell theme class \u2014 use a scoped selector (.my-extension .popup-menu-item)",
50+
"status": "FAIL",
51+
"check": "css/shell-class-override",
52+
"detail": ".popup-menu-item: overrides GNOME Shell theme class \u2014 use a scoped selector (.my-extension .popup-menu-item)"
53+
},
54+
{
55+
"id": "accessibility/accessible-name::2 icon-only St.Button(s) without accessible_name: extension.js, extension.js",
56+
"status": "WARN",
57+
"check": "accessibility/accessible-name",
58+
"detail": "2 icon-only St.Button(s) without accessible_name: extension.js:289, extension.js:552"
59+
},
60+
{
61+
"id": "R-WEB-01::Not applicable for declared shell-version(s)",
62+
"status": "SKIP",
63+
"check": "R-WEB-01",
64+
"detail": "Not applicable for declared shell-version(s)"
65+
},
66+
{
67+
"id": "R-WEB-02::Not applicable for declared shell-version(s)",
68+
"status": "SKIP",
69+
"check": "R-WEB-02",
70+
"detail": "Not applicable for declared shell-version(s)"
71+
},
72+
{
73+
"id": "R-WEB-10::Not applicable for declared shell-version(s)",
74+
"status": "SKIP",
75+
"check": "R-WEB-10",
76+
"detail": "Not applicable for declared shell-version(s)"
77+
},
78+
{
79+
"id": "R-WEB-11::Not applicable for declared shell-version(s)",
80+
"status": "SKIP",
81+
"check": "R-WEB-11",
82+
"detail": "Not applicable for declared shell-version(s)"
83+
},
84+
{
85+
"id": "R-DEPR-04-legacy::Not applicable for declared shell-version(s)",
86+
"status": "SKIP",
87+
"check": "R-DEPR-04-legacy",
88+
"detail": "Not applicable for declared shell-version(s)"
89+
},
90+
{
91+
"id": "R-DEPR-09::Use const/let instead of var; var has function scope and causes bugs in closures",
92+
"status": "WARN",
93+
"check": "R-DEPR-09",
94+
"detail": "extension.js:654: Use const/let instead of var; var has function scope and causes bugs in closures",
95+
"fix": "Replace var with const (preferred) or let (when reassignment needed)."
96+
},
97+
{
98+
"id": "R-DEPR-09::Use const/let instead of var; var has function scope and causes bugs in closures",
99+
"status": "WARN",
100+
"check": "R-DEPR-09",
101+
"detail": "extension.js:1142: Use const/let instead of var; var has function scope and causes bugs in closures",
102+
"fix": "Replace var with const (preferred) or let (when reassignment needed)."
103+
},
104+
{
105+
"id": "R-DEPR-09::Use const/let instead of var; var has function scope and causes bugs in closures",
106+
"status": "WARN",
107+
"check": "R-DEPR-09",
108+
"detail": "extension.js:1189: Use const/let instead of var; var has function scope and causes bugs in closures",
109+
"fix": "Replace var with const (preferred) or let (when reassignment needed)."
110+
},
111+
{
112+
"id": "R-DEPR-11::Shell.KeyBindingMode was removed before GNOME 40; use Shell.ActionMode",
113+
"status": "FAIL",
114+
"check": "R-DEPR-11",
115+
"detail": "extension.js:1190: Shell.KeyBindingMode was removed before GNOME 40; use Shell.ActionMode",
116+
"fix": "Replace Shell.KeyBindingMode with Shell.ActionMode"
117+
},
118+
{
119+
"id": "R-SEC-06::GObject.run_dispose() should not be used unless absolutely necessary",
120+
"status": "WARN",
121+
"check": "R-SEC-06",
122+
"detail": "keyboard.js:19: GObject.run_dispose() should not be used unless absolutely necessary",
123+
"fix": "Remove run_dispose() call. If genuinely needed, add a comment explaining why."
124+
},
125+
{
126+
"id": "R-PREFS-04c::GTK layout widget in prefs.js \u2014 verify no Adw equivalent for this specific use case",
127+
"status": "WARN",
128+
"check": "R-PREFS-04c",
129+
"detail": "GTK layout widget in prefs.js \u2014 verify no Adw equivalent for this specific use case in 1 file(s): prefs.js",
130+
"fix": "Gtk.ListBox with boxed-list CSS is valid for dynamic lists. Gtk.ScrolledWindow is valid for constrained-height content. Gtk.Grid/Stack may have Adw equivalents depending on usage."
131+
},
132+
{
133+
"id": "R-SLOP-40::new Promise(resolve, reject) wrapper \u2014 consider Gio._promisify() for GIO async methods",
134+
"status": "WARN",
135+
"check": "R-SLOP-40",
136+
"detail": "registry.js:250: new Promise(resolve, reject) wrapper \u2014 consider Gio._promisify() for GIO async methods",
137+
"fix": "Use Gio._promisify() to promisify GIO async methods instead of manual Promise wrapping"
138+
},
139+
{
140+
"id": "R-QUAL-34::enumerate_children() is synchronous \u2014 use enumerate_children_async() to avoid blocking the Shell main loop",
141+
"status": "WARN",
142+
"check": "R-QUAL-34",
143+
"detail": "registry.js:194: enumerate_children() is synchronous \u2014 use enumerate_children_async() to avoid blocking the Shell main loop",
144+
"fix": "Use file.enumerate_children_async(attributes, flags, priority, cancellable, callback)"
145+
},
146+
{
147+
"id": "R-LIFE-19::global.stage.add_child() \u2014 ensure matching remove_child() in disable()/destroy()",
148+
"status": "WARN",
149+
"check": "R-LIFE-19",
150+
"detail": "extension.js:1061: global.stage.add_child() \u2014 ensure matching remove_child() in disable()/destroy()",
151+
"fix": "In disable(), call global.stage.remove_child(this._actor); this._actor = null;"
152+
},
153+
{
154+
"id": "R-VER48-04b::vertical property in constructor config deprecated in GNOME 48; use orientation: Clutter.Orientation.VERTICAL (available since GNOME 47; keep vertical for GNOME <=46 compat)",
155+
"status": "WARN",
156+
"check": "R-VER48-04b",
157+
"detail": "vertical property in constructor config deprecated in GNOME 48; use orientation: Clutter.Orientation.VERTICAL (available since GNOME 47; keep vertical for GNOME <=46 compat) in 2 file(s): confirmDialog.js, extension.js"
158+
},
159+
{
160+
"id": "R-VER50-01::Not applicable for declared shell-version(s)",
161+
"status": "SKIP",
162+
"check": "R-VER50-01",
163+
"detail": "Not applicable for declared shell-version(s)"
164+
},
165+
{
166+
"id": "R-VER50-02::Not applicable for declared shell-version(s)",
167+
"status": "SKIP",
168+
"check": "R-VER50-02",
169+
"detail": "Not applicable for declared shell-version(s)"
170+
},
171+
{
172+
"id": "R-VER50-03::Not applicable for declared shell-version(s)",
173+
"status": "SKIP",
174+
"check": "R-VER50-03",
175+
"detail": "Not applicable for declared shell-version(s)"
176+
},
177+
{
178+
"id": "R-VER50-04::Not applicable for declared shell-version(s)",
179+
"status": "SKIP",
180+
"check": "R-VER50-04",
181+
"detail": "Not applicable for declared shell-version(s)"
182+
},
183+
{
184+
"id": "R-VER50-05::Not applicable for declared shell-version(s)",
185+
"status": "SKIP",
186+
"check": "R-VER50-05",
187+
"detail": "Not applicable for declared shell-version(s)"
188+
},
189+
{
190+
"id": "eslint::No eslint.config.mjs or node_modules/.bin/eslint found",
191+
"status": "SKIP",
192+
"check": "eslint",
193+
"detail": "No eslint.config.mjs or node_modules/.bin/eslint found"
194+
},
195+
{
196+
"id": "metadata/uuid-matches-dir::UUID 'clipboard-indicator@tudmotu.com' does not match directory 'clipboard-indicator' \u2014 must match when installed",
197+
"status": "WARN",
198+
"check": "metadata/uuid-matches-dir",
199+
"detail": "UUID 'clipboard-indicator@tudmotu.com' does not match directory 'clipboard-indicator' \u2014 must match when installed"
200+
},
201+
{
202+
"id": "schema-usage/unused-key::Dynamic key access detected \u2014 cannot verify statically",
203+
"status": "SKIP",
204+
"check": "schema-usage/unused-key",
205+
"detail": "Dynamic key access detected \u2014 cannot verify statically"
206+
},
207+
{
208+
"id": "schema-usage/undefined-key::Dynamic key access detected \u2014 cannot verify statically",
209+
"status": "SKIP",
210+
"check": "schema-usage/undefined-key",
211+
"detail": "Dynamic key access detected \u2014 cannot verify statically"
212+
},
213+
{
214+
"id": "quality/module-state::Module-level mutable state at extension.js, extension.js, extension.js, extension.js, extension.js \u2014 ensure reset in both enable() and disable()",
215+
"status": "WARN",
216+
"check": "quality/module-state",
217+
"detail": "Module-level mutable state at extension.js:23, extension.js:24, extension.js:25, extension.js:34, extension.js:35 \u2014 ensure reset in both enable() and disable()"
218+
},
219+
{
220+
"id": "quality/private-api::Main.panel private API access \u2014 requires reviewer justification and version pinning",
221+
"status": "WARN",
222+
"check": "quality/private-api",
223+
"detail": "extension.js:1024, extension.js:1024: Main.panel private API access \u2014 requires reviewer justification and version pinning"
224+
},
225+
{
226+
"id": "quality/run-dispose-no-comment::run_dispose() without explanatory comment \u2014 reviewers require justification",
227+
"status": "WARN",
228+
"check": "quality/run-dispose-no-comment",
229+
"detail": "keyboard.js:19: run_dispose() without explanatory comment \u2014 reviewers require justification"
230+
},
231+
{
232+
"id": "lifecycle/async-destroyed-guard::async/await used without _destroyed or _isDestroyed guard \u2014 extension may act on stale state after disable()",
233+
"status": "WARN",
234+
"check": "lifecycle/async-destroyed-guard",
235+
"detail": "async/await used without _destroyed or _isDestroyed guard \u2014 extension may act on stale state after disable()"
236+
},
237+
{
238+
"id": "lifecycle/clipboard-keybinding::St.Clipboard and addKeybinding() in same file \u2014 review whether keybinding-triggered clipboard access is intended and not a keylogger pattern",
239+
"status": "WARN",
240+
"check": "lifecycle/clipboard-keybinding",
241+
"detail": "extension.js: St.Clipboard and addKeybinding() in same file \u2014 review whether keybinding-triggered clipboard access is intended and not a keylogger pattern"
242+
},
243+
{
244+
"id": "lifecycle/timeout-reassignment::timeout/idle ID reassigned without prior GLib.Source.remove() \u2014 may leak GLib sources",
245+
"status": "WARN",
246+
"check": "lifecycle/timeout-reassignment",
247+
"detail": "extension.js:880: timeout/idle ID reassigned without prior GLib.Source.remove() \u2014 may leak GLib sources"
248+
},
249+
{
250+
"id": "gobject/missing-gtypename::GObject.registerClass without GTypeName \u2014 add GTypeName to avoid conflicts between extensions",
251+
"status": "WARN",
252+
"check": "gobject/missing-gtypename",
253+
"detail": "confirmDialog.js:22: GObject.registerClass without GTypeName \u2014 add GTypeName to avoid conflicts between extensions"
254+
},
255+
{
256+
"id": "async/no-cancellable::Gio async calls at registry.js, registry.js, registry.js without Gio.Cancellable \u2014 async operations should be cancellable via disable()",
257+
"status": "WARN",
258+
"check": "async/no-cancellable",
259+
"detail": "Gio async calls at registry.js:87, registry.js:250, registry.js:58 without Gio.Cancellable \u2014 async operations should be cancellable via disable()"
260+
},
261+
{
262+
"id": "async/missing-cancellable::_async() calls without Gio.Cancellable at registry.js, registry.js, registry.js (+6 more) \u2014 async operations may run after disable()",
263+
"status": "WARN",
264+
"check": "async/missing-cancellable",
265+
"detail": "_async() calls without Gio.Cancellable at registry.js:53, registry.js:58, registry.js:73 (+6 more) \u2014 async operations may run after disable()"
266+
},
267+
{
268+
"id": "async/disable-no-cancel::Extension uses async but disable() has no .cancel(), .abort(), or _destroyed flag \u2014 async operations may outlive disable()",
269+
"status": "WARN",
270+
"check": "async/disable-no-cancel",
271+
"detail": "Extension uses async but disable() has no .cancel(), .abort(), or _destroyed flag \u2014 async operations may outlive disable()"
272+
},
273+
{
274+
"id": "resource-tracking/no-destroy-method::registry.js \u2014 no cleanup method (destroy/disable/onDestroy) in registry.js",
275+
"status": "WARN",
276+
"check": "resource-tracking/no-destroy-method",
277+
"detail": "registry.js:148 \u2014 no cleanup method (destroy/disable/onDestroy) in registry.js"
278+
},
279+
{
280+
"id": "resource-tracking/ownership::5 files scanned, depth 2, 1 orphan detected",
281+
"status": "WARN",
282+
"check": "resource-tracking/ownership",
283+
"detail": "5 files scanned, depth 2, 1 orphan detected"
284+
},
285+
{
286+
"id": "package/exists::No zip package found in extension directory",
287+
"status": "SKIP",
288+
"check": "package/exists",
289+
"detail": "No zip package found in extension directory"
290+
}
291+
]
292+
}

0 commit comments

Comments
 (0)