feat: rename server package opds-sync -> quire-server#32
Merged
Conversation
Centralize QUIRE_SERVER_* / OPDS_SYNC_* precedence logic per coordinator §3.9. New prefix wins; legacy prefix triggers a one-shot WARNING per process per key. Per Lock #21, only os.environ is consulted (dotenv source not routed through the helper). Helper lives under the still-current opds_sync package; subsequent commit renames the package to quire_server and the helper moves with it.
Replace the default env source with LegacyEnvSettingsSource so each field is resolved from QUIRE_SERVER_* with one-cycle fallback to OPDS_SYNC_*. The dotenv source still uses env_prefix="QUIRE_SERVER_" (Lock #21). Switch test_settings primary cases to the new prefix and keep one back-compat test; add test_settings_env_compat covering precedence, WARNING emission, and complex-field (ai_token_secrets) round-trip under both prefixes.
main() now resolves PROGRESS_ENABLED / AI_ENABLED through resolve_env_prefix_value, so deployments can use either prefix during the one-cycle back-compat window. Adds test_migrate_env_compat covering both prefixes plus the both-set tiebreaker.
Mechanical commit: - git mv server/opds_sync -> server/quire_server - Rewrite every import (server source, tests, scripts/migrate, alembic env) - Switch test setenv calls from OPDS_SYNC_* to QUIRE_SERVER_* (legacy prefix still honored via _env_compat; one defensive back-compat case retained in test_settings) - Add tests/unit/test_no_stale_opds_sync_imports.py for fast local feedback if a stale import slips through DB role / DB name / volume name 'opds_sync' are a deliberate non-rename per Lock #20; the alembic.ini sqlalchemy.url default and the config.py database_url default explicitly preserve 'opds_sync' as the DB name.
- pyproject.toml: project name + setuptools include + marker descriptions
- Dockerfile: OCI labels + entrypoint comment refers to QUIRE_SERVER_*
- docker-compose.yml / docker-compose.full.yml: service name and image
switch to quire-server; env vars promoted to QUIRE_SERVER_* with
${QUIRE_SERVER_X:-${OPDS_SYNC_X:-default}} fallbacks so the back-compat
window also covers operators who pass values through Compose
- caddy/Caddyfile: upstream renamed to quire-server:8000
- .env.example: every key prefixed QUIRE_SERVER_*; banner explains Lock
#21 dotenv limitation
The DB role / DB name / Postgres volume (postgres user/db 'opds_sync',
volume 'opds_sync_pg') stay unchanged per Lock #20; alembic.ini and
config.py preserve the same DB name in their defaults.
server-ci.yaml: - Mode matrix env vars renamed to QUIRE_SERVER_* - Image build now produces both ghcr.io/.../quire-server and the legacy ghcr.io/.../opds-sync tags from the same digest, so operators have a one-cycle window to repin - Trivy scan targets the new image name - Adds a rename-guard regex (catches both opds-sync / opds_sync as standalone tokens and OPDS_SYNC_<X> env vars) with an explicit self-test fixture before it runs - Allowlist matches Lock #20 plus three defensive entries (env-compat tests + tests/conftest.py + import-graph regression test) android-ci.yaml: - Mirrors the same self-test + rename-guard step. The server CI is path-filtered to server/**, so a stale legacy reference added in an Android-side commit would slip past server-ci entirely (Required #5).
- Rename Python module / image / service references across docs/, README.md (active prose, with the historical sentence preserved per the Lock #20 allowlist note), CONTRIBUTING.md, SECURITY.md, NOTICE, fastlane Play Store copy, and Android KDocs that point at server-side files. - server/README.md gains a 'Migration from opds-sync' section covering the dual-prefix env helper, the dual-published image tag, and the deliberate DB-name non-rename. Also adds the five previously-omitted env vars (CWA_PROBE_PATH / CWA_PROBE_TIMEOUT_S / AUTH_CACHE_MAX_ENTRIES / AUTH_CACHE_POSITIVE_TTL_S already present) and an AI_PROMPT_VERSION row documenting the Lock #19 sentinel. - docs/release.md gains the 'Post-release cluster operator checklist' paragraph pointing at the operational ticket flow (Lock #4); the Quire repo does not modify any cluster manifests. - Update the rename-guard allowlist (server-ci + android-ci) to cover docs/release.md, docs/development.md, server/quire_server/config.py (DB-name preservation) and server/migrations/env.py (same). - Server-source docstrings, error messages, User-Agent strings, and the FastAPI title swap to QUIRE_SERVER_* / quire-server. Token-mode validation error messages now reference QUIRE_SERVER_AI_*; the unit tests assert on the suffix (AI_TOKEN_SECRETS / _ISSUER / _AUDIENCE) so they remain agnostic to the prefix change.
GitHub-hosted ubuntu-latest runners do not ship with ripgrep by default, so both the server-ci 'full' matrix cell and the android-ci 'build' job failed with 'rg: command not found' on the self-test step. Install via apt before the guard runs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Renames the Python package
server/opds_sync/→server/quire_server/, the env prefixOPDS_SYNC_*→QUIRE_SERVER_*, and the container imageghcr.io/vitofico/opds-sync→ghcr.io/vitofico/quire-server. Operator-facing only — HTTP paths, DB schema, and prompt/cache invariants are unchanged.For one release cycle the server keeps full back-compat:
LegacyEnvSettingsSourceinquire_server/_env_compat.pyresolves each Settings field from the new prefix first and falls back to the legacy prefix (one-shot WARNING per process, per key).scripts/migrate.pyreads itsPROGRESS_ENABLED/AI_ENABLEDflags through the same helper. Known limitation (Lock feat(android): inspect insight screen #21): onlyos.environis consulted; legacy names in a.envfile are NOT honored.server-ci.yamldual-publishes bothghcr.io/vitofico/quire-serverandghcr.io/vitofico/opds-syncfrom the same digest so existing pin operators get a window to repin.The Postgres role and database name
opds_syncare explicitly not renamed (Lock #20). The DB-name default is preserved verbatim inalembic.ini,quire_server/config.py, and both reference docker-compose files; renaming a production DB is high-risk and out of scope.CI gains a rename-guard step (regex
\bopds[-_]sync\b|(?<![A-Z0-9_])OPDS_SYNC_[A-Z0-9_]*) that runs in bothserver-ci.yamlandandroid-ci.yaml, with an explicit self-test fixture proving the regex catchesOPDS_SYNC_AI_ENABLED(the v1 plan's regex did not). Allowlist is the Lock #20 canonical set plus four defensive entries for files that intentionally reference the legacy names (the env-compat helper, the env-compat tests,tests/conftest.py, and the import-graph regression test) and three intentional DB-name carriers (server/migrations/env.py,server/quire_server/config.py, plusdocs/release.md/docs/development.mdwhich describe the migration).Commits, reviewable as a series:
feat(server): add env-prefix back-compat helper— TDD helper + 9 unit tests, lives under the still-currentopds_sync/package.feat(server): wire Settings to dual-prefix env source—Settings.settings_customise_sourcesswaps the env source forLegacyEnvSettingsSource. Includes complex-field (ai_token_secrets) JSON round-trip tests.feat(server): migrate.py reads QUIRE_SERVER_* with legacy fallback— script + integration tests.refactor(server): rename Python package opds_sync -> quire_server—git mv, sed-rewrite every import, switch test setenv calls to the new prefix, addtest_no_stale_opds_sync_imports.pybelt-and-braces.refactor(server): rename packaging/runtime metadata to quire-server—pyproject.toml,Dockerfile(with OCI labels),docker-compose*.yml(service + image + env keys),caddy/Caddyfile,.env.example. DB role / DB name / volume preserved.ci(server): dual-publish image and add rename-guard step— server-ci + android-ci.docs(server): rename opds-sync references and document migration— docs sweep, server/README.md "Migration from opds-sync" section, root README updates, fastlane copy, Android KDocs, NOTICE.Post-release operator checklist (cluster apply is out of scope per Lock #4)
After this PR merges, a separate operational ticket against
theficos-clustershould:quire-server./readyzgreen on the new pod.quire-server.opds-syncresources after the next release cycle confirms the new name is healthy.The dual-published
ghcr.io/vitofico/opds-syncimage tag stays valid throughout this window. The follow-up cleanup PR drops it.Test plan
cd server && uv run pytest -q— 375 passed, 178 warnings.cd server && uv run ruff check . && uv run ruff format --check .— clean.scripts/dgradle :app:assembleDebug --no-daemon— BUILD SUCCESSFUL.scripts/dgradle test --no-daemon— BUILD SUCCESSFUL.OPDS_SYNC_AI_ENABLED.full/sync_only/ai_onlymatrices + android-ci).docker inspectshows identical image IDs.Open questions resolved by defaults (call out if you disagree)
fastlane/.../26050830.txt): rewrote the oneopds-syncmention rather than allowlisting the file.NOTICE"formerly opds-sync": dropped the parenthetical; justQuire / Quire Servernow (option (a) from the plan).requires_progress/requires_aimarker names; only updated their description text.quire.renamed_from: dropped; the rename-guard would catch the value"opds-sync", and the OCI title/source labels already advertise the new name.