Skip to content

feat(r): add Jarl as fast R linter with autofix#425

Closed
sims1253 wants to merge 1 commit intopeteromallet:mainfrom
sims1253:feat/r-jarl-linter
Closed

feat(r): add Jarl as fast R linter with autofix#425
sims1253 wants to merge 1 commit intopeteromallet:mainfrom
sims1253:feat/r-jarl-linter

Conversation

@sims1253
Copy link
Contributor

Summary
Added Jarl (Just Another R Linter) as the fast, modern R linter with
auto-fix support.

Changes
• Added Jarl as tier 2 linter (becomes primary)
• Demoted lintr to tier 3 (fallback for projects without Jarl)
• Updated module docstring

Why Jarl?
• Speed: Orders of magnitude faster than lintr (0.131s vs 18.5s on dplyr)
• Auto-fix: Supports --fix flag for automatic fixes (lintr has no auto-fix)
• Active development: Built on Air (Posit's Rust formatter)
• 55+ rules: Growing rule set inspired by lintr

Testing
• All 416 tests pass
• R import resolver test passes

@peteromallet
Copy link
Owner

Thanks @sims1253! Jarl at tier-2 with autofix makes a lot of sense — 140x faster than lintr is a no-brainer, and --allow-dirty is the right call for a dev tool.

Merged into 0.9.10 as 55f9aaf0 with your attribution. Nice contribution!

peteromallet added a commit that referenced this pull request Mar 16, 2026
Co-Authored-By: Maximilian Scholz <dev.scholz@mailbox.org>
peteromallet added a commit that referenced this pull request Mar 16, 2026
* fix: strip image blocks from release notes on website

The release notes contain a mascot image that renders as a broken
or unwanted image on the website. Strip HTML <p><img></p> blocks
from release body before rendering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: derive project root from state_file path in do_import_run follow-up scan

When running `desloppify review --import-run --scan-after-import`, the
follow-up scan was using _runtime_project_root() which could return a
contaminated path (pointing to the results directory instead of the
actual project root). This caused state to be written to the wrong
location. Instead, derive the project root from the state_file parameter
which is known to be correct: state_file.parent.parent gives us the
project root from `<root>/.desloppify/state-<lang>.json`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: preserve plan_start_scores during force-rescan to protect manual clusters

_reset_cycle_for_force_rescan() was clearing plan_start_scores, which
made is_mid_cycle() return False. This caused auto_cluster_issues() to
run full cluster regeneration instead of early-returning, wiping manual
cluster items via issue ID reconciliation in scan_issue_reconcile.py.

The fix stops clearing plan_start_scores so is_mid_cycle() remains True
during force-rescan, preserving manual cluster data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: require explicit triage decisions for auto-clusters

Auto-clusters (auto/unused, auto/security, etc.) were silently left in
backlog because the triage prompt said "silence means leave in backlog"
and the output schema had no field for auto-cluster decisions. Now the
triager must make an explicit promote/skip/break_up decision for each
auto-cluster, and apply_triage_to_plan() processes those decisions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: require explicit backlog decisions for auto-clusters in staged triage

The staged triage pipeline previously treated auto-clusters as optional in
the reflect stage ("silence means it stays in backlog"). This change makes
auto-cluster decisions mandatory, matching the treatment review issues get
via the Coverage Ledger.

Changes:
- Reflect instructions: require a ## Backlog Decisions section listing every
  auto-cluster with promote/skip/supersede (replaces "silence means leave")
- Organize instructions: clarify that ALL backlog decisions from reflect
  must be executed, not just promotions
- Reflect validation: parse and persist BacklogDecision entries; warn (but
  don't block) when auto-clusters exist without a Backlog Decisions section
- Organize validation: warn when reflect requested promotions that weren't
  executed during organize

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: unified triage pipeline + step detail display improvements

Unified triage pipeline:
- Widen is_triage_finding to all defects (mechanical + review + concern)
- Sub-group auto-clusters by rule kind (auto/security-B602 instead of auto/security)
- Add MEDIUM+LOW bandit filter and skip_tests config option
- Auto-cluster statistical summaries in triage prompt (severity, confidence, samples)
- Cluster-level observe sampling (ClusterVerdict parsing)
- Blocking backlog decisions validation (every auto-cluster must have a decision)
- Threshold-based staleness (10% mechanical growth, any new review issue)
- Two-tier accounting: review issues get per-item ledger, mechanical via cluster decisions
- Auto-add manual cluster members to queue_order on add_to_cluster

Display improvements:
- cluster show: steps now show effort tag, wrapped detail (4 lines), short refs
- cluster show: members compact when steps exist (ID list, not full issue detail)
- cluster list --verbose: effort summary column (3T 1S), hide empty auto-clusters, drop noise columns
- next: cluster drill header shows step done markers and effort tags
- next: individual task shows full untruncated step detail matched via issue_refs
- next: focus mode shows cluster context + relevant step detail

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: lifecycle transition messages and agent directives

Add transition_messages config and directives CLI for phase-specific agent
instructions (model switching, constraints). Emit transition messages at
lifecycle phase changes across resolve, skip, reopen, review import, and
reconcile flows. Auto-focus cluster during mid-cluster execution so
desloppify next stays in context. Hermes reset includes cluster-aware
next-task instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add dev test-hermes command and bump skill doc version

desloppify dev test-hermes: smoke-test Hermes model switching by switching
to a random model and back. Skill doc version bumped to v6.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle missing git in review coordinator, remove unused import

Wrap git status call in try/except OSError so review coordinator doesn't
crash when git is unavailable. Remove unused triage_scoped_plan import
from stage_validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: update Hermes overlay for delegate_task, add directives docs, update website

Rewrite HERMES.md: delegate_task subagent pattern replaces worktree-based
parallel review. Add agent directives section to SKILL.md. Website:
initiative #2 now active with $1k bounty challenge details.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(r): correct shell quote escaping in lintr command (PR #424)

Co-Authored-By: Maximilian Scholz <dev.scholz@mailbox.org>

* feat(r): add Jarl as fast R linter with autofix (PR #425)

Co-Authored-By: Maximilian Scholz <dev.scholz@mailbox.org>

* fix: phpstan stderr/JSON parser fixes (PR #420)

Co-Authored-By: Nick Perkins <nick@nickperkins.au>

* fix(engine): prevent workflow::create-plan re-injection after resolution (PR #435)

Co-Authored-By: Charles Dunda <charles.dunda@perchwell.com>

* feat: add SCSS language plugin (PR #428)

Co-Authored-By: Klaus Agnoletti <github@agnoletti.dk>

* fix: Rust dep graph hangs from string-literal fake imports (PR #429)

Co-Authored-By: Riccardo Spagni <ric@spagni.net>

* fix: binding-aware unused import detection for JS/TS (PR #433)

Co-Authored-By: Tom <tswift1991@icloud.com>

* fix: project root detection, force-rescan plan wipe, and manual cluster visibility (PR #439)

* perf(scan): detector prefetch + cache for faster scans (PR #432)

Co-Authored-By: Tom <tswift1991@icloud.com>

* feat(frameworks): FrameworkSpec layer + Next.js spec (PR #414)

Co-Authored-By: Tom Swift <tswift1991@icloud.com>

* fix: allow scan when queue is fully drained regardless of lifecycle phase

Fixes #441

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: quote paths for Windows cmd /c and use utf-8 encoding in log recovery

Fixes #442

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: merge retry batch results with original run before coverage check

Fixes #443

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docs): SKILL.md cleanup — remove unsupported frontmatter, fix file naming, generalize install

Fixes #444, #445, #446

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* cleanup: remove dead _strip_c_style_comments_preserve_lines shim from rust/tools.py

Follow-up to PR #440 (Rust inline-test filtering).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: move queue_total==0 check into score_display_mode (#441)

Move the empty-queue guard from scan_queue_preflight into
score_display_mode() so ALL callers (status, plan nudge, next flow)
benefit from the fix, not just scan preflight.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: extract anonymous functions in tree-sitter specs (R lang)

PR #449 added an R anonymous function query pattern that captures @fn
but the extractor requires @name, silently skipping all anonymous
function matches. Fix the extractor to synthesize an "<anonymous>" name
when @name is absent but @func is present.

Original R spec contributed by sims1253 in PR #449.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(docs): sync .agents SKILL.md with docs copy, add pip fallback and batch naming note

- Remove `allowed-tools` frontmatter from .agents/skills/desloppify/SKILL.md (#444)
- Add `pip install` fallback note alongside uvx in both copies (#446)
- Add batch output naming clarification (batch-N.raw.txt vs .json imports) (#445)
- Sync agent directives section and version bump to .agents copy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: collapse cmd /c arguments into single string for proper Windows quoting

The previous fix pre-quoted the executable path, but the actual breakage was
in argument paths (-C repo_root, -o output_file) containing spaces. Pre-embedding
quotes in a subprocess list causes double-quoting because Popen's list2cmdline()
adds its own quotes.

The real issue: cmd /c concatenates everything after /c and re-parses it with its
own tokeniser. The fix introduces _wrap_cmd_c() which uses subprocess.list2cmdline()
to build the inner command as a single properly-quoted string, then passes that as
one token after /c: ["cmd", "/c", "codex exec -C \"path with spaces\" ..."].

- Revert incorrect executable pre-quoting in _resolve_executable
- Add _wrap_cmd_c() to properly collapse cmd /c commands
- Apply _wrap_cmd_c in codex_batch_command after building the full arg list
- Keep correct encoding="utf-8", errors="replace" fix in io.py
- Add tests for _wrap_cmd_c and Windows codex_batch_command path quoting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: skip coverage gate on partial batch retry instead of merging results

Replace the 195-line merge approach (find_prior_run_merged_results +
overlay_retry_results_on_prior) with a ~5-line bypass: when --only-batches
selects a subset of the packet's batches, set allow_partial=True so the
coverage gate does not reject the partial retry.

The merge approach had multiple issues: wrong prior-run selection after
failed retry chains, dimension name normalization mismatches, and stale
metadata in combined output. The simpler fix recognizes that a partial
retry inherently cannot cover all dimensions, and the original run already
handled the rest.

Fixes #443

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* bump version to 0.9.10

* bump version to 0.9.10

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* bump version to 0.9.10

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: gitignore .agents/ and untrack generated skill doc

The .agents/skills/desloppify/SKILL.md is a generated file (same as
.claude/skills/). Canonical copies live under docs/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add hermes and droid to update-skill help text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: draft 0.9.10 release notes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ruby): improve plugin — excludes, detect markers, default_src, spec/ support, README, tests (#462)

* feat(ruby): improve plugin — excludes, detect markers, default_src, README, tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Gemini <gemini@google.com>
Co-Authored-By: OpenAI Codex <codex@openai.com>

* feat(ruby): add spec/ test dir, bin/ exclusion; expose external_test_dirs in generic_lang

- Add external_test_dirs and test_file_extensions parameters to generic_lang()
  so plugins can override the hardcoded ["tests", "test"] defaults
- Configure Ruby plugin with external_test_dirs=["spec", "test"] (RSpec + Minitest)
- Add bin/ to Ruby exclusions (binstubs/shims)
- Update tests: add bin/ to excluded dirs list, add test_external_test_dirs_includes_spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Gemini <gemini@google.com>
Co-Authored-By: OpenAI Codex <codex@openai.com>

* docs(ruby): add bin/ to exclusions list in README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Gemini <gemini@google.com>
Co-Authored-By: OpenAI Codex <codex@openai.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Gemini <gemini@google.com>
Co-authored-by: OpenAI Codex <codex@openai.com>

* feat: add Factory Droid skill harness support (#451)

- Add 'droid' to SKILL_TARGETS (.factory/skills/desloppify/SKILL.md)
- Add .factory/skills/ to SKILL_SEARCH_PATHS for auto-discovery
- Create docs/DROID.md overlay with review and triage workflow
- Bump SKILL_VERSION to 6
- Add droid to README agent prompt harness list

* docs(python): add user-facing section to README (#459)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(javascript): add plugin tests and documentation (#458)

Co-authored-by: Gemini <gemini@google.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(docs): correct autofix command in Ruby and JS plugin READMEs

The command is `desloppify autofix`, not `desloppify fix` or
`desloppify scan --fix`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: update release notes with late-merged PRs and stats

Add #458, #459, #462 contributions from klausagnoletti.
Update stats to reflect final commit/file/test counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(scss): replace {file_path} placeholders with glob patterns and use unix formatter

The tool runner does not substitute {file_path} placeholders, so
stylelint was receiving literal "{file_path}" and failing silently.
Switch to glob patterns (matching every other plugin) and use
--formatter unix with the gnu parser, since stylelint's JSON output
doesn't match the expected json parser format.

Based on findings from @klausagnoletti in PR #452.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Maximilian Scholz <dev.scholz@mailbox.org>
Co-authored-by: Nick Perkins <nick@nickperkins.au>
Co-authored-by: Charles Dunda <charles.dunda@perchwell.com>
Co-authored-by: Klaus Agnoletti <github@agnoletti.dk>
Co-authored-by: Riccardo Spagni <ric@spagni.net>
Co-authored-by: Tom <tswift1991@icloud.com>
Co-authored-by: Klaus Agnoletti <24544601+klausagnoletti@users.noreply.github.com>
Co-authored-by: Gemini <gemini@google.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
@sims1253 sims1253 closed this Mar 18, 2026
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.

2 participants