Skip to content

Key Solargraph pin cache on fork revision; clear stale-cache @sg-ignore markers - #469

Merged
apiology merged 10 commits into
mainfrom
worktree-delegated-honking-duckling
Aug 7, 2026
Merged

Key Solargraph pin cache on fork revision; clear stale-cache @sg-ignore markers#469
apiology merged 10 commits into
mainfrom
worktree-delegated-honking-duckling

Conversation

@apiology

@apiology apiology commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • .envrc: sets SOLARGRAPH_FORCE_VERSION from the Gemfile.lock-pinned apiology/solargraph git revision, so Solargraph's PinCache (keyed only on the static Solargraph::VERSION string) busts automatically whenever the pinned fork revision changes -- previously a bundle update moving the branch to a new commit could silently reuse stale pins.
  • Removes the 49 tool-limitation:pr-1274-follow-on @sg-ignore markers: castwide/solargraph#1274's thread confirmed the generic<X>/generic<T> leak they guarded against was exactly this stale-cache artifact, not a real regression. bin/solargraph typecheck --level strong now reports 0 problems both under the old warm cache and a full rebuild under the new revision-keyed cache dir.
  • Tags one new marker the same run surfaced: .git-hooks/pre_commit/punchlist.rb's Overcommit::Hook::Message.new(...) call, where Solargraph resolves a block-form Struct subclass's generated initializer against Struct.new's own class-definition signature instead (tool-limitation:struct-new-block-form -- same neighborhood as open castwide/solargraph#1268/#1269/#260).

Test plan

  • bin/solargraph typecheck --level strong -- 0 problems, both before and after a full cache rebuild under the new SOLARGRAPH_FORCE_VERSION-keyed directory
  • bundle exec rake test -- 308 tests, 0 failures
  • bundle exec rubocop .git-hooks/pre_commit/punchlist.rb -- no offenses

apiology and others added 5 commits August 7, 2026 10:23
…ct gap

castwide/solargraph#1274's PR thread confirmed the generic<X>/generic<T> leak
that prompted these 49 markers was a stale on-disk pin cache artifact, not a
real regression: PinCache keys its cache dir only on the static
Solargraph::VERSION string, so a bundle update that swaps the gem revision
without clearing ~/.cache/solargraph reuses pins written under the old
Pin::Callable schema. A fresh cache makes the symptom disappear with no code
change needed. Removes all 49 tool-limitation:pr-1274-follow-on ignores this
implies; local strong typecheck now reports 0 problems.

Also tags one new marker surfaced by that same run:
.git-hooks/pre_commit/punchlist.rb's Overcommit::Hook::Message.new(...) call,
where Solargraph resolves the block-form Struct subclass's generated
initializer against Struct.new's own class-definition signature instead
(tool-limitation:struct-new-block-form) -- in the same neighborhood as the
open castwide/solargraph#1268/#1269/#260 Struct-support gaps, but not yet
filed as its own issue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
Solargraph's PinCache.work_dir keys its on-disk cache directory only on the
static Solargraph::VERSION string. This repo pins solargraph to a branch of
the apiology/solargraph integration fork rather than a released version, so
a `bundle update` that moves the branch to a new commit doesn't bump
VERSION -- stale pins from the old commit get silently reused. That exact
scenario produced a false-positive regression report against
castwide/solargraph#1274 (generic<X>/generic<T>
leaking into ordinary Hash#fetch calls) that turned out to be nothing but
this stale cache.

Sets SOLARGRAPH_FORCE_VERSION to include the Gemfile.lock-pinned git
revision whenever solargraph is git-sourced, so any revision change busts
the cache automatically. apiology/solargraph's own .envrc does something
similar already, keyed off branch name; this keys off the exact revision
instead, since a branch can move to a new commit without a corresponding
version bump.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
.envrc (e071f39) forces SOLARGRAPH_FORCE_VERSION from the pinned git
revision so Solargraph's PinCache busts on a revision bump. That same
variable also feeds the apiology/solargraph fork's own gemspec (s.version =
Solargraph::VERSION), so leaving Gemfile.lock's spec entry at the stale
static "solargraph (0.60.3)" label made Bundler see a mismatch against the
live-evaluated gemspec and fail with Bundler::GemNotFound on install/check.

`bundle update solargraph --conservative` (run with the forced version
active) re-resolves and records the matching label,
"solargraph (0.0.1.dev.pre.<revision>)", so Bundler and the forced version
agree going forward. `bundle check` and `bin/solargraph typecheck --level
strong` are both clean after this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
…nned

Bundler's git-source checkout for solargraph
(<GEM_HOME>/bundler/gems/solargraph-<shortsha>/) lives under the shared,
machine-wide GEM_HOME by default -- one checkout per revision, shared
across every worktree/repo on this machine. Its on-disk gemspec is
dynamic (s.version reads SOLARGRAPH_FORCE_VERSION), so any other process
resolving the same revision with a different (or absent) value races
against this worktree and can leave RubyGems' cached spec for that
checkout answering with the wrong version.

That race reproduced two distinct failures locally: a hard
`Bundler::GemNotFound`/"can no longer be found in that source" error on
plain `bundle install`/`bundle check`, and -- more subtly -- a silent
partial `rbs collection update` result (69 gems -> 25) with no error at
all, since rbs's Bundler-based gem enumeration degrades rather than
raising when the shared spec is momentarily wrong.

Setting BUNDLE_PATH to a worktree-local `vendor/bundle` (already
gitignored and already a supported mode per the Makefile's `realclean`
target) removes the sharing entirely -- there's nothing left to race
against. Scoped to only fire when solargraph is git-pinned (same
Gemfile.lock GIT-block check already used for SOLARGRAPH_FORCE_VERSION):
a released solargraph has no such dynamic gemspec, so there's nothing to
isolate and no need to pay a full per-worktree `bundle install` (measured
~1min for checkoff's ~150 gems).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
CI (and any other caller that skips .envrc) needs the same
SOLARGRAPH_FORCE_VERSION .envrc computes locally, or `bundle install`
fails: the apiology/solargraph fork's gemspec (s.version reads this env
var) evaluates to the plain default with it unset, which doesn't match
the forced label Gemfile.lock records for the pinned git revision.

A prior attempt added a separate CircleCI step exporting into
$BASH_ENV before fix.sh runs, but that didn't take effect in the
"Initialize packages" step that actually calls `bundle install` --
reverted. Computing it directly inside fix.sh (guarded so an
already-set value from .envrc wins) puts it in the exact process that
needs it, regardless of caller.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
@apiology
apiology force-pushed the worktree-delegated-honking-duckling branch from 5b2c9e1 to 6ff1d15 Compare August 7, 2026 19:11
apiology and others added 5 commits August 7, 2026 15:21
The "rbenv" cache (vendor/bundle, Gemfile.lock.installed, .bundle) used a
fallback key ladder ending in a bare "rbenv-" prefix. CircleCI's
restore_cache treats a dash-terminated key as a prefix match, so that
bare fallback matches *any* cache ever saved under "rbenv-v5-...", "-v4-",
etc, regardless of Gemfile.lock/Gemfile/gemspec/Makefile/config.yml
content. That let a stale vendor/bundle (with a bundler/gems/solargraph-*
checkout resolved under a different or absent SOLARGRAPH_FORCE_VERSION)
get restored ahead of fix.sh even running, reproducing the exact
Bundler::GemNotFound failure this session's fix.sh/.envrc/Gemfile.lock
changes were supposed to eliminate -- the same GEM_HOME race as the
original local bug, just via CircleCI's cache instead of a shared
GEM_HOME.

Bumping v5 -> v6 and removing the bare fallback forces a real cache miss
here, so this build actually exercises the new fix.sh logic instead of
restoring pre-fix state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
The previous commit fixed today's stale-cache restore by bumping the
version prefix and dropping the ladder's loosest fallback tiers, but
that made the cache bust on any gemspec/Gemfile/Makefile/config.yml
change too, defeating the point of the fallback ladder.

Gemfile.lock's checksum already changes whenever solargraph's pinned
git revision does, but every fallback tier past the first one drops
that checksum to tolerate unrelated Gemfile.lock churn (other gems'
version bumps). That's what let a stale vendor/bundle -- with a
bundler/gems/solargraph-* checkout resolved under a different or
absent SOLARGRAPH_FORCE_VERSION -- get restored ahead of fix.sh even
running.

Isolate solargraph's pinned revision into its own file
(/tmp/solargraph_revision, computed via the same Gemfile.lock GIT-block
awk extraction .envrc/fix.sh already use) and include its checksum in
every tier of the ladder, including the loosest. A solargraph revision
change now always forces a fresh install regardless of what else
changed, while unrelated file changes still get the existing graceful
degradation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
CI's last run got past bundle install for the first time this session
(the cache-key fix worked) but bin/solargraph typecheck --level strong
found 52 problems in 13 files that don't reproduce locally (0 problems).
solargraph cached 217 gems in CI vs 218 locally, so something about the
resolved environment differs between CI and local despite both showing
the correct forced version and pinned revision at the shell level.

Echoing SOLARGRAPH_FORCE_VERSION, BUNDLE_PATH, `solargraph --version`,
`bundle show solargraph`, and the Gemfile.lock pinned revision right
before typecheck runs, in the exact same job step, to compare CI's
actual values against local's next to each other. Temporary -- revert
once the mismatch is found.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
Debug output confirmed SOLARGRAPH_FORCE_VERSION and BUNDLE_PATH were
both <unset> at the ci-solargraph step, resolving solargraph against
the shared GEM_HOME path rather than the pinned/forced version --
explaining the 52 bogus typecheck problems in the last CI run despite
bundle install succeeding earlier in the same job.

CircleCI runs each `run:` step as its own fresh shell. fix.sh's
`export` only lives inside the "Initialize packages" step's process,
so `bundle install` there sees the correct forced version, but the
later "Typecheck" step's `bundle exec`/`solargraph typecheck` runs in a
new shell that never saw it, re-evaluates the pinned gem's dynamic
gemspec with the var unset, and gets the plain default version instead.

$BASH_ENV is sourced at the start of every step in a CircleCI job, so
appending the export there (guarded on $BASH_ENV being set, i.e. only
under CircleCI) makes every later step in the job see the same value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
Their output found the actual bug (SOLARGRAPH_FORCE_VERSION unset by
the time the Typecheck step ran, fixed by persisting it to $BASH_ENV
in fix.sh) -- no longer needed now that CI is green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3YDrArZm1e4DQ3MnFCSZk
@apiology
apiology marked this pull request as ready for review August 7, 2026 20:37
@apiology
apiology merged commit b42429c into main Aug 7, 2026
2 checks passed
@apiology
apiology deleted the worktree-delegated-honking-duckling branch August 7, 2026 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant