Skip to content

Tech-debt batch 3: tenant teardown, backend-mismatch guard, checksum reconciler (#583 #589 #590) - #605

Merged
antosubash merged 14 commits into
mainfrom
fix/debt-batch-3
Oct 23, 2026
Merged

antosubash merged 14 commits into
mainfrom
fix/debt-batch-3

Conversation

@antosubash

Copy link
Copy Markdown
Owner

Summary

  • tenants: deleting a tenant leaves its tenant-owned data (and public files) behind #583 Tenant deletion now tears down tenant-owned data. TenantDeleted moves to simple_module_core.tenant_events (still re-exported from tenants.contracts.events) and is published through the new EventBus.publish_durable_or_inline: durable via the outbox when background_tasks is installed, inline in the deleting transaction otherwise. Durable handlers purge file_storage files/upload sessions (backend objects deleted after commit from chunked manifests; failed aborts/deletes are retried), api_tokens, sharing grants, feature-flag overrides and framework tenant-scoped settings (incl. branding). Audit history is kept. On multi-tenant installs, public files of a deleted tenant 404 at once: a 60 s per-worker existence cache, evicted on every worker by TENANT_DELETED_CHANNEL, which tenants publishes after commit. The request connection is released before the lookup. Platform files and single-tenant installs (fallback tenant, no registry row) are unaffected.
  • file_storage: each file records its backend, but every operation uses the current backend #589 File storage refuses to route a file to a backend it was not stored on: download/public/thumbnail answer 409 with a translated message, and delete soft-deletes the row but leaves the object (logged). Checksum, reaper and tenant cleanup skip non-active backends. The manual migration path is documented.
  • background_tasks: enqueue_after_commit is at-most-once — a broker failure after commit loses the job #590 enqueue_after_commit is documented as at-most-once. New hourly file_storage.reconcile_checksums re-enqueues checksums for active-backend files left without one for 30 min, up to 500 random candidates per run.

Accepted residual risk: without background_tasks, backend-object deletion after commit is best-effort; a failure is logged with the keys, and file_storage.reap_objects removes the orphans once background_tasks runs (nothing is exposed: the rows are gone and public serving 404s). See docs/framework/multi-tenancy.md.

Follow-up (not in scope): there is no admin UI or REST route that deletes a tenant; TenantService.delete_tenant is a service API only.

Verification

  • Browser/HTTP-verified on a multi-tenant (:8213) and a single-tenant (:8214) server; no 5xx
  • Local CI: make lint, make test-py (5685 passed), make test-js (748 passed), full e2e suite (49 passed), Postgres run of tenants/file_storage/api_tokens/sharing/feature_flags/framework db+core (1675 passed)
  • Code review: 5 Sonnet passes + Codex passes; every finding fixed or recorded as a deliberate decision
  • Verification report: https://claude.ai/artifact/GJ6C7SSvzh6NBDmwrE21Vm

QA Report

  • Full QA cycle completed (1 iteration)
  • 0 bugs found, 0 fixed
  • Categories tested: Happy Path (multi-tenant setup, platform files), Error States (single-tenant public/private/deleted files, ranges, branding)
  • Live tenant deletion is not browser-testable (no route); covered by test_tenants_teardown_integration.py and the durable/inline deletion tests
  • Full QA report: https://claude.ai/artifact/VUqTbiD8J5W29ghAC8t8HK

Report links are Claude Artifacts and start private; the author can share them from claude.ai/code/artifacts if reviewers need access.

Test plan

  • Multi-tenant: delete a tenant through TenantService.delete_tenant; its public file URL 404s, another tenant's stays 200, the branding logo still loads
  • Single-tenant: public file and thumbnail URLs serve 200
  • CI is green, including the Postgres workflow

Closes #583
Closes #589
Closes #590

https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4

…handlers inline

Adds EventBus.publish_durable_or_inline; file_storage defers backend-object purge to on_commit when no transport is installed.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Platform files keep serving publicly; tenant object purge skips non-active backends; inline mode tolerates sessions without on_commit.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Checksum reconciliation only picks active-backend rows; public-file tenant checks are cached for 60 s and forgotten on TenantDeleted; tenant storage cleanup manifests are chunked.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Tenant-existence cache evicts across workers via a core TENANT_DELETED_CHANNEL published by tenants after commit; checksum reconciliation picks random candidates; tenant purge materializes rows before publishing, skips empty multipart ids, and warns when no bus is wired.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Public files check the tenant registry only on multi-tenant installs (single-tenant fallback tenants have no row); a failed multipart abort during tenant cleanup is logged instead of wedging the manifest.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Public-file tenant checks release the request connection first; tenant object cleanup retries when an abort or delete fails.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
Public-file tenant check releases the connection through the guarded _release_connection helper; publish_durable_or_inline skips a missing subscription instead of asserting.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: f001def
Status: ✅  Deploy successful!
Preview URL: https://bce6433a.simple-module-python.pages.dev
Branch Preview URL: https://fix-debt-batch-3.simple-module-python.pages.dev

View logs

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review 🔄 Running since 2026-10-23T08:25:23.206282Z f001def PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant