Skip to content

fix: a lane's branch pushes to itself, not to the default branch - #21

Merged
ancelin-code merged 1 commit into
developfrom
fix/lane-upstream
Oct 22, 2026
Merged

ancelin-code merged 1 commit into
developfrom
fix/lane-upstream

Conversation

@ancelin-code

Copy link
Copy Markdown
Owner

What and why

Feedback from the tiroir pilot: in the worktree of foundation-001, the
branch was set to push to develop. A plain git push was refused, and the
task had to be pushed explicitly to task/foundation-001.

Cause: launch-lanes.sh creates the branch with
git worktree add -b task/<id> <path> origin/<default>. Starting from a
remote-tracking branch, git makes it the upstream. With push.default=simple
the push is refused, because the names differ. With push.default=upstream it
would push the task's work to the default branch.

  • launch-lanes.sh creates the branch with --no-track.
  • claim.sh sets <remote>/task/<id> as the upstream of the branch it was run
    from, when that branch is task/<id>, and prints UPSTREAM. This also
    covers a developer who claims by hand on a branch started from the default
    branch.
  • conventions.md, the delivery-status skill and the changelog say so.

How to review

  • claim.sh writes branch.<name>.remote and branch.<name>.merge directly,
    so it does not depend on a remote-tracking ref existing yet.
  • It does so even with --no-advance: that option keeps the branch where it
    is, 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:

test_the_lane_branch_pushes_to_itself:   assert 'origin/main' == 'origin/task/a-001'
test_a_plain_push_goes_to_the_claimed_branch:   assert None == 'origin/task/ingestion-003'

With it, a lane's branch tracks origin/task/<id>, and a plain git push
after 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=upstream and no protection, it would put unreviewed work on the
default branch.

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>
@github-actions github-actions Bot added the ai-assisted AI agents worked on this change label Oct 22, 2026
@ancelin-code
ancelin-code merged commit d128440 into develop Oct 22, 2026
5 checks passed
@ancelin-code
ancelin-code deleted the fix/lane-upstream branch October 22, 2026 19:27
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted AI agents worked on this change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant