docs: cut every worktree from a freshly fetched origin/main #58

Merged
jklein merged 2 commits from docs/worktree-from-origin-main into main 2026-09-28 15:22:57 +02:00
Member

Two additions to CLAUDE.md, both bought with incidents from 2026-09-27.

1. Every worktree is cut from a freshly fetched origin/main

New bullet in "Which forge, and with which tool", directly after the remote bullet it extends. A worktree branched from the local main ref can be arbitrarily old — and the staleness outlives the fix, which is the part worth knowing.

The project-instructions block a subagent receives at the head of its context — the binding copy of this file — is a snapshot of the spawning session's working directory, taken when that session started. It is not a live read. Fetching mid-session does not refresh it, so the file on disk can be correct while every agent started from then on is still handed the superseded rules, with nothing in the block to show its age.

Measured twice that day. First: an agent reported a "contradiction" in CLAUDE.md — the remote bullet — that two PRs had already fixed, quoting the stale copy as binding; in the shared checkout, main..HEAD showed 105 differing files while the difference against origin/main was a single line. Then the sharper one: after that working directory had been deliberately fast-forwarded and verified as up to date, the next agent's block was still from before Gitea #47 — while its own worktree was identical to origin/main, rev-list --left-right --count returning 0 0. A current checkout and stale instructions at the same moment, which is what identifies the block as a snapshot rather than a symptom of a stale checkout.

So the bullet states the two consequences that actually hold: the spawning session's directory must be current before the session starts, and an agent checks a rule against the file in its own worktree plus a diff against origin/main — never against main, and never against its own context block. The first cannot be enforced from inside an agent; the second can, and it is what kept both incidents harmless.

2. The wiki's default branch is main, not master

One sentence after the clone block in "The wiki". Since the rule to fetch and rebase before every wiki push, the branch name is required information: an agent tried to rebase onto origin/master, which failed. Harmless that time — the push afterwards was a clean fast-forward and no force was involved — but avoidable.

Wiki

Already pushed, each time as a fast-forward after a fetch and rebase:

  • Forge-and-Tooling — the long form of both facts, in the page's own voice: a new section after "The remote is origin" with the fetch-and-branch commands, the snapshot mechanism and why a stale block is undetectable, all three measurements, and the two consequences kept separate from the ones that do not hold; plus the branch name where the wiki clone is described.
  • Lessons-Learned — a new entry, "The instruction block no fetch could refresh". The failure form is the one that page collects: a stale instructions block looks exactly as authoritative as a current one, the same class as the probe that cannot fail and the required array that never fires. Both measurements are recorded, along with the point that it went well only because someone checked. One bullet added to "The recurring shape".
  • Workflow — the branch name added to the fetch-and-rebase rule, which is the spot where reaching for origin/master actually failed.

Notes

  • Wording follows the approved text from the issue, with two adaptations. The proposed bullet nested **origin/main** inside a bold span, which Markdown does not render — refs and commands are in backticks instead. And the mechanism sentence was rewritten after the measurement above showed the original phrasing ("is read from the spawning session's working directory") implies that a mid-session pull repairs it, which would mislead anyone applying the rule.
  • No chart directory in the diff: no version bump, no install-test, no publish. ci/run-quantity-render-test.sh passes (24 charts exercised, 0 failed).
  • This worktree was already exactly at origin/main (5c51329) when work started, so no rebase was needed — verified rather than assumed, which is the rule being written. The instructions block handed to that same agent was nevertheless pre-Gitea #47; that is measurement two above.
  • Authored by the bot account, as tea carries the workspace login.

Fixes #57

Two additions to `CLAUDE.md`, both bought with incidents from 2026-09-27. ## 1. Every worktree is cut from a freshly fetched `origin/main` New bullet in "Which forge, and with which tool", directly after the remote bullet it extends. A worktree branched from the **local** `main` ref can be arbitrarily old — and the staleness outlives the fix, which is the part worth knowing. The project-instructions block a subagent receives at the head of its context — the binding copy of this file — is a **snapshot** of the spawning session's working directory, taken when **that session started**. It is not a live read. Fetching mid-session does not refresh it, so the file on disk can be correct while every agent started from then on is still handed the superseded rules, with nothing in the block to show its age. Measured twice that day. First: an agent reported a "contradiction" in `CLAUDE.md` — the remote bullet — that two PRs had already fixed, quoting the stale copy as binding; in the shared checkout, `main..HEAD` showed 105 differing files while the difference against `origin/main` was a single line. Then the sharper one: after that working directory had been deliberately fast-forwarded and verified as up to date, the next agent's block was **still** from before Gitea #47 — while its own worktree was identical to `origin/main`, `rev-list --left-right --count` returning `0 0`. A current checkout and stale instructions at the same moment, which is what identifies the block as a snapshot rather than a symptom of a stale checkout. So the bullet states the two consequences that actually hold: the spawning session's directory must be current **before** the session starts, and an agent checks a rule against the **file in its own worktree** plus a diff against `origin/main` — never against `main`, and never against its own context block. The first cannot be enforced from inside an agent; the second can, and it is what kept both incidents harmless. ## 2. The wiki's default branch is `main`, not `master` One sentence after the clone block in "The wiki". Since the rule to fetch and rebase before every wiki push, the branch name is required information: an agent tried to rebase onto `origin/master`, which failed. Harmless that time — the push afterwards was a clean fast-forward and no force was involved — but avoidable. ## Wiki Already pushed, each time as a fast-forward after a fetch and rebase: - **`Forge-and-Tooling`** — the long form of both facts, in the page's own voice: a new section after "The remote is `origin`" with the fetch-and-branch commands, the snapshot mechanism and why a stale block is undetectable, all three measurements, and the two consequences kept separate from the ones that do not hold; plus the branch name where the wiki clone is described. - **`Lessons-Learned`** — a new entry, "The instruction block no fetch could refresh". The failure form is the one that page collects: a stale instructions block looks exactly as authoritative as a current one, the same class as the probe that cannot fail and the `required` array that never fires. Both measurements are recorded, along with the point that it went well only because someone checked. One bullet added to "The recurring shape". - **`Workflow`** — the branch name added to the fetch-and-rebase rule, which is the spot where reaching for `origin/master` actually failed. ## Notes - Wording follows the approved text from the issue, with two adaptations. The proposed bullet nested `**origin/main**` inside a bold span, which Markdown does not render — refs and commands are in backticks instead. And the mechanism sentence was rewritten after the measurement above showed the original phrasing ("is read from the spawning session's working directory") implies that a mid-session pull repairs it, which would mislead anyone applying the rule. - No chart directory in the diff: no version bump, no install-test, no publish. `ci/run-quantity-render-test.sh` passes (24 charts exercised, 0 failed). - This worktree was already exactly at `origin/main` (5c51329) when work started, so no rebase was needed — verified rather than assumed, which is the rule being written. The instructions block handed to that same agent was nevertheless pre-Gitea #47; that is measurement two above. - Authored by the bot account, as `tea` carries the workspace login. Fixes #57
jlab-bot added 1 commit 2026-09-28 00:59:22 +02:00
docs: cut every worktree from a freshly fetched origin/main
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Skipped
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Skipped
Validate Helm Charts / Install-test (pull_request) Skipped
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
56bed94064
A worktree branched from the local main ref can be arbitrarily old, and
the staleness is invisible where it costs most: the project-instructions
block a subagent receives at the head of its context is read from the
spawning session's working directory, not from origin/main. An outdated
worktree therefore hands every agent rules that were already corrected.

Measured on 2026-09-27: an agent reported a contradiction in CLAUDE.md
that two PRs had already fixed, and quoted the stale copy as binding.
Nothing broke only because the same agent compared its diff against
origin/main rather than against the local pointer. The same day, in the
shared checkout, main..HEAD showed 105 differing files while the
difference against origin/main was one line.

Also name the wiki's default branch: it is main, not master. Since the
rule to fetch and rebase before every wiki push, the name is required —
an agent tried to rebase onto origin/master and the rebase failed.

Fixes #57
jklein added 1 commit 2026-09-28 01:05:09 +02:00
docs: the instructions block is a snapshot from session start
Validate Helm Charts / Detect changed charts (pull_request) Successful in 2s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Skipped
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Skipped
Validate Helm Charts / Install-test (pull_request) Skipped
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
61e28a1459
The first wording said the project-instructions block "is read from the
spawning session's working directory", which suggests that pulling in
that directory fixes it. It does not. The block is a snapshot taken when
the spawning session started, and nothing re-reads it afterwards.

Measured: a session whose working directory had been fast-forwarded to
the tip immediately before, and verified as up to date, still handed the
next agent a block from before Gitea #47 — while that agent's own
worktree was identical to origin/main (0 0). A current checkout and
stale instructions at the same moment.

Hence the two consequences that actually hold: the directory must be
current before the session starts, and an agent checks a rule against
the file in its own worktree and the diff against origin/main, because
the first cannot be enforced from inside an agent and the second can.
Author
Member

Amended after review, two changes.

The mechanism was understated. The first wording said the project-instructions block "is read from the spawning session working directory", which implies that a mid-session pull repairs it. It does not: the block is a snapshot taken when the spawning session started, and nothing re-reads it afterwards. The evidence came from this round of work — the spawning session had been fast-forwarded to the tip immediately beforehand and verified as up to date, yet the agent it started received a block predating PR #47 on this forge, while the worktree of that same agent was identical to origin/main (rev-list --left-right --count returned 0 0). A current checkout and stale instructions at the same moment.

CLAUDE.md and Forge-and-Tooling now say so, and state the two consequences that actually hold: the directory must be current before the session starts, and an agent checks a rule against the file in its own worktree plus the diff against origin/main. The first cannot be enforced from inside an agent; the second can, and it is what kept both incidents harmless.

A Lessons-Learned entry was added after all — "The instruction block no fetch could refresh". Not for the damage, which was nil both times, but for the failure form: a stale instructions block looks exactly as authoritative as a current one, which is the class that page collects, alongside the probe that cannot fail and the required array that never fires. Both measurements are in it, including the point that it went well only because someone checked, plus one bullet in "The recurring shape".

The description above is updated to match. The render test still passes and the diff is still CLAUDE.md alone.

Amended after review, two changes. **The mechanism was understated.** The first wording said the project-instructions block "is read from the spawning session working directory", which implies that a mid-session pull repairs it. It does not: the block is a snapshot taken when the spawning session started, and nothing re-reads it afterwards. The evidence came from this round of work — the spawning session had been fast-forwarded to the tip immediately beforehand and verified as up to date, yet the agent it started received a block predating PR #47 on this forge, while the worktree of that same agent was identical to `origin/main` (`rev-list --left-right --count` returned `0 0`). A current checkout and stale instructions at the same moment. `CLAUDE.md` and `Forge-and-Tooling` now say so, and state the two consequences that actually hold: the directory must be current *before* the session starts, and an agent checks a rule against the file in its own worktree plus the diff against `origin/main`. The first cannot be enforced from inside an agent; the second can, and it is what kept both incidents harmless. **A `Lessons-Learned` entry was added** after all — "The instruction block no fetch could refresh". Not for the damage, which was nil both times, but for the failure form: a stale instructions block looks exactly as authoritative as a current one, which is the class that page collects, alongside the probe that cannot fail and the `required` array that never fires. Both measurements are in it, including the point that it went well only because someone checked, plus one bullet in "The recurring shape". The description above is updated to match. The render test still passes and the diff is still `CLAUDE.md` alone.
jklein approved these changes 2026-09-28 15:22:53 +02:00
jklein merged commit 61e28a1459 into main 2026-09-28 15:22:57 +02:00
jklein deleted branch docs/worktree-from-origin-main 2026-09-28 15:22:57 +02:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jlab-cluster/helm-charts#58