diff --git a/docs/decisions/0027-worktree-scripts-as-plugin-commands.md b/docs/decisions/0027-worktree-scripts-as-plugin-commands.md index 786afe4..165b3be 100644 --- a/docs/decisions/0027-worktree-scripts-as-plugin-commands.md +++ b/docs/decisions/0027-worktree-scripts-as-plugin-commands.md @@ -1,6 +1,6 @@ # 0027: The worktree scripts are the plugin's commands — `adf-worktree-new`, `-ls`, `-rm` (parallel-agents module) -- **Status:** accepted; amended by [0032](0032-local-environment-layout.md) (the module's folder is `ops/agent/`; the commands read `scripts/agent/` until a project moves it) +- **Status:** accepted; amended by [0032](0032-local-environment-layout.md) (the module's folder is `ops/agent/`; the commands read `scripts/agent/` until a project moves it) and [0046](0046-a-scripted-upgrade-from-the-new-release.md) (`bin/` also carries `adf-upgrade`, a framework command the build copies from `scripts/adf-upgrade.sh`) - **Date:** 2026-10-09 - **Amends:** [0016](0016-packaged-install.md) — what a packaged project commits for a module; [0023](0023-plugins-by-concern.md) — what a module's plugin carries diff --git a/docs/decisions/0028-plugins-are-the-source.md b/docs/decisions/0028-plugins-are-the-source.md index c417972..17d066c 100644 --- a/docs/decisions/0028-plugins-are-the-source.md +++ b/docs/decisions/0028-plugins-are-the-source.md @@ -1,7 +1,7 @@ # 0028: The plugins are the machinery's source, and a committed install is written from them - **Status:** accepted; amended by [0029](0029-workflows-carry-agent-checklists.md) (the build also - generates the agent checklists `deep-review` carries) + generates the agent checklists `deep-review` carries) and [0046](0046-a-scripted-upgrade-from-the-new-release.md) (an upgrade builds both releases with `build-committed.py` from each release's own tree) - **Date:** 2026-10-09 - **Amends:** [0016](0016-packaged-install.md) — where the machinery's source lives ("generated from `skeleton/`", "the skeleton stays the single source"); [0019](0019-reference-docs-in-the-plugin.md) — diff --git a/docs/decisions/0046-a-scripted-upgrade-from-the-new-release.md b/docs/decisions/0046-a-scripted-upgrade-from-the-new-release.md new file mode 100644 index 0000000..de596b9 --- /dev/null +++ b/docs/decisions/0046-a-scripted-upgrade-from-the-new-release.md @@ -0,0 +1,265 @@ +# 0046: An upgrade runs a script from the new release, and the developer approves only what needs a person + +- **Status:** accepted +- **Date:** 2026-10-18 +- **Amends:** [0027](0027-worktree-scripts-as-plugin-commands.md) — what `bin/` carries and where it + comes from; [0028](0028-plugins-are-the-source.md) — how an upgrade diffs a committed install's + machinery + +## Context + +`/adf:upgrade` is a procedure an agent follows by hand. An adopting project on the packaged install, +with six modules, moved from v2.2.0 to v2.4.0 +([#86](https://github.com/aplyca/AgenticDevelopmentFramework/issues/86)): + +- **The agent found the releases by hand:** `gh release list`, a full clone, + `git rev-parse 'vX.Y.Z^{commit}'`, and an `awk` over `CHANGELOG.md`. +- **It merged eight files one at a time** with `git show OLD:path`, `git show NEW:path`, and + `git merge-file`. Six merged cleanly. `AGENTS.md` and `.claude/rules/deployment.md` had two + conflicting hunks each. +- **The rest was mechanical too:** rerunning the `docker` and `e2e` installers, moving the + marketplace's `ref` and adding `autoUpdate` (0041), dropping allow rules a broader one now covered, + `link-reference-docs.py --packaged`, and the restamp. +- **The developer approved a per-file plan** whose rows were mostly "clean merge". Two conflicts and + the new ask rules for the project's tasks (`dev-env`'s `SPECIFICATION.md` C9 and C10) needed a + person. +- **The hook smoke test failed with `unbound variable`.** The hooks use `set -u`, and Claude Code + always sets `CLAUDE_PLUGIN_ROOT` and `CLAUDE_PROJECT_DIR`; the agent hadn't exported them. That's + a gap in the test, not in the hooks. + +Each step costs agent calls and a chance to slip, and none of them needs judgment. A design review on +the issue found what a script has to get right before it can take them over: + +- **The pinned plugin is the old release.** An `adf-upgrade` command in `bin/` is code from OLD + upgrading to NEW, so it can't know the moves or migrations NEW added. The skill already reruns the + module installers from NEW for this reason. The skill itself is old too. +- **`bin/` is generated** (0027): every command there is a module's script, built by + `scripts/build-plugins.sh`. An upgrade command isn't a module's, and a committed install may not + have the plugin's commands on its path. +- **`git show OLD:path` isn't always the merge base.** It is for `skeleton/` and + `modules/*/files/`. A committed install's machinery comes from `build-committed.py` (0028), so both + sides have to be built. Renamed folders (`scripts/agent` → `ops/agent`), files the project deleted, + and new files are most of the work; `git merge-file` is the easy part. +- **Release-specific steps don't belong in one script.** "Add `autoUpdate`" is a step of one release. + A single script would collect every release's special case. +- **"Covered" allow rules need a narrow definition.** A permission change is exactly what the + developer should still see. +- **A clean merge can still be wrong,** a duplicated section in `AGENTS.md` for one, so the reviewer + needs to know where to look. + +## Decision + +### 1. A thin command in the plugin, the real script in the framework + +- **`adf-upgrade [] [--dry-run] [--offline] [--