From 4fe1e17038d492be70ca2b4d04406f3b9f7de328 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 14 Aug 2026 20:19:39 -0700 Subject: [PATCH] =?UTF-8?q?fix(slug):=20cached=20identity=20is=20sticky=20?= =?UTF-8?q?=E2=80=94=20heal=20ONLY=20the=20provable=20subdir-cache=20bug?= =?UTF-8?q?=20shape?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The walk-up rewrite recomputed the slug on every run and "healed" the cache toward the fresh value, which broke the #2212 continuity contract: a project that used gstack before adopting a git remote would be silently renamed to the remote-derived slug, orphaning everything under ~/.gstack/projects/. Cached identity now wins, with one precise exception: when the cached value equals THIS pwd's basename while the walk-up proves pwd is not the project root, the entry came from the pre-walk-up subdirectory bug (#1125) and is recomputed. All four slug contracts pass together (repo-mode #2212, walk-up #1125, sanitize, user-slug). Co-Authored-By: Claude Fable 5 --- bin/gstack-slug | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bin/gstack-slug b/bin/gstack-slug index 0386188d4..12c5b4643 100755 --- a/bin/gstack-slug +++ b/bin/gstack-slug @@ -101,6 +101,27 @@ if [[ -z "$SLUG" ]]; then PROJECT_ROOT=$(_outermost_project_root "$PROJECT_DIR") fi +# 1b. Cached identity is STICKY (#2212): a project that used gstack before it +# adopted a git remote keeps its pre-origin slug — recomputing from the +# remote here would rename the project mid-life and orphan everything +# under ~/.gstack/projects//. The ONE exception is the provable +# old-bug shape (#1125): the pre-walk-up resolver cached basename(pwd) +# for a SUBDIRECTORY of the real project — if the cached value equals this +# pwd's basename while the walk-up says pwd is NOT the project root, the +# cache came from that bug, not from legitimate identity; fall through and +# recompute so it heals. +if [[ -z "$SLUG" && -f "$CACHE_FILE" ]]; then + _CACHED=$(cat "$CACHE_FILE" 2>/dev/null | tr -cd 'a-zA-Z0-9._-') + if [[ -n "$_CACHED" ]]; then + _PWD_BASE=$(basename "$PROJECT_DIR" | tr -cd 'a-zA-Z0-9._-') + if [[ "$_CACHED" == "$_PWD_BASE" && -n "$PROJECT_ROOT" && "$PROJECT_ROOT" != "$PROJECT_DIR" ]]; then + : # old-bug shape — recompute below and self-heal the cache + else + SLUG="$_CACHED" + fi + fi +fi + # 2. If we found a project root and it has a git remote, derive slug from the # remote URL (existing logic — kept verbatim, just rooted at PROJECT_ROOT # instead of $PWD so a subdir without its own remote inherits the parent's).