Skip to content

fix(liveness): make the sweep importable when run by file path - #3199

Merged
stranske merged 1 commit into
mainfrom
fix/liveness-import-bootstrap
Aug 23, 2026
Merged

fix(liveness): make the sweep importable when run by file path#3199
stranske merged 1 commit into
mainfrom
fix/liveness-import-bootstrap

Conversation

@stranske

Copy link
Copy Markdown
Owner

The liveness job has never worked

Its first real CI run died immediately:

ModuleNotFoundError: No module named 'scripts'

health-40 runs python scripts/workflow_startup_failure_diagnostic.py --sweep, and docs/INTEGRATION_GUIDE.md documents the same file-path form. Running a file by path does not put the repo root on sys.path, so from scripts import api_client cannot resolve. The documented per-run recipe was broken the same way, and that predates the sweep.

How I shipped it broken

I verified the sweep locally with PYTHONPATH set and via python -m, then wrote a workflow step that used neither. Every local check passed while the job failed on every run.

A module whose entire purpose is noticing that a workflow stopped executing, shipped in a form that could not execute. Same class of defect, one level up.

The fix

The bootstrap already used by the other ten scripts here that import from scripts import … while being invoked by path (scripts/docs_drift_fix_agent.py:33-37):

ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
    sys.path.insert(0, str(ROOT))

This also repairs the documented --run-id recipe, which had the same defect.

The guard runs the real invocation

test_script_runs_when_invoked_by_path_without_pythonpath executes the script by path, in a subprocess, with PYTHONPATH stripped from the environment — deliberately the invocation CI uses rather than the convenient one that hid this. Removing the bootstrap fails it; reverting restores 36/36.

Also observed, not fixed here, not caused by this

health-42-actionlint.yml:31-32 evaluates fromJson(github.event.inputs || '{}'). On workflow_dispatch with inputs, github.event.inputs is an object rather than a JSON string, so fromJson fails with Unexpected character encountered while parsing value: O (the O is Object). It breaks only the dispatch-with-inputs path — scheduled runs pass because inputs is null — and has been present since at least 2026-06. Surfaced because I dispatched health-40 with run_branch_protection=false to verify the liveness job in isolation.

🤖 Generated with Claude Code

The health-40 liveness job has never worked. Its first real CI run died on

    ModuleNotFoundError: No module named 'scripts'

health-40 runs `python scripts/workflow_startup_failure_diagnostic.py
--sweep`, and docs/INTEGRATION_GUIDE.md documents the same file-path form.
Running a file by path does not put the repo root on sys.path, so
`from scripts import api_client` cannot resolve. The documented per-run
recipe was broken the same way, and predates this module's sweep support.

I verified the sweep locally with PYTHONPATH set and via `python -m`, then
wrote a workflow step that used neither. Every local check passed while the
job failed on every run. A module whose entire purpose is noticing that a
workflow stopped executing, shipped in a form that could not execute.

Uses the same bootstrap as the other ten scripts here that import
`from scripts import ...` while being invoked by path
(scripts/docs_drift_fix_agent.py:33-37).

The regression guard runs the REAL invocation - the script by path, in a
subprocess, with PYTHONPATH stripped from the environment - rather than the
convenient one. Removing the bootstrap fails it; reverting restores 36/36.

Separately observed while verifying, NOT fixed here and not caused by this:
health-42-actionlint.yml:31-32 evaluates
`fromJson(github.event.inputs || '{}')`. On workflow_dispatch WITH inputs,
github.event.inputs is an object rather than a JSON string, so fromJson
fails with "Unexpected character encountered while parsing value: O". It
only breaks the dispatch-with-inputs path; scheduled runs pass because
inputs is null. Present since at least 2026-06.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 42 minutes

Limit details: You’ve used the included review currently available. Your 75 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ee3a163c-dd36-4495-baf0-c03618073ffc

📥 Commits

Reviewing files that changed from the base of the PR and between 72a74ec and 251f341.

📒 Files selected for processing (2)
  • scripts/workflow_startup_failure_diagnostic.py
  • tests/scripts/test_workflow_startup_failure_diagnostic.py

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 251f341a12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"""
root = Path(__file__).resolve().parents[2]
script = root / "scripts" / "workflow_startup_failure_diagnostic.py"
env = {k: v for k, v in os.environ.items() if k != "PYTHONPATH"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Test the file-path invocation without undeclared packages

In the checked health-40-sweep.yml workflow, the liveness job only runs actions/setup-python before invoking this script; it never installs project dependencies. This test removes only PYTHONPATH, so under the normal pytest environment it inherits the installed requests package and passes, whereas a clean setup-python interpreter gets past the new path bootstrap and immediately fails in scripts/api_client.py with ModuleNotFoundError: No module named 'requests'. Thus the scheduled liveness job remains unable to run; either install the dependency in that job, remove the diagnostic's third-party runtime dependency, or exercise the subprocess with an actually clean Python environment.

Useful? React with 👍 / 👎.

@stranske-keepalive

Copy link
Copy Markdown
Contributor

Automated Status Summary

Head SHA: fd5a508
Latest Runs: ⏳ pending — Gate
Required contexts: summary
Required: core tests (3.12): ⏳ pending, core tests (3.13): ⏳ pending, docker smoke: ⏳ pending, gate: ⏳ pending

Workflow / Job Result Logs
(no jobs reported) ⏳ pending

Coverage Overview

  • Coverage history entries: 1

Coverage Trend

Metric Value
Current 76.61%
Baseline 85.00%
Delta -8.39%
Minimum 70.00%
Status ✅ Pass

Top Coverage Hotspots (lowest coverage)

File Coverage Missing
scripts/issue_dedup_smoke.py 0.0% 4
scripts/runner_lib/__main__.py 0.0% 3
scripts/validate_template_sync.py 0.0% 81
scripts/langchain/topic_splitter.py 19.1% 57
tools/codex_log_analyzer.py 19.6% 140
scripts/repo_review_round2_runner.py 25.1% 344
scripts/prune_agent_stubs.py 39.7% 26
scripts/repo_review_round1_runner.py 40.7% 133
tools/ensure_workflow_timeout_variables.py 42.1% 74
scripts/sync_label_docs.py 42.9% 64
tools/discover_model_catalog.py 44.8% 55
scripts/repo_review_backlog_scan.py 45.3% 116
scripts/repo_review_body_writer.py 46.5% 86
tools/codex_session_analyzer.py 47.9% 59
scripts/create_verifier_labels.py 48.3% 58

Low Coverage Files (<50.0%)

File Coverage Missing
scripts/issue_dedup_smoke.py 0.0% 4
scripts/runner_lib/__main__.py 0.0% 3
scripts/validate_template_sync.py 0.0% 81
scripts/langchain/topic_splitter.py 19.1% 57
tools/codex_log_analyzer.py 19.6% 140
scripts/repo_review_round2_runner.py 25.1% 344
scripts/prune_agent_stubs.py 39.7% 26
scripts/repo_review_round1_runner.py 40.7% 133
tools/ensure_workflow_timeout_variables.py 42.1% 74
scripts/sync_label_docs.py 42.9% 64
tools/discover_model_catalog.py 44.8% 55
scripts/repo_review_backlog_scan.py 45.3% 116
scripts/repo_review_body_writer.py 46.5% 86
tools/codex_session_analyzer.py 47.9% 59
scripts/create_verifier_labels.py 48.3% 58

Updated automatically; will refresh on subsequent CI/Docker completions.


Keepalive checklist

Scope

No scope information available

Tasks

  • No tasks defined

Acceptance criteria

  • No acceptance criteria defined

@stranske
stranske merged commit 1478857 into main Aug 23, 2026
49 checks passed
@stranske
stranske deleted the fix/liveness-import-bootstrap branch August 23, 2026 13:38
stranske added a commit that referenced this pull request Aug 23, 2026
Second CI failure of the liveness job, same class as the first. With the
sys.path bootstrap in (#3199) the import resolves, and the job then died on

    ModuleNotFoundError: No module named 'requests'

scripts/api_client imports requests; the job checked out the repo, set up
Python, and ran the sweep without installing anything. My machine had
requests, the runner did not.

Installs only that one package, with the pin read from requirements.txt
rather than written out again: `pip install -r requirements.txt` would drag
langchain, faiss, pandas and numpy onto a read-only sweep, and a second
literal pin is exactly the drift that file's own header warns about (#2404).
Fails loudly if the pin disappears rather than silently installing floating
requests.

Verified in a reproduction of the runner instead of my shell: fresh venv,
only requests==2.34.2 installed, PYTHONPATH stripped, script invoked by
path. It runs and reports correctly - 2 held, both the deliberately
unapproved probes, with the review verdicts intact.

Co-authored-by: Tim Stranske <tim@stranskemo.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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