G
YouTube TikTok Games
Skip to content

ISSUE-457: Let packs declare supported scopes - #460

Open
bguidolim wants to merge 8 commits into
mainfrom
bruno/ISSUE-457-pack-supported-scopes
Open

bguidolim wants to merge 8 commits into
mainfrom
bruno/ISSUE-457-pack-supported-scopes

Conversation

@bguidolim

Copy link
Copy Markdown
Collaborator

Summary

A pack that only works in a project could be installed globally, where its configure script never runs and __REPO_NAME__ stays unresolved in ~/.claude/CLAUDE.md. Packs can now declare which scopes they support, and sync refuses to add them anywhere else. #411 (scope-routed bootstrap) builds on this.

Closes #457

Release note

  • NEW: packs can declare scopes: [project] or scopes: [global] in techpack.yaml; mcs sync refuses to add a pack to a scope it doesn't support, and --all skips it
  • mcs doctor warns about a pack installed in a scope it no longer supports
  • mcs pack validate warns when a pack uses project-only features but allows global scope

Changes

  • scopes: manifest field; absent means both scopes
  • The check only rejects packs being added, so mcs update and doctor --fix keep re-applying a pack installed before it declared scopes:
  • --pack and --dry-run exit non-zero on a mismatch; --all skips with a warning; the picker hides those packs
  • Unknown scopes: values fail mcs pack validate but are dropped with a warning at sync time

Test plan

  • swift test passes locally
  • swiftformat --lint . and swiftlint pass without violations
  • Affected commands verified with a real pack (e.g. mcs sync, mcs doctor)
  • Local pack with scopes: [project]: mcs sync --global --pack <id> exits non-zero and ~/.claude is unchanged
  • Same pack with __REPO_NAME__ in a template and no scopes:: mcs pack validate warns
Checklist for engine changes
  • Integration tests updated for new features (LifecycleIntegrationTests or DoctorRunnerIntegrationTests)
  • Docs updated if behavior changed (CLAUDE.md, docs/, techpack.yaml schema in ExternalPackManifest.swift)

- `scopes:` in techpack.yaml (absent = both); validate errors on bad values, sync strips them with a warning
- Configurator rejects adding a pack to an unsupported scope before any change; --all skips such packs, the picker hides them
- Doctor warns on a pack already installed in an unsupported scope; validate warns on project-only features without `scopes: [project]`
- `scopes:` field, validation rule and project-only-features heuristic in the schema reference
- When to declare `scopes: [project]` in the pack authoring guide
- Scope-mismatch behavior for sync and doctor in the CLI reference and CLAUDE.md
- `supportedScopes` has no protocol default, so a wrapper that forgets to forward it no longer compiles
- `--all` and the global-block filter share one skip notice; the scope lives once on SyncScope
- Project-only placeholder keys come from project sync's own built-in key list

Copilot AI 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.

🟡 Changes recommended

Scope validation can be bypassed before destructive pruning, and doctor can miss unsupported global installations while removing their supported project copies.

2 open issues
What changed in this PR

Adds pack-declared scope support to the shared configuration engine, preventing new installations into unsupported scopes while preserving existing installations. This also provides a foundation for global bootstrap support.

Changes:

  • Adds manifest scope declarations, validation, runtime sanitization, and scope-aware pack selection.
  • Adds doctor warnings and validation heuristics for scope incompatibilities.
  • Adds lifecycle coverage and documents scope behavior.
File Description
Tests/​MCSTests/​TestHelpers.swift Adds scope support to shared test doubles.
Tests/​MCSTests/​ResourceRefCounterTests.swift Updates the pack stub for scope support.
Tests/​MCSTests/​PackHeuristicsTests.swift Tests project-only placeholder warnings.
Tests/​MCSTests/​LifecycleIntegrationTests.swift Covers scope rejection, filtering, and legacy installations.
Tests/​MCSTests/​ExternalPackManifestTests.swift Tests scope defaults, validation, and sanitization.
Tests/​MCSTests/​DestinationCollisionResolverTests.swift Updates the wrapper test double.
Tests/​MCSTests/​CrossPackPromptResolverTests.swift Updates the prompt test double.
Tests/​MCSTests/​CLAUDELocalFreshnessCheckTests.swift Updates freshness-check test doubles.
Sources/​mcs/​TechPack/​TechPack.swift Defines pack scopes and requires scope declarations.
Sources/​mcs/​Sync/​SyncScope.swift Represents the target scope explicitly.
Sources/​mcs/​Sync/​ProjectSyncStrategy.swift Centralizes project-only placeholder keys.
Sources/​mcs/​Sync/​PackScopeError.swift Reports unsupported pack selections.
Sources/​mcs/​Sync/​DestinationCollisionResolver.swift Forwards wrapped packs’ supported scopes.
Sources/​mcs/​Sync/​ConfiguratorSupport.swift Adds scope filtering and shared skip reporting.
Sources/​mcs/​Sync/​Configurator.swift Enforces scope support and filters picker options.
Sources/​mcs/​ExternalPack/​PackHeuristics.swift Warns about project-only features in global-capable packs.
Sources/​mcs/​ExternalPack/​ExternalPackManifest.swift Adds scope parsing, validation, and sanitization.
Sources/​mcs/​ExternalPack/​ExternalPackLoader.swift Applies runtime scope sanitization.
Sources/​mcs/​ExternalPack/​ExternalPackAdapter.swift Exposes manifest-supported scopes.
Sources/​mcs/​Doctor/​PackScopeCheck.swift Defines unsupported-installation diagnostics.
Sources/​mcs/​Doctor/​DoctorRunner.swift Collects scope-support checks.
Sources/​mcs/​Commands/​SyncCommand.swift Filters unsupported additions for --all.
docs/​techpack-schema.md Documents the scope field and validation rules.
docs/​creating-tech-packs.md Explains when authors should restrict scopes.
docs/​cli.md Documents sync rejection and doctor warnings.
CLAUDE.md Updates architecture and scope-design guidance.

Review effort: Balanced

Comment thread Sources/mcs/Commands/SyncCommand.swift Resolved
Comment thread Sources/mcs/Doctor/DoctorRunner.swift Outdated
Comment on lines +248 to +250
if !pack.supportedScopes.contains(scope.packScope) {
allChecks.append((check: PackScopeCheck(packID: pack.identifier, scope: scope.packScope), syncTarget: nil))
}
- A `scopes:` list with no valid value supports no scope instead of both; publish-time validation stays strict
- Doctor reports unsupported installs from each scope's state, and won't drop a supported project copy to keep an unsupported global one
- Named packs hit the scope check before the global-block filter; errors and the picker say where a pack can go
- Merge nested ifs and repeated guards the newer nestedIf/repeatedGuard rules flag across the repo
…nt alike

- Hoist the multi-line call out of each merged guard; behavior is unchanged

Copilot AI 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.

🟡 Changes recommended

Bootstrap can bypass scope validation and prune existing project packs instead of rejecting an incompatible declaration.

2 open issues
1 resolved since last review

Review effort: Balanced

Comment on lines +339 to +343
let rejected = ConfiguratorSupport.scopeUnsupported(
requested, scope: configurator.packScope, previouslyConfigured: previouslyConfigured
)
if !rejected.isEmpty {
throw PackScopeError(packs: rejected, scope: configurator.packScope)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the stacked #461: routing is checked in partitionByScope before the global-block filter and the dry-run branch, so a misrouted global-only pack errors first. Regression test for --prune --yes and --dry-run added in a0138dd. On #460 alone the behavior matches main.

- `scopes` is a `let` like every other manifest root field, so a rebuild that forgets it no longer widens the pack to both scopes
- Loader test: runtime sanitizing keeps declared scopes, strict validation rejects an unknown one
- Adding a project-only pack globally throws before any hook file or settings entry is written
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.

Let packs declare supported scopes and enforce them on sync

2 participants