Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .claude/skills/merge-when-green/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: merge-when-green
description: Merge a pull request once its CI has passed. This is the default for every pull request opened in this repo (a plain "pr" means open it and merge it when green); also use when the user says "merge" or runs /merge-when-green.
argument-hint: "[pull request number; default: the open pull request for the current branch]"
---

# Merge when green

The user has made this the default for this repo: after opening a pull request for them ("pr"), follow this skill and merge it with a merge commit (`merge_method: "merge"`, not squash or rebase) as soon as CI is green, without asking again. Invoking it by hand, or saying "merge", covers any open pull request they name. The authorisation is for pull requests I opened or they named; it does not cover Dependabot or anyone else's pull requests unless they ask. If the user says "pr only" or "don't merge", open it and stop.

## 1. Find the pull request
- With an argument, that number. Without one, the open pull request whose head is the current branch (`mcp__github__list_pull_requests`, state `open`, match `head.ref`). None, or more than one: say so and stop.
- Repository: `robdevops/ecobot` (check `git remote get-url origin` if in doubt). Read the pull request with `mcp__github__pull_request_read`. If it is already merged or closed, say so and stop.

## 2. Is it green?
Read the check runs on the **current head commit** (`get_check_runs`), not an earlier one.
- **Green** = the `test` check is `success`, and no other check is `failure`, `cancelled` or `timed_out`. `skipped` is fine (`newest` and `live-evals` only run on the schedule and the Run workflow button, never on pull requests).
- **Pending** (`queued` or `in_progress`, or no checks yet because a push just landed): do not poll in a loop and do not `sleep`. Call `mcp__github__subscribe_pr_activity` for the pull request and end your turn saying you will merge when CI finishes; if a CI result arrives, start again at step 2. (Also schedule a check-in with `mcp__Claude_Code_Remote__send_later` about 10 minutes out if it is available, since events can be missed.)
- **Red**: do not merge. Read the failing job (`get_job_logs`), say what failed. If it is a pull request you opened and the fix is yours to make, fix and push; otherwise report and stop. Never skip, disable or loosen a test to get green, and never push an empty commit to re-run CI.

## 3. Is it mergeable?
- `mergeable_state` of `dirty` (merge conflict): merge the base branch in and resolve it if the pull request is yours; for a Dependabot pull request comment `@dependabot rebase` and wait for its new CI run (back to step 2). Never rewrite someone else's branch.
- Review state: stop if a review has requested changes or a thread is open that names a red-circle (blocking) finding. Say what is open.
- Base moved since CI ran and it was not rebased: fine for GitHub's own check; the `test` run on the head commit is what counts.

## 4. Merge
`mcp__github__merge_pull_request` with `merge_method: "merge"`. Then confirm it merged (`state: closed`, `merged: true`) and report the merge commit.

## 5. After merging
- Bring the dev branch (the head branch, any branch but `main`) up to the merge: `git fetch origin main && git merge --ff-only origin/main && git push origin HEAD`. Never reset or recreate it; it persists between iterations. Delete no branch.
- If the user has other open pull requests that touch the same files (typically several Dependabot ones edit `.github/workflows/ci.yml`), list them: each may now be conflicted and need `@dependabot rebase` and a fresh CI run before its own merge.
- Unsubscribe from the pull request (`mcp__github__unsubscribe_pr_activity`).

## Rules
- One pull request per invocation. "Merge them all" is a separate instruction, and each is still checked as above.
- Never force-merge past a failing or missing required check, never `force` anything, and never merge a pull request you only watched unless the user named it.
- Report outcomes plainly: what was green, what was skipped, what was merged, and anything left open.
- Keep the final message to a couple of words ("Merged #32.", "CI red: test."). Say nothing about each notification along the way.
15 changes: 0 additions & 15 deletions .claude/skills/ship/SKILL.md

This file was deleted.

1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
push:
branches: [main]
pull_request:
workflow_call: # the Ship workflow runs the same gate on the dev branch
schedule:
- cron: "17 21 * * 0" # Sundays 21:17 UTC: the check against the newest matplotlib, numpy and Pillow (the "newest" job below)
workflow_dispatch:
Expand Down
46 changes: 0 additions & 46 deletions .github/workflows/ship.yml

This file was deleted.

2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Working in this repo

- **Iterating:** the "dev branch" is whichever branch the session is on, any branch except `main`. Keep using it between iterations: commit and push each change to it, with no pull request, so the user can pull it into their test environment. Never reset or recreate it.
- **Shipping:** "ship" (also "pr" or "merge": all the same) means start the Ship workflow on the dev branch and stop (see the `ship` skill). It tests, opens the pull request, merges it, and fast-forwards the branch to `main`. Do not open or merge the pull request by hand, and do not subscribe or wait. Other people's and Dependabot's pull requests are merged only when asked.
- **Pull requests:** "pr" (or "merge") means: create the pull request to `main`, subscribe to its events so CI shows up here (no polling), merge it with a merge commit once CI is green, then fast-forward the dev branch to `main` (`git fetch origin main && git merge --ff-only origin/main && git push`) and unsubscribe. Do all of it without asking. Finish with a couple of words, e.g. "Merged #32." or "CI red: <check>." Do not narrate notifications or recap. See the `merge-when-green` skill. "pr only" or "don't merge" means open it and stop. Other people's and Dependabot's pull requests are merged only when asked.
- **Checks before pushing:** `python -m pytest -q` and `python scripts/eval_prompts.py` (see `DEVELOPMENT.md`).
12 changes: 6 additions & 6 deletions lib/charts.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class Look:
in_headline: bool # the panel's name and unit are the figure's headline, and its colour key sits beside it


BIG = Look(30, 1.5, 8.5, 18, 1.2, 9, (0.35, 0.8), 6, 17, 0.26, 8.5, 1, True, 5, False, True)
SMALL = Look(20, 1.2, 7.5, 12, 0.8, 5, (0.25, 0.6), 4, 14, 0.3, 7, 2, False, 4, True, False)
BIG = Look(30, 1.5, 8.5, 18, 1.2, 9, (0.35, 0.8), 6, 17, 0.26, 10, 1, True, 5, False, True)
SMALL = Look(20, 1.2, 7.5, 12, 0.8, 5, (0.25, 0.6), 4, 14, 0.3, 8.5, 2, False, 4, True, False)


def _look_for(chart: Chart) -> Look:
Expand Down Expand Up @@ -381,7 +381,7 @@ def _render_rose(fig, compass: Compass):
a, b = compass.speed_steps
fig.legend([Line2D([], [], marker="s", linestyle="", markersize=6, color=c) for c in WIND_STEPS],
[f"under {a}", f"{a}–{b}", f"{b}+ km/h"], loc="lower right", bbox_to_anchor=(0.985, 0.0), ncol=3,
frameon=False, fontsize=7, labelcolor=MUTED, handletextpad=0.2, columnspacing=0.9)
frameon=False, fontsize=8.5, labelcolor=MUTED, handletextpad=0.2, columnspacing=0.9)


# ---------- several panels on one time axis ----------
Expand Down Expand Up @@ -461,14 +461,14 @@ def _end_labels(ax, drawn: list[tuple], show_floor: bool = False):
if not show_floor and max(d[2][-1] for d in drawn) - y_lo < 0.05 * (y_hi - y_lo):
return
height_pt = ax.get_position().height * ax.figure.get_figheight() * 72
gap = 8 * (y_hi - y_lo) / height_pt # 8 points, in data units
gap = 10 * (y_hi - y_lo) / height_pt # 10 points, in data units
placed = []
for colour, xs, ys in sorted(drawn, key=lambda d: d[2][-1]):
y = max(ys[-1], placed[-1] + gap) if placed else ys[-1]
placed.append(y)
shade = colour
ax.annotate(_figure(ys[-1]), (xs[-1], ys[-1]), xytext=(1.014, y), textcoords=("axes fraction", "data"), va="center", ha="left",
fontsize=7, fontweight="bold", color=shade, annotation_clip=False,
fontsize=8.5, fontweight="bold", color=shade, annotation_clip=False,
arrowprops={"arrowstyle": "-", "color": shade, "linewidth": 0.6, "alpha": 0.6, "shrinkA": 0, "shrinkB": 2},
bbox={"boxstyle": "round,pad=0.15", "fc": "none", "ec": "none"})

Expand All @@ -485,7 +485,7 @@ def _draw_panel(ax, p: Panel, tz: tzinfo, first: int, x0: float, x1: float, look
base += np.asarray(column, dtype=float)
ax.set_ylim(0, 100)
ax.legend([Line2D([], [], marker="s", linestyle="", markersize=5, color=c) for c in ZONE_COLOURS],
["good", "poor", "very poor"], loc="lower right", bbox_to_anchor=(1.0, 1.0), frameon=False, fontsize=7,
["good", "poor", "very poor"], loc="lower right", bbox_to_anchor=(1.0, 1.0), frameon=False, fontsize=8.5,
labelcolor=TEXT, ncol=3, handletextpad=0.2, columnspacing=0.9, borderaxespad=0.1)
return 0, _end_of(bx, s.width, x1), []
if not p.lines: # rain on its own
Expand Down
Binary file modified tests/charts/air.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/charts/all_week.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/charts/humidity_rain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/charts/quarter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/charts/temperature.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/charts/wind.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading