Skip to content

fix(ego-lint): reduce Tiling Shell false positives#22

Merged
ZviBaratz merged 5 commits intomainfrom
fix/tiling-shell-calibration
Mar 4, 2026
Merged

fix(ego-lint): reduce Tiling Shell false positives#22
ZviBaratz merged 5 commits intomainfrom
fix/tiling-shell-calibration

Conversation

@ZviBaratz
Copy link
Copy Markdown
Owner

@ZviBaratz ZviBaratz commented Mar 4, 2026

Summary

  • R-VER49-08/11 ternary guard: Same-line get_maximized ? suppresses maximize/unmaximize flags warnings — these are intentional version-compat shims
  • Minified JS threshold: Require 3+ lines >500 chars instead of 1 — single long lines in compiled TypeScript are not minification

Closes #16

Test plan

  • Updated fixture: gnome49-compat@test with ternary maximize/unmaximize methods
  • Updated fixture: minified-js@test with 3 long lines (still triggers)
  • Assertions verify: R-VER49-08/11 suppressed with ternary guard, minified-js still detected
  • bash tests/run-tests.sh passes (512 assertions)

🤖 Generated with Claude Code

Two calibration fixes from Tiling Shell field testing:

1. Add guard-pattern for R-VER49-08/11 (maximize/unmaximize flags) —
   ternary version-compat patterns like `get_maximized ? old(args) : new()`
   are intentional compatibility shims, not deprecated API usage.

2. Raise minified-js threshold to 3+ lines > 500 chars — a single long
   line (e.g., keyboard constant chain in compiled TypeScript) in an
   otherwise readable file is not minification.

Closes #16

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ZviBaratz
Copy link
Copy Markdown
Owner Author

Code review

Found 1 issue:

  1. guard-window: 0 is rejected by the apply-patterns.py validator (guard-window must be >= 1). At runtime, max(1, int(...)) silently clamps 0 to 1, so the guard works in practice — but running python3 apply-patterns.py --validate rules/patterns.yaml will now emit two ERRORs and exit non-zero. Using guard-window: 1 achieves the same behavior (current line is always checked regardless of window size) and passes validation.

min-version: 49
guard-pattern: "get_maximized\\s*\\?"
guard-window: 0

fix: "Call unmaximize() without the MaximizeFlags parameter"
guard-pattern: "get_maximized\\s*\\?"
guard-window: 0

Validator logic that rejects it:

gw_int = int(gw)
if gw_int < 1:
print(f"ERROR: {rid}: guard-window must be >= 1, got {gw}")
errors += 1
except (ValueError, TypeError):

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

ZviBaratz and others added 2 commits March 4, 2026 11:54
guard-window: 0 is silently clamped to 1 at runtime but rejected by
apply-patterns.py --validate. Use 1 explicitly for identical behavior
that also passes validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ZviBaratz
Copy link
Copy Markdown
Owner Author

PR Review Summary

Critical Issues (1)

set -euo pipefail regression in minified JS detection (ego-lint.sh:427,439)

The old code ran awk inside an if condition (exempt from set -e). The new bare command substitution long_line_count=$(awk ...) will abort the entire script silently if awk fails (permission denied, TOCTOU race, etc.). The 2>/dev/null swallows the error message.

Fix — add || true to both occurrences:

long_line_count=$(awk 'length > 500 { n++ } END { print n+0 }' "$f" 2>/dev/null || true)

Important Issues (1)

Missing boundary test for minified JS threshold. The fixture tests 3 lines (triggers), but there's no test that 2 long lines does not trigger — which is the exact behavioral contract this PR introduces. A regression lowering the threshold back would go undetected.

Suggestions

  • No test for multi-line ternary guard (where get_maximized ? is on the previous line, trigger on the next). Low risk since guard-window is battle-tested by other rules.
  • The lib/ directory code path for minified detection has zero test coverage. Mechanical copy of top-level code, so low risk.

Strengths

  • Guard pattern logic is correct — guard-window: 1 is the minimum valid value
  • Both R-VER49-08 and R-VER49-11 retain independent un-guarded fixtures, catching overly-broad guards
  • Test placement in gnome49-compat@test (which already fails on other rules) proves the guard doesn't mask unrelated violations
  • Commit messages and docs follow project conventions

Bare `var=$(cmd)` under `set -euo pipefail` aborts the script if cmd
returns non-zero. Add `|| true` to both minified-js awk invocations.
Also add a boundary test fixture (2 long lines, below 3-line threshold).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ZviBaratz
Copy link
Copy Markdown
Owner Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@ZviBaratz ZviBaratz merged commit 62c5509 into main Mar 4, 2026
3 checks passed
@ZviBaratz ZviBaratz deleted the fix/tiling-shell-calibration branch March 4, 2026 14:33
@ZviBaratz ZviBaratz added ego-lint Related to ego-lint skill false-positive Rule fires incorrectly labels Mar 6, 2026
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 false-positive Rule fires incorrectly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

False positives: R-VER49-08/11 ternary version-compat and minified JS single-line threshold

1 participant