From 09df8ecde1301cf9bb440e453b99088ca78f695d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 20 Jun 2026 18:29:20 +0000 Subject: [PATCH 1/2] Remove import-trace/watchdog debugging; set CI timeout to 1m The hang that the debugging in bd79d03/60c73cf chased was fixed at the root in 994e35d (stop importing __main__/dunder submodules that start mainloops). Clean up the leftover scaffolding: - Always print the import trace; drop the TRACE_IMPORTS env gate. - Remove the watchdog (--watchdog / WATCHDOG_SECONDS and its faulthandler abort) and the os._exit hang-workaround in the sanity gate. Both were mitigations for the now-fixed hang; the gate goes back to a plain sys.exit(). CI timeout-minutes is the remaining backstop. - Drop the WATCHDOG_SECONDS/TRACE_IMPORTS env vars from the workflow and set timeout-minutes: 1 for both jobs (they run ~15s). Signed-off-by: Claude Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01UxZtQYdfoRbgPm93SVDoRn --- .github/workflows/stdlib-introspect.yaml | 6 ++---- tools/stdlib_introspect.py | 17 +++-------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/.github/workflows/stdlib-introspect.yaml b/.github/workflows/stdlib-introspect.yaml index 49c00f2..82bf03e 100644 --- a/.github/workflows/stdlib-introspect.yaml +++ b/.github/workflows/stdlib-introspect.yaml @@ -27,7 +27,7 @@ jobs: introspect: name: introspect ${{ matrix.os }} / py${{ matrix.python-version }} runs-on: ${{ matrix.os }} - timeout-minutes: 5 + timeout-minutes: 1 strategy: fail-fast: false matrix: @@ -50,8 +50,6 @@ jobs: INCLUDE_DUNDERS: ${{ github.event.inputs.include_dunders || 'false' }} INCLUDE_PRIVATE: ${{ github.event.inputs.include_private || 'false' }} OUT: stdlib_api_${{ matrix.os }}_py${{ matrix.python-version }}.jsonl - WATCHDOG_SECONDS: "120" - TRACE_IMPORTS: "1" run: | flags=() [ "$INCLUDE_DUNDERS" = "true" ] && flags+=(--include-dunders) @@ -76,7 +74,7 @@ jobs: needs: [introspect] if: always() # union whatever cells succeeded, even if some cells failed runs-on: ubuntu-latest - timeout-minutes: 5 + timeout-minutes: 1 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 diff --git a/tools/stdlib_introspect.py b/tools/stdlib_introspect.py index 356e207..04fbd55 100644 --- a/tools/stdlib_introspect.py +++ b/tools/stdlib_introspect.py @@ -57,8 +57,7 @@ def safe_import(name): short_name = name.split(".")[-1] if name in SKIP_MODULES or short_name in SKIP_MODULES: return None - if os.environ.get("TRACE_IMPORTS"): - print(f" importing {name}", file=sys.stderr, flush=True) + print(f" importing {name}", file=sys.stderr, flush=True) try: with _silenced(): return importlib.import_module(name) @@ -208,13 +207,7 @@ def main(): parser.add_argument("--min-entities", type=int, default=5000, help="sanity gate: exit non-zero if fewer than N records were " "produced (a near-empty dump means the build is broken)") - parser.add_argument("--watchdog", type=int, default=int(os.environ.get("WATCHDOG_SECONDS", "0")), - help="if >0: dump all thread stacks and abort after N seconds " - "(a stdlib module that HANGS on import can't be caught by try/except)") args = parser.parse_args() - if args.watchdog > 0: - import faulthandler - faulthandler.dump_traceback_later(args.watchdog, exit=True) scanned, failed = 0, [] for name, module in roster(args.include_private): @@ -250,13 +243,9 @@ def main(): # Gate last, after the output and summaries are written, so a broken cell still # uploads its dump and renders a summary before the non-zero exit fails the job. - sys.stdout.flush(); sys.stderr.flush() if len(records) < args.min_entities: - print(f"\nSANITY GATE: only {len(records)} records " - f"(< --min-entities {args.min_entities}); this build looks broken.", - file=sys.stderr, flush=True) - os._exit(1) - os._exit(0) + sys.exit(f"\nSANITY GATE: only {len(records)} records (< --min-entities " + f"{args.min_entities}); this build looks broken.") def _stats(records, scanned, failed): from collections import Counter From 8aaf69bb37f2c3caa478007d8ae51a626ac42006 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 20 Jun 2026 18:38:23 +0000 Subject: [PATCH 2/2] Print import trace to stdout instead of stderr The trace is still always printed, but stderr now stays quiet on a normal run so consumers that treat stderr output as an error signal aren't tripped by progress lines. The sanity-gate failure still goes to stderr (via sys.exit), where an actual error belongs. Signed-off-by: Claude Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01UxZtQYdfoRbgPm93SVDoRn --- tools/stdlib_introspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/stdlib_introspect.py b/tools/stdlib_introspect.py index 04fbd55..c70655a 100644 --- a/tools/stdlib_introspect.py +++ b/tools/stdlib_introspect.py @@ -57,7 +57,7 @@ def safe_import(name): short_name = name.split(".")[-1] if name in SKIP_MODULES or short_name in SKIP_MODULES: return None - print(f" importing {name}", file=sys.stderr, flush=True) + print(f" importing {name}", flush=True) try: with _silenced(): return importlib.import_module(name)