docs: row 117 brief, fetch a role clone that is on another branch or dirty (#1611)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,101 @@
|
|||||||
|
# A role clone off the root's branch still gets fetched (2026-10-14)
|
||||||
|
|
||||||
|
Filed by Sage on Mos's report of 2026-10-14. Gitea #1611.
|
||||||
|
|
||||||
|
## Fetch a role clone that is on another branch or dirty
|
||||||
|
|
||||||
|
### Problem
|
||||||
|
|
||||||
|
At each launch the host updates a role's project clone only when the clone
|
||||||
|
is clean and on the root's branch (`packages/seat/src/checkout.mjs`,
|
||||||
|
`update()`). Every other clone is kept, and the host runs no more git in it.
|
||||||
|
For `other-branch` and `dirty` that is more than safety needs. By then
|
||||||
|
`unsafe()` has passed, the index has no gitlink and the root's branch is
|
||||||
|
known, so the host's fetch is as safe there as in a clean clone. Skipping it
|
||||||
|
leaves the clone's `refs/remotes/origin/*` as old as the last launch that
|
||||||
|
found the clone clean and on the root's branch.
|
||||||
|
|
||||||
|
A coder sits on a work branch for most of a task, so this happens all the
|
||||||
|
time. On 2026-10-14 the coder was blocked on 19/266 because its clone's
|
||||||
|
`origin/refactor` was 0c3826910, several landings behind. That clone was
|
||||||
|
also kept for `config-changed`, from a `[user]` section written at 19:53Z
|
||||||
|
on 10-13, before row 104 (#1598) gave sessions their identity through the
|
||||||
|
environment. The coder removes that section itself as a one-off. It isn't
|
||||||
|
part of this row, and `config-changed` stays as it is.
|
||||||
|
|
||||||
|
### Owner and reviewer
|
||||||
|
|
||||||
|
- Owner: darkwing, before row 116.
|
||||||
|
- Reviewer: dewey (decision 130: the host runs git in a clone the session
|
||||||
|
can write).
|
||||||
|
|
||||||
|
### Files owned
|
||||||
|
|
||||||
|
- `packages/seat/src/checkout.mjs`
|
||||||
|
- `packages/seat/tests/checkout.test.mjs`
|
||||||
|
- `packages/seat/README.md`, "The project clones"
|
||||||
|
- `packages/cli/src/launcher.mjs`, the record line after `ensureCheckouts`
|
||||||
|
- `packages/cli/tests/launcher.test.mjs`
|
||||||
|
- `packages/cli/README.md`, the checkout paragraph in "Sessions"
|
||||||
|
- `packages/harness/src/bundle.mjs`, `checkoutLines()`
|
||||||
|
- `packages/harness/tests/bundle.test.mjs`
|
||||||
|
|
||||||
|
Nothing in `unsafe()`, `allowed()`, `gitEnv()`, the `SAFE` arguments or the
|
||||||
|
sandbox changes. If the fix seems to need any of them, stop and tell Sage.
|
||||||
|
|
||||||
|
### What ships
|
||||||
|
|
||||||
|
1. In `update()`, a clone that would be kept for `other-branch` or `dirty`
|
||||||
|
gets the same fetch the clean path runs, with the same arguments and
|
||||||
|
environment, and no merge. Only those two reasons fetch. Every check
|
||||||
|
before them (`unsafe()`, the gitlink check, the root read) still keeps
|
||||||
|
the clone with no fetch, as today. A detached HEAD is `other-branch` and
|
||||||
|
fetches too.
|
||||||
|
2. The result is a new outcome, `fetched`, with:
|
||||||
|
- `reason`: `other-branch` or `dirty`;
|
||||||
|
- `branch`: the clone's own branch, or `null` on a detached HEAD;
|
||||||
|
- `commit`: the clone's HEAD (`null` when git can't read it);
|
||||||
|
- `origin`: `{ branch, commit }`, the root's branch and the commit of
|
||||||
|
`refs/remotes/origin/<branch>` after the fetch (`null` when unreadable).
|
||||||
|
A fetch that fails is `kept` with `fetch-failed`, as today. If you find a
|
||||||
|
better shape than a new outcome, record the choice and the reason in the
|
||||||
|
packet.
|
||||||
|
3. The launcher writes a `checkout-fetched` line to the launch log, with the
|
||||||
|
project and the reason, next to `checkout-kept`.
|
||||||
|
4. The bundle's prompt names a fetched clone's branch and commit, says it
|
||||||
|
wasn't fast-forwarded and why, and names `origin/<branch>` at its commit.
|
||||||
|
The shared sentence changes to say the host fetches every clone it can
|
||||||
|
safely run git in at a launch, and fast-forwards only a clean clone on
|
||||||
|
the root's branch. The rest of the sentence (never during a session,
|
||||||
|
don't set git config, identity from the environment) stays.
|
||||||
|
5. The READMEs say the same. The seat README's table gets the `fetched`
|
||||||
|
row, and the reason table says which reasons fetch.
|
||||||
|
|
||||||
|
### Not in this row
|
||||||
|
|
||||||
|
- Accepting `user.name` or `user.email` in a clone's config. Refusing them
|
||||||
|
is deliberate (row 104).
|
||||||
|
- Merging, rebasing or resetting anything in a fetched clone.
|
||||||
|
- Fetching a clone kept for any other reason.
|
||||||
|
|
||||||
|
### Acceptance
|
||||||
|
|
||||||
|
- For a dirty clone (modified, untracked, staged) and one on another branch
|
||||||
|
or detached: after a commit to the root, the launch returns `fetched`,
|
||||||
|
`refs/remotes/origin/<branch>` is the root's new commit, and HEAD,
|
||||||
|
`refs/heads/*`, the index and every file outside `.git` are byte-for-byte
|
||||||
|
what they were. The existing "kept as they are" test becomes this test,
|
||||||
|
with its fingerprint narrowed to those parts.
|
||||||
|
- A clone kept for each earlier reason (`not-a-clone`, `hooks-present`,
|
||||||
|
`submodule`, `config-changed`, `root-unreadable`, `root-detached`) still
|
||||||
|
runs no git, the fetch included. The rigged-clone test still passes
|
||||||
|
unchanged.
|
||||||
|
- A failed fetch in a dirty clone is `kept`, `fetch-failed`.
|
||||||
|
- The launcher test sees `checkout-fetched` with the reason, and the bundle
|
||||||
|
test sees the new line.
|
||||||
|
- Mutants, one per check, listed in the packet: fetch for a third reason;
|
||||||
|
merge after the fetch; drop the fetch; report the wrong `origin` commit;
|
||||||
|
fetch before the gitlink check. Each one fails a test.
|
||||||
|
- Full gate green. Dewey approves on #1611 naming the candidate manifest.
|
||||||
|
Sage reruns the gate at the landing target. Going live needs a re-pin on
|
||||||
|
Mos's go (decision 109).
|
||||||
Reference in New Issue
Block a user