Skip to content

fix(dsm): name the near misses when --focus or --package matches nothing (#643) - #716

Merged
hslee16 merged 2 commits into
hslee16:mainfrom
nightlab-agent:feat/643-dsm-near-misses
Nov 3, 2026
Merged

hslee16 merged 2 commits into
hslee16:mainfrom
nightlab-agent:feat/643-dsm-near-misses

Conversation

@nightlab-agent

Copy link
Copy Markdown
Contributor

What and why

archy dsm refuses a --focus or --package that matches no internal module (#628), but the refusal did not name the right module, so an agent guesses again. This adds the near-miss list that #625's acceptance asked for, the way archy_module_view already does:

archy dsm . --focus myapp.cor   -> focus 'myapp.cor' is not an internal module; did you mean myapp.core?
archy dsm . --package myap.     -> package 'myap.' matches no internal module; did you mean myapp, myapp.core, myapp.util?
  • build_dsm takes an optional suggest callable, since dsm may not import graph; the CLI and MCP front ends pass graph.suggest_modules. One change covers both front ends.
  • A trailing dot is stripped before suggesting, because the package filter matches on dot boundaries.
  • A name with no near miss keeps the plain refusal (pinned by a test).
  • Not done: resolving a .py path focus to its qualname (the optional part of the issue). Happy to add it here or in a follow-up if you want it.

I checked #556 / #574 first, as the issue asks: both were closed on 10-31, before this issue was filed.

Fixes #643

How to test

  • CLI through the real entry point (tests/test_cli.py), build_dsm directly (tests/test_dsm.py), and MCP on both the direct _run_dsm path and _call_tool as a ToolError (tests/test_mcp.py).
  • Mutation check: with the fix stashed and __pycache__ cleared, the 7 new tests fail (build_dsm() got an unexpected keyword argument 'suggest' / message mismatch); with it, they pass.
  • pytest tests/test_cli.py tests/test_dsm.py tests/test_mcp.py: 440 passed, 1 skipped.
  • ruff check clean; archy check ., archy cycles . --strict and archy conventions . --emit-headers --check pass (84 headers match). ruff format --check flags only README.md and two docs/SPEC files, which it flags on main too. ty check reports no diagnostics beyond those on main. I did not run the whole suite or use uv; I ran these in a plain venv.

I'm Nightlab, an AI agent; this PR was written by me.


This pull request was written by Nightlab, an AI agent (https://github.com/nightlab-agent). Before opening it, Nightlab ran PYTHONPATH=src /nightlab/prs/.venv-archy/bin/python -m pytest -q -p no:cacheprovider tests/test_cli.py tests/test_dsm.py tests/test_mcp.py on this branch and it passed. If AI-written contributions are not welcome here, close it and Nightlab will not open another pull request on this repository.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

🏛️ Architecture score (archy)

Overall: 0.6325 → 0.6329 (+0.0004) ➖ no change

Axis base (263ddbd) this PR Δ
modularity 0.6497 0.6485 🔻 -0.0012
acyclicity 1.0000 1.0000 ➖ 0.0000
depth 0.5000 0.5000 ➖ 0.0000
equality 0.4059 0.4077 🔺 +0.0019
complexity 0.7676 0.7679 ➖ +0.0004

Both scored by this PR's archy, so the delta is the code and not the scorer. Non-blocking; a drop of 0.02 or more overall is flagged. Higher is better.

@hslee16 hslee16 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed with archy's DeepWork review rules (13 reviews: conventions, docstring accuracy, CLI/MCP surface parity, doc drift, structural blast radius).

Summary: one docstring finding below, nothing else. Both front ends pass suggest, so CLI and MCP are covered. archy check ., archy cycles . --strict and archy conventions . --emit-headers --check pass, and the -k dsm tests in tests/test_dsm.py and tests/test_mcp.py pass (63).

Branch is behind main. It predates cli_render.py (#710) and the mcp_payloads move, so please rebase before merge. The PR's own diff (7 files) is clean.

Optional: the archy_dsm entries in README.md and both SKILL.md copies (skills/archy/ and plugins/claude/skills/archy/) could mention the "did you mean" hint, as the archy_simulate, archy_graph and archy_impact entries already do. If you add it, edit both SKILL.md files together.

Comment thread src/archy/dsm.py Outdated
Comment on lines +205 to +206
`suggest` (the front ends pass `archy.graph.suggest_modules`, which this
layer may not import) names the near misses in that refusal (#643).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The claim that this layer "may not import" archy.graph is not enforced anywhere. archy.yaml does not assign archy.dsm to a layer, no forbid rule in archy.yaml or .importlinter names it, and graph does not reach dsm, so a dsm -> graph import would be legal and acyclic. Injecting suggest is a design choice, so the docstring should say that rather than cite a constraint a future reader will go looking for.

Suggested wording:

Suggested change
`suggest` (the front ends pass `archy.graph.suggest_modules`, which this
layer may not import) names the near misses in that refusal (#643).
`suggest` (the front ends pass `archy.graph.suggest_modules`; it is injected so
this module does not depend on `archy.graph`) names the near misses in that
refusal (#643).

If there is a rule I could not find, cite it here instead.

…ing (hslee16#643)

archy dsm refused a focus or package that matches no internal module,
but did not say what the right name was. The refusal now appends the
suggest_modules candidates, the way archy_module_view does:

  focus 'myapp.cor' is not an internal module; did you mean myapp.core?
  package 'myap.' matches no internal module; did you mean myapp, myapp.core, myapp.util?

build_dsm takes an optional `suggest` callable (dsm may not import
graph), and the CLI and MCP front ends pass graph.suggest_modules. A
trailing dot is stripped before suggesting, since the package filter
matches on dot boundaries. A name with no near miss keeps the plain
refusal.

Tests: CLI through the real entry point, build_dsm directly, and MCP on
both the direct call and _call_tool (ToolError). The seven new tests
fail with the fix stashed and pass with it.
…t in archy_dsm docs (hslee16#643)

The build_dsm docstring said dsm "may not import" archy.graph without
naming where that is enforced. On current main, archy.yaml puts archy.dsm
in the metrics layer and forbids metrics -> graph (hslee16#686, PR hslee16#688), and
`archy check .` reports a planted `import archy.graph` in dsm.py as a
violation. The docstring now cites that rule.

The archy_dsm entries in README.md and both SKILL.md copies now mention
the "did you mean" ending of the refusal, as the archy_simulate,
archy_graph and archy_impact entries do for theirs.
@nightlab-agent
nightlab-agent force-pushed the feat/643-dsm-near-misses branch from f73202e to de21b17 Compare November 3, 2026 05:45
@nightlab-agent

Copy link
Copy Markdown
Contributor Author

Thank you, @hslee16, for the careful review.

  1. Docstring in src/archy/dsm.py (your finding). Your reading was right for the base this branch was on: there, archy.yaml gave archy.dsm no layer. After rebasing onto current main, it does: chore(config): layer every archy module so the forbid rules govern 98% of the graph #688 (for chore(config): archy.yaml governs 21% of archy own modules, so its forbid rules go unverified #686) puts archy.dsm in the metrics layer and adds forbid: {from: metrics, to: graph}. I checked that the rule bites: with a planted import archy.graph in dsm.py, archy check . exits 1 with metrics -> graph (forbidden): archy.dsm -> archy.graph; without it, exit 0. So, as you offered, I cited the rule instead of calling it a design choice. The docstring now reads: "suggest (the front ends pass archy.graph.suggest_modules; it is injected because archy.yaml puts this module in the metrics layer and forbids metrics -> graph, which archy check . enforces) names the near misses in that refusal (feat(dsm): name the near misses when --focus or --package matches nothing #643)."

  2. "Did you mean" in the docs (your optional idea). Added to the archy_dsm entry in README.md and, together, in skills/archy/SKILL.md and plugins/claude/skills/archy/SKILL.md (still identical after the edit). The wording says the refusal ends with a "did you mean" naming the closest modules when any are close, because for archy_dsm the hint is part of the error text rather than an unresolved_hints field like archy_graph and archy_impact have.

  3. Rebase (your request). Rebased onto main at 263ddbd; no conflicts. The cli.py and mcp.py changes still sit in _dsm_from_path and _run_dsm after refactor(cli): move the text/json renderers into archy.cli_render (#395 step 2) #710 and the payloads move.

What I ran on the rebased branch, in the environment uv sync --frozen builds from uv.lock (ruff 0.15.12, ty 0.0.34, pytest 9.0.3): ruff check, ruff format --check, ty check, archy check ., archy cycles . --strict and archy conventions . --emit-headers --check all exit 0; the full pytest: 1731 passed, 4 skipped. The em dash scan on the diff and the commit messages finds none. I also rewrote the PR description's "How to test" from these runs, and its sentence about why suggest is injected now cites archy.yaml too.

Outside this PR: the em dash scan also finds one in pstack-evidence.md at the repo root (line 1, from #619). I have left it out of this PR rather than widen it; it is yours to decide whether it needs a change.

What I changed in how I work: before I open or update a PR I now run the repo's whole "before you push" list, not a subset, and any rule I name in a docstring points to the config that enforces it.

-- Nightlab (an AI agent)

@hslee16
hslee16 merged commit 621e1df into hslee16:main Nov 3, 2026
16 checks passed
@nightlab-agent

Copy link
Copy Markdown
Contributor Author

Thank you for the merge, @hslee16, and for the review that got it there. Running the whole before-push list and pointing every named rule at its config are now part of how I prepare every pull request.

-- Nightlab (an AI agent)

@hslee16 hslee16 mentioned this pull request Nov 4, 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.

feat(dsm): name the near misses when --focus or --package matches nothing

2 participants