Skip to content

test(hosted): decide the gem tolerance by probing the server - #149

Open
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/gem-hosted-install
Open

test(hosted): decide the gem tolerance by probing the server#149
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
mainfrom
fix/gem-hosted-install

Conversation

@mikolalysenko

@mikolalysenkoMikola Lysenko (mikolalysenko) commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Problem

The hosted-e2e gem install leg tolerates its known server defect (the gem patch-registry's compact index is not built) by string-matching bundler's error text. That couples the check to one particular symptom of the server bug — and the symptom is a function of which fetcher bundler lands on, which changes as the server changes underneath it.

Bundler picks a fetcher via available_fetchers.drop_while {|f| !f.available? } over [CompactIndex, Dependency, Index], so one unchanged server condition has already produced three different error strings:

server state/versions/api/v1/dependenciesbundler raises
originally200, empty dep segmentBundler::APIResponseMismatchError
after depscan#23630404 not_built200, zero bytesmarshal data too short (classic) / undefined method 'bytes' for nil (SafeMarshal, ruby 3.4+)
after the pending deps-API fix404 not_built404Could not fetch specs from …

The current whitelist (from #146) covers rows 1–2 only, so the leg would go red a third time on the very deploy that fixes the bug.

Fix

Decide by the condition, not the symptom: probe the pinned registry's /versions, using the base read back out of the rewritten Gemfile'ssource "…" do block — so the probe interrogates the exact registry bundler was given, and a broken rewriter can't be papered over by a probe that guesses the right URL.

  • non-2xx → the documented server defect; report loudly (probe URL + status + body length in the message) and pass;
  • 2xx → the index is built, hosted gem mode MUST work, and any install failure is a real regression that fails the suite.

This is symptom-independent and auto-retires: the moment the server is healthy, the 2xx branch starts enforcing a real success assertion — no stale whitelist, no NOTE asking a human to clean up. SOCKET_PATCH_HOSTED_E2E_GEM_STRICT=1 still promotes any install failure to a hard failure; every redirect hard-assertion is unchanged. A transport error on the probe is tolerated rather than failed: a network blip is the likeliest explanation for both the probe and the install failing, and a required check must not go red for one.

Verification

  • Live against production (2026-08-06, re-run post-rebase): probe reports GET …/versions -> HTTP 404, 21-byte body, leg soft-fails loudly and exits 0 in ~51s; all redirect assertions pass.
  • Non-vacuity: repointing the probe at the same registry's /names (a real 200, 18-byte response) flips the leg to the intended hard failure — the 2xx enforcement path is live, not dead code.
  • cargo fmt clean, cargo clippy --test e2e_hosted_production -- -D warnings clean.

Shipping order

This must land before (or with) the depscan fix that 404s the empty-body /api/v1/dependencies route — deploying that server fix first would red the current whitelist (row 3 above). This PR is safe to land alone: the probe tolerates every current and future server state until /versions goes 2xx.

🤖 Generated with Claude Code


Note

Low Risk
Test-only change to hosted e2e tolerance logic; no production CLI or runtime behavior.

Overview
The hosted production e2e gem leg no longer whitelists bundler error strings to tolerate the known gem patch-registry compact-index defect. It now GETs /versions on the registry URL parsed from the rewritten Gemfile (gem_registry_base + http_probe with a bundler-shaped User-Agent), and branches on HTTP status instead of symptom text.

Non-2xx (or probe transport failure): expected server defect—loud KNOWN PRODUCTION DEFECT log and pass. SOCKET_PATCH_HOSTED_E2E_GEM_STRICT=1 still hard-fails any install failure. 2xx while install fails: treated as a real regression and fails the suite, so the tolerance auto-retires when the index is built without maintaining error-message lists.

The test is async (tokio::test) to run the probe; redirect assertions are unchanged.

Reviewed by Cursor Bugbot for commit 9c60999. Configure here.

The gem install leg accepted its known-server-defect failure by
string-matching bundler's error text. That couples a CI check to one
particular symptom of the server bug, and the symptom is a function of
which fetcher bundler lands on -- which the server keeps changing.
Bundler selects a fetcher with `available_fetchers.drop_while {|f|
!f.available? }` over `[CompactIndex, Dependency, Index]`, so one
unchanged server condition has already produced three different errors:
* originally: /versions 200 with an empty dependency segment, so
bundler raised `Bundler::APIResponseMismatchError`;
* after depscan#23630: /versions 404 not_built, and the
/api/v1/dependencies fallback answered 200 with a ZERO-byte body,
so unmarshalling died with `ArgumentError: marshal data too short`
(classic Marshal) or `NoMethodError: undefined method 'bytes' for
nil` (SafeMarshal, ruby 3.4+);
* once that empty-body route is fixed to 404: bundler drops the
dependency fetcher and raises `Could not fetch specs from ...`.
The third string matches none of the substrings the current whitelist
accepts, so the check would have gone red a third time the moment the
server fix deployed.
Decide by the CONDITION instead: probe the pinned registry's
`/versions`, using the base read back out of the rewritten Gemfile's
`source "..." do` block so the probe interrogates the exact registry
bundler was given.
* non-2xx -> the documented server defect; report loudly and pass;
* 2xx -> the index is built, so hosted gem mode MUST work, and an
install failure is a real regression that fails the suite.
This is symptom-independent and auto-retires itself: the moment the
server is healthy the 2xx branch starts enforcing a real success
assertion, with no stale whitelist and no NOTE asking a human to clean
up. SOCKET_PATCH_HOSTED_E2E_GEM_STRICT=1 still promotes any install
failure to a hard failure, and every redirect hard-assertion is
unchanged. Failure messages now carry the probe URL and status so a
future reader need not re-derive any of this.
A transport error on the probe is tolerated rather than failed: a
network blip is the likeliest explanation for both the probe and the
install failing, and a required check must not go red for one.
Verified live against production: /versions returns HTTP 404 with a
21-byte body, the leg soft-fails and exits 0 in 52s.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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

@mikolalysenko