ty advisory evaluation
This record evaluates ty beside the authoritative strict-mypy gate for the
AncestryLLM 0.6 development toolchain. It records the exact checker, complete
source-tree results, parity evidence, and the disposition of every diagnostic.
It does not authorize the conditional 0.7 type-checker cutover.
Evaluation contract
- Candidate:
ty 0.0.69(1dca8443e, 2026-08-06), pinned exactly in thetypecheckdependency group and resolved byuv.lock. - Authoritative checker: strict mypy with
pydantic.mypy, run bymake typecheckoversrc/ancestryllm. - Advisory checker:
make typecheck-ty, which runsty check src/ancestryllmand preserves ty’s real exit status. - CI: a dedicated Python 3.12 quality step has
continue-on-error: true. The blocking mypy step remains separate and does not mask either checker’s exit status. - Evidence profile: the CI-equivalent quality environment installs only
lintandtypecheck, with no provider extras. A second full-setup run records how the advisory changes whenmake setupinstalls every optional provider SDK. - Local characterization: Python 3.14.6 on macOS ARM64. The supported Python range remains 3.12-3.14, with Python 3.12 as the repository and CI default.
The evaluation started from commit
a336fbfb88263e256843f6345ff0c32fd3723d11. Strict mypy passed all 133 source
files before and after the focused defect fix. The final ty run returned status
1 and reported 58 diagnostics in the clean quality profile, as expected for a
visible advisory failure. After make setup, the same command reported 53
diagnostics because five optional provider imports became resolvable.
Diagnostic triage
The first complete quality-profile ty run reported 59 diagnostics. One Genuine code defect was fixed and protected by a focused regression test; the final quality-profile count is 58. The full-setup column is a second post-fix run, not an alternate acceptance profile.
| Category | Initial quality profile | Final quality profile | Full setup | Disposition |
|---|---|---|---|---|
| Genuine code defect | 1 | 0 | 0 | Fixed in a separate behavioral commit with a focused red-green regression test. |
| Pydantic/model behavior gap | 7 | 7 | 7 | Retained as advisory evidence; ty rejects the dynamically typed model-settings expansion in llm/profiles.py. |
| Missing third-party typing | 8 | 8 | 3 | The quality profile exposes five optional provider-import diagnostics and three sqlcipher3.connect diagnostics; installing all provider extras resolves only the former five. Strict mypy’s reviewed module overrides continue to cover them. |
| ty defect or unsupported feature | 43 | 43 | 43 | Retained for checker/platform incompatibilities described below; no broad ignore was added. |
| Total | 59 | 58 | 53 | ty does not yet pass the complete source tree in either environment. |
CI deliberately uses the final quality profile because quality jobs cannot gain
provider extras without a demonstrated runtime need. The 58-to-53 change is
therefore an explained dependency-profile effect, not a nondeterministic checker
result. Both runs covered every file under src/ancestryllm.
The genuine defect was a structural protocol mismatch:
_CurrentProgressAdapter.emit accepted a parameter named update, while the
declared ProgressPort.emit keyword was event. Calling the implementation
through that public keyword raised TypeError. The focused test first observed
that failure; the adapter now uses the declared keyword and strict mypy remains
green.
The 43 checker or unsupported-feature diagnostics comprise:
- 32 non-Windows-host diagnostics for guarded
ctypesandmsvcrtAPIs used by cross-platform atomic-publication and immutable-source controls; - four
listannotation diagnostics where ty resolves a method namedlistinstead of the built-in generic; - three declaration or inference disagreements in GEDCOM identity handling;
- two generic cached-result diagnostics already covered by narrow mypy return annotations;
- one synchronization-kernel iterable-narrowing disagreement; and
- one redundant-cast warning.
These classifications describe the current evidence, not permanent suppressions. A later evaluation must re-run the complete tree and reconsider each diagnostic against the then-current ty release.
Parity evidence
scripts/check_typechecker_parity.py runs both checkers against intentionally
invalid, isolated fixtures. One fixture is a direct language assignment error;
the other is an invalid Pydantic validator return. Both mypy and ty report the
expected file and line. Stable TYPEPARITY_DIAGNOSTIC_MISSED and
TYPEPARITY_CHECKER_FAILED codes distinguish a missed defect from a checker
execution failure.
The fixture result is narrow evidence only. It does not close the Pydantic
runtime gap: the full-tree run still produces seven model-construction
diagnostics, and strict mypy continues to use pydantic.mypy. Existing strict
mypy defects must remain detected by ty or protected by equivalent focused
tests before any cutover.
Suppressions
- Source
# type: ignorecomments: 25 before and 25 after the evaluation. - Source
# ty: ignorecomments: 0 before and 0 after the evaluation. - New module-wide or package-wide ignores: 0.
- New unchecked packages: 0.
No suppression was added to make advisory output appear cleaner. Existing mypy configuration, the Pydantic plugin, and editor/cache ownership remain unchanged.
Execution time
The clean final quality-profile run took 0.78 seconds elapsed, 1.16 seconds user, and 0.17 seconds system time. Two consecutive warm final runs produced the same 58 diagnostics in 0.16 and 0.17 seconds elapsed (1.05 seconds user and 0.07 seconds system each). These local measurements characterize one macOS ARM64 environment and are not a cross-platform performance guarantee.
Decision and future gate
The 0.7 cutover gate is not satisfied by this evaluation: ty does not pass the
complete source tree, model behavior is not yet equivalent, and platform-aware
results contain materially misleading diagnostics. The disposition is that
mypy remains authoritative for CI, release readiness, and release evidence.
The release-evidence result is still schema v1 mypy; it is not renamed to
type-check.
The checked-in .vscode/settings.json keeps Ruff as the Python formatter and
linter while mypy remains the authoritative editor checker. No ty editor or
cache ownership is configured during the advisory period; that change is
permitted only in a separately accepted cutover.
The conditional cutover must remain a separate change. It may proceed only if the complete gate in issue #309 passes without reduced strictness, broader suppressions, ignored modules, unsupported Python versions, crashes, nondeterminism, or unresolved misleading diagnostics.
Architecture and security impact
The advisory adds one exact, lock-hashed development checker and a nonblocking
quality step. It adds no runtime dependency, network path, privilege boundary,
user installation change, or executable trust exception; the verified uv
bootstrap and locked typecheck group remain the only acquisition path.
Apart from the keyword-compatible progress-adapter fix, application behavior
is unchanged. No ancestry API, CLI registry, service DTO, provider contract,
GEDCOM representation, RootsMagic write boundary, storage schema, FastAPI
contract, or Electron boundary changes. provider=none remains network-free,
cloud calls still require explicit consent, RootsMagic sources remain
immutable, and GEDCOM processing remains loss-minimal. ARCHITECTURE.md and
the threat-model evidence record this tooling-only disposition; installation,
release-runbook, and editor instructions are intentionally unchanged during
the advisory period.