Skip to content

release: v0.3.0 — checker: catch more real bugs; add --fix and CI autofix - #19

Merged
Paritsingla7 merged 5 commits into
mainfrom
fix/drop-empty-config-tables
Aug 28, 2026
Merged

Paritsingla7 merged 5 commits into
mainfrom
fix/drop-empty-config-tables

Conversation

@Paritsingla7

@Paritsingla7 Paritsingla7 commented Aug 28, 2026 •

Copy link
Copy Markdown
Owner

Summary

Five commits:

  • checker.py: three new checks derived from real Hyprland bug reports -

    • possible_missing_quotes — a bare, never-assigned identifier used as a string value (accel_profile = flat) silently evaluates to nil. Reproduces hyprwm/Hyprland#15727, which broke a real user's mouse sensitivity.
    • uncalled_dispatcher — a dispatcher factory referenced but not called.
    • duplicate_bind — the same key combo bound more than once. Caught 4 genuine collisions in this project's own vendored real-world test fixture.
    • Both uncalled_dispatcher and duplicate_bind are from hyprwm/Hyprland#15871; arity-checking dsp.* calls (that issue's third case) is deliberately not implemented — no argument-count data exists in the stub to check it against.
    • Also fixes a pre-existing crash on any config containing a colon-method definition (Method has no .func; Invoke is the real method-call node).
  • check --fix (new hyprvalidate/fixer.py): applies the two corrections above that have exactly one right answer, as targeted character-offset patches — never a full AST regenerate-and-reprint, so a hand-written config's comments/formatting survive. Everything else is still reported, never guessed at.

  • examples/ci/validate-hyprland-lua.yml: a ready-to-copy GitHub Actions workflow, split into a read-only check gate on PRs and a check --fix autofix job on push that commits corrections back onto the branch.

  • site/bundle.js regenerated (CI's own site-bundle-in-sync job caught the drift).

  • Version bump to 0.3.0, finalizing the changelog and fixing packaging/PKGBUILD, which had been stuck at pkgver=0.1.0 since before this PR.

Release plan

This PR does not create or push the v0.3.0 tag — that happens after merge, against main, since a release tag should point at what's actually merged rather than a feature-branch commit. After merging, either:

  • push the tag from anywhere: git checkout main && git pull && git tag v0.3.0 && git push origin v0.3.0, or
  • draft a GitHub Release from the mobile app targeting a new tag v0.3.0 on main — creating the release also creates+pushes the tag, which is all publish.yml needs to trigger the PyPI publish.

Test plan

  • pytest tests/ — 195 passed (3 pre-existing/environmental entry-point failures unrelated to this change, deselected)
  • Verified possible_missing_quotes against the real bug report in Mouse cursor speed significantly higher after updating Hyprland hyprwm/Hyprland#15727 directly
  • --fix verified end-to-end on a scratch file with a mix of fixable and unfixable findings
  • site/bundle.js regenerated and CI's site-bundle-in-sync job confirmed green

Adds three schema/AST-derived diagnostics with no hand-maintained
per-dispatcher data, closing gaps confirmed against real Hyprland
issues:

- possible_missing_quotes: a bare identifier value (e.g.
  accel_profile = flat) that's never assigned anywhere in the file
  would silently evaluate to nil at runtime. Reproduces the exact bug
  in hyprwm/Hyprland#15727, which broke a user's mouse sensitivity
  after a .conf migration.
- uncalled_dispatcher: a dispatcher factory referenced but not called
  (hl.dsp.window.close instead of hl.dsp.window.close()), which
  type-checks under the stub's HL.Dispatcher|function union so nothing
  else catches it.
- duplicate_bind: the same key combo bound more than once, silently
  shadowing one binding. Caught four genuine, previously-undetected
  collisions in this project's own vendored real-world test fixture.

Both uncalled_dispatcher and duplicate_bind are from
hyprwm/Hyprland#15871 ("Improve lua error reporting"); arity-checking
dsp.* calls (the issue's third case) is deliberately not implemented
since the stub carries no argument-count data for those factories.

Also fixes a pre-existing crash: check() grouped Method (a
`function T:method() end` definition, no .func attribute) with Call
for call-detection; a colon-method definition anywhere in a config
raised AttributeError. Invoke is the actual method-call node.
check --fix (hyprvalidate/fixer.py): applies the two corrections that
have exactly one right answer - quoting a bare-identifier string value
(possible_missing_quotes) and adding () to a referenced-but-uncalled
dispatcher factory (uncalled_dispatcher) - as targeted character-offset
patches against the original source, never a full AST regenerate-and-
reprint, so a user's comments and formatting outside the flagged span
survive untouched. Findings with no single correct fix (unknown
symbols/keys, type/arity mismatches, duplicate binds) are left
reported, never guessed at. Patched output goes through the luac gate
and a re-check before being written, same discipline convert already
applies to its own output.

examples/ci/validate-hyprland-lua.yml: a ready-to-copy GitHub Actions
workflow for validating a dotfiles repo's Lua config with no Hyprland
installed - pins the hyprvalidate version and its schema.json snapshot
to the same git tag so they can't drift apart. Also fixes the README's
own CI section, which had gone stale (pipx install git+... from before
the PyPI release, and a schema.json reference with no explanation of
where it comes from).
checker.py picked up three new checks and a bugfix this PR without a
bundle regen - the CI site-bundle-in-sync job caught it.
The validate job only ever flagged problems; closing the loop means
the mechanical fixes (missing quotes, uncalled dispatcher factories)
get committed automatically instead of waiting on a human to notice
and run --fix locally.

Split into two jobs by trigger since push and pull_request need
different permission/safety postures:
- validate (pull_request): unchanged, read-only check. Works the same
  for a same-repo branch or a fork - no write access, no surprise
  commits landing mid-review.
- validate-and-autofix (push): runs check --fix, commits and pushes
  any change back onto the branch, still fails the job if something
  unfixable remains. Guarded against re-triggering itself on its own
  fix commit via a [hyprvalidate-autofix] marker in the commit message.
@Paritsingla7 Paritsingla7 changed the title checker: catch missing quotes, uncalled dispatchers, duplicate binds checker: catch more real-world config bugs; add --fix and CI autofix Aug 28, 2026
Finalizes the Unreleased changelog entries from this PR (checker: three
new checks + a crash fix, check --fix, the CI template + autofix
wiring) as 0.3.0. Also bumps the CI template's default
HYPRVALIDATE_VERSION and the README's inline example to match, and
fixes packaging/PKGBUILD, which had been stuck at pkgver=0.1.0 even
after the 0.2.0 release.

Tagging and pushing v0.3.0 (which triggers the PyPI publish via
Trusted Publishing) happens after this merges to main, not on this
branch - a release tag should point at what's actually on main.
@Paritsingla7 Paritsingla7 changed the title checker: catch more real-world config bugs; add --fix and CI autofix release: v0.3.0 — checker: catch more real bugs; add --fix and CI autofix Aug 28, 2026
@Paritsingla7
Paritsingla7 merged commit 883ec32 into main Aug 28, 2026
6 checks passed

This branch was successfully deployed

1 active deployment
pypi — 47df0fa4 Deployed Aug 28, 2026 by Paritsingla7 via publish #2
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.

1 participant