Added
- ADR 2026-05-28-1: Documents CI dependency resolution and test surface consistency —
five structural gaps identified from CI run 26558837157, chosen remediations, and
confirmation criteria.
(architecture/adrs/2026-05-28-1-ci-dependency-resolution-and-test-surface-consistency.md) - Typer-surface smoke test (
tests/agent/test_json_group_typer_surface.py) that exercises
the_JSONErrorGroup/ JSON-envelope contract end-to-end usingtyper.Exit(not
click.exceptions.Exit). Acts as a canary for the typer 0.26+ vendored-click regression. agentpytest marker for orchestrator-api / agent-facing contract surface tests.
Changed
- CI: all test and lint jobs now use
uv sync --frozen --all-extrasinstead of
pip install -e .[test]. The lockfile is the single environment contract for both
local and CI, eliminating resolver drift betweenuv.lockandpyproject.tomlbounds.
Three infrastructure jobs (uv-lock-check,build-wheel,clean-install-verification)
are unaffected. - Python version pinned to
3.11.15in.python-versionfor reproducibility.
Fixed
_JSONErrorGroupexception handlers now use_CLICK_USAGE_ERRORS/_CLICK_ABORTS
tuples that include bothclick.exceptions.*andtyper._click.exceptions.*variants,
fixing silent miss of all exceptions raised by typer 0.26+ which vendors click
internally astyper._click.- Charter-preflight test fixtures (
tests/specify_cli/charter_preflight/_fixtures.py)
now usecharter.hasher.hash_content()instead of rawhashlib.sha256(bytes),
aligning with the production algorithm and eliminating hash-format divergence. - E2e conftest synthesises
.kittify/charter/metadata.yamlaftercopytreeusing
the productioncharter.hasher.hash_content()helper, making fixtures self-contained
and reproducible on clean clones without gitignored runtime state. - Missing
import clickinorchestrator_api/commands.pythat causedNameErrorin the
except ImportErrorfallback when importing the module on typer < 0.26. - Restored
doctrineCLI group registration (incorrectly removed when a stale regression
test was treated as a contract); narrowed the curation-excision guard tocurate/promote
only; restoredspec-kitty doctrinesections indocs/reference/cli-commands.md.
Security / Lint
TID251(flake8-tidy-importsbanned-api) added to ruff:hashlib.sha256usage in
tests/must go throughcharter.hasher.hash_content();click.exceptions.Exit,
UsageError, andAbortin tests must usetyper.*equivalents instead.TID251is now enforced, not advisory: a dedicated[ENFORCED] banned-API lint gate (TID251)step inci-quality.ymlrunsruff check src tests --select TID251
withoutcontinue-on-error, so an unannotated banned call fails the build. The
previous whole-directoryper-file-ignores(which silently exempted 10 test trees and
defeated the "new sha256 still needs a# noqa" policy) were removed; every legitimate
rawhashlib.sha256now carries an inline# noqa: TID251 — <justification>. A guard
test (tests/architectural/test_tid251_enforcement.py) pins the enforcement so it
cannot silently regress to advisory. (Closes the adversarial review block on #1395.)