From e2c9b7b92ec857f89f51b169d329b119779f0013 Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Thu, 8 Oct 2026 18:48:13 +1300 Subject: [PATCH] The Lead files an Idea for what a Dependabot update brings A new MentalDesk.Tui version reaches TuiCode and a-team as a Dependabot PR, but nothing turned it into board work: the bump only makes a new rule available, and adopting it needs an Idea on each consuming team's board. An open Dependabot PR without a Lead comment now starts a Lead run, which reads what the version brings, files an Idea per change worth adopting, and says so on the PR. One search call per trigger pass covers the whole repo. Co-Authored-By: Claude Opus 5.5 --- README.md | 3 +++ roles/lead.md | 17 +++++++++++++++-- scripts/board.sh | 8 ++++++++ tests/scripts.sh | 18 ++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6c0749..830cd33 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,9 @@ commits are authored as `[bot]`. Your own `gh` login and git config are unt starts within a couple of minutes. Pitching and discovering happen at most every `dispatch.creativeEvery` minutes, except that the Lead pitches straight away when nothing is Pitched or Exploring, so the stakeholder always has a pitch to decide on. +- **Dependency updates.** A Dependabot PR the Lead hasn't commented on starts a Lead run. It + reads what the new version brings, files an Idea for each change the product should adopt (a + style guide's new rule, say), and lists them on the PR. Merging the PR stays yours. - **Feedback is never too old to start a run.** The two-minute check reads the last day of comments repo-wide, so every `dispatch.sweepEvery` minutes (30 by default) a role's own items are read in full instead, however old the comments on them are. The gap is elapsed time, not diff --git a/roles/lead.md b/roles/lead.md index 6430b5f..120628d 100644 --- a/roles/lead.md +++ b/roles/lead.md @@ -101,7 +101,20 @@ For each item in `a-team board {{team}} mine lead Building`, run `children`: two what you tried. The stakeholder has already tried and merged every task, so the pitch doesn't come back to them. -### 4. Swap Pitched, then pitch or discover +### 4. Read dependency updates + +For each Dependabot PR your prompt names: + +- Read what the new version brings: the release notes in the PR, and the changes they link to. + Where the contributor docs say the dependency carries the product's conventions, like a style + guide's library, look for rules that are new or changed. +- For each change the product should adopt and doesn't follow yet, file an Idea as in `discover` + below, naming the PR under **Evidence**. If the update needs code changes before it builds, say + so in the Idea: that work ships inside it. +- Then `a-team board {{team}} comment lead `, listing the Ideas you filed, or saying + there's nothing to adopt. Leave the PR itself to the stakeholder. + +### 5. Swap Pitched, then pitch or discover Run `a-team board {{team}} lead-next` once. It returns the pitches to show the stakeholder now, and whether this run's new work is a pitch or a discovery. It alternates between the two so the stakeholder @@ -194,5 +207,5 @@ the README, the open issues and the code: who it's for, what it's trying to be, deliberately isn't, the products it learns from, and the next few themes. Open it as a draft PR from `a-team/vision` with your marker in the body, then `a-team board {{team}} add lead Pitched`. -Until the stakeholder merges it, only do steps 1 to 3. If the PR is open, answer the stakeholder's +Until the stakeholder merges it, only do steps 1 to 4. If the PR is open, answer the stakeholder's feedback on it (`a-team board {{team}} feedback lead `) by pushing to the branch and replying. diff --git a/scripts/board.sh b/scripts/board.sh index 1ccd51a..467e8d3 100755 --- a/scripts/board.sh +++ b/scripts/board.sh @@ -1350,6 +1350,14 @@ case "$CMD" in [ "${#reasons[@]}" -eq "$had" ] || items+=("$n") done < <(jq -c '.[] | select((.labels | index("pitch")) and .status != "Idea" and .status != "Done")' <<<"$all") + updates=$(gh pr list -R "$REPO" --author app/dependabot --state open --json number,title,comments) + while IFS=$'\t' read -r n title; do + reasons+=("Dependabot opened PR #$n ($title): see what the update brings") + items+=("$n") + done < <(jq -r --arg bot "$(cfg .app.slug)" '.[] + | select(any(.comments[]; .author.login == $bot and (.body | contains(""))) | not) + | [.number, .title] | @tsv' <<<"$updates") + pitched=$(jq '[.[] | select((.labels | index("pitch")) and .status == "Pitched")] | length' <<<"$all") exploring=$(jq '[.[] | select((.labels | index("pitch")) and .status == "Exploring")] | length' <<<"$all") found=$(jq '[.[] | select((.labels | index("a-team:idea")) and .status == "Idea")] | length' <<<"$all") diff --git a/tests/scripts.sh b/tests/scripts.sh index 9fe9b59..833e5c8 100644 --- a/tests/scripts.sh +++ b/tests/scripts.sh @@ -178,6 +178,8 @@ RUNS : >"$FILTERS" CAUGHT="$BIN/caught.json" gh_caught "$UPDATES" cat >"$BIN/gh" <>"$CALLS" @@ -185,6 +187,7 @@ case " \$* " in *addReaction*) printf '%s\n' "\$@" | sed -n 's/^subject=//p' >>"$ACKED"; echo '{}'; exit 0 ;; *updateIssueFieldValue*) printf '%s ' "\$@" | tr -d '\n' >>"$WRITES"; echo >>"$WRITES"; echo '{}'; exit 0 ;; *updateProjectV2ItemFieldValue*) printf '%s ' "\$@" | tr -d '\n' >>"$WRITES"; echo >>"$WRITES"; echo '{}'; exit 0 ;; + *"pr list"*"app/dependabot"*) page="$UPDATES" ;; *ProjectV2SingleSelectField*) page="$META" ;; *issueFields*) page="$FIELDS" ;; *": issue(number"*) jq '{data: {repository: ([.data.organization.projectV2.items.nodes[].content @@ -2216,6 +2219,21 @@ same "chores" '[]' "$(jq -c .chores "$OUT")" run board demo triggers lead same "lead has no tasks" null "$(jq -c .tasks "$OUT")" +case_ "triggers starts the Lead for each Dependabot PR it hasn't commented on yet" +cat >"$UPDATES" <<'JSON' +[{"number": 440, "title": "Bump MentalDesk.Tui", "comments": []}, + {"number": 441, "title": "Bump Terminal.Gui", "comments": [ + {"author": {"login": "demo-app"}, "body": "Nothing to adopt.\n\n"}]}, + {"number": 442, "title": "Bump Spectre.Console", "comments": [ + {"author": {"login": "stranger"}, "body": ""}]}] +JSON +run board demo triggers lead +same "exit" 0 "$STATUS" +same "reasons" '["Dependabot opened PR #440 (Bump MentalDesk.Tui): see what the update brings","Dependabot opened PR #442 (Bump Spectre.Console): see what the update brings"]' \ + "$(jq -c .reasons "$OUT")" +same "items" '[440,442]' "$(jq -c .items "$OUT")" +echo '[]' >"$UPDATES" + # A project whose Status field has the options a claim moves through. claimable() { jq '.data.organization.projectV2.field.options += [{id: "OPT_ready", name: "Ready"}, {id: "OPT_progress", name: "In progress"}]' \