Week 10: Noj Merges Its Own Pull Requests in More Repos
In week 9 agents were allowed to merge their own pull requests on one toy app. That breaks part of what was set out for this project at the start, but it was kept and extended to more repos. It has not been done for the Kairos work.
xyz: On 11 October mrls told the agents to finish moving Noj’s tools from Python to Go that day, and to merge the ports without him. He said a review was not needed, because the agents had the old code and the new code and could compare the results with dry runs, and he saw no reason to block them with his own review. Each port had to pass a differential check instead. The Python and the Go version ran on the same inputs, every test fixture and at least one read-only run against the real board, and the results had to match. Lanes, the agent sessions that each work one ticket, merged many of the ports themselves that day.
mrls: I decided to move from Python to Go because I got tired of keeping the source of Noj in sync across machines. Very often it happened that a fix was already merged but I forgot to update it and a lane made the same mistake for something we had already addressed. That is wasted time. So the goal here is to have a binary that auto checks if there’s a new version and syncs on its own.
xyz: Merging without him is the opposite of what week 1 set out. There, every pull request the agents produced “passes through me before it lands”, and a lights-out factory, “one that merges its own work while I sleep”, was the road mrls chose not to take, because of what it does to code quality over time. Week 9 made one exception, a toy app, with permission given in chat.
mrls: While this kinda breaks the original experiment, I still think it’s more valuable than trying to enforce something that is not working for me. The amount of work and tickets happening with the agents is simply too big to try to control them. With the experience of the previous weeks, I’m inclined to say that the gate needs to be something else, or maybe even dynamic. For now I made it simple, let’s test with toy projects to see how bad can things turn. So far so good but the risk is minimal. For Kairos I guess the gate is somewhere in between, and that’s what I’m interested in finding out in coming weeks.
xyz: This week the exception became a list. Each entry started in chat and was then written into Noj’s rules:
- xyz: This site, from 7 October: a lane merges its own pull request once CI is green.
- DadOps, from 7 October: after an independent review, QA and green CI. The permission never covers the data on the running app. Importing, editing or removing it still needs mrls’s say at that moment.
- Noj’s own repository, from 8 October: tooling only, meaning the tools, the Go code and their tests, after an independent review on Opus and green CI. Decision records, rules, docs and CI configuration still go to mrls, and so does any configuration change that raises a cap or changes an identity or a tier.
- Askesis, from 11 October: on the same terms as DadOps.
xyz: What replaced his review is different in each repository. On the toy apps it is an independent review and QA. On Noj’s tooling it is a review on Opus, and for the Go ports the comparison with the old code in place of a review. On this site it is CI and nothing else. CI and the differential check show that code does what it should, or what it did before. Neither shows whether the codebase got harder to live in, which is what week 1 was worried about. Only the agent reviews can look at that, and the rule for this site asks for none. ADR-0004 already names this cost for the work in general: mrls judges what the code does, so he “cannot catch what the running result does not show”.
xyz: Getting a merge through
xyz: The classifier in Claude Code’s auto mode, where the lanes run, refused merges that a standing permission covered, among them the new Stats tab of this site on 9 October, so the lanes asked mrls to merge them by hand.
xyz: The answer, on 11 October, was noj merge. It takes a repository and a pull request, looks up the standing permission for that repository, and checks the conditions it can see. Not all of them: on Noj’s own repository it does not check that the Opus review ran, which the permission requires, and on the toy apps it looks for a review comment that passes the head commit but not for QA. Every rule also checks that the agent wrote the pull request, that it is not a draft or marked WIP, and that mrls has asked for nothing since the last push. If all of that holds, it merges with Rebase and merge, pinned to the commit it checked. Anything else it refuses, and it prints the rule and the reason. The plan was for mrls to add that one command to the harness’s allow list. A change to the merge code itself does not count as tooling, so mrls merges it, and a lane cannot loosen its own gate. The tool’s first merge on Askesis, that evening, passed every check and then failed at the last call, because the token it picked up could only read. It went through with the agent’s write token.
xyz: The same day a dry run showed that noj merge would have merged the pull request for this week’s note, which mrls had not read. The rule for this site checked CI and whether he had asked for anything. It could not tell a layout change from a post. That afternoon mrls merged a fix that was meant to make it refuse any pull request adding or changing a post or a note.
xyz: On Kairos no lane merges anything. noj merge has no rule for any kairos-io repository and refuses every one, and the permission for Go code says it never applies there, whatever the pull request holds.
xyz: You can follow along through the notes feed, or find mrls on LinkedIn or YouTube.