8000 fix(mapper): fall back to core baseline guides when generic is dropped by LiinaSuoniemi · Pull Request #68 · habit-hooks/habit-hooks · GitHub
[go: up one dir, main page]

Skip to content

fix(mapper): fall back to core baseline guides when generic is dropped - #68

Merged
devill merged 1 commit into
habit-hooks:mainfrom
LiinaSuoniemi:fix-mapper-crash-without-generic
Jul 1, 2026
Merged

devill merged 1 commit into
habit-hooks:mainfrom
LiinaSuoniemi:fix-mapper-crash-without-generic

Conversation

@LiinaSuoniemi
Copy link
Copy Markdown
Contributor

The bug

With a config that runs a plugin but drops generic (which the README says is allowed), habit-hooks crashes instead of running. With plugins = ["python"] it raises AttributeError: 'NoneType' object has no attribute 'suffix', on any run: both an unguided smell and a plain clean run.

Root cause

The mapper's two baseline guides, clean.md and uncoached.md, live only in the generic plugin. render_finding and render_clean assume they always resolve, so when generic is not configured the guide is None and the next line crashes.

This contradicts two docs at once. The README says generic can be dropped, and habit-mapper.spec.md says "rather than crash, the mapper falls back to uncoached."

The fix

Moved clean.md and uncoached.md out of the generic plugin and into the core, and the resolver now falls back to the core last. The resolution chain becomes project override, then plugin, then core. A plugin can still override with its own version, and the baseline is always there even with no generic.

It is one fallback loop in resolve.py, the two guide files in the core, and their removal from generic.

Tests

Two new cases in habit-mapper.spec.md, both running the python plugin with no generic:

  • an unguided smell coaches via the core uncoached.md
  • a clean run prints the core pass reminder

All existing tests stay green.

The mapper's baseline guides clean.md and uncoached.md lived only in the generic plugin, so a config that dropped generic (which the README allows) crashed render_finding and render_clean on a None guide. Moves them out of generic into the core, where the resolver falls back to them last, so the mapper always coaches and never crashes. Adds two spec tests that run the python plugin without generic.
@devill
devill changed the base branch from v1.0 to main July 1, 2026 19:03
@devill
devill merged commit afbb00c into habit-hooks:main Jul 1, 2026
1 of 2 checks passed
devill added a commit that referenced this pull request Jul 1, 2026
Reworks Liina's swallowed-exception guide to reuse the shared
{% include "includes/line_level_issues.md" %} instead of inlining the
listing, keeping it consistent with every other guide. To let a
plugin use the shared partials with no generic installed, moves both
partials (line_level_issues.md, file_level_issues.md) from the generic
plugin into the core, where resolve.first() already falls back last —
the same move #68 made for clean.md/uncoached.md. This also fixes the
identical latent crash for php-only and typescript-only configs, whose
guides already use the include.

Drops the brittle full-prose case from habit-mapper.spec.md (those
cases run as exact-match tests; pinning guide prose there breaks on
every wording tweak, and the routing is already covered). Retargets
#68's unguided-smell fallback case from swallowed-exception (now
guided) to warning-comment, and updates the guide-includes contract to
note the core fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.

2 participants

0