Skip to content

Add preset update convenience wrapper - #4599

Open
digimangos wants to merge 13 commits into
github:mainfrom
digimangos:feat/preset-update-command
Open

digimangos wants to merge 13 commits into
github:mainfrom
digimangos:feat/preset-update-command

Conversation

@digimangos

@digimangos digimangos commented Sep 15, 2026

Copy link
Copy Markdown

Description

Adds specify preset update as a deliberately destructive convenience command that runs the existing preset removal flow followed by the existing preset addition flow. It forwards the replacement source and priority options without introducing separate update semantics, rollback, staging, or reconciliation optimizations.

Acceptance criteria

Command contract

  • specify preset update <preset-id> requires one already-installed preset ID.
  • An unknown preset ID exits non-zero without invoking add.
  • Update supports the existing add options --from, --dev, and --priority.
  • --from and --dev remain mutually exclusive.
  • Update does not support --all or --dry-run in this iteration.

Update behavior

  • Update invokes the existing preset remove behavior first, followed by the existing preset add behavior only when removal succeeds.
  • The preset ID and any supplied --from, --dev, or --priority values are forwarded to add without introducing separate update semantics.
  • An explicit --from or --dev value determines the replacement source. Update does not attempt to recover or reuse the previous installation source.
  • Without --from or --dev, update performs add's normal bundled and catalog resolution by preset ID, regardless of how the previous installation was sourced.
  • An explicit --priority value becomes the replacement preset's priority. When omitted, add uses its normal default of 10.
  • Normal remove and add reconciliation both run. Update does not merge or special-case either pass.

Failure behavior

  • If remove fails, add is not attempted and update exits non-zero without claiming the previous preset is intact.
  • If add fails, update exits non-zero and clearly states that the previous preset was removed.
  • Add failure output includes a copy-pastable specify preset add command with the requested preset ID and supplied source and priority options.
  • Existing remove and add error output is preserved.
  • Invalid priority values are rejected before removal, preventing a destructive update that could only produce an invalid retry command.

Documented limitations

  • Update is destructive. The installed preset is removed before the replacement source is downloaded or fully validated.
  • Update performs no source pre-flight, version comparison, manifest diff, staging, rollback, automatic repair, or recovery transaction.
  • A missing, invalid, incompatible, or changed --from or --dev source may leave the preset removed.
  • A successful update re-enables a previously disabled preset, recreates installed_at, and removes local modifications through normal remove and add behavior.
  • Supplying --from or --dev intentionally changes the replacement source.
  • With --from or --dev, add installs the source manifest's preset ID. A mismatched source can therefore remove the requested preset and install a differently identified preset.
  • When constitution-template and constitution-sync apply, removal reconciles the generated constitution against the intermediate stack and successful addition reconciles it against the final stack.
  • The generated-file guard continues to protect a hand-edited .specify/memory/constitution.md.
  • If addition fails after removal, the generated constitution may remain reconciled against the stack without the removed preset.
  • Update introduces no constitution-specific optimization. Normal remove and add passes may rewrite generated constitution content even when the final resolved content is unchanged.

Testing

  • .venv/bin/python -m pytest tests/test_presets.py -q
    • 684 preset tests pass.
  • CLI help exposes the required preset ID and only --from, --dev, and --priority update options.
  • Testing on local repository using copilot to repeat automation.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Code generated by Copilot CLI, reviewed by Copilot Code Review Agent.

Closes #4427

Copilot AI balanced review requested due to automatic review settings September 15, 2026 17:28

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

🟢 Approval recommended

The implementation matches the stated contract and includes comprehensive failure and workflow coverage.

Review tier: Balanced
Findings: None

What changed in this PR

Adds a destructive preset update wrapper using existing remove/add flows.

Changes:

  • Adds update orchestration, validation, and recovery guidance.
  • Documents destructive behavior and limitations.
  • Adds unit and end-to-end coverage.
File Description
src/​specify_cli/​presets/​_commands.py Implements update and shared priority validation.
tests/​test_presets.py Tests orchestration and failures.
tests/​integration/​test_preset_update_workflow.py Tests real CLI workflows.
docs/​reference/​presets.md Documents usage and risks.

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

@digimangos
digimangos marked this pull request as ready for review September 15, 2026 17:39
@digimangos
digimangos requested a review from mnriem as a code owner September 15, 2026 17:39
@mnriem mnriem added the triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review label Sep 16, 2026
@mnriem

mnriem commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Thanks @digimangos — this follows the smaller remove-then-add scope we agreed on.

Before merging, please correct the Windows retry-command quoting. list2cmdline() leaves shell metacharacters such as & unquoted, so URLs and paths can become separate commands in PowerShell/CMD. Please use quoting appropriate to the advertised shell and cover that case with a regression.

Please also correct the missing or malformed Assisted-by: commit trailers. No broader update-engine changes are needed.

Drafted for @mnriem by GitHub Copilot (model: GPT-6 Astra).

@mnriem mnriem added author-needs-disclosure AI use, or the agent/model/settings behind it, not disclosed per CONTRIBUTING author-awaiting Waiting on author response author-needs-tests Real change but missing a regression test — add one that fails before / passes after labels Sep 17, 2026
Copilot AI review requested due to automatic review settings September 17, 2026 11:50
@digimangos
digimangos force-pushed the feat/preset-update-command branch from cf79748 to 8d85620 Compare September 17, 2026 11:50

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

🟢 Approval recommended

The implementation matches the stated command contract and has comprehensive unit, integration, and documentation coverage.

Review effort: Balanced
Findings: None

digimangos and others added 13 commits September 17, 2026 12:53
Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Assisted-by: GitHub Copilot Autofix (autonomous)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Assisted-by: GitHub Copilot Autofix (autonomous)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Document that update does not preflight-check replacement manifest IDs for --from and --dev sources.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 29b77f74-30d5-4969-981b-07a05607e971
Use the same command-line rendering rules as preset update so the retry-command test passes on Windows and POSIX systems.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 29b77f74-30d5-4969-981b-07a05607e971
specify preset update foo --priority 0 removed foo before add rejected the
priority, leaving the preset gone and printing a retry command that carried
the same rejected value, so the retry could never succeed. Validate priority
before preset_remove runs.

Extract the check into _validate_priority so add, set-priority, and update
cannot drift apart on the accepted range or the message they print. The
substitution in add and set-priority is behaviour-preserving: same condition,
same message, same exit code.

Also pass explicit option values in the direct-call update tests. Two of them
previously omitted from_url/dev, leaving Typer OptionInfo defaults in place;
because those objects are truthy, the tests exercised the mutually-exclusive
branch rather than the path they described.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 29b77f74-30d5-4969-981b-07a05607e971
State that a failed add after removal can leave a generated constitution
reconciled against the stack without the removed preset, and that the
normal remove and add passes may rewrite it even when the final resolved
content is unchanged.

Assisted-by: GitHub Copilot (model: claude-opus-5, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Correct documentation spelling to behavior, synchronization, and optimization.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add end-to-end coverage for successful preset replacement and failed replacement retry recovery. Update the preset documentation to describe manifest-diff limitations.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercise Typer parsing for the required preset ID, unsupported options, and help output.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject explicitly supplied empty --from and --dev values before removing the installed preset, and treat supplied options as mutually exclusive regardless of their contents.

Assisted-by: GitHub Copilot (model: gpt-5.6-luna, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A preset ID starting with a hyphen satisfies manifest validation but Typer parses it as an option, so the printed retry command could not be copy-pasted. Place the source and priority options before a -- separator for such IDs, preserving the existing order for normal ones.

Assisted-by: GitHub Copilot (model: claude-opus-5, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Render Windows recovery commands explicitly for PowerShell, using literal argument quoting so shell metacharacters remain part of URLs and paths. Add regression coverage against a real PowerShell parser when available.

Assisted-by: GitHub Copilot (model: HydraFusion, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@digimangos
digimangos force-pushed the feat/preset-update-command branch from 8d85620 to 8b5f516 Compare September 17, 2026 11:54
@digimangos

Copy link
Copy Markdown
Author

@mnriem that should be the items covered that you mentioned above.

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

Labels

author-awaiting Waiting on author response author-needs-disclosure AI use, or the agent/model/settings behind it, not disclosed per CONTRIBUTING author-needs-tests Real change but missing a regression test — add one that fails before / passes after triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: specify preset update single update convenience wrapper around the existing remove and add operations

3 participants