Skip to content

bug(guards): a parse failure in check_websockets_cap is laundered into "dependency absent", retiring the cap #17401

Open

Description

@mrveiss

Parent: #17400. Umbrella: #15826.

scripts/check_websockets_cap.py enforces the websockets<16 cap that #11030 and #11031 were filed for. It can retire itself on a typo.

The laundering chain

_requirement_for() parses candidate lines:

# scripts/check_websockets_cap.py:62-65
try:
    req = Requirement(line)
except Exception:
    continue

A line that fails to parse is skipped with no message and no record. If that line is the trigger package's own, _requirement_for falls through to return None, and main() reads None as absence:

# scripts/check_websockets_cap.py:77-79
langgraph = _requirement_for(_CAP_TRIGGER_PKG, _BACKEND_REQ)
if langgraph is None:
    print(f"OK: {_CAP_TRIGGER_PKG} not present in {_BACKEND_REQ} — websockets cap no longer required.")
    return 0

So: could not parse → dependency absent → this gate no longer applies → exit 0, printing a sentence that asserts the opposite of what happened. Three distinct states collapse into the one that disables the check.

The guard is otherwise careful — a missing requirements file is a hard error at :72-74, and a declared trigger with no explicit pin is a hard error at :82-88. The input file's existence is validated; a line it could not read is not.

Why it matters

The failure is reachable by ordinary edits — a stray character, an unusual marker or environment specifier, a Requirement grammar change on a dependency bump. It fails silently in the green direction on a cap whose violation previously broke the base build twice (#11030, #11031). Nothing else asserts the cap.

Fix

Distinguish "no such requirement" from "a line naming this requirement could not be parsed". The second is an error, never a skip — the same rule check_shell_file_size.py:230-237 already applies to unreadable files, and for the same stated reason.

Acceptance criteria

  • A malformed line naming the trigger package fails the guard with a message naming the line, and never prints the "no longer required" sentence.
  • A malformed line naming an unrelated package does not fail the guard, but is reported.
  • Genuine absence of the trigger package still exits 0 with its existing message.
  • A test plants an unparseable trigger line and asserts a non-zero exit — the guard must fail on the thing it exists for.

Read in the tree at bcd7c8dbea; behaviour derived from control flow, not from executing the script.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions