feat(buds): edit impacted_repos from BUD detail - #195
Merged
Conversation
Lets a BUD opt out of the repo-wide tracking branch and watch its own
pattern instead. Release-train BUDs whose PRs target ``release/*`` can
be tracked without retraining the global repo setting; one-off ad-hoc
release branches can be pointed at directly.
Backend
- New ``branch_overrides`` JSONB column on ``bud_documents``, keyed by
stage (``uat`` / ``prod``) with fnmatch-style values.
- ``BUDUpdate`` accepts ``branch_overrides`` and ``impacted_repos`` on
PATCH. The validator rejects unknown stage keys, empty / whitespace
patterns, and the wrong case (``"UAT"`` / ``"production"``) — typos
surface as 422 at the API edge instead of silently missing in the
filter.
- PATCH handler MERGES branch_overrides per-key so saving a UAT
override doesn't clobber an existing prod override; ``{"uat": null}``
is the clear-this-stage signal and drops the key from the merged
column. Sending ``branch_overrides: null`` wipes both stages.
- ``bud_prs.py::release_stage`` honors ``bud.branch_overrides[stage]``
before falling back to ``repo.uat_branch`` / ``repo.main_branch``.
Reuses the existing ``branch_matches()`` fnmatch utility so wildcard
semantics stay consistent with release detection.
- Editing ``impacted_repos`` after the planning phase logs
``bud_impacted_repos_edited_post_planning`` so an operator can audit
scope changes that may leave PR rows linked to repos that no longer
appear on the stage tab.
Frontend
- New ``BUDStageBranchOverride.vue`` widget rendered inside the shared
``BUDReleaseStagePanel.vue``. Shows the currently-effective pattern
(override or repo default), an Edit affordance opening an inline
dialog, and — for multi-repo BUDs — a one-line "applies to N repos"
disclosure so the per-stage scope is explicit before saving.
- Save → PATCH ``/v1/buds/{id}`` with ``branch_overrides``; on success
the panel re-fetches its stage data and emits ``refresh-bud`` so
``BUDDetail`` pulls the new override into the props feed.
- Empty input on Save and the dedicated Clear button both send
``{[stage]: null}`` — the merge-aware handler drops just that key.
Schema validator covered by 16 new parametrized tests.
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
The override widget previously described only the fnmatch half of the
filter ("Open PRs are matched against this pattern on each impacted
repo. Supports fnmatch wildcards"). After the over-match fix added the
content guard that requires PRs to also reference the BUD by number,
that copy understated what surfaces a PR on a release-stage tab.
Rewrites the in-card hint and the dialog body so both rules are
visible. The example is now per-BUD: BUD-4 sees
``release/bud-001-bud-004``, BUD-12 sees ``release/bud-001-bud-012``.
Threads ``bud_number`` from BUDDetail → BUDReleaseStagePanel → the
override widget so the copy renders the actual reference, not a
placeholder.
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
The validator hardcoded ``{"uat", "prod"}`` next to a comment that
already pointed at the existing ``Literal["uat", "prod"]`` in
``app.schemas.bud_release``. Drop the duplicate and source the
allowed-keys set from ``get_args(ReleaseStage)`` so adding a new
release-stage tab in one place automatically widens the override
contract — no second edit needed, no drift possible.
Behaviour and tests unchanged (16 cases pass).
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
The tech-arch agent's initial guess at which repos a BUD touches is
often close but not perfect — and scope sometimes drifts mid-build.
This adds an Edit affordance next to the impacted-repos chip row on
``BUDDevelopmentPanel.vue`` so a PM can correct the list without
re-running the agent or hand-editing JSON.
UI
- ``BUDImpactedReposDialog.vue`` multi-select bound to the org's
``active`` tracked repos. Filter-by-name field, in-flight loader,
per-row checkbox, count chip with ``aria-live`` so screen readers
announce selection changes.
- Repos already on the BUD but no longer ``active`` in the tracked
list render as separate "retired" rows, pre-checked. The user
consciously preserves or drops them — never silently erased.
- Always refreshes the tracked-repo list on open (one cheap GET) so
a repo added in another tab shows up in the picker before driving
a destructive PATCH. In-flight ``fetchRepos`` is memoised so
reopen-during-load is safe.
- Save → ``PATCH /v1/buds/{id}`` with the full new list. Clearing
every row when the BUD previously had repos requires a confirm
prompt — release-stage tabs and code-review status both go quiet
on empty, so the consequence is surfaced before the write lands.
- Empty-state copy on the chip row is reworded to read in any phase
(the previous imperative read as tech_arch-only).
Plumbing
- ``BUDDevelopmentPanel`` emits ``refresh-bud`` after a successful
save; ``BUDDetail`` calls ``budStore.fetchBUD`` so the chip row
updates everywhere and any downstream panel relying on
``bud.impacted_repos`` picks up the new list.
- Dialog is non-persistent so Esc and backdrop-click work; the
``persistent`` flag only activates during the in-flight save.
Backend already accepts ``impacted_repos`` on the ``BUDUpdate`` PATCH
schema and logs ``bud_impacted_repos_edited_post_planning`` for
mid-development edits — both landed in the per-BUD branch override PR
this stacks on.
Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
Vite's Vue compiler rejected the no-matches placeholder because the literal '.' between the inline v-if span and the v-else span counted as a text node, breaking the v-if/v-else adjacency rule. Move the two variants into <template v-if> / <template v-else> wrappers so the directive pair sits on directly adjacent siblings with no intervening text. Vue 3 template-compile rule — both branches still render the same wording, only the wrapping element changes. Found at runtime while testing the integration branch — would have blocked the picker from rendering whenever the filter input matched zero repos or no repos were tracked yet. Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
The Edit affordance only lived inside the empty-state branch of ``BUDDevelopmentPanel``. Once a BUD had any dev activity (commits, PRs, todos), the panel switched to the has-activity template and the button vanished — leaving no way to correct ``impacted_repos`` from the UI on a BUD that had moved past tech_arch. Reproduced on BUD-004 after promotion to development. Adds a compact impacted-repos row at the top of the activity view with the same Edit button. Mirrors the empty-state semantics — chip list when the array has entries, "none yet" otherwise — but slimmer so it sits cleanly above the stats grid. Signed-off-by: Arun Rajkumar <mickyarunr@gmail.com>
mickyarun
force-pushed
the
feat/bud-edit-impacted-repos
branch
from
June 3, 2026 06:41
3e5a7fe to
3a75aac
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets a PM correct the impacted-repos list from the BUD detail UI instead of hand-editing JSON or re-running the tech-arch agent. Adds an inline Edit affordance on
BUDDevelopmentPanel.vueand a multi-select dialog.Stacked on #194 (per-BUD branch overrides). That PR added
impacted_reposto theBUDUpdatePATCH schema and thebud_impacted_repos_edited_post_planningaudit log — this PR is purely the UI on top.What changed
BUDImpactedReposDialog.vuemulti-select bound to the org'sactivetracked repos. Filter field, in-flight loader, per-row checkbox,aria-livecount chip.activerender as separate retired rows, pre-checked. The user consciously keeps or drops them — never silently erased.settingsStore.fetchRepos()on open (one cheap GET) so a repo added in another tab shows up before driving a destructive PATCH. In-flight fetch is memoised so reopen-during-load is safe.PATCH /v1/buds/{id}with the full new list. Clearing every row when the BUD previously had repos prompts a confirm — release-stage tabs and code-review status both go quiet on empty.persistentflag only activates during the in-flight save.Test plan
vue-tsc --noEmitclean.Notes
window.confirm— that matches the existing destructive-action pattern in the codebase. A custom Vuetify dialog could replace it later if the team standardises on one shell.