github feder-cr/AIHawk v0.68.0
0.68.0

one hour ago

pyproject.toml states this rule twice, in its own words, about three packages:
python-dotenv is "declared rather than inherited ... a transitive dependency is
one somebody else can drop in a minor release without telling us", and starlette
and uvicorn are "declared even though mcp already pulls both in ... the day mcp
stops needing them, the failure would otherwise land here".

It was not applied to pydantic. src/aihawk/mcp/server.py says
from pydantic import Field and nothing declared it: it arrives because mcp
requires pydantic>=2.11,<3. The project knew the rule, wrote it down twice, and
missed the third - which is the shape that asks for a gate on the class rather
than a fourth careful sentence.

WHY NOTHING COULD HAVE FOUND IT. Every environment that has mcp has pydantic,
so the suite is green, the six matrix jobs are green, and a clean-environment
check installing from the index is green too. The wheel is broken only in a
future that has not happened yet, and when it does the traceback names pydantic
while the cause is in somebody else's pyproject. httpx is the same defect in the
test extra: the real-server test imports it and it was arriving through mcp.

THE GATE IS ON THE CLASS. Every third-party module the package imports must be
declared, and the same question is asked of the suite against the test extra. It
was written before the fix and went red on the real state, naming pydantic and
the file that imports it, which is the only way to know a gate can fail.

AND AN IMPORT THAT DECLARES ITSELF OPTIONAL IS EXEMPT, which the same scan
taught by being wrong. Run over the two sibling packages, it raised exactly one
thing in shipped code: from packaging.markers import Marker in invisible_core,
which is correct - inside a function, in a try that catches ImportError and
answers "cannot tell", with a docstring saying packaging is not one of that
package's runtime dependencies. The scan was wrong, not the line, and this gate
had the same blind spot waiting for the first optional import anybody writes
here. The exemption is the SHAPE of the code, not a name on a list, and both
sides are held: guarded is left alone, the same module imported at module level
is still caught.

The first version of the gate also carried a hand-written list of local module
names and was already wrong on its first run: it missed test_web_service, which
another test imports by bare name under this suite's convention. The list is
resolved from the tree now. A list of what a directory already says is a second
declaration, which is the thing this release is about.

What it does not see is written into it: an import through importlib with a
computed name, and whether a floor is high enough, which only a resolver can
answer. pytest-asyncio is correctly declared and correctly never imported,
because a plugin is loaded by pytest rather than by code.

THE 503 BRANCH OF /live/frame IS NOW CHOSEN BY THE SERVER. That route picks
between 204 and 503 by asking whether the sentence a tool raised IS the not-open
one, and only the yes was proven end to end: a comparison that answered "not
open" to EVERYTHING passed the whole suite, which turns every real breakage into
a silently idle pane. Reaching the other side without starting a browser costs
nothing once you notice that browser is declared Literal["main", "support"],
so a third value is refused by the tool's own schema and comes back as an error
result that is not that sentence. Known-bad applied to the real route: the new
test fails and the 204 one stays green, which is what should happen.

WHAT WAS SCANNED AND IS CLEAN, recorded as measured negatives rather than
assumptions. The six scripts in scripts/ are all invoked by workflows and carry
no unreferenced top-level definition and no uncalled method. All eight runtime
dependencies are genuinely imported by the package.

AND ONE THING THIS AUDIT REPORTED THAT WAS FALSE. It listed mixed line endings
as remaining debt. Measured on the index: 255 of 255 text files are LF only,
zero CRLF, zero mixed, zero lines a renormalisation would rewrite. The working
tree is CRLF because core.autocrlf is true on that machine, which is a property
of a checkout and not of this repository. A claim carried over from a sibling
repo without being measured, which is the error this audit exists to find, made
by the audit.

Suite 671 green from 664.

Don't miss a new AIHawk release

NewReleases is sending notifications on new releases.