Skip to content

feat(presets): support regex resource selectors - #4776

Open
lmtyy wants to merge 13 commits into
github:mainfrom
lmtyy:feat/4659-regex-preset-selectors
Open

lmtyy wants to merge 13 commits into
github:mainfrom
lmtyy:feat/4659-regex-preset-selectors

Conversation

@lmtyy

@lmtyy lmtyy commented Sep 28, 2026

Copy link
Copy Markdown

Add regex: selectors for preset templates, scripts, and commands. Existing exact-name matching remains unchanged; regex patterns are validated and matched against complete resource names.

Command selectors are expanded to concrete lower-layer command names before registration, keeping selector expressions out of command filenames and registry records. Reconciliation and diagnostics handle matched resources across preset lifecycle changes.

Closes #4659

Testing

  • Tested locally with uv run specify --help
  • Ran the full test suite: 8415 passed, 211 skipped
  • Ran targeted selector, resolver, manifest, and command lifecycle tests: 376 passed
  • Ran Python parity tests: 98 passed, 2 skipped
  • Ran Ruff checks, ShellCheck, PowerShell syntax parsing, Python compilation, and git diff --check

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: Implemented with Hermes Agent (Nous Research), using the gpt-6-Astra model in an interactive, human-supervised workflow. AI assistance was used for code changes, tests, debugging, and validation; the contributor should review the final diff before merging.

Add regex:<pattern> selectors for preset templates, scripts, and commands while preserving exact-name behavior. Validate regex patterns and use full-name matching. Expand command selectors to concrete lower-layer commands before registration and reconcile affected commands across preset lifecycle changes.

Add selector, resolver, command lifecycle, and diagnostic coverage. Verified with the full test suite (8415 passed, 211 skipped), Ruff, ShellCheck, PowerShell syntax parsing, Python compilation, and git diff --check.

Closes github#4659

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Command resolution, skill registration, diagnostics, warnings, and lifecycle reconciliation have unresolved functional gaps.

Review effort: Balanced
Findings: 3 High severity · 2 Medium severity

Open (5)
What changed in this PR

Adds regex: resource selectors to preset resolution and command materialization.

Changes:

  • Validates and full-matches regex selectors.
  • Expands command selectors and adds lifecycle reconciliation.
  • Adds resolver and selector coverage.
File Description
tests/​specify_cli/​presets/​test_regex_selectors.py Tests selector matching and resolution.
src/​specify_cli/​presets/​command_set_priority.py Reconciles commands after priority changes.
src/​specify_cli/​presets/​command_info.py Displays selector matches.
src/​specify_cli/​presets/​command_enable.py Reconciles enabled preset commands.
src/​specify_cli/​presets/​_selectors.py Implements selector helpers.
src/​specify_cli/​presets/​_resolver.py Resolves regex template and script layers.
src/​specify_cli/​presets/​_manifest.py Validates regex expressions.
src/​specify_cli/​presets/​_manager.py Integrates expansion into lifecycle handling.
src/​specify_cli/​presets/​_manager_commands.py Expands command selectors.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/specify_cli/presets/_resolver.py Outdated
Comment thread src/specify_cli/presets/_resolver.py Outdated
Comment thread src/specify_cli/presets/command_info.py Outdated
Comment thread src/specify_cli/presets/_manager.py
Comment thread src/specify_cli/presets/_manager_commands.py
@mnriem

mnriem commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

Add regex:<pattern> selectors for preset templates, scripts, and commands while preserving exact-name behavior. Resolve all matching declarations in manifest order, expand command selectors before registration, and reconcile matches after preset and extension changes. Add selector diagnostics and regression coverage.

Closes github#4659
@lmtyy

lmtyy commented Sep 28, 2026

Copy link
Copy Markdown
Author

Addressed all five Copilot review findings:

  • Added command regex selectors to normal layer resolution and composition.
  • Preserved all matching regex declarations in manifest order.
  • Fixed the invalid _selectors imports used by diagnostics.
  • Reused selector expansion for AI-skill registration.
  • Added selector-aware reconciliation for relevant preset/extension lifecycle changes.

Also added regression coverage for overlapping selectors, command composition strategies, diagnostics, AI-skill registration, and lifecycle state changes.

Validation:

  • 8624 passed, 17 skipped
  • 183 targeted regression tests passed
  • Ruff passed
  • Python compilation passed
  • git diff --check passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@mnriem mnriem added the triage-can-wait Verdict: valid and in-scope but deprioritized; held behind the evidence gate label Sep 28, 2026
@lmtyy

lmtyy commented Sep 29, 2026

Copy link
Copy Markdown
Author

All previous Copilot review findings have been addressed and the updated test suite is passing. The latest Copilot re-review appears to have failed due to a review error, so the PR is ready for another review when convenient.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Selector lifecycle paths can leave stale commands or skills and several acceptance criteria remain incomplete.

Review effort: Balanced
Findings: 6 Medium severity

Open (6)

Comment thread src/specify_cli/presets/_manager.py Outdated
Comment thread src/specify_cli/presets/_manager.py
Comment thread src/specify_cli/presets/_manager_skills.py
Comment thread src/specify_cli/presets/command_info.py Outdated
Comment thread src/specify_cli/presets/command_set_priority.py Outdated
Comment thread tests/specify_cli/presets/test_regex_selector_lifecycle.py Outdated
@mnriem

mnriem commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

Add install-time warnings for unmatched template, script, and command selectors while keeping zero-match selectors non-fatal.

Reconcile constitution snapshots when regex selectors target the constitution template, and preserve concrete command matches during AI skill registration and reconciliation.

Include extension manifest-declared resources in selector diagnostics so reported matches stay consistent with actual resolver behavior.

Handle preset and extension lifecycle changes using selector-aware reconciliation to remove stale command and skill artifacts and restore newly matching resources.

Make priority-change reconciliation failures consistent with existing lifecycle behavior and add regression coverage for enable, disable, priority, diagnostics, constitution, and skill scenarios.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Selector lifecycle transitions can leave stale or untracked command and skill artifacts.

Review effort: Balanced
Findings: 3 Medium severity · 2 Low severity

Open (5)
Resolved since last review (6)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Stale artifacts remain when selectors lose all matches

src/​specify_cli/​extensions/​_commands.py:121

This refresh runs only after the extension state has changed, so a selector whose sole lower layer was disabled or removed now expands to nothing. register_enabled_presets_for_agent() never sees the previously materialized concrete name, and its reconciler also skips names with no remaining layers, leaving the old command/SKILL artifact active. Capture the pre-mutation matches (or persisted registrations), reconcile the union with post-mutation matches, and explicitly unregister names that no longer resolve.

Comment thread src/specify_cli/presets/_manager_commands.py
Comment thread src/specify_cli/presets/_manager_commands.py Outdated
Comment thread src/specify_cli/presets/_manager_commands.py Outdated
Comment thread src/specify_cli/presets/command_info.py
Comment thread tests/specify_cli/presets/test_regex_selector_lifecycle.py
text
- Expand regex command selectors before resolving layers and registering AI skills.
- Track concrete command and skill names for regex-owned and composed commands.
- Reconcile generated artifacts when presets are disabled or re-enabled.
- Preserve the Templates count in preset info output.
- Add end-to-end tests for selector artifact lifecycle and composition.

Validation:
- 8,626 passed, 17 skipped
- Ruff checks passed
- git diff --check passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Selector cleanup, disabled-extension resolution, and installation rollback still have correctness gaps.

Review effort: Balanced
Findings: 1 High severity · 3 Medium severity

Open (4)
Resolved since last review (5)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Selector expansion failure leaves partial installation

src/​specify_cli/​presets/​_manager.py:456

Selector diagnostics and expansion run after the preset directory and registry entry are created but before the existing rollback guard. _expand_command_selectors() deliberately raises when artifact enumeration fails, so such a failure leaves an enabled, partially installed preset behind. Move both calls into the guarded installation phase so the established cleanup executes.

Medium severity Re-enumeration causes false failure after registration

src/​specify_cli/​presets/​_manager.py:507

This repeats artifact enumeration outside the transactional registration block. If inventory changes or becomes unreadable after registration, the command reports installation failure even though the preset and artifacts are already committed. Reuse the concrete command_templates computed for registration.

Comment thread src/specify_cli/presets/_resolver.py Outdated
Comment thread src/specify_cli/integrations/_command_upgrade_layout.py Outdated
Comment thread src/specify_cli/presets/_manager_commands.py
Comment thread src/specify_cli/presets/command_disable.py Outdated
@mnriem

mnriem commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

- Track expanded selector matches through preset and extension lifecycle operations.
- Clean up generated command and skill artifacts when providers are disabled or removed.
- Preserve registry provenance and restore prior installs when preset or extension installation fails.
- Add lifecycle and failure-injection regression tests.
@lmtyy

lmtyy commented Sep 30, 2026

Copy link
Copy Markdown
Author

@mnriem I've addressed the latest Copilot feedback in commit 1ce59c1, including the disabled-extension fallback, include_disabled handling, stale selector tracking/cleanup, and install rollback coverage.

When convenient, could you please re-request the Copilot review? Thanks!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Selector rollback, disabled-state handling, and extension-layer deduplication contain unresolved correctness issues.

Review effort: Balanced
Findings: 1 High severity · 5 Medium severity

Open (6)
Resolved since last review (3)

Comment thread src/specify_cli/extensions/__init__.py Outdated
Comment thread src/specify_cli/integrations/_command_upgrade_layout.py Outdated
Comment thread src/specify_cli/presets/_manager.py Outdated
Comment thread src/specify_cli/presets/_resolver.py Outdated
Comment thread src/specify_cli/presets/command_disable.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread src/specify_cli/extensions/__init__.py Outdated
Comment thread src/specify_cli/presets/_resolver.py Outdated
Comment thread src/specify_cli/presets/command_info.py Outdated
Comment thread src/specify_cli/presets/command_set_priority.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread src/specify_cli/extensions/_commands.py Outdated
Comment thread src/specify_cli/presets/_manager.py
Comment thread src/specify_cli/presets/_resolver.py Outdated
@mnriem

mnriem commented Sep 30, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

Reconcile historical command and skill destinations across preset enable and disable, including post-enable regex matches and integration changes.

Unify ordered selector resolution for direct and composed lookups, and normalize malformed regex compilation failures as preset validation errors.

Propagate failures through atomic priority and extension enable paths so selector artifacts, ownership, registry state, and winner state are restored consistently.

Preserve kept-config recovery while restoring newly published extension eligibility and preset ownership after failed operations.

Add lifecycle, filesystem, fault-injection, and resolver contract regressions covering historical fallback, regex ordering, partial writes, and disabled-provider behavior.

Verified with 9550 passed, 18 skipped, plus Ruff, Python compile, pre-commit, and git diff checks.
@lmtyy

lmtyy commented Oct 6, 2026

Copy link
Copy Markdown
Author

Thanks for your patience, and sorry for the delayed update. I’ve been a bit busy over the past few days, but I’ve now finished working through the latest feedback and completed the remaining fixes.

I’ve also added regression coverage for the issues that came up and verified the changes against the full test suite.

Really appreciate the review and your patience with the follow-up.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment on lines +70 to +72
# Extension reordering can change the lower-layer candidates matched by
# enabled preset regex selectors.
_commands._refresh_presets_and_warn(project_root)
Comment on lines +270 to +273
if is_regex_selector(tmpl["name"]):
try:
compile_name_selector(tmpl["name"])
except REGEX_COMPILE_ERRORS as exc:
Comment on lines +104 to +115
manager.registry.update(preset_id, {"enabled": False})
try:
names.update(
manager._collect_selector_command_names(PresetResolver(project_root))
)
if names:
manager._reconcile_composed_commands(
sorted(names), extra_agents=historical_agents or None
)
manager._reconcile_skills(
sorted(names), extra_skills_dirs=historical_skills_dirs or None
)
@mnriem

mnriem commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback and resolve conflicts

lmtyy added 2 commits October 7, 2026 12:19
Add regression coverage for selector recomposition after extension reprioritization and for selector-generated artifact cleanup and fallback recomposition after extension removal.

Document regex preset selector syntax, full-match expansion semantics, zero-match behavior, and the lifecycle of generated command and skill artifacts when presets are disabled.

No production behavior changes are required because the reviewed lifecycle paths already implement the expected reconciliation semantics.

Verified with 9560 passed, 18 skipped, plus Ruff, compile, markdownlint, and git diff checks.
Resolve the upstream conflict in tests/specify_cli/workflows/test_catalog_versions.py while preserving both sides of the catalog archive determinism changes.

Keep the upstream versioned catalog updates and regression coverage alongside the existing selector-related changes in this branch.

Verified the merged tree with targeted tests, package tests, Ruff, compile checks, markdownlint, git diff checks, and the full test suite.

Full test suite: 10108 passed, 19 skipped.
@lmtyy

lmtyy commented Oct 7, 2026

Copy link
Copy Markdown
Author

@mnriem Thanks for your patience. I’ve addressed the latest Copilot feedback, resolved the upstream merge conflict, and pushed the updated changes.

The full test suite is passing locally, and the branch should now be ready for another review.

Thanks again for your time!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment on lines 68 to 72
for historical_agent in sorted(historical_agents):
manager.unregister_agent_artifacts(
historical_agent, extension_ids={extension_id}
)
manager.registry.update(extension_id, {"enabled": False})
Comment on lines +77 to +80
_capture_preset_artifacts(
preset_manager,
snapshot,
extra_commands=manager._collect_manifest_command_names(manifest),
Comment on lines +68 to +72
manager.registry.update(extension_id, {"priority": priority})

console.print(f"[green]✓[/green] Extension '{_escape_markup(str(display_name))}' priority changed: {old_priority} → {priority}")
console.print("\n[dim]Lower priority = higher precedence in template resolution[/dim]")
# Extension reordering can change the lower-layer candidates matched by
# enabled preset regex selectors.
_commands._refresh_presets_and_warn(project_root)
@mnriem

mnriem commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback and resolve conflicts

lmtyy added 2 commits October 8, 2026 09:27
…k safety

Make extension disable operations transactional across historical agents, ensuring that partial cleanup failures restore artifacts, registry state, and ownership information.

Expand extension enable rollback snapshots to include conventional command resources and selector-generated global skill artifacts.

Implement strict extension priority reconciliation with automatic rollback when command or skill updates fail.

Improve cross-platform test compatibility by addressing Windows path normalization, invalid filenames, and encoding issues.

Add regression tests covering partial cleanup failures, successful disablement, rollback recovery, extension enable failures, and priority changes.

Verify 10416 tests passed and 19 skipped locally, with Ruff, Python compilation, markdownlint, and Git diff checks passing.

Windows CI verification remains pending.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-can-wait Verdict: valid and in-scope but deprioritized; held behind the evidence gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support regex selectors for preset commands, templates, and scripts

3 participants