Skip to content

fix(ego-lint): skip signal callback bodies in constructor init check#129

Merged
ZviBaratz merged 1 commit intomainfrom
fix/init-signal-callback-fp
Mar 10, 2026
Merged

fix(ego-lint): skip signal callback bodies in constructor init check#129
ZviBaratz merged 1 commit intomainfrom
fix/init-signal-callback-fp

Conversation

@ZviBaratz
Copy link
Copy Markdown
Owner

Summary

  • Add filter_signal_callbacks() to check-init.py that excludes signal callback body lines (.connect(), .connectObject()) from the constructor init-time check, while still checking the .connect() line itself (the receiver may be a Shell global accessed at construction time)
  • Add test fixture init-constructor-signal@test with both .connect() and .connectObject() callbacks containing Shell globals, plus a direct Shell global access that should still be flagged
  • Mark tiling-shell annotation for constructor signal callback FP as fixed

Context

Issue #118 identified 8 FPs for init/shell-modification across tiling-shell and v-shell. Research showed that 6 of 8 were already resolved by prior PRs (#21 scoped constructor checks to extension.js, #88 added arrow fn exemption). The remaining 2 (tiling-shell globalState.js constructor signal callbacks) are addressed by this PR.

Signal callbacks are deferred — they don't execute during construction, only when the signal fires at runtime. The .connect() line itself is kept because the receiver object (e.g., Main.panel.connect(...)) IS accessed immediately during construction.

Test plan

  • New fixture init-constructor-signal@test verifies:
    • Direct Shell global in constructor is flagged (line 10)
    • .connect() callback body is NOT flagged (lines 15-17)
    • .connectObject() callback body is NOT flagged (lines 21-24)
  • All 653 existing test assertions pass (0 regressions)
  • Existing init fixtures unchanged: init-time-safety, init-helper-constructor, init-modification, constructor-gobject

Closes #118

🤖 Generated with Claude Code

Signal callbacks (.connect(), .connectObject()) inside constructors are
deferred — they don't execute during construction, so Shell globals
inside them are not init-time violations. Add filter_signal_callbacks()
to exclude callback body lines while still checking the .connect() line
itself (the receiver may be a Shell global accessed at construction
time).

Closes #118

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ZviBaratz ZviBaratz self-assigned this Mar 10, 2026
Copy link
Copy Markdown
Owner Author

@ZviBaratz ZviBaratz left a comment

Choose a reason for hiding this comment

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

Review: Approve

Clean, well-scoped fix. The semantic reasoning is correct — signal callbacks are deferred, not executed at construction time — and the implementation is consistent with existing brace-depth tracking patterns in the file.

What's good:

  • filter_signal_callbacks() correctly keeps the .connect() line (receiver IS evaluated at construction time) while filtering callback body lines
  • Test fixture covers both .connect() and .connectObject(), plus a direct Shell global access that should still be flagged
  • No regressions — existing init fixtures unaffected

Minor observations (non-blocking):

  1. Multi-line .connectObject() with callback on next line — if the call is split so the () => { starts on a different line than .connectObject(, the brace count on the .connect() line is 0, so callback_depth stays 0 and the callback body won't be filtered. Conservative behavior (flags when uncertain), which is the right default
  2. Single-line inline callbacksthis.connect('notify', () => Main.panel.x) keeps the whole line, so Main.panel gets flagged even though it's deferred. Unlikely in practice inside constructors
  3. .connect_after() not matched by the regex — very rare, fine to address if/when it causes a real FP

@ZviBaratz ZviBaratz merged commit d1fa661 into main Mar 10, 2026
3 checks passed
@ZviBaratz ZviBaratz deleted the fix/init-signal-callback-fp branch March 10, 2026 19:33
ZviBaratz added a commit that referenced this pull request Mar 11, 2026
…es (#131)

## Summary

- Re-ran field tests after merging PRs #123, #126, #127, #128, #129,
#130 which addressed ~22 false positives across 7 rules
- Updated all 10 baselines to current ego-lint output (`a441201`)
- Reclassified 92 findings as `resolved` (no longer emitted)
- Annotated 9 new findings across 5 extensions
- Updated README with refreshed metrics

### Results comparison

| Metric | Before (03-08) | After (03-10) | Change |
|--------|----------------|---------------|--------|
| PASS | 1,849 | 1,917 | +68 |
| FAIL | 47 | 30 | -17 |
| WARN | 467 | 461 | -6 |
| SKIP | 202 | 167 | -35 |
| Strict precision | 81.5% | 85.1% | +3.6pp |
| Lenient precision | 83.3% | 86.7% | +3.4pp |
| Active FPs | 80 | 58 | -22 |
| Resolved | 9 | 92 | +83 |

## Test plan

- [x] All 734 tests pass
- [x] Zero unannotated findings across all 10 extensions
- [x] 100% annotation coverage maintained

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
ZviBaratz pushed a commit that referenced this pull request Mar 25, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.1.1](v0.1.0...v0.1.1)
(2026-03-25)


### Features

* add automated field test pipeline
([#34](#34))
([6d906d6](6d906d6))
* add parse-review-results.py for structured finding extraction
([#56](#56))
([2083bc7](2083bc7))
* **ego-lint:** add --show and --report flags for output filtering
([#111](#111))
([5fc5a6e](5fc5a6e))
* **ego-lint:** add .destroy without parentheses detection (R-LIFE-23)
([#50](#50))
([f9c035b](f9c035b))
* **ego-lint:** add compat-downgrade for version-aware deprecated API
gating
([#104](#104))
([3e00e6e](3e00e6e))
* **ego-lint:** add D-Bus connectSignal leak detection (R-LIFE-25)
([#59](#59))
([c54d848](c54d848))
* **ego-lint:** add lifecycle leak detection (R-LIFE-21, R-LIFE-22,
R-LIFE-24)
([#48](#48))
([10f6bbd](10f6bbd))
* **ego-lint:** add module-scope mutable state detection (R-LIFE-26)
([#60](#60))
([9c5d2e3](9c5d2e3))
* **ego-lint:** add module-scope prototype mutation detection
(R-LIFE-27)
([#83](#83))
([0d2df8d](0d2df8d))
* **ego-lint:** add notification urgency abuse detection (R-QUAL-36)
([#49](#49))
([546bd10](546bd10))
* **ego-lint:** detect indirect prototype mutation via function calls
([#114](#114))
([bce145b](bce145b))
* **ego-review:** eliminate redundant work by referencing ego-lint
findings
([787261a](787261a))


### Bug Fixes

* **ego-field-test:** fix IFS collapse and commit-hash fetch failures
([f4b480f](f4b480f))
* **ego-field-test:** indent multi-line expressions in json_extract
wrapper
([ae650be](ae650be))
* **ego-field-test:** resolve imports/no-gtk-in-extension false
positives
([#128](#128))
([8e39d98](8e39d98))
* **ego-lint:** add missing CSS shell classes to KNOWN_SHELL_CLASSES
([#54](#54))
([c6c61be](c6c61be))
* **ego-lint:** add replacement-pattern to R-VER rules for
version-compat suppression
([#84](#84))
([d7051cf](d7051cf))
* **ego-lint:** add skip-comments to R-LOG-03 to prevent block comment
FPs
([#132](#132))
([f138a43](f138a43))
* **ego-lint:** add src/ layout license fallback and UUID-dir skip
([#30](#30))
([9f616ec](9f616ec))
* **ego-lint:** add src/ metadata.json fallback for build-system
extensions
([#24](#24))
([145b639](145b639))
* **ego-lint:** add src/schemas/ fallback for non-standard layouts
([#80](#80))
([4d00563](4d00563))
* **ego-lint:** add version-compat suppression and calibrate severities
([#69](#69))
([5442f13](5442f13))
* **ego-lint:** anchor Gdk import pattern to avoid matching GdkPixbuf
([#101](#101))
([0e07043](0e07043))
* **ego-lint:** auto-detect and exclude vendored files from all lint
checks
([#152](#152))
([81d48cd](81d48cd))
* **ego-lint:** avoid false FAIL when enum-id precedes schema-id in
check-schema
([#148](#148))
([8399589](8399589))
* **ego-lint:** correct R-SLOP-01 provenance post-filter matching
([#85](#85))
([ff05efb](ff05efb))
* **ego-lint:** deduplicate prototype-override warnings
([#32](#32))
([431ad18](431ad18))
* **ego-lint:** detect compiled TypeScript and suppress noisy rules
([#52](#52))
([1b1b5d4](1b1b5d4))
* **ego-lint:** downgrade css/shell-class-override from FAIL to WARN
([#100](#100))
([4aa6f2f](4aa6f2f))
* **ego-lint:** downgrade css/shell-class-override from FAIL to WARN
([#112](#112))
([dc83726](dc83726))
* **ego-lint:** downgrade missing LICENSE from FAIL to WARN
([#110](#110))
([fe0eab7](fe0eab7))
* **ego-lint:** enhance GSettings signal leak detection for helper
classes
([#87](#87))
([21f7390](21f7390))
* **ego-lint:** exclude preferences/ dirs from gsettings-signal-leak
([#102](#102))
([60b15d3](60b15d3))
* **ego-lint:** exclude service/ daemon code from extension-specific
checks
([#147](#147))
([2962779](2962779))
* **ego-lint:** exclude service/ dir from R-DEPR-06 and R-DEPR-10
([#99](#99))
([ed40e47](ed40e47))
* **ego-lint:** exempt isLocked guard from impossible-state and
session-modes checks
([#31](#31))
([69c6254](69c6254))
* **ego-lint:** expand CSS shell-class list from GNOME Shell SCSS source
([#57](#57))
([311da35](311da35))
* **ego-lint:** expand init/shell-modification and constructor-resources
exemptions
([#88](#88))
([14d0ca3](14d0ca3))
* **ego-lint:** expand R-SLOP-24 guard for system schema identifiers
([#139](#139))
([1a58b06](1a58b06))
* **ego-lint:** expand R-SLOP-24 guard for system schemas and multi-line
constructors
([#135](#135))
([27787a6](27787a6))
* **ego-lint:** expand R-SLOP-38 guard for domain-specific identifiers
([#141](#141))
([4aaf615](4aaf615))
* **ego-lint:** handle async arrow functions and GObject branch in
check-init.py
([#55](#55))
([9d6654a](9d6654a))
* **ego-lint:** make R-LIFE-25 bare connectSignal always FAIL regardless
of disconnectSignal elsewhere
([#91](#91))
([05523f9](05523f9))
* **ego-lint:** narrow R-LIFE-25 auto-cleanup to D-Bus-specific
disconnectSignal
([#65](#65))
([8263cbc](8263cbc))
* **ego-lint:** propagate strip_comments newline preservation to all
scripts
([#61](#61))
([4178a5a](4178a5a))
* **ego-lint:** recognize alternative cleanup methods in resource
tracking
([#130](#130))
([bbc0f51](bbc0f51))
* **ego-lint:** recognize array-based signal ID storage in
gsettings-signal-leak
([#64](#64))
([99c89c0](99c89c0))
* **ego-lint:** recognize full GPL license text in license check
([#127](#127))
([38cbb59](38cbb59))
* **ego-lint:** reduce false positives for R-SLOP-35, R-SEC-03,
R-SLOP-13
([#123](#123))
([860fc0b](860fc0b))
* **ego-lint:** reduce init-time safety false positives
([#21](#21))
([e46e2df](e46e2df))
* **ego-lint:** reduce Media Controls false positives
([#23](#23))
([7cea626](7cea626))
* **ego-lint:** reduce resource-tracking FPs for blur-my-shell
([#143](#143))
([99c5903](99c5903))
* **ego-lint:** reduce resource-tracking/no-destroy-method false
positives
([#86](#86))
([30bbeac](30bbeac))
* **ego-lint:** reduce signal-balance false positives
([#13](#13))
([900b133](900b133))
* **ego-lint:** reduce Tiling Shell false positives
([#22](#22))
([62c5509](62c5509))
* **ego-lint:** remove Shell.ActionMode.ALL from hallucinated-API list
([#149](#149))
([715519f](715519f))
* **ego-lint:** scope init/shell-modification to Extension class
constructors
([#140](#140))
([5e86aa6](5e86aa6))
* **ego-lint:** skip file-structure checks for compiled TypeScript
extensions
([#103](#103))
([f15ddcb](f15ddcb))
* **ego-lint:** skip JSDoc block comments in R-WEB-06 document.* check
([#150](#150))
([fc10806](fc10806))
* **ego-lint:** skip R-LOG-03 in resources/ and detect Promise-returning
methods in catch-on-sync
([#145](#145))
([7d76ee5](7d76ee5))
* **ego-lint:** skip signal callback bodies in constructor init check
([#129](#129))
([d1fa661](d1fa661))
* **ego-lint:** split R-SLOP-11 to fix false positive on
GLib.source_remove()
([#126](#126))
([a441201](a441201))
* **ego-lint:** suppress R-QUAL-28 for distinct getSettings() schema
arguments
([#81](#81))
([f8e1da7](f8e1da7))
* **ego-lint:** suppress R-VER46-01/02 for ShellVersion-guarded else
branches
([#151](#151))
([614883e](614883e))
* **ego-lint:** tighten R-SLOP-38 to reduce over-long identifier false
positives
([#82](#82))
([fe88f1b](fe88f1b))
* **ego-lint:** verify R-VER48-02 guard matches Config.PACKAGE_VERSION
([#133](#133))
([6dfeca1](6dfeca1))
* **ego-lint:** widen R-VER48-02 guard-window for distant version checks
([#53](#53))
([5ae31e0](5ae31e0))


### Documentation

* add ego-review pipeline efficiency design spec
([56bcdc3](56bcdc3))
* add field test reports for Tiling Shell and Media Controls
([#25](#25))
([f8b55f7](f8b55f7))
* add field-tests/README.md with extension catalog and results
([#67](#67))
([22fc27c](22fc27c))
* add missing skill labels and fix issue template auto-labels
([782c7b4](782c7b4))
* add resource-tracking FP reduction design spec
([a7e0a2c](a7e0a2c))
* **ego-field-test:** add 03-08 regression report, update baselines and
annotations
([c5b823e](c5b823e))
* **ego-field-test:** add version info to README extension catalog and
update to 03-08
([bdb4919](bdb4919))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

init/shell-modification flags runtime-only constructors

1 participant