Effect catalog, pyright cross-check, and resolution fixes - #7
Merged
Merged
Conversation
- A factory without a return annotation types its result when every non-None return constructs a class, directly or through another factory (return Repo(), return build()). Async and generator factories do not. - A name assigned once from a function or attribute (alias = clean) resolves through that value as a possible target; parameters, loop targets, and reassigned names stay unknown. - A syntax error names the Python that parsed the file and, below the newest tested Python, suggests running Threadline with it. Gate: the unannotated-factory expectation moves from unknown to possible, with new contrasts for a lookup and an async factory; a new alias case covers direct and chained aliases and a conditional reassignment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/pyright_crosscheck.py asks pyright's language server where a deterministic sample of calls goes and fails when pyright names a different project function for a call Threadline labels supported. Possible-call mismatches and calls pyright resolves where Threadline cannot are reported as review leads without failing. CI runs it on this repository (Linux, Python 3.12) and on flask and requests in the public-repository job. Pyright is pinned as a dev dependency beside axe-core; Threadline has no runtime dependency on it. Local result: 0 disagreements across 563 supported and 560 possible calls in threadline, flask, and requests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
threadline/effects.py maps known library calls to effect classes, with
reads and writes separate: SQLAlchemy/SQLModel sessions and DB-API
cursors (execute classified by its statement), requests/httpx/aiohttp
(by HTTP verb), open/pathlib/os/shutil/json (open by mode), subprocess,
and logging. Untyped session/db/logger receivers match by name as
possible. Effects and raised exceptions propagate through resolved
project calls with their path; probable or deferred calls make them
possible.
The method summary gains an Effects row ("DB write via update_user"),
and Raises lists exceptions from called project functions. threadline
method returns the records as `effects`.
Supporting analyzer changes: external calls record their library target;
`with X() as y` and dotted library factories (logging.getLogger) type
their receivers.
Gate: an `effects` check kind with 12 cases covering each library family
and propagation, including a function of pure helpers and a recursive
pair that must have no effects. Pyright cross-check, public-repository
validation, browser smoke, and accessibility checks pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A CI runner stalled headless Chrome at startup: DevTools never answered, and cleanup then raised TimeoutExpired because Chrome ignored terminate, hiding the real error. The browser smoke test now tries Chrome twice with a fresh port and profile, logs the failed attempt, and force-kills a browser that ignores terminate. The release smoke test gets the same force-kill fallback for its server. Checked with a fake Chrome that never opens DevTools and ignores SIGTERM: two attempts, both killed, one clear RuntimeError, no leftover processes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three pieces, one commit each. They follow the resolver feasibility study, which recommended against delegating resolution to Jedi or pyright.
1. Resolution fixes (
b775f43)Nonereturn constructs a class (return Repo(), orreturn build()that does). Async and generator factories don't.alias = clean) resolves through that value as probably. Parameters, loop targets and reassigned names stay unknown.2. Pyright cross-check in CI (
fdbb5f1)tests/pyright_crosscheck.pyasks pyright's language server where a deterministic sample of calls goes.3. Effect catalog (
00a77aa)threadline/effects.pymaps known library calls to effect classes, with reads and writes separate:executeis classified by its statement (select/insert,update,delete)open(by mode),pathlib,os,shutil,json/picklesubprocess,os.system, …logging, loguru, structlograisestatementsCertainty: identified library targets are definite. Untyped
session/db/loggerreceivers match by name and are possible.Propagation: effects travel through resolved project calls with their path. Probable or deferred calls (an unawaited coroutine, a generator) make them possible.
Summary: the method summary gains an Effects row, e.g. "DB write via
update_user". Raises also lists exceptions from called project functions.CLI:
threadline methodreturns the records aseffects.Supporting analyzer changes: external calls record their library target.
with X() as y:and dotted library factories (logging.getLogger(__name__)) now type their receivers.Example (agent-kanban-pm,
POST /tasks): Effects DB write, DB read; RaisesHTTPException,PermissionErrorviacreate_task_record,TaskReferenceErrorviacreate_task_record.Gate
Each change landed its semantic-corpus cases first, with contrasting checks, and each case failed before its fix. A new
effectscheck kind covers every library family plus propagation, including a function built from pure helpers and a recursive pair that must have no effects.The corpus now has 73 checks, 0 incorrect supported.
Testing
python -m pytest: 163 pass.python test_semantic_accuracy.py: 73 pass.tests/browser_smoke.pyin all four modes: all pass, including new Effects-row checks.tests/browser_accessibility.py --browser chrome: all pass.tests/pyright_crosscheck.py --project . --repo flask --repo requests: 0 disagreements on 563 supported and 561 probably calls.tests/online_repo_smoke.py: all 7 pinned repositories pass.Limits (documented in
docs/CAPABILITIES.md)🤖 Generated with Claude Code