feat(cms): auto-switch stale session branches to a fresh one on CMS open - #6639
Merged
Conversation
Opening the CMS on a branch whose head commit is older than the staleness
window (2 days) moves the session to a freshly minted branch cut from the
default branch. The stale branch is left intact on GitHub (recoverable).
Gated by the org flag cms_auto_fresh_branch (default off); one switch per
thread per tab, mirroring the existing branch-adopt guard.
Git stores no ref-creation time, so the signal is the branch head commit's
date: a never-edited side branch keeps the (old) base commit it was cut
from, so it is still detected as stale without any commits of its own.
- api: getBranchHead on the git-data client; decofile /status now returns
lastCommitAt (null for the default branch and unmaterialized branches).
- web: pure isBranchStale predicate + decofile status query; one-shot
switch effect in VmEventsBridge, gated on runtime === "cms" and the flag.
- e2e: github stub grows commit dates + a /branches/{branch} route; new
/status contract test; existing status assertions updated for the field.
- unit: isBranchStale.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guitavano
force-pushed
the
guitavano/cms-auto-fresh-branch
branch
from
August 28, 2026 12:29
eb6ea8a to
6d5c9d1
Compare
decocms Bot
pushed a commit
that referenced
this pull request
Aug 28, 2026
PR: #6639 feat(cms): auto-switch stale session branches to a fresh one on CMS open Bump type: minor - decocms (apps/api/package.json): 4.290.1 -> 4.291.0 - @decocms/native (apps/native/package.json): 4.290.1 -> 4.291.0 - @decocms/e2e (packages/e2e/package.json): 1.56.0 -> 1.57.0 - @decocms/shared (packages/shared/package.json): 0.66.0 -> 0.67.0 Deploy-Scope: both
pedrofrxncx
added a commit
that referenced
this pull request
Aug 28, 2026
…McpId) call (#6678) VmEventsBridge called useSessionRuntime(virtualMcpId) twice with identical args - once for the auto-fresh-branch staleness check (#6639), once further down for the sandbox events gate. Both calls resolve to the same answer for the same render; the second was pure recompute. Reuse the first result.
guitavano
added a commit
that referenced
this pull request
Aug 28, 2026
…p) (#6680) After #6667 started addressing destinations by path, a repo-backed agent editor could open with no thread in the URL (`?thread=` absent — a deep link, choose-editor, or any navigation that didn't carry it, since the shell deliberately doesn't retain `thread`). The branch is a thread field, so a threadless editor stranded the branch picker on "Select branch…" with selecting and "New" both silently no-op (setCurrentTaskBranch is gated on an active thread), and the adopt/auto-fresh effects never fired. AgentInsetProvider now guarantees a thread for repo-backed agents: when the URL names none it mints one into `?thread=` before mounting, reusing the user's idle empty "New chat" for that agent when one exists — exactly what useNavigateToAgent does (findReusableNewChat ?? fresh id). This restores the pre-#6667 behavior where the client minted the thread id and the ensure fallback created the row on landing. Scoped to repo-backed agents; the Super Agent keeps its lazy threadless composer. Complements #6639: with a thread guaranteed, adopt-branch mints a fresh (unmaterialized, non-stale) branch and the auto-fresh-stale check evaluates correctly instead of sitting dead on a threadless entry. Co-authored-by: Claude Opus 4.8 <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.
O que é
Quando alguém abre o CMS numa branch de sessão cujo último commit é mais antigo que a janela de staleness (2 dias), a sessão troca automaticamente para uma branch nova cortada da default branch. A branch velha não é apagada nem alterada — continua no GitHub, recuperável.
Motivação: alguém some por ~15 dias e volta pra uma branch defasada/quebrada; em vez disso passa a cair numa branch limpa e atual.
cms_auto_fresh_branch(default OFF) — nada muda até uma org ligar explicitamente.ref, mesmo padrão do branch-adopt que já existia).runtime === "cms".Por que "data do último commit" e não "data de criação"
Git não guarda quando um ref nasceu e a API do GitHub não expõe isso de forma confiável. O sinal robusto — sem depender do nome da branch — é a data do commit para o qual o head aponta. Isso pega inclusive a branch nunca editada: o ref fica congelado no commit da main de quando nasceu, então uma branch de 15 dias tem head com data velha e é detectada como stale, mesmo sem nenhum commit próprio.
Mudanças
getBranchHeadno git-data client;decofile /statusagora devolvelastCommitAt(nullpara a default branch e branches ainda não materializadas → nunca troca).isBranchStale+ query de status do decofile; efeito one-shot de troca noVmEventsBridge.cms_auto_fresh_branch+ contratos regenerados./branches/{branch}; novo teste de contrato do/status; asserts antigos do status atualizados para o campo novo.isBranchStale.Como ligar
Testing
tsc(api/web/shared/e2e),fmt,lint(0 erros),kniplimpoisBranchStale(7/7):5432) — roda no CI.Caveat
Se a própria
mainficar parada +2 dias, trocar uma branch limpa-porém-antiga geraria outra branch limpa (churn inofensivo, sem perda de dado) — irrelevante em repo ativo. Se incomodar, o passo seguinte é o servidor gravarbranchCreatedAtno momento de criação do ref.🤖 Generated with Claude Code
Summary by cubic
Auto-switches the CMS session to a fresh branch when the current branch's last commit is older than 2 days, so returning users don't keep working on a lagging branch. The stale branch stays intact on GitHub; the behavior is off by default behind the
cms_auto_fresh_branchorg flag.Changes
getBranchHeadto the git-data client andlastCommitAtto the decofile/statusresponse (null for default/unmaterialized branches).isBranchStalecheck and a one-shot switch effect inVmEventsBridge, gated onruntime === "cms"./branches/{branch}route; adds a/statuscontract test and unit tests forisBranchStale.ORGANIZATION_SETTINGS_UPDATEwithcms_auto_fresh_branch: true.Written for commit 6d5c9d1. Summary will update on new commits.