Skip to content

fix: refuse pharn add when clone layout mismatches recorded layout - #77

Merged
PrzemekGalarowicz merged 2 commits into
mainfrom
add-layout-gate
Aug 9, 2026
Merged

fix: refuse pharn add when clone layout mismatches recorded layout#77
PrzemekGalarowicz merged 2 commits into
mainfrom
add-layout-gate

Conversation

@PrzemekGalarowicz

@PrzemekGalarowicz PrzemekGalarowicz commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

What this changes

pharn add copied capabilities at the clone's layout while remove / status / list address the project via configLayout. When those disagreed, adds landed where nothing looked for them — invisible to status/list, and a later remove dropped only the config entry while reporting files already gone (orphaning the dir).

This adds a layout gate (sibling of the version gate) that refuses when detectLayout(clone) !== configLayout(config), names both layouts, points at pharn update, and writes nothing. Version still wins when both mismatch (?? short-circuit). add deliberately does not stamp the clone's layout the way update does — that would re-address the rest of an install that still lives at the old paths.

Type of change

  • feat — new stack option, wizard step, or command capability
  • fix — bug fix
  • docs — docs-only change
  • chore / refactor — tooling or internal restructure, no behavior change

Area(s) touched

commands/add | tests/add | docs/commands/add | docs/reference/pharn-config | CHANGELOG | CLAUDE.md

Checklist

  • Read the existing file(s) before editing; followed the ESM .js-extension import convention.
  • Updated the matching tests/*.test.ts when wizard behavior changed (tests mirror step/lib files one-to-one).
  • Updated the relevant docs/ page (see the "Documentation maintenance" table in CONTRIBUTING.md); unimplemented behavior is marked Coming soon or linked to docs/roadmap.md.
  • Preserved the security invariants in src/lib/github.ts / src/lib/validate.ts (regex allowlists, .. checks, redirect: 'error', timeout/size caps, schemaVersion === 1) if I touched remote-input handling.

Quality gates

  • npm run check passes locally (format:check + lint + typecheck + test).
  • npm run build succeeds.
  • npm run test:coverage passes (coverage thresholds met).

Test plan

  • Named add refuses when clone is pharn and config records flat (and the reverse); message names both layouts and pharn update
  • Refusal writes nothing: no capability dir, no config write, records store unchanged
  • Picker refuses before groupMultiselect renders
  • When both version and layout mismatch, version refusal wins
  • Absent layout proceeds against a flat clone (configLayout default) and refuses against a pharn clone
  • Matching pharn/pharn path installs and records pharn/-prefixed paths

Notes for the reviewer

Look at layoutGate + the versionGate(...) ?? layoutGate(...) call sites in src/commands/add.ts first — especially why we refuse rather than recording the clone layout (unlike update). Residual same-version layout drift still needs pharn update --force because plain update early-returns on matching skillsVersion.

Made with Cursor

Summary by CodeRabbit

  • New Features

    • pharn add now checks that the fetched repository layout matches the project’s configured layout.
    • Mismatched layouts are rejected before prompts, installation, or project changes.
    • Error messages show both layouts and direct users to pharn update.
  • Bug Fixes

    • Preserved version-check precedence when both version and layout validation fail.
    • Ensured successful installations and capability records use the configured layout.
  • Documentation

    • Updated command, configuration, and changelog documentation with layout-validation behavior and migration guidance.

Prevent orphan capability dirs by gating add on detectLayout vs configLayout before any write.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@PrzemekGalarowicz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6323b8eb-0b29-478d-bba4-61d80b920ddd

📥 Commits

Reviewing files that changed from the base of the PR and between 5b1cea7 and 950d71d.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • CLAUDE.md
  • docs/commands/add.md
  • src/commands/add.ts
  • tests/add.test.ts
📝 Walkthrough

Walkthrough

pharn add now compares the fetched clone layout with the configured project layout before prompting or writing. Version validation remains first. Matching layouts use the clone layout for installation and records. Documentation, tests, and verification artifacts cover the new behavior.

Changes

Add layout gate

Layer / File(s) Summary
Gate contract and implementation plan
.dev/features/add-layout-gate/PLAN.md
Defines layout detection, gate ordering, refusal behavior, test coverage, and migration semantics.
Layout gate and add-flow coverage
src/commands/add.ts, tests/add.test.ts
Adds ordered version and layout gates to named and picker flows. Tests cover mismatches, defaults, cleanup, successful pharn installation, and record accumulation.
Command and configuration documentation
docs/commands/add.md, docs/reference/pharn-config.md, CLAUDE.md, CHANGELOG.md
Documents mismatch refusal, no-write behavior, configured-layout handling, and pharn update --force migration.
Verification and ship records
.dev/features/add-layout-gate/*, .pharn/writes-scope.json
Records planning, review, regression, verification, shipping, and write-scope results.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AddCommand
  participant LayoutGate
  participant Installer
  User->>AddCommand: run pharn add
  AddCommand->>LayoutGate: compare fetched and configured layouts
  LayoutGate-->>AddCommand: allow or refuse
  AddCommand->>Installer: install capabilities when layouts match
  Installer-->>User: report installation result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: refusing pharn add when the clone layout differs from the recorded layout.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-layout-gate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.dev/features/add-layout-gate/GRILL.md:
- Line 3: Correct the future-dated GATE 1 approval record by replacing
2026-08-09 with the verified approval date in
.dev/features/add-layout-gate/GRILL.md lines 3-3 and use that same date in
.dev/features/add-layout-gate/SHIP.md lines 10-10.

In @.dev/features/add-layout-gate/PLAN.md:
- Line 181: Update the fenced pseudocode block in PLAN.md by labeling its
opening fence with the text language identifier, resolving the Markdownlint
MD040 violation.
- Around line 294-296: Update the recorded Gate 1 approval date in the “Open
questions — RESOLVED at GATE 1” section to the actual decision date, which must
not be later than August 8, 2026; leave the resolution status and surrounding
plan text unchanged.

In @.dev/features/add-layout-gate/REVIEW.md:
- Around line 95-96: Repair the inline Markdown in the review comments so the
`update` reference does not contain nested backticks; use plain quotation marks
or a double-backtick span. Then regenerate verify-report.json from the corrected
final file so its markdown lint result reflects the fix.
- Around line 117-120: Correct the advisory finding count so the verdict matches
the actual findings, either by adding the missing advisory entry or changing the
reported count. Update `.dev/features/add-layout-gate/REVIEW.md` lines 117-120
and synchronize `.dev/features/add-layout-gate/SHIP.md` lines 34-35 with the
same count.

In `@src/commands/add.ts`:
- Around line 106-110: Update the mismatch guidance returned by layoutGate to
direct users to run `pharn update --force` instead of plain `pharn update`, so
the recorded layout is migrated before retrying `pharn add`. Update the
corresponding message assertions and documentation examples to match the new
command.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3149112e-68ec-4573-8984-919680673e0c

📥 Commits

Reviewing files that changed from the base of the PR and between a8e9aca and 5b1cea7.

📒 Files selected for processing (15)
  • .dev/features/add-layout-gate/GRILL.md
  • .dev/features/add-layout-gate/PLAN.md
  • .dev/features/add-layout-gate/REGRESSION.md
  • .dev/features/add-layout-gate/REVIEW.md
  • .dev/features/add-layout-gate/SHIP.md
  • .dev/features/add-layout-gate/VERIFY.md
  • .dev/features/add-layout-gate/regression-report.json
  • .dev/features/add-layout-gate/verify-report.json
  • .pharn/writes-scope.json
  • CHANGELOG.md
  • CLAUDE.md
  • docs/commands/add.md
  • docs/reference/pharn-config.md
  • src/commands/add.ts
  • tests/add.test.ts

@@ -0,0 +1,183 @@
# GRILL — add-layout-gate

Plan under interrogation: `.dev/features/add-layout-gate/PLAN.md` (approved at GATE 1, 2026-08-09).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Correct the future-dated approval records.

Both files state that GATE 1 was approved on August 9, 2026, while the current date is August 8, 2026. Correct both records to the verified approval date.

  • .dev/features/add-layout-gate/GRILL.md#L3-L3: replace 2026-08-09 with the verified approval date.
  • .dev/features/add-layout-gate/SHIP.md#L10-L10: use the same verified approval date.
📍 Affects 2 files
  • .dev/features/add-layout-gate/GRILL.md#L3-L3 (this comment)
  • .dev/features/add-layout-gate/SHIP.md#L10-L10
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/add-layout-gate/GRILL.md at line 3, Correct the future-dated
GATE 1 approval record by replacing 2026-08-09 with the verified approval date
in .dev/features/add-layout-gate/GRILL.md lines 3-3 and use that same date in
.dev/features/add-layout-gate/SHIP.md lines 10-10.

A single local helper in `add.ts`, mirroring `versionGate`'s shape exactly, called **once per
command**, inside each path's existing `try`:

```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language identifier to this fenced block.

Line 181 opens an unlabeled code fence. Markdownlint reports MD040 for this fence. Use text for the pseudocode block.

🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 181-181: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/add-layout-gate/PLAN.md at line 181, Update the fenced
pseudocode block in PLAN.md by labeling its opening fence with the text language
identifier, resolving the Markdownlint MD040 violation.

Source: Linters/SAST tools

Comment on lines +294 to +296
## Open questions — RESOLVED at GATE 1 (human, 2026-08-09)

Both were answered before any code was written; neither remains open. **Plan approved as written.**

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the recorded approval date.

Line 294 states that Gate 1 was resolved on August 9, 2026. That date is after the current review date of August 8, 2026. Use the actual decision date so the plan remains auditable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/add-layout-gate/PLAN.md around lines 294 - 296, Update the
recorded Gate 1 approval date in the “Open questions — RESOLVED at GATE 1”
section to the actual decision date, which must not be later than August 8,
2026; leave the resolution status and surrounding plan text unchanged.

Comment on lines +95 to +96
new comments are dense and directive in tone (`"add must NEVER record the clone's layout"`,
`"Only `update` can migrate a tree"`), and `CLAUDE.md` gained an imperative clause — but these are

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Repair the inline code span.

The backticks around update are nested inside the surrounding inline-code span. Static analysis reports markdownlint MD038 at Line 96, while verify-report.json records lint:md: 0. Use plain quotation marks or a double-backtick span, then regenerate the verification record from the final file.

🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 96-96: Spaces inside code span elements

(MD038, no-space-in-code)


[warning] 96-96: Spaces inside code span elements

(MD038, no-space-in-code)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/add-layout-gate/REVIEW.md around lines 95 - 96, Repair the
inline Markdown in the review comments so the `update` reference does not
contain nested backticks; use plain quotation marks or a double-backtick span.
Then regenerate verify-report.json from the corrected final file so its markdown
lint result reflects the fix.

Source: Linters/SAST tools

Comment on lines +117 to +120
**GREEN — 0 floor-gate findings, 4 advisory (2 important, 2 minor/other).** The increment is done by the
floor's measure: `validate` GREEN, `/pharn-dev-verify` PASS on all five gates,
`/pharn-dev-regress` `no-regressions`, 605 tests. The four advisory findings are for the human to weigh
at the post-review gate; none of them blocks, and none of them rests on anything the floor could have

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Correct the advisory finding count.

REVIEW.md lists three advisory findings, but both summaries report four. Correct the count in both files or add the missing finding.

  • .dev/features/add-layout-gate/REVIEW.md#L117-L120: change the verdict count or add the missing advisory entry.
  • .dev/features/add-layout-gate/SHIP.md#L34-L35: synchronize the ship summary with REVIEW.md.
📍 Affects 2 files
  • .dev/features/add-layout-gate/REVIEW.md#L117-L120 (this comment)
  • .dev/features/add-layout-gate/SHIP.md#L34-L35
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/add-layout-gate/REVIEW.md around lines 117 - 120, Correct the
advisory finding count so the verdict matches the actual findings, either by
adding the missing advisory entry or changing the reported count. Update
`.dev/features/add-layout-gate/REVIEW.md` lines 117-120 and synchronize
`.dev/features/add-layout-gate/SHIP.md` lines 34-35 with the same count.

Comment thread src/commands/add.ts Outdated
@PrzemekGalarowicz
PrzemekGalarowicz merged commit 74a6b40 into main Aug 9, 2026
8 checks passed
@PrzemekGalarowicz
PrzemekGalarowicz deleted the add-layout-gate branch August 9, 2026 00:38
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.

1 participant