Keep resident checkouts under ~/projects/coily*/ pinned to main, and make leaving main a deliberate act #1033

Closed
opened 2026-08-12 21:26:52 +00:00 by coilyco-ops · 1 comment
Member

Resident checkouts drift off main and stay there, and a checkout sitting on a feature branch silently changes what tooling reads from it. Today that nearly put unlanded work into a committed artifact.

Survey, 2026-08-12

Twelve resident checkouts under ~/projects/coily*/:

  • 6 of 12 were not on main. agentic-os-kai on fix/restore-pronoun-binding, agent-compose on meld/231-shared-role-melds, agent-proxy on build-publish-image, infrastructure on chore/aos-precommit-v0.18-bump, plus two others.
  • 19 branches carried unpushed work. 9 had never been pushed at all. 10 had diverged from their upstream, so they could only be preserved by pushing to backup/ refs, since a normal push is rejected and force-push is off limits.
  • 5 repos had uncommitted changes, four of them a stale in-flight apply-agentic-os-hooks bump to aos-precommit-v0.18.0.

The unpushed work is now on remotes. The point is that none of it was visible until someone looked.

The concrete harm

agentic-os-kai sitting on fix/restore-pronoun-binding changed what compose-review-sirens-deep composed for the Sirens Deep review artifact in coilyco-bridge/deploy.

That branch carries 10 personal-preference paths. origin/main carries 1. So the regenerated artifact recorded ten skills resolving from /catalogs/aosk when upstream still resolves them from /catalogs/aos, and it recorded a creator composed body of 47,054 bytes against main's 46,942.

The artifact was internally consistent and passed its sirens-deep-bundle-artifact hook, because that hook checks internal consistency and the image pin rather than catalogue provenance. It was one git commit away from recording an unlanded catalogue layout as live deployment state. Caught only because compose-review prints a behind-origin warning that someone happened to read. See deploy#409.

Any tool that reads a resident checkout as a source of truth has this exposure. Catalogue composition is simply the one that surfaced.

What to decide

Scope. Resident checkouts are the ones Agent Compose's repository-plan.yaml places under ~/projects/<owner>/. That file is the natural source for which directories are in scope, so the policy should read from it rather than hardcode a glob.

Mechanism. Options, roughly in increasing strength:

  1. Advisory only. A session-start or prompt check that reports any resident checkout not on main, or dirty, or holding unpushed branches.
  2. A post-checkout hook that warns loudly on leaving main in a resident path.
  3. A guard that refuses the checkout outright, with an explicit override.
  4. Tool-side. Any command that reads a checkout as a catalogue or source of truth refuses when that checkout is off main or behind origin. compose-review already detects this and writes anyway, which is the specific gap that let today's artifact through.

Option 4 is worth doing regardless of what happens with 1 through 3, because it fails closed at the point where the wrong state actually causes damage.

Escape hatch, non-negotiable. Several repos explicitly direct agents to work outside the resident checkout. agent-proxy's AGENTS.md says to use a task-scoped temporary clone and remove it afterward. Whatever lands must leave git worktree, temporary clones, and scratch paths completely unaffected, or it will simply be bypassed.

Suggested first step

Ship the advisory check and option 4 together. The advisory makes drift visible without blocking anyone, and the tool-side refusal closes the path where drift actually corrupts an artifact. Decide on hard enforcement after seeing how often the advisory fires.

Resident checkouts drift off `main` and stay there, and a checkout sitting on a feature branch silently changes what tooling reads from it. Today that nearly put unlanded work into a committed artifact. ## Survey, 2026-08-12 Twelve resident checkouts under `~/projects/coily*/`: - **6 of 12 were not on `main`.** `agentic-os-kai` on `fix/restore-pronoun-binding`, `agent-compose` on `meld/231-shared-role-melds`, `agent-proxy` on `build-publish-image`, `infrastructure` on `chore/aos-precommit-v0.18-bump`, plus two others. - **19 branches carried unpushed work.** 9 had never been pushed at all. 10 had diverged from their upstream, so they could only be preserved by pushing to `backup/` refs, since a normal push is rejected and force-push is off limits. - **5 repos had uncommitted changes**, four of them a stale in-flight `apply-agentic-os-hooks` bump to `aos-precommit-v0.18.0`. The unpushed work is now on remotes. The point is that none of it was visible until someone looked. ## The concrete harm `agentic-os-kai` sitting on `fix/restore-pronoun-binding` changed what `compose-review-sirens-deep` composed for the Sirens Deep review artifact in `coilyco-bridge/deploy`. That branch carries 10 `personal-preference` paths. `origin/main` carries 1. So the regenerated artifact recorded ten skills resolving from `/catalogs/aosk` when upstream still resolves them from `/catalogs/aos`, and it recorded a `creator` composed body of 47,054 bytes against main's 46,942. The artifact was internally consistent and **passed its `sirens-deep-bundle-artifact` hook**, because that hook checks internal consistency and the image pin rather than catalogue provenance. It was one `git commit` away from recording an unlanded catalogue layout as live deployment state. Caught only because `compose-review` prints a behind-origin warning that someone happened to read. See [deploy#409](https://forgejo.coilysiren.me/coilyco-bridge/deploy/issues/409). Any tool that reads a resident checkout as a source of truth has this exposure. Catalogue composition is simply the one that surfaced. ## What to decide **Scope.** Resident checkouts are the ones Agent Compose's `repository-plan.yaml` places under `~/projects/<owner>/`. That file is the natural source for which directories are in scope, so the policy should read from it rather than hardcode a glob. **Mechanism.** Options, roughly in increasing strength: 1. Advisory only. A session-start or prompt check that reports any resident checkout not on `main`, or dirty, or holding unpushed branches. 2. A `post-checkout` hook that warns loudly on leaving `main` in a resident path. 3. A guard that refuses the checkout outright, with an explicit override. 4. Tool-side. Any command that reads a checkout as a catalogue or source of truth refuses when that checkout is off `main` or behind origin. `compose-review` already detects this and writes anyway, which is the specific gap that let today's artifact through. Option 4 is worth doing regardless of what happens with 1 through 3, because it fails closed at the point where the wrong state actually causes damage. **Escape hatch, non-negotiable.** Several repos explicitly direct agents to work outside the resident checkout. `agent-proxy`'s `AGENTS.md` says to use a task-scoped temporary clone and remove it afterward. Whatever lands must leave `git worktree`, temporary clones, and scratch paths completely unaffected, or it will simply be bypassed. ## Suggested first step Ship the advisory check and option 4 together. The advisory makes drift visible without blocking anyone, and the tool-side refusal closes the path where drift actually corrupts an artifact. Decide on hard enforcement after seeing how often the advisory fires.
Author
Member

Option 4 is filed as coilyco-bridge/deploy#778. #1203 merged and closed this citing deploy#409, which is closed and was the artifact regeneration rather than the guard, so the half this issue calls the important one was tracked nowhere.

I found the line rather than describing it. services/sirens-echo/scripts/compose-review.sh:44, in coilyco-bridge/deploy:

    if [ "${branch}" != "${base#origin/}" ] || [ "${behind:-0}" != 0 ]; then
        echo "compose-review: ${dir} is ${behind:-?} commit(s) behind ${base}." >&2
        echo "  A written artifact would not match the runner's fresh clone." >&2
    fi

Detects the condition, states that the artifact will not match the runner's clone, returns 0, writes it. Exactly as this issue described, and it is the shape phase 3 of #1177 spent today removing.

deploy#778 carries the line, what it already cost once, and the ask: refuse rather than warn, with an explicit override, naming off-main and behind-origin separately since the operator's next move differs.

The advisory half that shipped here is good and I have no findings on it. This comment is only so the pair this issue asked to ship together is not half-lost in a closed thread.

**Option 4 is filed as `coilyco-bridge/deploy#778`.** #1203 merged and closed this citing deploy#409, which is closed and was the artifact regeneration rather than the guard, so the half this issue calls the important one was tracked nowhere. I found the line rather than describing it. `services/sirens-echo/scripts/compose-review.sh:44`, in `coilyco-bridge/deploy`: ```sh if [ "${branch}" != "${base#origin/}" ] || [ "${behind:-0}" != 0 ]; then echo "compose-review: ${dir} is ${behind:-?} commit(s) behind ${base}." >&2 echo " A written artifact would not match the runner's fresh clone." >&2 fi ``` Detects the condition, states that the artifact will not match the runner's clone, returns 0, writes it. Exactly as this issue described, and it is the shape phase 3 of #1177 spent today removing. deploy#778 carries the line, what it already cost once, and the ask: refuse rather than warn, with an explicit override, naming off-main and behind-origin separately since the operator's next move differs. The advisory half that shipped here is good and I have no findings on it. This comment is only so the pair this issue asked to ship together is not half-lost in a closed thread.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os#1033
No description provided.