Skip to content

feat(ego-lint): add notification urgency abuse detection (R-QUAL-36)#49

Merged
ZviBaratz merged 4 commits intomainfrom
feat/urgency-critical-rule
Mar 6, 2026
Merged

feat(ego-lint): add notification urgency abuse detection (R-QUAL-36)#49
ZviBaratz merged 4 commits intomainfrom
feat/urgency-critical-rule

Conversation

@ZviBaratz
Copy link
Copy Markdown
Owner

@ZviBaratz ZviBaratz commented Mar 6, 2026

Summary

  • Add Tier 1 pattern rule R-QUAL-36 to detect Urgency.CRITICAL assignment on notifications
  • CRITICAL urgency bypasses Do Not Disturb — reserved for system alerts, not extension notifications (e.g. donation prompts)
  • Pattern requires = (assignment) so read/comparison contexts like Dash to Panel's n.urgency > ... CRITICAL won't false-positive
  • skip-comments: true avoids false positives on commented-out code mentioning CRITICAL urgency

Closes #37

Test plan

  • New fixture urgency-critical@test triggers [WARN] R-QUAL-36 with exit code 0
  • Full test suite passes (546 assertions)
  • Verify Dash to Panel field test doesn't false-positive on urgency comparison
  • Verify Just Perfection field test triggers R-QUAL-36 (src/lib/SupportNotifier.js:263)

🤖 Generated with Claude Code

Add Tier 1 pattern rule to detect assignment of Urgency.CRITICAL to
notification urgency. CRITICAL bypasses Do Not Disturb and is reserved
for system alerts — using it for extension notifications (e.g. donation
prompts) is abuse.

Pattern requires assignment (=) so comparisons like
`n.urgency > MessageTray.Urgency.CRITICAL` won't false-positive.

Closes #37

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ZviBaratz ZviBaratz added new-rule Proposal for a new lint rule ego-lint Related to ego-lint skill labels Mar 6, 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.

Nice, clean rule addition — well-scoped PR with good documentation and test coverage. One issue to fix:

Bug: Pattern matches ==/=== comparisons (false positive)

The regex \.urgency\s*=\s*.*Urgency\.CRITICAL will match equality comparisons, not just assignments:

// ✅ Correctly matches (assignment)
notification.urgency = Urgency.CRITICAL;

// ❌ False positive (comparisons)
if (notification.urgency === Urgency.CRITICAL) ...
if (n.urgency == Urgency.CRITICAL) ...

The = in the pattern matches the first = of ===, then \s* matches zero chars, then .* greedily consumes the rest including == Urgency.CRITICAL.

Fix: Add a negative lookahead after =:

pattern: "\\.urgency\\s*=(?!=)\\s*.*Urgency\\.CRITICAL"

This is already supported — patterns.yaml uses (?!...) in R-WEB-06 and R-SLOP-24.

Verified locally:

Input Current With =(?!=)
.urgency = Urgency.CRITICAL ✅ match ✅ match
.urgency === Urgency.CRITICAL ❌ match ✅ no match
.urgency == Urgency.CRITICAL ❌ match ✅ no match
.urgency > Urgency.CRITICAL ✅ no match ✅ no match

Minor suggestion

Consider adding a negative test case to the fixture (a comparison line that should not trigger the rule) to prevent regressions on the lookahead.

Everything else looks good

  • Rule documentation in rules-reference.md is thorough
  • Test fixture follows conventions (LICENSE, metadata UUID match, no "gnome" in name)
  • Assertion file will be auto-sourced correctly
  • Advisory severity is appropriate for this rule

ZviBaratz and others added 2 commits March 6, 2026 09:13
…sons

Add negative lookahead =(?!=) so the pattern only matches assignment,
not equality checks. Add comparison line to fixture and assert exactly
one hit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…positives

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ZviBaratz ZviBaratz self-assigned this Mar 6, 2026
@ZviBaratz ZviBaratz enabled auto-merge (squash) March 6, 2026 07:39
@ZviBaratz ZviBaratz merged commit 546bd10 into main Mar 6, 2026
3 checks passed
@ZviBaratz ZviBaratz deleted the feat/urgency-critical-rule branch March 6, 2026 07:41
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

ego-lint Related to ego-lint skill new-rule Proposal for a new lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

new-rule: notification urgency abuse (R-QUAL-36)

1 participant