* fix(ai): let the fix step own config.yaml, and require the patch-counter bump The premise that the fix step cannot touch config.yaml turned out to be wrong, and the real problem was the opposite of what it looked like. config.yaml was already in scope — issue-fix.md lists it among the files the sweep reads and owns, and all three merged ai-fix PRs edited it. What they edited, though, was the one thing hard limit 2 forbade outright: PR #2970 qbittorrent version: "5.2.3.2" -> "5.2.3.3" PR #2912 bazarr version: "1.6.0.1" -> "1.6.0.2" Both bumped only the LOCAL PATCH COUNTER, leaving the upstream X.Y.Z alone — i.e. exactly the right thing, in direct violation of the written rule. Nothing enforces that rule (ai_guard_paths.sh only covers .github/ and .templates/), so it has been quietly contradicted by practice, and it also contradicts CLAUDE.md's own PR requirement to bump version. It matters because Supervisor will not offer a rebuild without the bump: a fix merged without one ships inert while the issue looks closed. That is the worst outcome available — worse than not fixing it. So the carve-out is narrowed to what addons_updater actually owns (the `upstream` field and the upstream X.Y.Z), and bumping the trailing .N is now required rather than forbidden, with the dot-not-hyphen trap called out (X.Y.Z-N reads as a semver pre-release and Supervisor treats it as older). Exotic version shapes — LSIO tags, dates, nightlies — are explicitly left alone rather than guessed at. Applied to all four places the rule is stated so they cannot drift: issue-fix.md, issue-execute-plan.md, CLAUDE.md, and pr-coderabbit.md — the last keeps the restriction, since it amends a PR whose single bump already covers it, but now says why instead of reading as a contradiction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ai): derive the patch counter from updater.json, not from version's shape Six review findings, all reproduced against the repo before accepting. Codex (P1) — the rule "increment the trailing .N" is wrong for most of this repo, because you cannot tell a local counter from an upstream component by looking at `version`. Checked all 134 add-ons: version == upstream_version (no counter, must APPEND .1): 82 version == upstream_version + .N (counter, INCREMENT): 8 version drifted from upstream (LEAVE ALONE): 36 no usable updater.json (LEAVE ALONE): 8 So the previous wording would have mutated updater-owned data on 82 add-ons: sonarr's 4.0.19.3001 IS the upstream version, and incrementing it to 4.0.19.3002 burns the identifier of a future real release; linkwarden's 2.16.0 would have become 2.16.1, indistinguishable from an upstream minor bump. updater.json's upstream_version is now the authority: append .1 when version equals it, increment only the digits that follow it, otherwise leave version alone. Validated by running the rule as written over every add-on — 0 violations of the invariant that a bumped version must still start with upstream_version. Copilot — there is no `upstream:` key in any config.yaml (0 of 134); upstream tracking lives in updater.json as upstream_repo / upstream_version. That was inherited text naming a field that does not exist, in all four places. Replaced with the real constraint: never edit updater.json. Copilot — the "a workflow step enforces them" headers over-claimed. Only limit 1 is machine-enforced (ai_guard_paths.sh); the rest ship silently if broken, which is worth saying plainly given limit 2 has been quietly contradicted by practice for months. Copilot — Outcome B produces a plan and no PR, so "say so in the pull request body" had no place to land. Now covers both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
3.6 KiB
Execute an approved plan — tier 3
@alexbelgium reviewed an AI-written plan and approved it. Your job is to carry that plan out and open a pull request. The plan was already accepted, so do not re-litigate it — execute it. The only judgement left to you is whether the plan still applies to the current source.
Read:
/tmp/ai-exec/plan.md— the approved plan (root cause, the exact files and diff, verification, risk). This is your spec./tmp/ai-exec/issue.json— the issue it fixes (forCloses #<n>and context).
Hard limits (identical to the fix sweep; only limit 1 is machine-enforced)
- Never modify
.github/or.templates/. Repo-wide infrastructure. config.yamlis yours to edit, except the upstream part ofversion; never editupdater.json—addons_updaterowns both. (There is noupstream:key inconfig.yaml.) You must still bump the local patch counter, or Supervisor never offers the rebuild and the fix ships inert. Readupdater.jsonto find the boundary — you cannot tell it fromversionalone, since upstream versions here run to four or five components. WithU=upstream_version: ifversionequalsU, append.1(sonarr4.0.19.3001->4.0.19.3001.1); if it isU+.+ digits, increment those digits (radarr6.3.0.10514.1->6.3.0.10514.2); anything else — noupdater.json, drifted version, LSIO tag, date, nightly — leaveversionalone and say so in the pull request body. A dot, never a hyphen.- One add-on, one branch:
ai-fix/<addon>-<issue-number>. - Never merge, never close the issue, never enable auto-merge. Open the
pull request ready for review — CI (
onpr_check-pr.yaml) validates it, a human ships it.
Do this in order
-
Apply the plan. Make exactly the edits it describes. Match surrounding style (bash / Dockerfile; conventions vary per add-on). Run
shellcheckon any shell you change. Add aCHANGELOG.mdentry in the add-on's format. -
If the plan is stale — the source moved since it was written and the diff no longer applies cleanly:
- Small drift (a line shifted, a nearby rename): adapt minimally to achieve the plan's stated intent, and note the deviation in the PR body.
- Large drift (the root cause or the target code is gone or now different):
stop. Do not guess a new fix. Comment on the issue explaining why the
plan no longer applies, relabel
ai:needs-human(see step 5), open no PR.
-
Open the pull request, ready for review. Body: the root cause with file and line, what the change does, how you verified it (or an explicit statement that you could not), any deviation from the plan, and
Closes #<n>. Note that it was executed from an approved plan. -
Comment on the issue with the root cause in plain language (the reader is a Home Assistant user) and the pull request link. Close with a note that this is automated analysis pending Alex's review.
-
Relabel, as your last action:
gh issue edit <n> --remove-label ai:approved --remove-label ai:plan-pending --add-label <result><result>isai:fixedif you opened a PR, orai:needs-humanif the plan was too stale to apply (step 2). A workflow step also strips the approval labels afterwards and flagsai:needs-humanif no PR resulted — treat that as a bug in your run, not a safety net.
Keep the change within the spirit of the approved plan. If carrying it out
honestly requires substantially more than the plan described, that is a sign the
plan was wrong — stop and relabel ai:needs-human rather than expanding scope.