Skip to content

feat: rename server package opds-sync -> quire-server#32

Merged
vitofico merged 8 commits into
mainfrom
quire/rename
May 20, 2026
Merged

feat: rename server package opds-sync -> quire-server#32
vitofico merged 8 commits into
mainfrom
quire/rename

Conversation

@vitofico
Copy link
Copy Markdown
Owner

Summary

Renames the Python package server/opds_sync/server/quire_server/, the env prefix OPDS_SYNC_*QUIRE_SERVER_*, and the container image ghcr.io/vitofico/opds-syncghcr.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:

  • A custom LegacyEnvSettingsSource in quire_server/_env_compat.py resolves each Settings field from the new prefix first and falls back to the legacy prefix (one-shot WARNING per process, per key). scripts/migrate.py reads its PROGRESS_ENABLED / AI_ENABLED flags through the same helper. Known limitation (Lock feat(android): inspect insight screen #21): only os.environ is consulted; legacy names in a .env file are NOT honored.
  • server-ci.yaml dual-publishes both ghcr.io/vitofico/quire-server and ghcr.io/vitofico/opds-sync from the same digest so existing pin operators get a window to repin.

The Postgres role and database name opds_sync are explicitly not renamed (Lock #20). The DB-name default is preserved verbatim in alembic.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 both server-ci.yaml and android-ci.yaml, with an explicit self-test fixture proving the regex catches OPDS_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, plus docs/release.md / docs/development.md which describe the migration).

Commits, reviewable as a series:

  1. feat(server): add env-prefix back-compat helper — TDD helper + 9 unit tests, lives under the still-current opds_sync/ package.
  2. feat(server): wire Settings to dual-prefix env sourceSettings.settings_customise_sources swaps the env source for LegacyEnvSettingsSource. Includes complex-field (ai_token_secrets) JSON round-trip tests.
  3. feat(server): migrate.py reads QUIRE_SERVER_* with legacy fallback — script + integration tests.
  4. refactor(server): rename Python package opds_sync -> quire_servergit mv, sed-rewrite every import, switch test setenv calls to the new prefix, add test_no_stale_opds_sync_imports.py belt-and-braces.
  5. refactor(server): rename packaging/runtime metadata to quire-serverpyproject.toml, Dockerfile (with OCI labels), docker-compose*.yml (service + image + env keys), caddy/Caddyfile, .env.example. DB role / DB name / volume preserved.
  6. ci(server): dual-publish image and add rename-guard step — server-ci + android-ci.
  7. 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-cluster should:

  1. Additively apply the new Secret / ConfigMap / Deployment / Service for quire-server.
  2. Wait for /readyz green on the new pod.
  3. Flip the calibre-web ingress backend to point at quire-server.
  4. Remove the old opds-sync resources after the next release cycle confirms the new name is healthy.

The dual-published ghcr.io/vitofico/opds-sync image 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.
  • Local rename-guard run with the canonical allowlist — zero matches.
  • Self-test fixture: regex matches OPDS_SYNC_AI_ENABLED.
  • CI green (server-ci full / sync_only / ai_only matrices + android-ci).
  • Post-merge: docker pull both image tags and docker inspect shows identical image IDs.

Open questions resolved by defaults (call out if you disagree)

  1. Historical changelog (fastlane/.../26050830.txt): rewrote the one opds-sync mention rather than allowlisting the file.
  2. NOTICE "formerly opds-sync": dropped the parenthetical; just Quire / Quire Server now (option (a) from the plan).
  3. Test markers: kept requires_progress / requires_ai marker names; only updated their description text.
  4. OCI label quire.renamed_from: dropped; the rename-guard would catch the value "opds-sync", and the OCI title/source labels already advertise the new name.

vitofico added 8 commits May 20, 2026 17:46
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.
@vitofico vitofico merged commit 0392670 into main May 20, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant