Dependency maintenance
AncestryLLM records application features as optional extras and repository
tooling as purpose-specific PEP 735 dependency groups. The complete resolution
for every extra and group is committed in uv.lock. Local setup synchronizes
the complete graph; purpose-specific workflow jobs synchronize only the
environment they need before calling the canonical Make command. This keeps
quality, security, build, desktop, and release-verification jobs from relying
on undeclared cross-profile tools.
The repository-local, verified uv 0.12.1 bootstrap is the only supported way
to create or update these environments. It requires a system-supplied Python
3.12-3.15; .python-version selects 3.12 by default, and [tool.uv] prohibits
Python downloads. uv is not a project dependency and must not be installed
through a dependency group, pip, an alternate index, or an unverified
executable on PATH.
Environment contracts
The dependency groups are:
| Group | Purpose | Canonical consumers |
|---|---|---|
lint |
Ruff, pre-commit, rendered-Markdown and GFM validation, and repository checks | make lint, make markdown-check, make hooks, and CI quality jobs |
typecheck |
Strict mypy, third-party type information, and exact ty advisory evaluation | make typecheck, make typecheck-ty, and CI quality jobs |
test |
Pytest and coverage | make test, Python test matrices, and release-project proof jobs |
security |
Dependency audit, SBOM, and workflow audit tools | make security, make sbom, make workflow-audit, and matching workflow jobs |
build |
Distribution construction, artifact validation, and isolated backend evaluation | make package, make evaluate-uv-build, and package/release build jobs |
release-verifier |
Exact PyPI attestation verifier | Release artifact verification only |
make setup runs uv sync --locked --all-extras --all-groups, including the
release-verifier group, so a local source checkout has the complete locked
graph. Canonical gates use exact uv run --locked --group ... commands. A
purpose-specific workflow may first synchronize a smaller profile with
--no-default-groups, but it then invokes the same Make target without changing
the actual command or flags.
make sbom is the only supported release-SBOM interface. It executes the locked
CycloneDX tool from security in reproducible mode, then passes its output
through the standard-library-only canonicalizer before atomically publishing
the result. The canonicalizer removes the reviewed editable-project local
distribution reference, emits one canonical project root, proves exact
component/dependency-node coverage, and rejects any residual local path,
conflicting duplicate, unknown schema, or malformed graph with a stable code.
CI, release readiness, and release jobs must not duplicate or narrow this
command by invoking cyclonedx-py directly.
markdown-it-py>=4,<5 is declared directly in lint because the screenshot
manifest validator parses rendered Markdown image tokens, including reference
images, while deliberately ignoring fenced and inline code examples. The
validator must not rely on Rich or another runtime package to install that
parser transitively.
ty==0.0.69 is deliberately exact because the 0.6 work is a reproducible
advisory evaluation, not a floating checker migration. make typecheck-ty
preserves its real exit status in a dedicated nonblocking CI step. Strict mypy,
types-python-dateutil, and pydantic.mypy remain authoritative until every
conditional cutover gate passes. See the
ty advisory evaluation for the current diagnostic
triage, the quality-profile and all-extras counts, and the failed cutover
conditions.
uv_build>=0.12.0,<0.13 belongs to build only as the locked candidate for
the isolated 0.6 backend evaluation. The production [build-system] remains
setuptools.build_meta, and make package plus every release workflow retain
the established setuptools normalization and validation path. From a clean
checkout, make evaluate-uv-build compares both backends under one source
epoch and writes a schema-v1 report; its nonzero incompatible result must not
be masked. The checked uv_build evaluation records
why adoption is rejected/deferred for the candidate configuration.
Provider SDKs remain user-facing optional extras: ollama, openai,
anthropic, gemini, openrouter, and the aggregate all-llm. The Python
test matrix combines test with all-llm for provider coverage. Quality,
security, and build jobs do not install provider extras because their commands
do not import or execute those SDKs. Installing an extra never selects a
provider or grants cloud consent; provider=none remains network-free.
desktop-build remains a user-facing build extra because PyInstaller is part
of the desktop sidecar artifact rather than an ordinary repository tooling
environment. Desktop native build jobs install that extra alone. click is no
longer a direct dependency after source-import and entry-point audits found no
repository consumer; it may still appear transitively in uv.lock. The
verified bootstrap supplies uv, so the lock intentionally contains no direct
uv environment dependency.
Complete dependency-audit export
make dependency-audit executes scripts/run_dependency_audit.py from the
locked security group. The runner generates its input with the exact command
uv export --locked --all-extras --all-groups, then compares normalized
package-name/version pairs with every applicable package in uv.lock before
allowing pip-audit to run. A missing provider extra, desktop-build package,
dependency-group tool, release verifier, or transitive dependency fails closed
instead of silently narrowing the audit.
The closed-schema allowlist at
config/dependency-audit-exclusions.json documents the only formal export
exception: the editable source project itself. Unknown fields, duplicate or
unused entries, unpinned export records, and lock/export drift are stable coded
errors. pip-audit still runs from the locked security group with hashes and
strict dependency processing; this completeness check does not replace
Semgrep, zizmor, CycloneDX, gitleaks, TruffleHog, or CodeQL.
Update procedure
- Record the failing audit, affected dependency paths, advisory identifiers, and available fixed versions before changing the graph. Keep raw audit output outside tracked documentation; record only sanitized findings and validation results in release evidence.
- Edit the narrow direct dependency in
pyproject.tomlwhen its constraint prevents a fix. Keep application extras separate from repository tooling groups and preserve exact pins for trust-sensitive verifiers. For an already-compatible transitive fix, use verified repository-localuv lock --upgrade-package <package>rather than adding an unused direct dependency.make lockverifies and executes repository-localuv0.12.1 when a manifest change requires regenerating the complete lock. - Run
make lock-check, then inspect both the direct-dependency diff and every changed package record inuv.lock. An unrelated version change, missing artifact hash, alternate source, or unexplained transitive re-resolution is a failure, not routine lockfile noise. - Run the focused dependency-group and workflow contract tests, followed by each affected canonical Make target from a clean environment. Purpose- specific workflow profiles must succeed without tools inherited from another group.
- Run the full applicable quality and security gates and update contributor, CI, security, release, and user installation documentation when the changed dependency affects those surfaces.
The lock-check workflow installs no group and runs make lock-check, whose
canonical command is uv lock --check.
Stock-pip wheel and source-distribution smoke jobs remain intentionally
outside these repository-tool profiles: they verify supported non-uv
consumer installation and do not build or authorize release artifacts.
Security-remediation acceptance
A dependency-only fix uses the observed failing audit as its initial failure
evidence. If compatibility requires application behavior changes, first add
and observe a focused failing regression test under the normal
red-green process documented in the repository’s CONTRIBUTING.md. Do not add
audit exclusions, suppress advisory identifiers, lower severity thresholds,
or remove security checks to obtain a passing result.
For Python, require make lock-check, make security, make test, make lint,
and make typecheck on the integrated locked graph. make security must
complete both the full-export dependency audit and the pinned static scan.
Update code documentation when compatibility changes alter a code contract;
record why architecture, threat-model, user, API, and release surfaces are
unaffected when the change only selects fixed dependency versions.
For desktop, use the Node and pnpm versions pinned in desktop/package.json,
preserve the frozen-lockfile installation, and review every changed dependency
path in desktop/pnpm-lock.yaml. Capture the complete pnpm --dir desktop
audit --json result, including findings below the canonical high-severity
threshold. Require make desktop-check, make desktop-security, and the
affected source E2E checks. The security gate includes package construction,
ASAR integrity, and Electron fuse verification; an audit alone does not replace
those checks. Any transitive override needs an identified dependency path,
upstream compatibility evidence, and regression validation.
When an advisory has no published fixed version, an optional dependency may be removed only after reviewing its callers and documenting the resulting unsupported capability. Keep the complete audit scope unchanged. Reject any explicit request for that removed capability before dependency installation or packaging; do not silently fall back to a different network path. Exercise normal operation and the rejection path in regression tests. A major-version override must preserve the parent package’s actual contract, including archive extraction, proxy handling, or watch globs where applicable.
Integrate independently owned Python and desktop changes sequentially, then rerun the canonical gates on their combined revision. Record tested commit, audit counts, checks, skipped tests, and package target in release evidence. A passing local dependency remediation does not establish hosted checks, manual desktop acceptance, signing, notarization, or published provenance.
Review checklist
- Every former development dependency is present in exactly one appropriate group, retained as a named optional extra, or has a documented removal audit.
- Provider extras and
desktop-buildretain their public installation meaning. - Workflow jobs use the group profile declared for their canonical Make target,
pass
--no-default-groups, and invoke that target without command drift. - Semgrep continues through the independently pinned script even though the
surrounding security tools come from the
securitygroup. - The dependency-audit export covers all extras and groups, and its normalized
package pairs match
uv.lockexcept for the reviewed, used source-project entry inconfig/dependency-audit-exclusions.json. - Production release verification installs only
release-verifier; release construction does not inherit it. Full local setup intentionally includes every group. - The complete lock retains artifact hashes for every supported platform and all extras and groups without unexplained package-version movement.
- Application APIs, CLI commands, service DTOs, provider policy, GEDCOM behavior, storage, FastAPI, and Electron boundaries remain unchanged by a tooling-only dependency update.