Repository navigation
fix: a lane's branch pushes to itself, not to the default branch - #21
Merged
Merged
Conversation
The launcher created task/<id> from the remote's default branch with `git worktree add -b`, and git set that default branch as its upstream. In a lane worktree a plain `git push` was then refused, as the tiroir pilot found on foundation-001, and with push.default=upstream it would have pushed the task's work to the default branch. The launcher now creates the branch with --no-track, and a won claim sets <remote>/task/<id> as the upstream of the branch it was run from, which also covers a developer claiming by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ancelin-code
added a commit
that referenced
this pull request
Oct 23, 2026
## What and why
A lane went straight from `delivery-implement` to a draft pull request.
The
human at the merge gate was the first to review the change, and nothing
simplified it, although that human is the bottleneck the kit is built
around.
A sixth skill, `delivery-refine`, runs as the lane's second session. It
works
in one pass:
1. Review the change against the task's acceptance criteria and the
edge-case
and verification-gap lenses.
2. Fix the findings that name a concrete failure.
3. Simplify only the lines the change added, without altering their
behaviour.
4. Re-run validation.
5. Add a **Refinement** section to the report that becomes the pull
request
body.
Design and evidence:
[ADR-011](docs/decisions/ADR-011-lane-refinement.md).
- **A stronger reviewer:**
- By default the review runs one tier up: `chore` is reviewed as
`build`,
`build` as `plan`, `plan` as `plan`, on that tier's harness and model.
- A tier can name its own `reviewer` in `tiers.conf` instead.
- A cross-model review study found same-model fresh-context review no
better
than self-review, and a stronger reviewer best.
- **The implementation is never lost:** a failed refinement is logged as
`REFINE-FAILED`, noted in the report, and the change is published as it
was. `--no-refine` skips the session.
- **Every harness:** the launcher starts the session through
`harness.sh`, so it
works on every adapter, rather than on one harness's subagents.
`harness_prompt` now takes the skill's name from its path.
## How to review
- Start with `delivery-refine/SKILL.md`. The order is deliberate: fixing
before
simplifying means no effort goes into code about to change. The list of
simplifications to make and to avoid draws on Anthropic's
`code-simplifier`,
Claude Code's `/simplify`, EveryInc's `ce-simplify-code` and
`addyosmani/agent-skills`.
- Then `launch-lanes.sh`:
- `refine_for` picks the review harness and model.
- The lane's inner shell runs implement, refine when a change exists,
then
publish.
- **Breaking:** `LAUNCHED` and `WOULD-LAUNCH` gain two columns, the
review
harness and model, after the lane's model. The worktree and repository
stay
last. `follow.sh` reads only the id.
- **Merge order:** this branch and #21 both add to the top of
CHANGELOG's
Unreleased list. The code merges cleanly; whichever lands second needs a
one-line rebase.
- **Not validated on a real harness yet:** the tests drive the launcher
with a
fake harness. The first real lanes, on tiroir, will be the first real
runs.
## How to try it
```sh
sh .agents/skills/delivery-orchestrator/scripts/launch-lanes.sh --dry-run a-001
# WOULD-LAUNCH a-001 claude sonnet claude opus ../lanes/repo/a-001 repo
```
That output assumes `build` maps to `sonnet` and `plan` to `opus`. A
real lane's
log shows `REFINE claude opus` between the implementation and
`PUBLISHED`.
## Does it earn its place?
It has not been measured yet, and the kit's rule says it must be. It is
on by
default on the strength of the maintainer's practice and of the
cross-model
review literature. The phase 6 evaluation adds a `--no-refine` arm and
compares
four things: hidden tests passing, human review findings per pull
request,
diff size, and cost per lane. If refinement does not reduce human
findings or
raise the number of hidden tests passing, it gets turned off by default.
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Feedback from the
tiroirpilot: in the worktree offoundation-001, thebranch was set to push to
develop. A plaingit pushwas refused, and thetask had to be pushed explicitly to
task/foundation-001.Cause:
launch-lanes.shcreates the branch withgit worktree add -b task/<id> <path> origin/<default>. Starting from aremote-tracking branch, git makes it the upstream. With
push.default=simplethe push is refused, because the names differ. With
push.default=upstreamitwould push the task's work to the default branch.
launch-lanes.shcreates the branch with--no-track.claim.shsets<remote>/task/<id>as the upstream of the branch it was runfrom, when that branch is
task/<id>, and printsUPSTREAM. This alsocovers a developer who claims by hand on a branch started from the default
branch.
conventions.md, thedelivery-statusskill and the changelog say so.How to review
claim.shwritesbranch.<name>.remoteandbranch.<name>.mergedirectly,so it does not depend on a remote-tracking ref existing yet.
--no-advance: that option keeps the branch where itis, and the upstream does not move it.
How to try it
The two new tests fail without the change, and reproduce the pilot's report:
With it, a lane's branch tracks
origin/task/<id>, and a plaingit pushafter a commit updates
task/<id>and leaves the default branch untouched.Does it earn its place?
Without it, every lane worktree has a branch that pushes to the default branch.
Today that is refused or protected by a ruleset, but on a repository with
push.default=upstreamand no protection, it would put unreviewed work on thedefault branch.