Skip to content

Risks and Mitigations

The risk in Typhon is not technological — every stage has a mature, MIT-licensed Rust implementation to depend on, vendor, or learn from. The risk is scope. This page lists the hazards we’ve identified and the mitigations.

RiskSeverityMitigation
Structural subtyping is months of workHighDeferred to Phase 3; Phase 0–2 ships without interfaces. Nominal types alone are useful.
Ruff parser API drifts under usMediumPin to a SHA; review upstream monthly; keep diff small.
Salsa breaking changes between minor versionsMediumEvery Salsa call sits behind a one-function-wide wrapper module.
Free-threaded Python is a moving targetMediumDefault off until 3.14 ships as default. Sequential fallback via sys._is_gil_enabled().
Auto-parallelisation introduces racesHighShip only the explicit gather: keyword in v1; inference is opt-in and conservative.
Pydantic coupling alienates usersMediumDefault emit is @dataclass, not BaseModel. Pydantic is opt-in via model.
Pre-emptive runtime helpers force a Typhon package on usersMediumEmit typhon_runtime/ as generated source the build owns; no PyPI package required.
Solo-developer burnout on a multi-year projectHighCut scope aggressively. The minimum-viable Typhon is publishable.
Generics syntax choice locks parser fork shapeResolvedPEP 695 brackets — vendored parser accepts them natively.
go tasks GC’d mid-flight (weak refs in event loop)MediumLower go through typhon_runtime.tasks.spawn with a strong-ref registry. Never bare asyncio.create_task.
asyncio.gather exception semantics surprise usersMediumgather: defaults to TaskGroup (cancel-on-failure). Reserve gather(strategy="best-effort") for return_exceptions=True.
Pydantic’s default extra='ignore' silently drops inputMediummodel emission always injects extra='forbid'.
.pyi interop drift from .dty sourceMediumtyc check --stubs runs an AST diff; tyc stubtest runs runtime introspection.
Auto-memoisation extends object lifetimes invisiblyMediumNever silently insert @functools.cache. Requires @memo, @pure(memo=True), or [strictness] auto-memoise = true, plus all six purity conditions.
Runtime isinstance(x, MyInterface) gives false confidenceLow@runtime_checkable only checks attribute presence. Typhon refuses to compile interface isinstance unless explicitly opted in.
Lazy from x import y defeats deferral (PEP 690)LowRejected at parse time. Use lazy import x plus x.y instead.
comptime sandbox lets users do dangerous thingsLowSandbox is intentionally tiny; no I/O, time, random, imports. Auditable on one screen.

Two dominant risks

The two hazards that genuinely worry us:

  1. Structural subtyping correctness. The recursive-type cases and bounded type vars are the largest single source of latent bugs. Mitigated by: extensive tests, conservative implementation, deferring full variance to Phase 4+, the tyc ty second-opinion option.
  2. Parser sync with upstream Python. Every CPython release that adds syntax (PEP 695, structural patterns, etc.) we have to track. Mitigated by: vendoring Ruff (which already tracks upstream), keeping the diff small, monthly upstream review.

What we don’t worry about

  • Performance. The architecture is the same as rust-analyzer, ty, and oxc — all of which are fast.
  • Runtime correctness. The lowering produces standard Python; CPython does the work.
  • Adoption. This is a personal-project / community-of-interest tool. We are not trying to be Mojo.

Where next