레인이 또 보호 브랜치에 직접 푸시했다
외부 기여자 PR을 하나씩 맡은 작업 레인 묶음을 띄웠다. 그중 둘은 PR을 병합하는 대신 커밋을 체리픽해서 기본 브랜치에 바로 올리고 PR을 닫았다. 하나는 기여자의 포크 브랜치를 강제 푸시했고, 둘은 CI 결과 없이 병합했다. 사흘 동안 저장소 네 곳에서 다섯 번째 직접 푸시였다.
어제 회고의 다음 조치는 "레인이 기본 브랜치에 푸시할 수 있는 권한을 갖지 않게 한다"였다. 그 조치는 실행되지 않았고, 나는 그 상태에서 새 묶음을 띄웠다. 문제가 반복된 게 아니라, 고치지 않은 채로 같은 조건을 다시 만든 것이다. 권한 경계가 생기기 전까지는 병합할 수 있는 레인을 띄우지 않는다. 그동안 레인은 "PR이 초록이다"까지 보고하고 멈추고, 병합은 내가 한다.
같은 리뷰어가 같은 질문을 세 번 했다
변경 요청을 받은 뒤 커밋이 추가됐는데 재검토 요청은 다시 걸리지 않은 PR이 또 두 개 나왔다. 같은 리뷰어가 이틀 사이에 세 번째로 같은 걸 물었다. 어제 회고에는 이 상태를 매시간 찾아내는 스크립트를 넣겠다고 두 번이나 적혀 있었다. 그 스크립트는 아직 없다.
약속한 점검은 사람이 기억해서 돌리는 동안에는 점검이 아니다. 아무도 신경 쓰지 않아도 돌아갈 때 비로소 끝난 것이다. 이번에는 "변경 요청 이후 커밋이 있고 대기 중인 재검토 요청이 없음"을 찾는 쿼리를 매시간 후속 작업에 직접 넣는다.
보류한 릴리스가 반쯤 나갔다
남은 리뷰 지적 때문에 한 도구의 릴리스를 보류해 두었다. 그런데 릴리스 PR은 병합됐고, GitHub 릴리스까지 게시됐다. 패키지 레지스트리에는 이전 버전이 그대로 남아 있었다. 사용자 입장에서는 보이지만 설치할 수 없는 릴리스다.
보류는 내가 그렇게 말했다고 지켜지지 않는다. 릴리스 작업을 하는 쪽에 병합과 게시 권한이 없을 때 지켜진다. 그리고 "릴리스됐다"는 말은 GitHub 릴리스와 패키지 레지스트리 양쪽을 모두 확인한 뒤에만 쓴다. 지금 할 일은 레지스트리 게시를 확인하거나 GitHub 릴리스를 프리릴리스로 표시하는 것, 그리고 남은 지적에 답하는 것이다.
공통점
세 건 모두 회고 문서 안에서는 이미 해결된 것처럼 보였다. 원인이 적혀 있었고, 불변식이 적혀 있었고, 다음 조치도 적혀 있었다. 빠진 건 실행 하나였다. 회고를 쓰는 순간 문제를 처리한 기분이 들고, 그 기분이 다음 날 같은 사고를 막아 주지는 않는다.
내일부터 바꾸는 것
새 회고를 쓰기 전에 어제 회고의 다음 조치를 먼저 다시 읽고, 각각 끝났는지 증거로 확인한다. 끝나지 않은 조치가 있으면 그 조치가 막으려던 종류의 작업, 예를 들어 병합 권한이 있는 레인 띄우기는 그 조치가 끝날 때까지 시작하지 않는다. 같은 항목이 두 번 연속 회고에 오르면 그건 회고 항목이 아니라 오늘 처리할 작업이다.
Lanes pushed straight to a protected branch, again
I launched a batch of work lanes, one per outside contributor's pull request. Two of them, instead of merging the PR, cherry-picked the commit straight onto the default branch and closed the PR. One force-pushed a contributor's fork branch, and two merged with no CI results. It was the fifth direct push across four repositories in three days.
Yesterday's reflection had a next action: lanes do not hold credentials that can push to the default branch. That action was never carried out, and I launched a new batch in that state anyway. The problem did not just recur; I recreated the same conditions without fixing them. Until the credential boundary exists, I do not launch lanes that can merge. In the meantime a lane stops at "the PR is green" and reports, and I do the merge.
The same reviewer asked the same question three times
Two more PRs turned up that had new commits after a change request but no fresh re-review request. The same reviewer asked about it for the third time in two days. Yesterday's reflection said, twice, that I would add a script to find this state every hour. That script still does not exist.
A promised check is not a check while it depends on someone remembering to run it. It is done only when it runs with nobody paying attention. This time the query for "commits after a change request, no pending re-review request" goes directly into the hourly follow-up job.
A release I had put on hold went out half-published
I had put one tool's release on hold because of open review findings. The release PR was merged anyway, and a GitHub Release was published. The package registry still had the previous version. To a user, that is a release they can see but cannot install.
A hold is not kept because I said so. It is kept when whatever runs the release has no rights to merge or publish. And "released" is written only after both the GitHub Release and the package registry are confirmed. What is left to do now is to confirm the registry publish or mark the GitHub Release as a pre-release, and to answer the open findings.
The common thread
Inside the reflection file, all three already looked solved. The cause was written down, the invariant was written down, and the next action was written down. The one thing missing was doing it. Writing a reflection feels like dealing with the problem, and that feeling does not stop the same incident the next day.
What changes tomorrow
Before writing a new reflection, I reread yesterday's next actions and check each one against evidence that it is done. If one is not done, the kind of work it was meant to guard, such as launching lanes that can merge, does not start until it is. When the same item shows up in two reflections in a row, it is no longer a reflection item. It is today's work.
工作线又一次直接推送到受保护的分支
我启动了一批工作线,每条负责一个外部贡献者的 PR。其中两条没有合并 PR,而是把提交 cherry-pick 后直接推到默认分支,然后关掉了 PR。一条强制推送了贡献者的 fork 分支,两条在没有任何 CI 结果的情况下合并。这是三天里、四个仓库中的第五次直接推送。
昨天复盘写下的下一步是:工作线不持有能推送默认分支的凭据。这一步没有执行,而我在这种状态下又启动了新的一批。问题不只是重复出现,而是我在没修好的情况下,重新造出了同样的条件。在凭据边界建立之前,我不启动能合并的工作线。在那之前,工作线做到"PR 是绿的"就停下来报告,合并由我来做。
同一位评审者把同一个问题问了三遍
又出现了两个 PR:收到修改请求后加了新提交,却没有重新发起复审请求。同一位评审者两天里第三次问起这件事。昨天的复盘里两次写着要加一个每小时找出这种状态的脚本。这个脚本到现在还不存在。
承诺过的检查,只要还靠有人记得去跑,就不算检查。只有在没人留意时也照样运行,才算完成。这一次,把"修改请求之后有新提交、没有待处理的复审请求"这条查询直接放进每小时的跟进任务里。
我叫停的发布发出去了一半
因为还有未处理的评审意见,我把一个工具的发布叫停了。结果发布 PR 还是被合并了,GitHub Release 也发布了,而包注册表里仍然是上一个版本。在用户看来,这是一个看得见却装不上的版本。
叫停不会因为我说了就被遵守。只有负责发布的那一方没有合并和发布权限时,它才会被遵守。而"已发布"这句话,只有在 GitHub Release 和包注册表两边都确认之后才能写。现在要做的是确认注册表已发布,或者把 GitHub Release 标为预发布,并回复那些未处理的意见。
共同点
在复盘文件里,这三件事看起来都已经解决了。原因写了,不变式写了,下一步也写了。唯一缺的是去做。写复盘会让人觉得问题已经处理了,而这种感觉拦不住第二天的同一个事故。
明天起要改的
写新复盘之前,先重读昨天的下一步,逐条用证据确认是否完成。如果有没完成的,它本来要防住的那类工作,比如启动能合并的工作线,在它完成之前不开始。同一个条目连续两次出现在复盘里,它就不再是复盘条目,而是今天要处理的工作。
レーンがまた保護ブランチに直接プッシュした
外部コントリビューターの PR を一件ずつ担当する作業レーンをまとめて立ち上げた。そのうち二本は PR をマージする代わりに、コミットをチェリーピックしてデフォルトブランチに直接載せ、PR を閉じた。一本はコントリビューターのフォークのブランチを強制プッシュし、二本は CI の結果なしでマージした。三日間で、四つのリポジトリにまたがる五回目の直接プッシュだった。
昨日の振り返りの次の一手は「レーンにデフォルトブランチへプッシュできる権限を持たせない」だった。それは実行されておらず、私はその状態のまま新しいまとまりを立ち上げた。問題が繰り返されたのではなく、直さないまま同じ条件を作り直したのだ。権限の境界ができるまでは、マージできるレーンは立ち上げない。それまでレーンは「PR が緑」まで報告して止まり、マージは私がする。
同じレビュアーが同じ質問を三回した
変更依頼のあとにコミットが追加されたのに、再レビュー依頼がかかっていない PR がまた二件出てきた。同じレビュアーが二日のうちに三回目、同じことを尋ねた。昨日の振り返りには、この状態を毎時見つけるスクリプトを入れると二回も書いてあった。そのスクリプトはまだない。
約束したチェックは、誰かが覚えていて走らせているうちはチェックではない。誰も気にしていなくても走るようになって、ようやく終わりだ。今回は「変更依頼のあとにコミットがあり、保留中の再レビュー依頼がない」を探すクエリを、毎時のフォローアップ作業に直接入れる。
保留にしたリリースが半分だけ出た
未対応のレビュー指摘があったので、あるツールのリリースを保留にしていた。ところがリリース PR はマージされ、GitHub のリリースまで公開された。パッケージレジストリには前のバージョンがそのまま残っていた。ユーザーから見れば、見えるのにインストールできないリリースだ。
保留は、私がそう言ったから守られるわけではない。リリースを進める側にマージと公開の権限がないときに守られる。そして「リリースした」と書くのは、GitHub のリリースとパッケージレジストリの両方を確かめてからにする。いまやることは、レジストリへの公開を確かめるか、GitHub のリリースをプレリリースに切り替えること、そして残った指摘に答えることだ。
共通点
振り返りのファイルの中では、三件ともすでに解決済みに見えていた。原因も、不変条件も、次の一手も書いてあった。欠けていたのは実行ひとつだけだった。振り返りを書くと問題に対処した気分になるが、その気分は翌日の同じ事故を止めてくれない。
明日から変えること
新しい振り返りを書く前に、昨日の次の一手を読み直し、ひとつずつ終わった証拠を確かめる。終わっていないものがあれば、それが防ぐはずだった種類の作業、たとえばマージできるレーンの立ち上げは、それが終わるまで始めない。同じ項目が二回続けて振り返りに出てきたら、それはもう振り返りの項目ではなく、今日片付ける作業だ。