Skip to content

refactor: address code-review findings on the containment fixes - #29

Open
steve-calvert-glean wants to merge 1 commit into
mainfrom
refactor/containment-review-followup
Open

refactor: address code-review findings on the containment fixes#29
steve-calvert-glean wants to merge 1 commit into
mainfrom
refactor/containment-review-followup

Conversation

@steve-calvert-glean

Copy link
Copy Markdown
Contributor

Follow-up to #28, addressing the Standards axis of the code review — which reported after that PR merged rather than before. No behaviour change: all 199 tests pass unchanged, and each of #28's three original reproductions was re-run and still resolves correctly.

Duplicated Code — the pointed one

listSourcePluginDirs was discoverSourcePlugins's scan loop copied verbatim: same exists guard, same readdir({ withFileTypes: true }), same dotfile/non-dir skip, same isSourcePluginDir call. Two copies of "what counts as a source plugin" will drift — which is the bug class this entire 1.0 review is about, and #28's own PR body argued that avoiding that duplication was the reason for putting the helper in config.ts. It then duplicated the loop anyway.

discoverSourcePlugins is now expressed over listSourcePluginDirs, so there is one definition.

Duplicated Code — second instance

managed.ts's pathsEqual(a, root) || isUnder(a, root) was fs.ts's isInside plus folding. Replaced with one exported isInsideFolded beside isInside. That also removes a Mysterious Name: isUnder vs isInside gave a reader no hint which of the two folded case.

Data Clump

All three call sites passed project.rootDir, project.config, project.configPath — which is exactly ResolvedProjectConfig. buildDeleteGuard(project, force) collapses #28's sync→async ripple to one signature.

It deliberately still takes the loaded config rather than plugin-discovery results. The reviewer's stronger suggestion — derive the guard at load time, since loadConfig already discovered those directories — would couple clean to a working build, and clean not requiring one is load-bearing (it's often why someone is cleaning). The shallow readdir is the price of that independence.

Smaller

  • missing.reverse() was safe — it sat on the return line and the function exited immediately — but the safety depended on a reader noticing the adjacent return. [...missing].reverse() costs nothing and removes the reasoning step.
  • Dropped incident framing from two comment blocks ("the shape of test that was missing when this class of bug shipped twice"), keeping the behavioural rationale.

Still open from the review

The Spec axis never reported — two escalations, no output. And one question neither axis resolved: whether main's existing test refuses to clean the default source.plugins root even when unset in config still asserts correct behaviour under the narrowed guard. My read is that it does, because its fixture's plugins/demo contains a skills/ component dir and so is a genuine discovered source plugin — but I wrote both that test and the fix, so it's noted rather than closed.

🤖 Generated with Claude Code

Follow-up to #28. The Standards axis of the code review reported after that PR
merged; these are its findings. No behaviour change — all 199 tests pass
unchanged and each of #28's three reproductions was re-run and still resolves
correctly.

Duplicated Code, and the pointed one: listSourcePluginDirs was
discoverSourcePlugins's scan loop copied verbatim — same exists guard, same
readdir({withFileTypes}), same dotfile/non-dir skip, same isSourcePluginDir. Two
copies of "what counts as a source plugin" drift, which is the bug class this
whole review is about, and #28's own PR body claimed avoiding that duplication
was the reason for putting the helper in config.ts. discoverSourcePlugins is now
expressed over listSourcePluginDirs.

Second instance: managed.ts's `pathsEqual(a, root) || isUnder(a, root)` was
fs.ts's isInside plus folding. Replaced by one exported isInsideFolded beside
isInside, which also removes a Mysterious Name — isUnder vs isInside gave no
hint which one folded case.

Data Clump: all three call sites passed project.rootDir, project.config,
project.configPath, which is just ResolvedProjectConfig. buildDeleteGuard now
takes (project, force), collapsing #28's sync->async ripple to one signature.
Deliberately keeps taking the loaded config rather than discovery results, so
clean still works when the source tree no longer loads.

missing.reverse() was safe — it sat on the return line and the function exited
immediately — but safety depended on a reader noticing the adjacent return.
[...missing].reverse() costs nothing and removes the reasoning step.

Comment style: dropped incident framing from two blocks, keeping the rationale.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@steve-calvert-glean steve-calvert-glean added the internal Internal refactoring, cleanup, or maintenance work label Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal Internal refactoring, cleanup, or maintenance work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant