Skip to content

refactor(yapper): inject event DB URI provider; campus.yapper imports no campus packages - #981

Merged
ngjunsiang merged 3 commits into
weeklyfrom
refactor/yapper-creds-injection
Oct 27, 2026
Merged

ngjunsiang merged 3 commits into
weeklyfrom
refactor/yapper-creds-injection

Conversation

@nycomp

@nycomp nycomp commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Part of #970 — phase 2 (yapper↔auth cycle), single commit, base weekly.

Change

campus.yapper is now self-contained: it imports no campus package at all. The lazy from campus.auth import resources calls (the yapper↔auth cycle) are gone at the source, replaced by dependency injection at the DB-URI seam.

create() resolves the event database URI in priority order:

  1. db_uri argument
  2. db_uri_provider() callable — the injection point
  3. YAPPERDB_URI environment variable
  4. remote campus vault "campus.yapper" via campus_python (unchanged default for api's bare create() in production)

Client identity (CLIENT_ID/CLIENT_SECRET) stays env-driven, unchanged.

Callers

  • campus.auth — get_yapper() now injects a provider backed by its own in-process vault (vault["campus.yapper"]["YAPPERDB_URI"]), replacing the DEPLOY=campus.auth env special-case (branch deleted; yapper no longer consults DEPLOY). The ~40 get_yapper().emit(...) call sites are untouched, and contract tests patch get_yapper by name — unaffected.
  • campus.api — the three bare campus.yapper.create() route calls are untouched: production still resolves via the remote vault; in test mode the fixture exports the seeded URI as YAPPERDB_URI env.
  • Test fixtures (tests/fixtures/yapper.py) — still seed the vault secret (the vault-delivery contract and its integration test are unchanged) and additionally set the env var, with a comment explaining the split.

Safety properties

  • Test mode never touches the network: STORAGE_MODE=1 with no resolvable URI raises ValueError instead of falling through to the remote vault (guards issue fix(integration): yapper backend tries to connect to external service in test mode #319's class of bug).
  • Boundary contract hardened (test_package_boundaries.py): yapper moves out of SERVICE_LAYERS into SHARED_ALLOWED with zero allowed campus deps — emitters may import yapper; it must never grow campus dependencies back. Statically enforced.
  • New tests/unit/yapper/test_factory.py covers the resolution order and asserts at runtime (subprocess) that create() never loads campus.auth.

Verification

import campus.yapper loads only campus.yapper; bare create() under test mode runs with campus.auth unimported. Unit, contract, integration, and ruff check . all green.

Note for reviewers: this is the injection fix from the phase-2 discussion on #970. The yapper-into-campus.audit placement idea was assessed and set aside (audit never imports yapper; the move would drag audit's init into every emitter and widen the cycle into auth⇄audit).

…imports (#970)

Phase 2 of the campus-core carve: campus.yapper is now self-contained —
it imports no campus package at all, so the lazy yapper<->auth cycle is
gone at the source.

create() resolves the event database URI in priority order: db_uri
argument > db_uri_provider() callable > YAPPERDB_URI env var > remote
campus vault via campus_python. The two branches that lazily imported
campus.auth.resources to read the local vault (STORAGE_MODE=1 test mode
and DEPLOY=campus.auth) are removed: the auth service now injects a
provider backed by its own vault in get_yapper(), and test fixtures
export the seeded URI as YAPPERDB_URI env for bare create() calls (the
vault secret stays seeded for the vault-delivery contract). Test mode
never contacts the remote vault: with no URI resolvable it raises
instead of reaching the network (guards issue #319's class of bug).

The boundary contract (test_package_boundaries) moves yapper out of
SERVICE_LAYERS into SHARED_ALLOWED with zero allowed deps: emitters
(auth, api) may import yapper; it must never grow campus dependencies
back. New factory unit tests cover the resolution order and assert
campus.auth stays unimported at runtime.

Verified: import campus.yapper loads only campus.yapper; bare create()
under test mode never loads campus.auth. Unit, contract, integration,
ruff all green.
Adds docs/yapper.md: what the event bus is, the self-contained
contract (no campus imports, boundary-enforced), the create() URI
resolution order, per-caller recipes (api-style bare create, auth's
injected provider, test fixtures), the removed DEPLOY=campus.auth
special case, emit/handle usage, and the vault-delivery contract.

Also corrects the three package-tree listings that still labelled
yapper a 'Logging framework' (it is the event bus), adds yapper to
campus/README's Services and Key Components, and records the
'yapper -> (nothing)' dependency rule in PACKAGING.md alongside the
other constraints. The stale create() docstring TODO (issue #177,
closed long ago) is resolved by the rewritten docstring in the
previous commit.
Repo-wide check of all 172 campus modules: every module docstring's
first line must be the module's dotted path. Fixes 18 stale ones
(legacy pre-reorg paths like campus.apps.api.routes.* and
campus.auth.routes.* that survived the oauth_proxy/resources moves,
singular/plural drift like routes.booking -> routes.bookings and
routes.api_keys -> routes.apikeys, a missing campus. prefix, and a
stray .py suffix), normalizes two descriptive-first docstrings
(audit.helpers.audit_events, logging_config), and adds the two missing
module docstrings (flask_campus.utils, model.booking).

Docs module-reference sweep found no stale module paths: the
campus.common.http mentions are deliberate history notes on the #976
move, and campus.test / campus.with_user_session in the guides are a
test URL and the Campus-client instance method respectively, not
modules.
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.

2 participants