From 964f59f73e89ed2fdb400f2e716dc5a6668655f9 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:18:17 +0000 Subject: [PATCH 1/2] ci: make what's new updates incremental Skip the model when no merges or expirations need review, persist successful no-change checkpoints, and support manual full-window recalibration. Remove the unsupported Sonnet 5 temperature setting. --- .agents/skills/curate-whats-new/SKILL.md | 23 +++-- .github/agents/whats-new.yaml | 1 - .github/workflows/update-whats-new.yml | 102 +++++++++++++++++++++-- 3 files changed, 114 insertions(+), 12 deletions(-) diff --git a/.agents/skills/curate-whats-new/SKILL.md b/.agents/skills/curate-whats-new/SKILL.md index c5a25a31885..6e3bfb7b4bc 100644 --- a/.agents/skills/curate-whats-new/SKILL.md +++ b/.agents/skills/curate-whats-new/SKILL.md @@ -52,17 +52,30 @@ status only when the relative importance of the candidate set changes. ## Procedure 1. Read `data/whats-new.json`. -2. List every PR merged in the requested period: +2. Determine the review mode from the request: + - For an incremental review, inspect only PRs merged in the supplied + candidate range. Retain existing items inside the publication window + without re-reviewing their source PRs. If the request says there are no new + candidates, skip PR discovery and only remove expired items and reconsider + featured status. + - For a full review, inspect every PR merged in the supplied publication + window. +3. Unless there are no new candidates, list every PR in the range that applies + to the review mode: ```console $ gh pr list --repo docker/docs --state merged --search 'merged:START..END' --limit 200 ``` -3. Inspect the diff and resulting pages for every plausible candidate. -4. Decide what qualifies using only evidence in the merged documentation. -5. Replace `period_start`, `period_end`, and `items` in +4. Inspect the diff and resulting pages for every plausible new candidate. +5. Decide what qualifies using only evidence in the merged documentation. +6. Remove existing items published before the requested publication window. + Add newly qualifying launches, combine related PRs, and reconsider featured + status across the resulting list. Do not replace or rewrite retained items + merely because they were not part of the incremental candidate range. +7. Replace `period_start`, `period_end`, and `items` in `data/whats-new.json`. Sort items by `published` date, newest first. -6. Write `.pr-body.md` with the publication period, selected highlights and +8. Write `.pr-body.md` with the publication period, selected highlights and source PRs, plus concise reasons for plausible exclusions. Each item must contain `product`, `title`, `description`, `url`, `published`, diff --git a/.github/agents/whats-new.yaml b/.github/agents/whats-new.yaml index 04f9f290a5f..73f6894f274 100644 --- a/.github/agents/whats-new.yaml +++ b/.github/agents/whats-new.yaml @@ -4,7 +4,6 @@ models: provider: anthropic model: claude-sonnet-5 max_tokens: 4096 - temperature: 0.1 agents: root: diff --git a/.github/workflows/update-whats-new.yml b/.github/workflows/update-whats-new.yml index 2d4fec1b797..5f48cee3d77 100644 --- a/.github/workflows/update-whats-new.yml +++ b/.github/workflows/update-whats-new.yml @@ -2,7 +2,7 @@ name: Update What's New on: schedule: - # Review the previous 30 complete UTC days every day at 06:00 UTC. + # Review new merges and expire old highlights every day at 06:00 UTC. - cron: "0 6 * * *" workflow_dispatch: inputs: @@ -10,6 +10,10 @@ on: description: "Propose highlights without opening a pull request" type: boolean default: false + full-rescan: + description: "Re-evaluate every pull request in the 30-day window" + type: boolean + default: false permissions: contents: write @@ -40,6 +44,14 @@ jobs: echo "start=$(date -u -d "$PERIOD_END - 29 days" +%F)" >> "$GITHUB_OUTPUT" echo "end=$PERIOD_END" >> "$GITHUB_OUTPUT" + - name: Restore curator state + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: ${{ runner.temp }}/whats-new-state.json + key: whats-new-state-${{ github.repository }}-${{ github.run_id }} + restore-keys: | + whats-new-state-${{ github.repository }}- + - name: Configure AWS credentials id: aws-credentials continue-on-error: true @@ -68,21 +80,92 @@ jobs: git show "origin/$BRANCH_NAME:data/whats-new.json" > data/whats-new.json fi + - name: Check for work + id: preflight + env: + FULL_RESCAN: ${{ inputs.full-rescan == true }} + GH_TOKEN: ${{ env.GITHUB_APP_TOKEN || github.token }} + PERIOD_START: ${{ steps.period.outputs.start }} + PERIOD_END: ${{ steps.period.outputs.end }} + STATE_FILE: ${{ runner.temp }}/whats-new-state.json + run: | + REVIEWED_THROUGH=$(jq -r '.reviewed_through // empty' "$STATE_FILE" 2>/dev/null || true) + if ! [[ "$REVIEWED_THROUGH" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then + REVIEWED_THROUGH=$(jq -r '.period_end' data/whats-new.json) + fi + DATA_PERIOD_END=$(jq -r '.period_end' data/whats-new.json) + if [[ "$DATA_PERIOD_END" > "$REVIEWED_THROUGH" ]]; then + REVIEWED_THROUGH=$DATA_PERIOD_END + fi + + if [ "$FULL_RESCAN" = "true" ]; then + CANDIDATE_START=$PERIOD_START + MODE=full + else + CANDIDATE_START=$(date -u -d "$REVIEWED_THROUGH + 1 day" +%F) + MODE=incremental + fi + + HAS_NEW_PRS=false + if [[ "$CANDIDATE_START" < "$PERIOD_END" || "$CANDIDATE_START" = "$PERIOD_END" ]]; then + CANDIDATE_RANGE="$CANDIDATE_START through $PERIOD_END, inclusive" + PR_COUNT=$(gh pr list \ + --repo docker/docs \ + --state merged \ + --search "merged:$CANDIDATE_START..$PERIOD_END" \ + --limit 1 \ + --json number \ + --jq 'length') + if [ "$PR_COUNT" -gt 0 ]; then + HAS_NEW_PRS=true + elif [ "$MODE" = "incremental" ]; then + CANDIDATE_RANGE="none; there are no new candidate pull requests" + fi + else + CANDIDATE_RANGE="none; there are no new candidate pull requests" + fi + + HAS_EXPIRED=$(jq --arg start "$PERIOD_START" \ + 'any(.items[]; .published < $start)' data/whats-new.json) + + RUN_AGENT=false + if [ "$MODE" = "full" ] || [ "$HAS_NEW_PRS" = "true" ] || [ "$HAS_EXPIRED" = "true" ]; then + RUN_AGENT=true + fi + + jq -n --arg reviewed_through "$PERIOD_END" \ + '{reviewed_through: $reviewed_through}' > "$STATE_FILE" + + { + echo "mode=$MODE" + echo "candidate-range=$CANDIDATE_RANGE" + echo "run-agent=$RUN_AGENT" + } >> "$GITHUB_OUTPUT" + echo "New PRs: $HAS_NEW_PRS; expired items: $HAS_EXPIRED; run agent: $RUN_AGENT" + + - name: Report no changes to review + if: steps.preflight.outputs.run-agent == 'false' + run: | + echo "No pull requests were merged since the last successful review, and no highlights expired from the 30-day window." | tee -a "$GITHUB_STEP_SUMMARY" + - name: Curate highlights + if: steps.preflight.outputs.run-agent == 'true' uses: docker/docker-agent-action@e96a4bb40cac114f64358621e1d08346c8eadc8c # v2.0.1 env: GH_TOKEN: ${{ env.GITHUB_APP_TOKEN || github.token }} with: agent: ${{ github.workspace }}/.github/agents/whats-new.yaml prompt: >- - Use the curate-whats-new skill to review documentation pull requests merged from - ${{ steps.period.outputs.start }} through - ${{ steps.period.outputs.end }}, inclusive. + Use the curate-whats-new skill in ${{ steps.preflight.outputs.mode }} mode. + The publication window is ${{ steps.period.outputs.start }} through + ${{ steps.period.outputs.end }}, inclusive. Candidate range: + ${{ steps.preflight.outputs.candidate-range }}. anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} github-token: ${{ env.GITHUB_APP_TOKEN || github.token }} timeout: 1200 - name: Verify agent changes + if: steps.preflight.outputs.run-agent == 'true' env: PERIOD_START: ${{ steps.period.outputs.start }} PERIOD_END: ${{ steps.period.outputs.end }} @@ -98,14 +181,14 @@ jobs: node hack/validate-whats-new.mjs data/whats-new.json "$PERIOD_START" "$PERIOD_END" - name: Show proposal - if: inputs.dry-run == true + if: steps.preflight.outputs.run-agent == 'true' && inputs.dry-run == true run: | git diff -- data/whats-new.json cat .pr-body.md - name: Detect changes id: changes - if: inputs.dry-run != true + if: steps.preflight.outputs.run-agent == 'true' && inputs.dry-run != true run: | if cmp -s \ <(git show HEAD:data/whats-new.json | jq -S '.items') \ @@ -158,3 +241,10 @@ jobs: --base main \ --head "$BRANCH_NAME" fi + + - name: Save curator state + if: success() && inputs.dry-run != true && steps.changes.outputs.changed != 'true' + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: ${{ runner.temp }}/whats-new-state.json + key: whats-new-state-${{ github.repository }}-${{ github.run_id }} From 1324723ae198ec8c94dd4c0327376dd6d2663e31 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:49:05 +0000 Subject: [PATCH 2/2] ci: let curator discover incremental work --- .agents/skills/curate-whats-new/SKILL.md | 13 +++--- .github/workflows/update-whats-new.yml | 56 ++++-------------------- 2 files changed, 14 insertions(+), 55 deletions(-) diff --git a/.agents/skills/curate-whats-new/SKILL.md b/.agents/skills/curate-whats-new/SKILL.md index 6e3bfb7b4bc..446416c9b0b 100644 --- a/.agents/skills/curate-whats-new/SKILL.md +++ b/.agents/skills/curate-whats-new/SKILL.md @@ -53,20 +53,19 @@ status only when the relative importance of the candidate set changes. 1. Read `data/whats-new.json`. 2. Determine the review mode from the request: - - For an incremental review, inspect only PRs merged in the supplied - candidate range. Retain existing items inside the publication window - without re-reviewing their source PRs. If the request says there are no new - candidates, skip PR discovery and only remove expired items and reconsider - featured status. + - For an incremental review, list PRs merged from the day after the supplied + checkpoint through the end of the publication window. Retain existing + items inside the publication window without re-reviewing their source PRs. - For a full review, inspect every PR merged in the supplied publication window. -3. Unless there are no new candidates, list every PR in the range that applies - to the review mode: +3. List PRs in the range that applies to the review mode: ```console $ gh pr list --repo docker/docs --state merged --search 'merged:START..END' --limit 200 ``` + If an incremental search returns no PRs, skip candidate inspection and only + remove expired items. 4. Inspect the diff and resulting pages for every plausible new candidate. 5. Decide what qualifies using only evidence in the merged documentation. 6. Remove existing items published before the requested publication window. diff --git a/.github/workflows/update-whats-new.yml b/.github/workflows/update-whats-new.yml index 5f48cee3d77..112ce7066f9 100644 --- a/.github/workflows/update-whats-new.yml +++ b/.github/workflows/update-whats-new.yml @@ -80,12 +80,10 @@ jobs: git show "origin/$BRANCH_NAME:data/whats-new.json" > data/whats-new.json fi - - name: Check for work - id: preflight + - name: Set review mode and checkpoint + id: review env: FULL_RESCAN: ${{ inputs.full-rescan == true }} - GH_TOKEN: ${{ env.GITHUB_APP_TOKEN || github.token }} - PERIOD_START: ${{ steps.period.outputs.start }} PERIOD_END: ${{ steps.period.outputs.end }} STATE_FILE: ${{ runner.temp }}/whats-new-state.json run: | @@ -99,73 +97,35 @@ jobs: fi if [ "$FULL_RESCAN" = "true" ]; then - CANDIDATE_START=$PERIOD_START MODE=full else - CANDIDATE_START=$(date -u -d "$REVIEWED_THROUGH + 1 day" +%F) MODE=incremental fi - HAS_NEW_PRS=false - if [[ "$CANDIDATE_START" < "$PERIOD_END" || "$CANDIDATE_START" = "$PERIOD_END" ]]; then - CANDIDATE_RANGE="$CANDIDATE_START through $PERIOD_END, inclusive" - PR_COUNT=$(gh pr list \ - --repo docker/docs \ - --state merged \ - --search "merged:$CANDIDATE_START..$PERIOD_END" \ - --limit 1 \ - --json number \ - --jq 'length') - if [ "$PR_COUNT" -gt 0 ]; then - HAS_NEW_PRS=true - elif [ "$MODE" = "incremental" ]; then - CANDIDATE_RANGE="none; there are no new candidate pull requests" - fi - else - CANDIDATE_RANGE="none; there are no new candidate pull requests" - fi - - HAS_EXPIRED=$(jq --arg start "$PERIOD_START" \ - 'any(.items[]; .published < $start)' data/whats-new.json) - - RUN_AGENT=false - if [ "$MODE" = "full" ] || [ "$HAS_NEW_PRS" = "true" ] || [ "$HAS_EXPIRED" = "true" ]; then - RUN_AGENT=true - fi - jq -n --arg reviewed_through "$PERIOD_END" \ '{reviewed_through: $reviewed_through}' > "$STATE_FILE" { echo "mode=$MODE" - echo "candidate-range=$CANDIDATE_RANGE" - echo "run-agent=$RUN_AGENT" + echo "reviewed-through=$REVIEWED_THROUGH" } >> "$GITHUB_OUTPUT" - echo "New PRs: $HAS_NEW_PRS; expired items: $HAS_EXPIRED; run agent: $RUN_AGENT" - - - name: Report no changes to review - if: steps.preflight.outputs.run-agent == 'false' - run: | - echo "No pull requests were merged since the last successful review, and no highlights expired from the 30-day window." | tee -a "$GITHUB_STEP_SUMMARY" - name: Curate highlights - if: steps.preflight.outputs.run-agent == 'true' uses: docker/docker-agent-action@e96a4bb40cac114f64358621e1d08346c8eadc8c # v2.0.1 env: GH_TOKEN: ${{ env.GITHUB_APP_TOKEN || github.token }} with: agent: ${{ github.workspace }}/.github/agents/whats-new.yaml prompt: >- - Use the curate-whats-new skill in ${{ steps.preflight.outputs.mode }} mode. + Use the curate-whats-new skill in ${{ steps.review.outputs.mode }} mode. The publication window is ${{ steps.period.outputs.start }} through - ${{ steps.period.outputs.end }}, inclusive. Candidate range: - ${{ steps.preflight.outputs.candidate-range }}. + ${{ steps.period.outputs.end }}, inclusive. The last successful incremental + review covered through ${{ steps.review.outputs.reviewed-through }}. anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} github-token: ${{ env.GITHUB_APP_TOKEN || github.token }} timeout: 1200 - name: Verify agent changes - if: steps.preflight.outputs.run-agent == 'true' env: PERIOD_START: ${{ steps.period.outputs.start }} PERIOD_END: ${{ steps.period.outputs.end }} @@ -181,14 +141,14 @@ jobs: node hack/validate-whats-new.mjs data/whats-new.json "$PERIOD_START" "$PERIOD_END" - name: Show proposal - if: steps.preflight.outputs.run-agent == 'true' && inputs.dry-run == true + if: inputs.dry-run == true run: | git diff -- data/whats-new.json cat .pr-body.md - name: Detect changes id: changes - if: steps.preflight.outputs.run-agent == 'true' && inputs.dry-run != true + if: inputs.dry-run != true run: | if cmp -s \ <(git show HEAD:data/whats-new.json | jq -S '.items') \