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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions docs/habit-mapper.spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -610,3 +610,66 @@ habit-mapper
```text
Could not auto-split; manual extraction needed.
```

## Core baseline fallback (works without generic)

The baseline `clean.md` and `uncoached.md` guides ship in the core, so the mapper
coaches and never crashes even when no plugin supplies them, e.g. a project that
runs the `python` plugin without `generic`.

### A python-only config coaches an unguided smell via the core uncoached guide

`swallowed-exception` has no guide in the `python` plugin and `generic` is not
configured, so the mapper falls back to the core `uncoached.md` rather than
crashing. The smell is `suggested`, so the run still passes.

📄.habit-hooks/config.toml
```toml
plugins = ["python"]
```

⌨️
```json
[{"smell":"swallowed-exception","details":{},"issues":[{"key":"x.py:4","details":{"file":"x.py","line":4}}]}]
```

```bash
habit-mapper
```

🖥️ ✅
```text
── swallowed-exception (1 issue) ──

General guidance: the issues listed are code smells. They tell you that there is likely something wrong with the code. Follow these steps:
- Ask yourself why the rule exists in the first place. What is it telling you about the code?
- Find a fix that improves maintainability, cuts cruft — doing the same with fewer statements where that lowers cognitive load — and/or improves security, scalability, and resilience.
- AVOID AT ALL COST: any fix that is designed to appease the reporting tool, but goes against the spirit of the warning.

x.py:4
```

### A python-only clean run prints the core pass reminder

With no findings and no `generic`, the run still renders the core `clean.md`.

📄.habit-hooks/config.toml
```toml
plugins = ["python"]
```

⌨️
```json
[]
```

```bash
habit-mapper
```

🖥️ ✅
```text
✅ Habit Hooks: automated checks passed.

Habit Hooks catches structural smells, not correctness or design. If no reviewer sub-agent has reviewed this change set, run one before declaring done.
```
13 changes: 12 additions & 1 deletion src/habit_hooks/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@

PLUGIN_ENTRY_POINT_GROUP = "habit_hooks.plugins"

# The core ships baseline guides (clean.md, uncoached.md) as the final fallback, so
# the mapper still coaches and never crashes when no configured plugin supplies them
# (for example a project that drops the generic plugin).
CORE_GUIDES = Path(__file__).parent / "guides"


@cache
def installed_plugin_dirs() -> dict[str, Path]:
Expand Down Expand Up @@ -80,11 +85,17 @@ def guide(self, guide: str, plugins: list[str]) -> Path | None:

def first(self, plugins: list[str], candidates: list[str]) -> Path | None:
"""First existing guide, walking plugins then override-before-package; within
one directory the candidate names are tried in order."""
one directory the candidate names are tried in order. Falls back last to the
core's built-in baseline guides, so the mapper still coaches (never crashes)
when no configured plugin supplies the guide."""
for plugin in plugins:
for base in self.plugin_dirs(plugin):
for name in candidates:
candidate = base / "guides" / name
if candidate.is_file():
return candidate
for name in candidates:
candidate = CORE_GUIDES / name
if candidate.is_file():
return candidate
return None
Loading
0