Contracts
distribution-profile.md
Contract: DistributionProfile
Shape
@dataclass(frozen=True)
class DistributionProfile:
package_name: str
package_aliases: tuple[str, ...] = ()
upgrade_provider: object | None = None # LatestVersionProvider instance or None
index_url: str | None = None
extra_index_url: str | None = None
data_freshness_seconds: int | None = None
disable_public_pypi_notifier: bool = False
version_label: str | None = None
Consumers
| Consumer | Fields used |
|---|
resolve_cli_package_name / version utils | package_name, package_aliases |
| session-presence refresh / compat planner | provider + package_name |
has_fresh_data path | data_freshness_seconds |
| remediation / upgrade_hint | package_name, index_url, extra_index_url |
maybe_emit_no_upgrade_notice | disable_public_pypi_notifier |
--version banner | version_label or package_name |
Stock profile
package_name="spec-kitty-cli", empty aliases, PyPIProvider, no index URLs, default freshness, notifier enabled, version_label=None (banner uses package name).
entry-points.md
Contract: Packager entry-point groups
Groups
| Group | Cardinality | Load shape | Fallback |
|---|
spec_kitty.cli_package | 0..n (prefer 1) | str, zero-arg callable → str, or object with package_name/name | packages_distributions → "spec-kitty-cli" |
spec_kitty.upgrade_provider | 0..n | zero-arg callable/type → object with get_latest | PyPIProvider() |
spec_kitty.distribution_profile | 0..1 preferred | zero-arg callable/type → DistributionProfile | synthesize from above / stock |
Multi-registration
- Upgrade providers:
SPEC_KITTY_UPGRADE_PROVIDER=<entry_point_name> selects; else first name alphabetically. - Unknown env name: ignore and use deterministic alphabetical pick (or stock if load fails) — never invent a class.
- Load/construct errors: fall back to stock; never raise to callers.
Non-goals
- No runtime env var for distribution package name.
- No
.kittify/config.yaml keys for these hooks.
simple-index-provider.md
Contract: SimpleIndexProvider
Behaviour
- Implements
LatestVersionProvider.get_latest(package) -> LatestVersionResult. - Never raises.
- Fetches PEP 503 simple index HTML for the configured base URL + package.
- Parses version candidates from anchor hrefs / wheel filenames; returns the highest stable sanitised version matching
_VERSION_RE. Pre-releases are excluded (mirroring PyPIProvider's stable info.version); the highest pre-release is returned only when no stable version exists. Anchors carrying a PEP 592 data-yanked attribute are skipped. - TLS verification on; response size capped (same order as PyPIProvider 1 MiB); redirects not followed.
- Successful lookups set
source="simple_index". - Failures return
version=None, source="none", error=<token> (timeout, http_error, parse_error, oversized).
Construction
- Base class accepts
index_url (+ optional package filename prefix) in __init__. - Fork subclasses provide zero-arg
__init__ that calls super().__init__(...) with their URL — upstream defaults must not embed fork URLs.
Non-goals
- Full PEP 503 JSON simple API (HTML only for this mission unless already trivial).
- Authentication headers for private indexes (packager subclass may override fetch later; not required in upstream base).