Nimblesite / Nimblesite/Basilisk

directives_cast rejects legal string forward refs (conflicts with ruff TC006) and only fires on assignment RHS

Open
#335 3 comments 0 reactions 1 assignee View on GitHub

@MelbourneDeveloper is already working on this.

Since Aug 2, 2026.

critical
Dominant language
Rust
Stars
54
Forks
3
PR merge metrics
No merged PRs in 30d

Description

Summary

Two problems with directives_cast:

  1. It rejects string forward references as cast()'s first argument, which PEP 484 and typeshed explicitly permit.
  2. It only fires when the cast() call is the right-hand side of an assignment. In every other syntactic position it is silently not checked.

Together these make the rule both wrong and unevenly applied — and (1) puts Basilisk in direct, unsatisfiable conflict with ruff's TC006.

Problem 1 — string forward references are legal

typeshed's own signature admits str:

def cast(typ: type[_T] | str | Any, val: Any) -> _T: ...

Every quoted form is rejected:

from typing import cast
from uuid import UUID


class Local: ...


a = cast("UUID", object())            # error[directives_cast]
b = cast("Local", object())           # error
c = cast("int", 1)                    # error
d = cast("str", "x")                  # error
e = cast("dict[str, str]", {})        # error
f = cast("tuple[int, bytes]", (1, b""))  # error
g = cast(int, 1)                      # OK — only the unquoted form passes
Found 6 diagnostics (6 errors).

The message — "must be a type, not a value literal" — suggests the intent was to catch cast(1, x) or cast("some string value", x). A quoted type expression is not a value literal; it is the standard forward-reference spelling.

Unsatisfiable conflict with ruff

ruff's TC006 (runtime-cast-value) enforces the exact opposite and is in ruff's ALL set:

TC006 Add quotes to type expression in `typing.cast()`

A project running Basilisk + ruff (as Basilisk's own docs encourage, and as make lint does here) cannot satisfy both. Quoting satisfies ruff and fails Basilisk; unquoting satisfies Basilisk and fails ruff. The only escapes are a suppression in one tool or restructuring the code to avoid cast entirely — which is what we did:

# was: _, stdout, _ = cast("tuple[int, bytes, bytes]", raw)
raw: tuple[int, bytes, bytes] = Git().execute(..., with_extended_output=True)
_, stdout, _ = raw

Problem 2 — the rule only sees assignment RHS

from typing import cast


def sink(x: object, y: object = None) -> None: ...


assigned = cast("int", 1)                    # line  8 — FLAGGED
sink(cast("int", 1))                         # line  9 — not flagged
sink(x=cast("int", 1))                       # line 10 — not flagged
sink(cast("int", 1), y=cast("str", "a"))     # line 11 — not flagged
def ret() -> int:
    return cast("int", 1)                    # line 15 — not flagged
  --> _castpos.py:8:17
Found 1 diagnostic (1 error).

Only the assignment is reported. This is how it presents in the wild: the Nimblesite Agentic Platform has 19 quoted cast() calls and basilisk check passes clean, because 18 of them sit in keyword-argument or return position:

src/nap/agent_workspace/host.py:517   agent_config_id=cast("UUID", kwargs["agent_config_id"]),   # not flagged
src/nap/core/tool_content.py:115      return cast("ToolResultContent", raw)                      # not flagged
workspaces/.../git_http_server.py:129 _, stdout, _ = cast("tuple[...]", raw)                     # FLAGGED

One file out of the set errors, purely because of where the call sits. That reads as a random false positive to a user and makes the rule's real blast radius invisible until code is refactored.

Expected

  • Accept str as cast()'s first argument, resolving it as a forward reference (and ideally validate that the string parses as a type expression, which would catch the genuine cast("hello", x) mistake).
  • Whatever the decision on (1), apply the rule uniformly across all expression positions.
  • If quoted casts are to stay rejected, that conflict with ruff TC006 should be documented, because the two cannot both be satisfied.

Version

Reproduced identically on released basilisk 0.35.0 (Homebrew) and on 0.0.0-PLACEHOLDER built from typeshed @ 9ada1f77 (2026-07-21).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.