fix(pm): route check-half-states' probe through the session proxy - #13574
Merged
os-project-manager merged 1 commit intoAug 31, 2026
Merged
Conversation
`check-half-states --probe` reported PREREQUISITE NOT MET in containers that reach api.github.com perfectly well. Node's `fetch` ignores `HTTPS_PROXY`, so the script sent the agent proxy's 14-character placeholder token straight to GitHub, earned a 401, and reported that refusal as the container's verdict — the #4690 class inverted: readable looks like unreadable. Live modes now re-exec once with `--use-env-proxy` when a proxy is configured and the process is not already routed through it. It has to be a re-exec: assigning `process.env.NODE_USE_ENV_PROXY` from inside is too late (measured). Same mechanism `check-governed-merges.mjs` already carries, kept as its own copy because this file is copied verbatim into sibling repos. The refusal itself is untouched: a failed probe still prints PREREQUISITE NOT MET and still exits 3. Two wordings that the fix falsified are corrected — a bypassed reading now prescribes the ROUTE instead of a credential nobody needs, and a routed refusal no longer reassures the reader that node ignores the proxy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
This was referenced Aug 31, 2026
os-project-manager
marked this pull request as ready for review
August 31, 2026 02:11
os-project-manager
deleted the
claude/issue-13544-half-states-probe-proxy
branch
August 31, 2026 02:29
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.
Fixes #13544
The defect
scripts/pm/check-half-states.mjs --probereportedPREREQUISITE NOT METincontainers that reach
api.github.comperfectly well, and prescribed acredential the caller does not need. Node's
fetchignoresHTTPS_PROXY, sothe script sent the agent proxy's 14-character
prox…placeholder straight toGitHub, earned a 401, and reported that refusal as the container's verdict.
Re-derived in this container before writing a line — same host, same token, same
second, three endpoints, two routes:
GET /rate_limitserver: github.comGET /userGET /repos/objectstack-ai/objectstackx-github-request-idcurlanswered 200 on all three throughout, because it honours the proxy. Thisis the #4690 class inverted: readable looks like unreadable, and a probe
that says "you can't" is not argued with.
The shape, and why it is this one
The card offered two shapes and asked for the choice to be measured. Both
were measured, and the result rewrites the tradeoff the card stated:
NODE_USE_ENV_PROXY=1from within the script — doesnot work. The switch is read at process start; assigning
process.env.NODE_USE_ENV_PROXYfrom inside still answered 403 fromserver: Varnish, i.e. still the bypassed route. It has to be a re-exec.EnvHttpProxyAgent+setGlobalDispatcher— isunavailable here.
require.resolve('undici')isMODULE_NOT_FOUNDin thisrepo, so (b) would add a dependency to a file whose entire adoption story is
"copy it verbatim into sibling repos" ([finding] The half-state patrol sweeps objectstack ONLY — 37 blocked cards in objectui/cloud/objectos have never been machine-swept, and 7 stale blocks were sitting in the gap #11217). Rejected on that constraint.
--disable-warning=UNDICI-EHPAsilences it, so the diff carries neither thewarning nor a dependency.
So live modes re-exec once with
--use-env-proxywhen a proxy is configured andthe process is not already routed through it.
scripts/pm/check-governed-merges.mjsalready carries exactly this mechanism for exactly this reason; this file keeps
its own copy rather than importing it, because the patrol pair is copied
verbatim and must not acquire a dependency on a file outside that pair.
What did NOT change — the three constraints
PREREQUISITE NOT METand still exits 3. Nothing was weakened so the sweep could proceed on a
failed probe.
EXIT_PREREQUISITE_NOT_METis untouched,and the "nothing was swept" paragraph is untouched.
classifyTransportProbeis unchanged for its other importer. The routereading is an optional field; handed none, every verdict is byte-identical
— pinned as a self-test case, so
scripts/pm/ci-failure.mjsis unaffected.The stage-2 repo-scoped probe (#9946) also stays exactly as it is. The class it
was built for refused repo-scoped reads through the proxy; this container
allows them. Both readings are true, of different routes, and the proxy's
repo-scope policy is per-container — so the discriminator is still needed.
Two wordings the fix falsified, and corrected
node --use-env-proxy …)and demotes the credential remedy to
If the route is not the problem: ….The old text sent the reader after a secret they do not need.
not use HTTPS_PROXY" — that stopped being true the moment this file routes
it. A stale reassurance inside a refusal is the same defect one layer down.
Verification — the control runs BOTH ways
Every leg below is a real run in a proxied agent container with the placeholder
token unchanged (
len 14, prefixproxy). No real credential was supplied.Leg A — reachable direction,
--probe:EXIT=0Leg A2 — non-vacuity, the FULL sweep against the live board:
SWEEP_EXIT=0,465 lines of findings, run
2026-08-31T01:31:51Z→01:33:39Z:(The card's reference reading was 217 at
2026-08-30T19:3xZ; the board has movedsince. Non-zero against the live board, which is what the acceptance asked for —
no fixture, no recorded response.)
Leg B — genuinely unreachable transport, the control that matters (proxy
pointed at a dead port; the re-exec still fires, the child still cannot reach the
host):
EXIT=3, and the sweep leg wrote 0 bytes to stdout.Leg C — the GitHub Actions runner shape (no proxy env): a proven no-op. With
HTTPS_PROXY/https_proxyunset, the probe output is byte-identical to thepre-change baseline captured before the first edit — 1232 bytes,
diffclean,EXIT=3both. No child process, no extra line. This is the leg that keeps thefile safe to copy verbatim, and it is measured rather than argued.
Leg D — proxy configured but the re-exec did not happen (the older-node /
failed-spawn fallback, forced via the guard env):
EXIT=3, and the report leadswith the route remedy while keeping the credential remedy as a named alternative.
Leg E — the workflow's own invocation (
--format=markdown --provenance=…):EXIT=0, 59939 bytes on stdout, and 0 occurrences of the re-exec notice instdout. The notice goes to stderr, because that stdout is redirected into an
issue body.
Gates — union run at
f892cd8a6(final commit, clean tree)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackderived31 families + 2 convention-triggered (this diff edits a gate script), harvested
with
--commandsso neither spelling is dropped. 31 green, 2 NOT MEASURED:node scripts/check-test-completeness.mjs→ exit 3, its own text: "thelocal reading for this gate is NOT MEASURED. ⛔ It is not a red, and there is
nothing here to fix." CI passes it a real log.
node scripts/check-partof-closing-keyword.mjs(bare) → exit 2, its owntext: "NOT WIRED — neither PR_BODY nor PR_NUMBER is set … This is a wiring or
usage failure, NOT a verdict." The wired spelling
pnpm check:partof-closing-keywordis green, and this body was additionally run through it with
PR_BODYset.Also green:
node scripts/pm/check-half-states.mjs --self-test— 1584 cases,30 of them new and covering the re-exec decision in every branch, the corrected
wording in both directions, the unchanged-for-ci-failure guarantee, and the
refusal-survives control.
node scripts/pm/ci-failure.mjs --self-test(the otherimporter) and
node scripts/pm/check-governed-merges.mjs --self-test(230assertions, the file this mechanism is mirrored from) are green too.
Full-repo
pnpm lint(eslint . --no-inline-config) run under the sharedverify lock:
os-verify-lock: VERDICT command-exit 0 · held the lock 102s.No changeset: this diff touches only
scripts/pm/**and one workflow docblock,publishing nothing from any package —
skip-changesetapplies and is labelled.Scope
⛔ #13526 is not addressed here and remains open — no bulk relabel, no sweep.
This card restores the probe; that population is its own card. The scheduled
patrol is untouched: it is right for the #9844 reason, which was never a
transport reason.
Generated by Claude Code