What’s new in ThreadWork

The running log of every release across our API and frontend. Auto-generated from GitHub on every push to dev, so you see exactly what shipped, when.

[Frontend] v0.1.0-dev.56

0.1.0-dev.56 (2026-06-04)

Features

  • stream: add useValidatedActiveWorkspaceId selector hook (0a64549)
  • stream: add workspace-stream guards (validate/clear/heal decisions) (bfc0b0e)

Bug Fixes

  • stream: clear stale workspace id on every authed surface (e181410)
  • stream: invalidate workspace list on stream reconnect to heal stale id (d2f99e8)
  • stream: open the unified stream only for a validated workspace id (b882b1d)
  • stream: watchdog only nudges connected streams so failures escalate (13ef7c6)

Refactors

  • stream: tighten heal/guard comments; drop inert "use client" (9ae9639)

[API] v1.0.0-dev.164

1.0.0-dev.164 (2026-06-03)

Features

  • automation: inline image processing before visibility flip + vision timeout (e4adb0e)
  • connectors: location review-sync lease/attempt columns (cda1e51)
  • gbp: 429 retry-with-backoff + _slept_s accounting in list_reviews (9285df3)
  • gbp: backoff constants (5436d59)
  • gbp: cumulative in-job sleep budget -> GBPThrottledError (a706938)
  • gbp: fail-open QPM token bucket + gate all GBP egress (fe4a6ea)
  • gbp: typed GBPAPIError + GBPThrottledError (6932181)
  • review-sync: CAS lease (DB-clock, claimed-aware reap, retry-release) (31c456a)
  • review-sync: constants (69b5bf2)
  • review-sync: dedicated review_sync ARQ worker (Task 2.9) (321d832)
  • review-sync: fire-safe enqueue seam (2acfaa1)
  • review-sync: public-API exports + reaper cron; fix init-cycle & R13 (518b69f)
  • review-sync: reaper (claimed-aware bump, dead-letter + alert, stuck gauge) (5702163)
  • review-sync: Tier-1 durable job (throttle-aware, CAS, stdlib logging) (17c5b01)
  • reviews: idempotent image insert (pre-check + ON CONFLICT DO NOTHING) (99acf31)
  • reviews: persist photo_urls + unique image (review,position) index (c6166d5)

Bug Fixes

  • gbp: default max_total_wait_s to GBP_MAX_TOTAL_WAIT_SECONDS in all list_all_reviews signatures (c7ec04d)
  • insights: inbox not 'complete' while any location SYNCING/ERROR (5959183)
  • review-sync: loud failures, latest-first, stamp-per-batch commit, throttle passthrough; drop inline images (c78b569)
  • review-sync: resolve final-audit findings (CI-red tests, ungated egress, deploy prereq) (9b83be9)
  • review-sync: satisfy mypy typecheck (CI make verify gate) (dabf473)
  • review-sync: unify 6 triggers onto durable seam; reset dead-letter budget; remove orphans (6dff61c)

Refactors

  • gbp: harden list_reviews retry (guarded+capped Retry-After, jittered backoff, transient-only + transport retry, retry_after on exhaustion) (93fd405)

[Frontend] v0.1.0-dev.53

0.1.0-dev.53 (2026-06-03)

Features

  • brand: add brand policy table, resolvers, and SVG→TS codegen (8ee8748)
  • brand: commit canonical brand SVG atoms + reference lockups (d72e107)
  • brand: export @threadworks/shared/brand + atom equivalence tests (018c85f)
  • client: resolve production to the Beta lockup across app chrome (a2edfa0)
  • email-renderer: accept + thread deploy environment into brand lockup (307e921)
  • email: env-aware brand badge primitive + Beta green tokens (8eea4e3)
  • pdf: re-base brand variant on shared policy; prod now renders Beta (8a0018a)
  • pdf: render PdfBrandBadge from shared glyph + themed colors (orange/green) (3fb86e7)
  • pdf: shared mark in PdfLogoTile; env badge on invoice footer (533d36f)
  • ui: drive logo lockup from brand policy; add prod/Beta; canonical widths (eb0d454)

Bug Fixes

  • shared: re-export createStore return types to fix client TS2742 (c20ca85)

Refactors

  • brand: drift guard regenerates in-memory, drop child_process (d32ddbb), closes #168
  • brand: non-null lockup badge + harden env resolver and codegen (f91f7c8)
  • brand: tighten drift guard — trim dead imports, cover neutral (5d3485d)
  • email: render mark + wordmark from @threadworks/shared/brand (f066e66), closes #161 #ffffff #ea6c3a
  • pdf: keep brandVariant out of the invoice wire payload (44c5b42)
  • ui: render logo atoms from @threadworks/shared/brand (a4a58a8)

[API] v1.0.0-dev.161

1.0.0-dev.161 (2026-06-02)

Features

  • auth: access-code exchange mints scoped sa_ws + sa_ws_exp elevation (phase 4) (312a343)
  • auth: ActorAuth/OptionalAuth carry both identities + scoped elevation (phase 2) (b99f121)
  • auth: admin-status reports the dual-identity contract (phase 6) (3e6bfe2)
  • auth: client middleware dual-identity + scoped sa_ws elevation (phase 1) (758b954)

Bug Fixes

  • authz: scope support FK-sink + ownership bypass to the session's workspace (phase 5) (c9fcd0a)
  • authz: scope the support OWNER-bypass to the session's workspace (phase 3, R1) (c2fe09f)

Refactors

  • auth: remove unscoped effective-role helpers + rewrite auth docs (phase 7) (a192935)

[Frontend] v0.1.0-dev.49

0.1.0-dev.49 (2026-06-02)

Features

  • client: add review report PDF download api + mutation (T22) (d540fed)
  • client: wire dashboard Download button to the report PDF (T23) (fd3c045)
  • pdf-renderer: add /render/review-summary-report route (d23b0ad)
  • pdf-renderer: add review_summary_report to the Zod union (63ef075)
  • pdf: add chart color tokens for the review report (92845d4)
  • pdf: add PdfMetricCard primitive with SVG sparkline (282a270)
  • pdf: add PdfReportHeader primitive (be5ebce)
  • pdf: add PdfReviewSummary primitive (32c22bb)
  • pdf: add PdfReviewVolumeChart primitive (f682800)
  • pdf: add PdfStarDistribution primitive (9d69e0c)
  • pdf: add review-summary report fixtures (39de6e4)
  • pdf: add review-summary report prop types (06c5682)
  • pdf: add ReviewSummaryReport template (8dfed78)
  • pdf: environment-aware footer badge on the review report (b64566c)
  • pdf: make PdfBrandFooter ID block optional for the report (6a34adb)
  • pdf: register review_summary_report in the template registry (7078f8d)
  • storybook: add review-summary report stories (3f3fb0a)

Bug Fixes

  • pdf-renderer: narrow render-request union + literal star rating (9e2e487)
  • pdf: pixel-match metric cards to Figma + web MetricCard (ed27a86), closes #e8e6e0 #17B26A
  • pdf: pixel-match report header to Figma spec (43aa783), closes #101323 #121722 #726d60
  • pdf: pixel-match report sections to Figma (rating block, metric card, widths) (c081863)
  • pdf: pixel-match volume chart to Figma + dashboard geometry (a6a59a1)

[API] v1.0.0-dev.160

1.0.0-dev.160 (2026-06-02)

Features

  • pdf: add review_summary_report DTOs to the renderer contract (3bb237e)
  • pdf: unify renderer transport + add render_review_summary_report (caa350e)
  • threads: add fetch_distinct_providers for report sources (e503d5c)
  • threads: add pure StatisticsResponse->report props builder (bd868eb)
  • threads: add review-report formatters (pixel-parity with dashboard) (0a0966b)
  • threads: dashboard review-report PDF download routes (T21) (94dbb9d)
  • threads: ReviewSummaryReportPdfService IO glue (T20) (43ffa19)

[API] v1.0.0-dev.157

1.0.0-dev.157 (2026-06-01)

Features

  • auth: gate JIT registration on closed-beta allowlist + orphan cleanup (29607ed)
  • firebase: deny-all Firestore rules for closed-beta beta_allowlist (3bf8933)
  • identity: BetaAccessService + pure domain allowlist policy (c0b5551)
  • identity: gate Cloud-Function account sync on closed-beta allowlist (e33528e)
  • identity: gate email/password signup on closed-beta allowlist (27a8a77)
  • identity: POST /api/waitlist Mailchimp proxy (rate-limited) (fd3d62b)
  • identity: WaitlistNotApprovedException + Mailchimp settings (closed-beta) (b25c3bb)
  • integrations: Firestore-backed closed-beta allowlist provider (512eb7f)
  • integrations: Mailchimp Marketing-API waitlist client (1a50588)

[API] v1.0.0-dev.156

1.0.0-dev.156 (2026-06-01)

Features

  • billing: add format_address formatter for invoice billed-to (9513407)
  • billing: add itemization fields to invoice _LineItem dataclass (e9ab5d6)
  • billing: attribute per-location overage on invoices from usage ledger (4623f7c)
  • billing: bill-to real Stripe customer + render invoice billing period (815f548)
  • billing: detect plan-change tag + humanize proration/overage children (0f8a4ec)
  • billing: itemize invoice groups into parent + proration/overage children (7e16f9a)
  • billing: map catalog prices to plans + extract Stripe line price id (ad5a4ff)
  • pdf: extend invoice DTO with line-item tag/note/children + billing period (4b41091)

Bug Fixes

  • identity: narrow HTTPException.detail in email-change tests for mypy (#218) (1c9069e), closes #216

[Frontend] v0.1.0-dev.45

0.1.0-dev.45 (2026-05-31)

Features

  • account-settings: change-email OTP modal flow (9c050c8)
  • account-settings: slide Account Settings in from the top over the workspace (2f5c67c)
  • chrome: add pure Atrium focus → watermark model (32ad94e)
  • chrome: go-home from the Account Settings deck via a RootChrome exit layer (f586c54)
  • chrome: hold Account Settings open state in useShellChrome (27a9524)
  • ui: add showWatermark prop to AuthShell (c2e9888)

Bug Fixes

  • account-settings: 32px label↔content gap in settings rows (72b4f10)
  • account-settings: drop success toast on avatar upload (9ab08cb)
  • account-settings: drop the workspace overlay's stray watermark; consolidate overlay state into useShellChrome (ae69c41)
  • account-settings: let auth cards + language picker fill the column (02d3ab4)
  • account-settings: map all /verify error codes in change-email modal (573ed2b), closes #216
  • account-settings: pixel-perfect avatar upload card (b3196aa), closes #514d42
  • account-settings: skip avatar crop, center-cover the upload (68cdfb5)
  • account-settings: trim change-email verify error copy to the OTP cases (e8e9c4a)
  • account-settings: use design edit-04 pencil on the email row (f9cb6cb), closes #c0bbae
  • account-settings: vertically center the Delete account button (88bd4d1)
  • scripts: exclude co-located test/spec/story files from storybook-coverage (fd461e0)
  • ui: use design loading-02 spinner in editable avatar overlay (a76c522)

Refactors

  • chrome: derive the Atrium watermark from focus; retire watermarkOffsetY push (e92c5ef)

[API] v1.0.0-dev.146

1.0.0-dev.146 (2026-05-29)

⚠ BREAKING CHANGES

  • automation: Pass-1 admission redesign — atomic cap + visibility
  • threads: backend-enforced client visibility gate (post-Pass-1)
  • identity: OTPSignupRequestBody.app_language required (R28)
  • notifications: typed reason enum on MenuExtractionFailedPayload
  • threads: to the wire shape, but pre-release-safe: no external API consumers, the FE switched over before this PR fired (per planning team confirmation).

Diff:

  • modules/threads/schemas/actions.pySelectVariationRequest narrows from {variation_index?, variation_id?, custom validator} to a single required variation_id: str. model_validator import dropped.
  • modules/threads/routes/client/edit.py:select_variation — the dual-supply branch + mismatch-400 + range-check fall away. The route now resolves body.variation_id to its positional index for the (still-positional) storage column selected_variation_index, raising 400 only on unknown variation_id.
  • tests/unit/threads/test_variation_ids.py::TestSelectVariationRequest — drops test_accepts_index_only and test_accepts_both (those paths are gone); retains test_accepts_id (happy path)
    • test_rejects_empty_body (validation failure on missing id).
  • OpenAPI snapshot regenerated — SelectVariationRequest shrinks to \{variation_id: string\}, schema-level required: ["variation_id"] added; variation_index removed.

Coverage: make verify ✓ green: 2325 unit tests pass, 72.03%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Features

  • .claude: add /cleanup-merged-worktrees slash command (ec2f37c)
  • agents: add tag-polarity-driven sentiment derivation helper (c6eae1b)
  • auth: FirebaseTokenAuth carries photo_url from picture claim (65a46a2)
  • automation/queue: ARQ retry on transient Memorystore disconnects (#7) (f7df65a)
  • automation: add ReviewSnapshot dataclass for job payload (c8a4af2)
  • automation: carry review snapshot fields through RoutingContext (d0f4440)
  • automation: gate auto-publish on working-hours toggle pair + Q4 dual-snapshot SLA (94bb29a)
  • automation: Pass 2 success stamps client_visible_at + G1 trial guard (04feb31)
  • automation: pass review snapshot through enqueue to ARQ payload (44c1f01)
  • automation: Pass-1 admission redesign — atomic cap + visibility (f5c1421)
  • automation: snapshot as existence proof, delete visibility retry (392924a)
  • b-17.0.6: assert FIREBASE_AUTH_EMULATOR_HOST unset outside LOCAL (be2e64f)
  • b-17.0.6: firebase-auth emulator service in docker-compose.test.yml (3cd8f97)
  • b-17.0.6: real Firebase emulator fixtures (replaces stub) (f3952c5)
  • b-17.0.6: verify auth.py accepts emulator-issued ID tokens (0676ca0)
  • billing: _mirror stamps BillingSubscription.customer_id from Stripe sub (d0b9a65)
  • billing/admin: retry_failed_move CLI for FAILED_TARGET_ADD recovery (T18) (4eb8023)
  • billing/api: expose pending_transition on LocationPlanResponse (T27a) (1cb2b64)
  • billing/api: POST /move + POST /move/preview routes (T20) (c6c024e)
  • billing/migration: rename billing_split_off to billing_location_transition + move columns (acf2444)
  • billing/repo: kind-aware finders + move-target retry methods + cross-flow guards (T6) (b7c8482)
  • billing/webhooks: recompute move-transition status on anchor events (T14) (932b508)
  • billing: add _pdf_formatters (currency, date, filename safety) (0af001a)
  • billing: add BillingInvoicePdfService.fetch_invoice (auth-leak-safe 404) (e418ad0)
  • billing: add CustomerService.refresh_billing_entity_for_customer (c666642)
  • billing: add invoice_pdf routes (workspace-rollup + per-location) (661f537)
  • billing: add per-subscription invoice endpoint (d846fde)
  • billing: assemble InvoicePdfRenderProps (both variants + edge cases) (03780b2)
  • billing: BillingInvoicePdfService.render orchestration + cross-location 404 (398f42b)
  • billing: BulkSignup uses create_for_workspace (1:N customer model) (cd07d4e)
  • billing: cancel-at-period-end branch for empty-source move (T10) (80401c8)
  • billing: cancel-by-user endpoint for pending moves (T17) (6e426cb)
  • billing: canonical state field on LocationPlanResponse (#101) (9040944)
  • billing: create_for_workspace replaces get_or_create; delete sync_email (ac0ac7a)
  • billing: cross-flow guards block attach/remove during pending transition (T15+T16) (ff2424d)
  • billing: drop hosted_invoice_url + invoice_pdf_url from API responses (R27, no shim) (d756344)
  • billing: EnterpriseAdmin uses create_for_workspace (1:N customer model) (ebe547f)
  • billing: env-aware seed fail-loud in dev/staging/prod (9763cb3)
  • billing: instrument 3DS-pending METERED race-surface (#56) (#104) (9c5cde0)
  • billing: kind-aware state recompute for move (T11) (7599098)
  • billing: metered-lifecycle helpers (ensure / end_if_last) (d1d6045)
  • billing: one-off FLAT price spec builder (381271b)
  • billing: per-group portal session route (5ce3562)
  • billing: periodic one-off Stripe Price archival cron (#53) (#103) (e276f7a)
  • billing: remove per-location checkout endpoints (now bulk-only) (3b1974e)
  • billing: restore create_for_workspace observability + clarify retry layers (67d04ad)
  • billing: source-side Schedule branch for move (T9) (7d4a02f)
  • billing: SplitOff uses create_for_workspace (1:N customer model) (ba1c76f)
  • billing: start_transition(kind=MOVE) with pre-flight matrix (T8) (315f810)
  • billing: target-add cron with SAVEPOINT-per-row + retry exhaustion (T13) (2d7457b)
  • billing: target-side completion for move (T12) (a69be7d)
  • check: B-16.4-S3 coverage gate (R14) — per-module floor 55% (216a616)
  • ci: cross-repo auto-bump job (Stage 5 T9) (78eadbb), closes #103 #103
  • ci: GCP Artifact Registry build-push via WIF (Stage 4) (88db71a)
  • ci: Trivy scan gate + workflow_dispatch SHA replay (Stage 5 T8 + T10) (dea1b24)
  • client-api: /internal/drain endpoint for graceful SSE shutdown (#6) (40a5b82)
  • connectors: /webhooks/google/reviews with OIDC verification (237952b)
  • connectors: add GBP regular_hours_json → working_hours mapper (ad837e1)
  • connectors: add GoogleAccount model (aaaa5c5)
  • connectors: add GoogleLocation model (37134d1)
  • connectors: add GoogleWorkspaceGrant model (ff825cf)
  • connectors: backfill google_account_email onto GoogleAccount (381c60d)
  • connectors: Connect Source flow — OAuth routing + GoogleLocation on attach (#161) (5e7d141)
  • connectors: daily review reconciliation cron (456587a)
  • connectors: hourly notification setting reconciliation cron (2a72c93)
  • connectors: map GBP regularHours into LocationGeneralProfile.working_hours (af8faab)
  • connectors: NotificationSettingLifecycleService + GBPNotificationsClient (5abc617)
  • connectors: OAuth callback routes Settings add-location via redirect_target (#148) (665855e)
  • connectors: repositories for GoogleAccount/Grant/Location (e359228)
  • connectors: settings_accounts redirect target for OAuth (#151) (3bb54e0), closes #79
  • connectors: stage-2 inbound worker — pull-subscription service (8e61cb9)
  • connectors: TokenResolver with grant fallback (c3a4c7d)
  • connectors: weekly cron to refresh GBP details + working_hours (ec44dca)
  • connectors: wire NotificationSettingLifecycleService into disconnect (e6c63b7)
  • connectors: wire NotificationSettingLifecycleService into reconnect (21a39c4)
  • core: pin BE webhook convergence budget for FE coupling (#59) (#102) (3ca57f0)
  • cors: allow *.dev.thread.work origins during domain migration (#125) (001e610), closes #253 #255
  • cors: drop legacy *.dev.threadwork.ch origins now that thread.work is live (#128) (5600582), closes #125
  • db: warmup_db_engine helper for Pub/Sub workers (b9b7241)
  • drop container_name, parameterize ports, add tw labels (406f468)
  • events: add unified event envelope models (2e55dbf)
  • events: add unified event publisher service (794558b)
  • events: add unified event registry (75c1193)
  • events: add unified event scope types (d23acfe)
  • events: add unified EventKind enum (4f8f202)
  • events: expose publisher public API (d5b532f)
  • events: sprint 1 phase 0 — prerequisites + post-grace-period rollback runbook stub (943ae32), closes #43
  • events: sprint 1 phase 1 — pilot module migration (audit + queue) (766ec9e), closes #43
  • events: sprint 1 phase 2 — thread module migration (9 callsites) (c2f7a4e)
  • events: sprint 1 phase 3 — notification module migration (1 callsite, UserScope critical) (4fc2a8f), closes #43
  • fe5: bump-bot also writes mock-gbp image tag (e0b87cf), closes #36
  • fe5: Environment enum — kill 'dev' vs 'development' string drift (ac46ef7)
  • fe5: mock-gbp image CI + Dockerfile hardening (uid 10001) (83ac196)
  • fe5: provider_kind column on workspace_connectors (55d5f97)
  • firebase: cross-project impersonation init path (Stage 5 T4 / F-18) (2957bdb)
  • functions: set accountSynced custom claim after onCreate sync (e45feef)
  • gbp: /mock/auth route + callback writes provider_kind (5d176b4)
  • identity: add app_language column to users (D-11 inline) (192e4ef)
  • identity: app_language email i18n foundation + ARQ welcome migration (2261ca1)
  • identity: app_language end-to-end (R28-strict service + routes) (ed103f4)
  • identity: OTPSignupRequestBody.app_language required (R28) (a71cd6a)
  • identity: POST /api/auth/account-sync/retry endpoint (452d8d9)
  • identity: POST /api/profile/avatar/import-from-sso (e2432c0)
  • identity: UserService.ensure_avatar_from_sso — universal reconciliation (303264f)
  • insights: add _merge_balanced card assembler for tag-cards (47f3e0f)
  • insights: add GET /tag-cards endpoint with cursor-keyed cache (310ac13)
  • insights: add InsightsService.get_tag_cards facade (b6462d0)
  • insights: add load_tag_review_cards tag-scoped SQL loader (f0a0a6c)
  • insights: add ReviewProcessingStatusService classify state machine (8ffb435)
  • insights: add TagCardsResponse schema (d8da46c)
  • insights: threshold=0 for SSE-driven processing indicator (#131) (c7f888b), closes #25 #6 #15 #19 #20 #78 #120 #17 #18
  • insights: wire SQL queries for ReviewProcessingStatusService (9e4c3ae), closes #3
  • internal_test: add _google_location_seed_helpers module (0668f25)
  • internal_test: GET /internal/test/auth/last-otp (89578ca)
  • internal_test: GET /internal/test/health endpoint (ebd04bc)
  • internal_test: Layer 1 safety gate + LOCAL_OTP_SEED boot assertion (c6ed76a)
  • internal_test: Layer 2 — conditional include_router in main.py (e6523c5)
  • internal_test: Layer 3.5 — /internal/test/* in EXEMPT_PATHS (LOCAL only) (b88b92c)
  • internal_test: POST /internal/test/auth/seed-access-code (d7f2f85)
  • internal_test: POST /internal/test/reset/billing (4817afb), closes #58
  • internal_test: POST /internal/test/seed/workspace (ccef8ea)
  • internal_test: POST /internal/test/sse/wait-for-event (81bd7f9)
  • internal_test: POST /internal/test/stripe/webhook + sign_event re-export (e9ffa0e)
  • internal_test: router aggregator + _helpers + 7 endpoint stubs (3986e4c)
  • internal-test: /billing/catalog/ensure-configured endpoint (#81) (ed3bf68)
  • internal-test: /billing/seed/location-transition endpoint (#83) (cda3799), closes #81 #82
  • internal-test: /billing/seed/secondary-group endpoint (#82) (216f677), closes #81
  • internal-test: /billing/stripe-customer lookup endpoint (#87) (1616eec)
  • internal-test: seed-bulk-pending-checkout endpoint (#91) (fec9b85), closes #3
  • internal-test: seed-workspace accepts role override (#69) (b9a1737)
  • internal-test: seed-workspace sets workspaces.owner_id when role=OWNER (#76) (31f4480)
  • internal-test: seedWorkspace cancellationMode flag (#95) (f784f91), closes #6 #7
  • internal-test: seedWorkspace materializes real Stripe state (Customer + Subscription) (#88) (e2b3b6d), closes #3
  • internal-test: unified kind path for /internal/test/sse-wait (acde41c)
  • local-dev: add pdf-renderer service to docker-compose (c5e6a86)
  • make: worktree-* shims + fix tests-billing + migrate for project scope (36ea171)
  • messaging: add register_after_root_commit utility (SAVEPOINT-safe) (e88d31a)
  • mock-gbp: /dev locations browser + /dev/api/generate endpoint (490379f)
  • mock-gbp: /dev/api/publish — instant dispatch (delay=0) (d73a9da)
  • mock-gbp: add Anthropic wrapper for synthetic review generation (dc8e753)
  • mock-gbp: AI image generation for review drafting (1-5 photos) (#127) (7b17fd3)
  • mock-gbp: drafting page + Generate flow wiring (c6716e0)
  • mock-gbp: loading skeleton during AI generation (068e6b1)
  • mock-gbp: migrate /oauth/authorize to Jinja2 template + visual refresh (50101d1)
  • mock-gbp: notificationSetting v1 endpoints (bc0b8e7)
  • mock-gbp: Pub/Sub publisher + /admin/fire-notification endpoint (5897de1)
  • mock-gbp: re-anchor fixture timestamps + rename admin/reset → test/reset (3a854fb)
  • mock-gbp: scaffold /dev tool — deps, color palette, language inference (8993bd7)
  • mock-gbp: scheduled dispatches — table, scheduler, list/cancel endpoints (b41e595)
  • mock-gbp: scheduled queue modal + topbar pending badge (5af558b)
  • mock-gbp: self-hosted public review page for Source button (#147) (0051489)
  • notifications: B-17.1 NotificationService + per-kind payloads (transient) (0a1d65c)
  • notifications: B-17.2 SSE channel + per-user stream endpoint (432cadf)
  • notifications: B-17.3 producer-wiring — edit_rules + menu_extraction live (cc18e60)
  • notifications: typed reason enum on MenuExtractionFailedPayload (8537a59)
  • observability: emit sse.subscribers.total gauge (caf2b4e)
  • observability: measure SSE filter CPU cost (044279f)
  • observability: PubSubPipelineMetrics + wiring at every stage (357876c)
  • onboarding: brand-name rename + reply-language fallback (5cd6c1a)
  • otp: add _generate_deterministic_code sibling for LOCAL-only path (d627b21)
  • pdf_renderer: add BE integration package — DTOs, httpx client, exceptions (fef8ac8)
  • processing-status: add batch-aware progress counts to review processing endpoint (f3d8de3)
  • pubsub: add Pub/Sub emulator service + google-cloud-pubsub dep + settings (9b465c7)
  • pubsub: client wrapper + idempotent topology bootstrap (1b5f0bf)
  • pubsub: GoogleNotificationSetting + ProcessedEvent models (ca1baa3)
  • pubsub: repositories for NotificationSetting + ProcessedEvent (ba1f207)
  • review image pipeline — ingest, store, analyze, feed to agent (#118) (6118825)
  • reviews: platform consumer service — pull subscription (2b8e2b0)
  • schema: connectorstatus + locationstatus + locationsourcestatus enums (d28aa95)
  • schema: create location_sources (N:M edge) table + ORM model (d3dfe45)
  • schema: denormalised workspace_id + closed_at/sla_met for dashboard stats (3c02e35)
  • schema: drop google_workspace_grants table + ORM (tokens collapsed in 1.4) (7b2316f)
  • schema: locations drops connector_id; bidirectional sources edge wired (dd1e4a8)
  • schema: rebase gbp_location_details onto LocationSource (1:1 with source) (9de3d6d)
  • schema: rebase google_locations onto LocationSource + system-wide unique (e335ae5)
  • schema: rename google_accounts → provider_accounts (provider-agnostic) (b6379ed)
  • schema: reshape workspace_connectors for multi-account (b969de9)
  • schema: retarget google_notification_settings FK at provider_accounts (8408af2)
  • schema: unified_reviews + gbp_reviews carry location_source_id (NOT NULL) (2164eea)
  • settings: add pdf_renderer_url (default http://localhost:3002) (9efc164)
  • settings: add STREAM_UNIFIED flags (ff4998f)
  • sse: add SSESubscription.take_first() helper (c9b82cd)
  • sse: add unified client stream filtering (5676ebd)
  • sse: add unified subscription scope carrier (41c5a27)
  • sse: allow unified_events subscriptions (4efb419)
  • sse: mount GET /api/stream behind STREAM_UNIFIED flag (99ab706)
  • sse: unified per-kind ClientStreamSession + EventPublisher metrics + bidirectional dual-publish isolation (c5eebe9)
  • stacked setup cards — per-location resolver + state-machine collapse (BE) (#12) (9740ce9)
  • stacked setup cards — per-location resolver + state-machine collapse (BE) (#14) (c503978)
  • stage-5b: async oauth.py — await Redis-backed state + 503 fail-closed (830cc03)
  • stage-5b: async reconnect.py — await Redis-backed state + 503 fail-closed (1a686fb)
  • stage-5b: Redis-backed OAuth state (Phase 1) (6461d81)
  • stage-6c: close_redis_pool public API + oauth_state pool invalidation (c5fb80b)
  • stage-6c: CORS-on-exception via custom middleware (f3c7fa3)
  • stage-6c: FrontendPaths SSOT for BE-composed FE URLs (a43428d)
  • stream: Sprint 1 Phase 4 Task 4.7-pre — admin API unified-stream mount (06c8c8b)
  • stream: Sprint 1 Phase 5 BE — heartbeat-as-event + liveness watchdog (2e364c1)
  • threads: activity feed accepts time_range + location_id filters (ec91b6d)
  • threads: activity route exposes filter query params (8e14dad)
  • threads: add approved_for_processing gate column and approve methods (4bf7c43)
  • threads: add find_next_working_moment helper for auto-publish gate (6a577fe)
  • threads: add rating_distribution + average_rating to dashboard statistics response (30455e2)
  • threads: add window-scoped unreplied parity for dashboard and list (#191) (8c89a7b)
  • threads: backend-enforced client visibility gate (post-Pass-1) (bf60667)
  • threads: C3-BE add GET /api/threads/counts (3-state bucket projection) (6860d7c)
  • threads: C6-narrow drop variation_index from SelectVariationRequest (ace1b42)
  • threads: capture closed_at + sla_met at REPLY_PUBLISHED close time (532e576)
  • threads: dashboard SLA reads ur.sla_met (no JOIN to review_threads) (45c147c)
  • threads: dashboard statistics endpoints + 60s Redis cache (e2ab44a)
  • threads: deterministic delta_percent for previous=0 (always-show-badge convention) (b8e0c8f)
  • threads: include reviewer_avatar_url in thread list response (#178) (ba6cbe5)
  • threads: per-bucket rating counts in dashboard time_series (a51e1bc)
  • threads: per-bucket sla_eligible + sla_met in dashboard time_series (3f56c40)
  • threads: pure bucket + comparison-window logic for dashboard stats (e896d1b)
  • threads: single-source SLA service + ThreadSummary.sla wire field (23cac44)
  • threads: SQL composition layer for dashboard statistics (e58cd60)
  • threads: stamp approved_for_processing at sync and PubSub ingest (5570e67)
  • threads: StatisticsService orchestration + dashboard response schemas (87f4438)
  • threads: wire Source button to Google review URL (#135) (1d1c9cd)
  • verbosity: enforce per-tier char bands on generated replies (#107) (3ae336f)
  • workspaces: add GET /review-processing-status endpoint (4c85954)
  • workspaces: add InboxProcessingStatusResponse schema (fb31f26)
  • workspaces: auto-populate region & timezone from GBP location data (#171) (b15b04f)

Bug Fixes

  • #78: mirror response_time_ms → top-level latency_ms (6c94579), closes #78 #120
  • agents: drop escalate_to_human from prompts + dispatch + dead helpers (59403f6)
  • agents: drop sentiment + 'escalation' intent from analysis prompt + taxonomy spec (7ce8b9d)
  • agents: remove EscalateToHumanTool (f72b2c8)
  • agents: SubmitAnalysisTool derives sentiment from tags; drops escalation intent (b475351)
  • alembic: handle asyncpg driver + URL-encoded % in DATABASE_URL (269e611), closes 85/#86
  • arch-lint: allowlist admin unified_stream route (R16 co-location) (4093ebc)
  • arch-lint: re-pin publisher-imports baseline to shifted line numbers (8202394)
  • arq-retry: wrap redis-py imports in infra/integrations/redis/ (589ee8d)
  • auth: silence pre-existing mypy no-any-return on firebase token decode (6796661)
  • automation/queue: handle rediss:// scheme + Memorystore TLS (9f1f59a)
  • automation: add in-process thread visibility retry for Cloud SQL (0d4a4f9)
  • automation: lease reclaimer Phase B excludes Phase A's resets (#50) (#97) (6a35252)
  • automation: remove analysis-severity escalation gate; add Pass-2-runs unit-integration test (4c3678f)
  • automation: resolve mypy type errors for ReviewSnapshot duck-typing (7c8dbbc)
  • automation: skip Pass 1 analysis for rating-only reviews (#117) (ae3a69a)
  • automation: use ReviewSnapshot directly, skip SELECT on hot path (b6cf18f)
  • b-17.0.6: emulator-mode init fallback in FirebaseAuthService._get_app (3889925)
  • b-17.0.6: LOCAL_OTP_SEED interpolation — fail loud, generate in Makefile (e886ed2)
  • b-17.0.6: teardown LOCAL_OTP_SEED + docs drift cleanup (0fd1e1a)
  • b-17.0.6: wire FIREBASE_AUTH_EMULATOR_HOST in CI + Makefile + quality polish (69be27d)
  • b-17.0.6: worker depends_on firebase-auth-test + drop dead EXPOSE 4400 (ec5a18b)
  • batch: centralize processing_batch_size in stamp_approved_threads (1692ffa)
  • billing/model: kind enum needs values_callable (T7b/T20/T27a real-DB blocker) (df43a5c)
  • billing/repo: get_by_stripe_id filters out soft-deleted rows (5917afa)
  • billing/tests: swap pytest_plugins for explicit re-imports (6cc0537)
  • billing/webhook: drop METERED-missing-plan_code hard-fail (smoke fix) (60a22e0), closes #32
  • billing: attach uses one-off FLAT price per location (31a2575)
  • billing: B-18.6 race — joint-state-gated activation fan-out (1988cab)
  • billing: backfill billing entity on subscription.created (a4c05df)
  • billing: bulk-signup propagation + webhook error visibility (8fab6de)
  • billing: catalog is authoritative for item plan_code resolution (cbb29b0)
  • billing: coerce StripeObject Customer.address to dict before JSONB write (c98090a)
  • billing: D36-compliant swap via end + ensure pattern (e8e1d16)
  • billing: drift reconciler iterates N customers per workspace (9d31837)
  • billing: drop nickname from inline price_data (Stripe rejects it on SubscriptionItem.create) (e4651ac)
  • billing: drop receipt_url end-to-end to close §D19 drift (B1) (0f56cf8)
  • billing: drop stale hosted_invoice_url from _transition_response (58eba18)
  • billing: list_locations handles N customers per workspace (c8a30ec)
  • billing: metered-lifecycle helper crashes on real Stripe SDK shape (333b866)
  • billing: mypy type narrowing on datetime|None + UUID|None (13ddaf2), closes #58
  • billing: partial unique on stripe_item_id (active rows only) (96522c2)
  • billing: refresh_billing_entity_for_customer narrows to customer_id (85da360)
  • billing: resolve_plan_code_for_price reads Product.metadata.plan_code (e203e71)
  • billing: restore plan-row close-out on customer.subscription.deleted (3a0989c)
  • billing: route both .updated and .deleted loops through resolvers (441b149)
  • billing: swap + snapshot guard look up FLAT by (sub, location, kind) (b45e451)
  • billing: swap guards against from_plan disagreeing with location tier (d863760)
  • billing: swap mints one-off destination FLAT price (be0ffb5)
  • billing: swap mirrors only the swapped item, not the whole sub (cf02956)
  • billing: T5 follow-on — orphan-cleanup + end-helper tests + rename (8aab44e)
  • billing: tolerate out-of-order webhook delivery for bulk plan-row materialization (#105) (0eddae7)
  • billing: use after_root_commit so meter enqueue waits for outer commit (5fbb5fd)
  • billing: use Subscription.retrieve().schedule for pre-flight (smoke fix) (c4b9e32)
  • billing: watermark gate rejects out-of-order subscription webhooks (#54) (#98) (2965af0), closes #50
  • check_scripts: exclude .worktrees/ from _lib.walk_python_files (#195) (4ba0523)
  • check: allowlist apis/client/routes/internal.py as platform entry-point (bfa3579)
  • checks: allow shared/app/db/models/ shim + register isolation as blocking (d7d2b90)
  • ci: add .trivyignore file referenced by build-push-gcp (d381ed9)
  • ci: aim pytest-host DATABASE_URL/REDIS_URL at the test stack (da20733), closes #35
  • ci: bounded allowlist for CVE-2026-27135 — unblock BE dev deploys (4862fde), closes #65
  • ci: bump-bot --auto with direct-merge fallback (094b191)
  • ci: firebase_admin import-untyped — match existing per-line ignore pattern (a7ca073)
  • ci: patch 3 additional Debian CVEs in both Dockerfiles (#94) (aee7b75)
  • ci: trivy-action 0.28.0 doesn't exist — bump to 0.36.0 (0e57ee3)
  • ci: trivy-action needs v-prefix on tag (157fbdb)
  • ci: tune Postgres connection limits for test stack (95fc64d)
  • ci: unblock verify + integration on x86_64 runners (ace17c2)
  • communication: restore load-bearing comment on true() SQL idiom (71ac6cb)
  • communication: use production character bands in voice preview (#170) (1c75cb1)
  • connectors: add gen_random_uuid() server_default to google_accounts.id (bcb350c)
  • connectors: bare google_location_id, parser inside infra/integrations/gbp (52a910c)
  • connectors: disconnect idempotency + reconnect cross-account guard (4720600)
  • connectors: extract original text from Google reviews, strip embedded translation (#108) (16ef594)
  • connectors: finish workspace_locations -> locations rename in raw SQL + factory (adc5934)
  • connectors: make GoogleLocation.location_id unique + REVOKED filter test (089fa76)
  • connectors: OIDC validates issuer claim + typecheck cleanup (158ae50)
  • connectors: preserve reply audit trail when sync transiently omits (1db9a3f)
  • connectors: rewire post-refactor stale callers + types (afd6c5a)
  • connectors: server-side WC persistence + sync trigger + disconnect cleanup (#159) (064e454), closes #79
  • core/enums: revert unrequested value lowercasing + fix missed caller (a4b5835)
  • db: drop workspace working_hours cascade + workdays + legacy scalars; add SLA toggles + typed Pydantic shape (362ab56)
  • detect reply language when review.original_language is null (#115) (8f713c0)
  • dev: pin docker-compose Postgres to 17 (ADR-0006 parity) (f193858)
  • docker: B-16.4-S7 update arq worker path to canonical module (cf36c1a)
  • enums: mark LedgerEntryType re-export explicit for mypy strict (8f36b9f)
  • event_service: use after_root_commit so ARQ dispatch waits for outer commit (a7963e3)
  • events: harden publisher validation contract (57ae0ed)
  • events: require queue processing time payload field (2b8f683)
  • events: sprint 1 phase 1 patch — close HIGH-SP-01 + MEDIUM-SP-01 (a901ca3)
  • events: sprint 1 phase 2 patch — close MEDIUM-P2-S2, MEDIUM-RP2-01, document MEDIUM-P2-S1 as VF-1-093 (df77f98), closes #43
  • events: sprint 1 phase 3 patch — close MEDIUM-RP3-01 + Phase 3 Fact line-shift (32538b1)
  • fe5: bump mock-gbp deps to clear Trivy HIGH CVEs (25529df)
  • fe5: callback redirects use /onboarding not /dashboard/onboarding (6a26809)
  • fe5: chown /app/data in mock-gbp Dockerfile for docker-compose (fdeb220)
  • fe5: CORS allowlist for renamed dev frontend hostnames (e034b57)
  • fe5: drop unused type: ignore — CI mypy stubs differ from local (f868fe0)
  • fe5: mypy errors blocking CI verify gate (bc53914)
  • fe5: provider_kind column uses postgresql.ENUM(create_type=False) (f2c09c0)
  • fe5: regen OpenAPI snapshot after docstring trim (94e3ba0)
  • fe5: reviewer findings — test miss + 4 polish items (450337d)
  • fe5: test_client_helpers_extended.SimpleNamespace needs provider_kind (1dfa4f6)
  • fe5: trim ConnectorProviderKind docstring to clear 650-line cap (7185fdc)
  • finalize: pre-stamp SYNCING so FE shows processing card from second 0 (11c7c0f)
  • firebase: pass serviceAccountId in impersonation init so create_custom_token works (79a0571)
  • firebase: remove type-ignore that CI flags as unused (b1df000)
  • firebase: silence mypy on untyped Base subclass + Credentials call (6660fbc)
  • firebase: split impersonation path to satisfy file-size cap (1e6e784)
  • gate: remove reply_text exception from approved_for_processing gate (2c725c5)
  • gbp: correct v1 Business Information API URL format (ed2da60)
  • gbp: merge overnight tails into previous day's close time (f406f88)
  • gbp: populate place_id + maps_uri from listing API at workspace setup (#146) (71c40e0)
  • gbp: prefer longest period for multi-period days in working hours mapper (3fff3e8)
  • gbp: remove invalid profilePhotoUrl from readMask (ff1aaf5)
  • h2: fastapi 0.115.5 → 0.123.10 — close starlette CVE-2025-62727 (6237133)
  • h3: structured logs — JSON emit + workspace_id correlation field (f1594c1)
  • http: stringify ctx.error before JSON-encoding validation responses (8682212)
  • identity: /email/verify must actually flip Firebase emailVerified (#72) (1ddc1d0)
  • identity: commit OTP attempts increment on verify-failure path (security) (#71) (3bd2b2c)
  • identity: retry endpoint passes photo_url to sync_account (7788dd7)
  • images: add missing commit + dedup + try/except + tests (#124) (b246b2f)
  • images: drain deferred images on Pub/Sub path + mount Firebase creds (#129) (c6d2dd7)
  • images: use Google's actual field name reviewMediaItems/thumbnailUrl (#120) (b95ad33)
  • import: B-16.4-S8 cache PEP 562 lazy exports to win submodule shadow (222afda)
  • inbox: switch processing indicator to in-progress-only count (#139) (529db06)
  • infra: mock-gbp healthcheck uses python stdlib instead of curl (ec7d798)
  • insights,snapshots: update public-API list + OpenAPI snapshot (80a584c)
  • insights: exclude terminal-pre-analysis threads from inbox bar denominator (a27db67)
  • insights: scope inbox processing counts to paid locations only (d253728)
  • integration: defer firebase-auth-test compose service to B-17.0.6 (fa95d2d)
  • integration: make B-17.0.1 + B-17.0.2 stack actually boot (ee45180)
  • integration: use a valid Fernet key for the test stack (4b6f369)
  • internal_test: close pre-PR verify gates — typecheck, schema, integrations, 13-module count (01cd094)
  • internal_test: mark seed/reset/access_code as transaction owners (R21) (276bb2b)
  • internal_test: route Customer.modify through StripeClient wrapper (#73) (7aef836)
  • internal_test: seed_user also clears stale GoogleLocation claims (831fc7c)
  • internal_test: seed_workspace clears stale GoogleLocation claims (8967fb5), closes #161 #93
  • internal-test: seedWorkspace creates METERED + FLAT BillingSubscriptionItems (#90) (c1e69d1), closes #4
  • internal-test: seedWorkspace mirrors current_period_start/end from Stripe (#92) (80e4ff7), closes #4
  • internal-test: use returned PaymentMethod id from attach (not literal pm_card_visa) (#89) (4282ce2)
  • ledger: drop LedgerEntryType.ESCALATED downstream; mark enum deprecated (0d7aa01)
  • local-dev: align Firebase project ID to canonical threadworks-local + wire Postmark for OTP (#68) (fc48aee)
  • local-dev: unblock smoke-test path discovered post-Plan-B (0afd6b2)
  • make: exclude pytest.mark.load from test-cov default invocation (ce91f63)
  • make: quote TWDEV_LIB path; switch worktree-status/up to ALL=/FULL= vars (11b65c3)
  • messaging: defer ARQ dispatch to after_commit (bulk-sync 'Review not found' race) (#179) (b2288ff)
  • mock-gbp: add dev cluster redirect URI to default allowlist (#168) (6421569)
  • mock-gbp: auto-bootstrap notificationSetting on /dev/api/publish (9302d75)
  • mock-gbp: publish full GBP resource path as Pub/Sub reviewId (db11189)
  • mock-gbp: set DRAFTING flag before loading app.js (e6eb618)
  • models/invoice: repoint stale FK string to billing_subscription (fca4474)
  • processing-status: count client_visible_at not analyzed_at (46a4239)
  • requirements: declare aiosqlite — used by billing predicate test (6c9a9ae)
  • reviews: map reply_updated_at on UnifiedReview + accept in apply_reply_to_review (413d294)
  • schema: tighten Task 1 review issues — explicit None guard + DISTINCT ON in sla_met backfill (c885c15)
  • security: bump deps to clear Stage 5 T8 Trivy CVE findings (8e376dd), closes 24/#25
  • security: clear remaining 3 Trivy findings (round-2) (ad6f0fe), closes #26 #1 #2 #3
  • security: CVE-2026-27135 base image patch + OTP verify disabled check (6d8d10b), closes #65 #74
  • sla: switch review_reply_target_hours validation to 1-168 range (cff1bc8)
  • sse: complete PR #131 — pass thread_created through producer + subscriber filter (#133) (eabc24f)
  • sse: correct publish_thread_visible call signature in already-replied path (943ab28)
  • sse: fire publish_thread_visible in already-replied close path (ff05d39)
  • sse: import drain_subscribers from drain.py (T6 hotfix) (647dceb)
  • sse: publish_thread_event fires after db.commit() (ADR-0019) (#96) (d252cdd), closes #52
  • sse: split drain registry into its own file (AGENTS.md §4 cap) (c25de08)
  • sse: tighten heartbeat 25s → 15s (ADR-0017 headroom) (b5ceed7)
  • sse: use after_root_commit so NOTIFY waits for outer commit (cbecb81)
  • stage-5b: allowlist core/environment.py in enum SSOT rule (3fc6f07)
  • stage-5b: coerce ENVIRONMENT=test/integration_test → LOCAL (39b790b)
  • stage-5b: mypy strict — cast json.loads return in pop_oauth_state (1cf5a70), closes #44
  • stage-5b: patch async store_oauth_state in env-guard tests (6395cf2)
  • stepper: show processing card during active sync (aa4ed32)
  • stream: Phase 5 BE heartbeat format — drop the event: name (07f11ee)
  • stream: Sprint 1 Phase 5 patch — wire circuit breaker + metrics + runbook + integration tests (fa79b41), closes #3 #2 #3 #4 #5
  • stream: Sprint 1 Phase 5 patch round 2 — close MEDIUM-RP5R-01 (6ce215f), closes #1 #1b #4
  • sync: cap initial review sync to TRIAL_CAP_PER_LOCATION (30) (e2f3f10)
  • sync: move stamp_approved out of per-review loop to PubSub path (38738e2)
  • sync: store real provider review count for limit_reached card (ce1a159)
  • t9: use --rebase merge method + handle 'updated' PRs (15ef6c6)
  • task-1.6: apply ACTIVE filter consistently across all single-source bridges (2a08d25)
  • task-1.6: drop stale connector_type assertion + add ACTIVE filter to single-source bridges (ada8bf2)
  • test-compose: drop explicit volume names; rely on project-prefix isolation (33525ea)
  • test-infra: set GBP_REDIRECT_URI + expand mock-gbp allowlist for test stack (#142) (3bb0025), closes #138 132/#138
  • test-infra: set MOCK_GBP_BROWSER_URL for client-api-test (#138) (a03baf2)
  • test-infra: wire ANTHROPIC_API_KEY pass-through to test stack (#144) (a1ef8a3), closes #1 #138 #142 #68
  • test: add type:ignore for asyncpg in integration conftest probe (c5705a7)
  • test: drain orphan fire-and-forget tasks before engine.dispose() (62feb5b), closes api#164 api#164 #3 #6 #2
  • test: repair notification.new golden frame stale since Phase 3 (860935e)
  • tests: add stamp_approved_threads to connectors public API test (5a9bc47)
  • tests: align google_location_model assertion with bare-id contract (6653dcd)
  • tests: guard async db fixture against GeneratorExit teardown race (#153) (f572574)
  • tests: integration test fixes for approved_for_processing refactor (4193974)
  • test: skip pubsub_bootstrap cleanly when emulator absent (f8b3afe), closes #35
  • tests: update fixtures + smoke scripts for slim WorkspaceConnector (ddb6d6c)
  • test: update review persistence test for new snapshot kwargs (6e5774c)
  • test: wire STRIPE_SECRET_KEY into admin-api-test container (#78) (89b8f57)
  • test: wire STRIPE_TEST_WEBHOOK_SECRET into client+admin api containers (#84) (8e9cd1c)
  • threads: activity route service-injection seam + structured 400 errors (6fb71eb)
  • threads: add reviewer_avatar_url to client list schema (04d3486)
  • threads: B-18.6 retire scheduled_publish_held; relocate SLA snapshot to commit-for-delivery (0f99091)
  • threads: drop escalated from activity-feed BE surface (4b6ef4f)
  • threads: drop escalation_reason column + dead read sites (9387f27)
  • threads: drop SLA workspace cascade; gate pause on workspace toggle (73889fa)
  • threads: include FAILED-trigger events in escalated_at source (b32375a)
  • threads: JOIN through LocationSource for the new multi-source schema (#143) (4e9af5c), closes #135 #141
  • threads: replace where(Class.attr==x) with filter_by(attr=x) (#141) (203e3e2)
  • threads: wire reviewer_avatar_url through client list route (f07f77c)
  • typecheck: drop unused type-ignore comments (c32822e)
  • typecheck: restore load-bearing type-ignore comments (540b65c)
  • typecheck: unblock CI on feat/working-hours-redesign (a2da8b4)
  • types: B-16.4-S6 type-checker debt exposed by shim removal (6064a55)
  • visibility: stamp client_visible_at in already-replied close path (aab98af)
  • worker: initialize Firebase in platform-review-consumer startup (fa0b97e)
  • worker: process images before commit so thread lands atomically (cb3bec0)
  • workers: distinguish handler_error from malformed in metrics (508769b)
  • workers: platform-review-consumer registers EventRouter handlers at startup (a4e9676)
  • workspaces: drop working_hours from list-view Custom badge predicate (80139eb)
  • workspaces: drop working-hours fields from workspace general API; add SLA toggles (72f55e8)
  • workspaces: location general API uses per-day working_hours; override semantic shifts (3e23c11)
  • workspaces: reject explicit-null PATCH on non-nullable SLA toggles (408b516)
  • workspaces: tighten reset_to_imported handler — explicit 422s + rename + race note (3bd2ddd)

Performance

  • automation: cache SQLAlchemy engine at module level in worker (cb1c417)
  • images: decouple image pipeline from sync + fix field names (#122) (11edd68)

Refactors

  • api: co-locate EventTypeRegistry under apis/client/_platform_schemas (R15) (c0f7729)
  • apis: B-16.4-S4 mypy --strict apis/ ratchet (24c965c)
  • audit: B-16.4-S1a — delete billing shim (callerless) (88e3e79), closes #7
  • audit: B-16.4-S1b — delete realtime shim (callerless) (c5fa5a2)
  • audit: B-16.4-S1c — delete review_processor shim (callerless) (e1df4f9)
  • audit: B-16.4-S1d — delete insights shim + canonicalise doc references (fb66830)
  • audit: B-16.4-S1e — delete communication shim + fix automation_defaults paths (147498a)
  • audit: B-16.4-S1f — delete dead compliance/ tree (66e2edf)
  • audit: B-16.4-S1g — promote threads callers + delete shim (1eabca0)
  • audit: B-16.4-S1h — delete connectors shim (189b835)
  • audit: B-16.4-S1i — promote automation callers + delete shim (f189cd5)
  • audit: B-16.4-S1j — promote workspaces callers + delete shim (4cb1baf)
  • audit: B-16.4-S1k — promote general callers + delete shim (3bf8e4a)
  • audit: B-16.4-S1l — promote auth callers + delete shim (4c8f1b4)
  • audit: B-16.4-S1m — promote reviews callers + delete shim (1665988)
  • audit: B-16.4-S1n — promote otp callers + delete shim (fa0ec75)
  • audit: B-16.4-S1o — promote llm callers + delete shim (3f9e235)
  • audit: B-16.4-S1p — promote ledger callers + delete shim (53df9af)
  • audit: B-16.4-S2a — relocate text_assist to modules/communication/ (a78c339)
  • audit: B-16.4-S2b — relocate confidence to modules/automation/ (9f7e99f)
  • audit: B-16.4-S2c relocate setup to modules workspaces (cea0c94)
  • audit: B-16.4-S2d relocate translation to modules communication (cedc446)
  • audit: B-16.4-S2e relocate variation to modules automation (14658ae)
  • audit: B-16.4-S2f relocate menus to modules communication (cd9a385)
  • audit: B-16.4-S2g relocate menu_ingestion to modules communication (b1858d8)
  • audit: B-16.4-S2h relocate admin_support split (797c473)
  • audit: B-16.4-S2i relocate taxonomy to modules communication (ed86247)
  • audit: B-16.4-S2j relocate response_features to modules automation (7c308c5)
  • audit: B-16.4-S2k retire accounts shim and services namespace (537e6eb)
  • automation: replace entitlement/admission gate with approved_for_processing flag (797a7cd)
  • automation: use resolve_timezone() in working-hours gate (efc35a0)
  • billing,enums: split oversized modules per R13 file-size cap (2146f85)
  • billing/tests: split conftest into per-flow fixture modules (R13) (9cce188)
  • billing: customer.updated uses CustomerService for entity mirror (ab866ac)
  • billing: drop CheckoutService.create_session_for_location (per-location-only path) (2b5d220)
  • billing: drop isawaitable defensive branch; fix test mock (a38bf4a)
  • billing: drop sub-level metadata.location_id fallback (f4dce57)
  • billing: fail-loud on missing FLAT metadata + fix METERED fixture (def8758)
  • billing: in-place price swap + per-item metadata invariant (7ec2fb3)
  • billing: rename BillingSplitOff -> BillingLocationTransition (e2b6bc0)
  • billing: route attach METERED through ensure_metered_item_for_tier (c335ded)
  • billing: T5 follow-on — reduce ensure_metered_item_for_tier cognitive complexity (a78cbb9)
  • billing: unify webhook handling — every sub is bulk-shaped (575ff35)
  • communication: MultiLocationAnalyzer reads UnifiedReview, not GBPReview (64ab8fb)
  • communication: VoiceProfileGenerator reads UnifiedReview, not GBPReview (1933073)
  • connectors: collapse review_service thin delegators to keep R13 cap (d02a404)
  • connectors: drop OAuth+google columns from WorkspaceConnector (8dd56e2)
  • connectors: extract _handle_external_reply to its own module (2542372)
  • connectors: OAuth flow writes new connector tables (04e4165)
  • connectors: promote RefreshRevokedError to public API (06980f6)
  • connectors: rename WorkspaceLocation -> Location, drop google_* columns (a29c2bf)
  • connectors: review_service + gbp_data_service read GoogleLocation (49c780f)
  • connectors: tidy working_hours_mapper after code review (e8d401c)
  • connectors: TokenResolver always returns plaintext, encrypts at assignment (fb92836)
  • core: split enums.py into a package (4d5f935)
  • db: tidy Workspace docstring after Task 4 schema shift (2408765)
  • docker: multi-stage build + fixed-uid system user (bf81ce4)
  • enums: move LedgerEntryType to canonical infra owner (R22) (0a126d1)
  • gbp: per-call provider + per-connector dispatch (7de52ef)
  • gbp: token operations go through TokenResolver (3aa0df2)
  • hoist _sign_payload to infra/integrations/stripe/_signing (bd3c491)
  • identity: delete dead UserService.create_user (R7) (421762c)
  • identity: extract deterministic OTP helpers to public R9-compliant module (76220b4)
  • identity: sync_account delegates avatar import to UserService (374460e)
  • insights: extract _hydrate_card_split shared by both card loaders (d95db05)
  • insights: extract _resolve_custom_range shared by both handlers (04ac5b8)
  • insights: trim docstrings + drop scaffolding imports (79ddf2f)
  • remove unused SLA fields + rename section to Response time targets (#172) (446e20c)
  • reviews: route all reply_text writes through apply_reply_to_review chokepoint (ea51279)
  • route subscription unlock + reclaimer Phase B + counts via approved_for_processing (bd6ed82)
  • split files exceeding 650-line cap into use-case packages (ba34dae)
  • stage-6c: connectors → FrontendPaths SSOT (b139abe)
  • stage-6c: identity → FrontendPaths SSOT (25aa65a)
  • stage-6c: workspaces invitations → FrontendPaths SSOT (a3bb1aa)
  • sync: run details + enrichment inline during finalize (d9bef93)
  • threads: align dashboard-stats validation with ValidationException error envelope (a7e8d5b)
  • threads: move TimeRange/BucketSize enums to types.py + ValueError on CUSTOM (97d56c0)
  • threads: tighten Task 2 — fix stale docstring, test name/assertion alignment, prune dead branch (65b1bf6)
  • threads: tighten Task 2 review issues — drop paranoid guards, inline trivial helper, real-SQL test pins (7046f56)
  • threads: use tags={'path': ...} for SLA toggle metric; add spec= parity (984f630)

[API] v1.0.0-dev.63

Bug Fixes

  • arch: B-0a — repoint client-api pytest config bind mount to pyproject.toml (6cc7aa4)
  • insights: per-branch CTE alias in _load_top_review_cards SQL (c00d53e)
  • insights: R27 + Ticket-5 cursor orphan repair (ADR-0004) (aedfab5)

Features

[API] v1.0.0-dev.22

Bug Fixes

  • Add job deduplication and cleanup unused code (179f63f)
  • add SSE pool cleanup to app shutdown lifecycle (0f30105)
  • admin: Inherit voice style from parent for location profiles (901da88)
  • admin: Inheriting locations always use parent style_suggested (f9a3895)
  • admin: Use parent's EFFECTIVE style for inheritance (b7cf28a)
  • Agent tools now use proper get_effective_voice method (e73b587)
  • cascade: Update workspace profile first, then only locations with overrides (d533b95)
  • Code review fixes for Phase 2 (0110238)
  • Commit agent runs to database after completion (c3df991)
  • Complete setup now accepts automation from workspace OR location level (6d9f1c8)
  • complete_workspace_setup now supports per-location mode (350870d)
  • CONSERVATIVE mode now always requires approval (ed25d1d)
  • Correct import order for ReviewThread model (399d0ab)
  • correct import path for get_db in detail.py (6b76aa9)
  • Correct query in _enqueue_pending_threads (a0aeab5)
  • create workspace VoiceProfile when saving voice style defaults (2b26482)
  • critical bug - use automation_config column (not automation) (9437cb4)
  • Critical bug in WorkspaceModeService for voice profile routes (c05236f)
  • Critical bugs found during code review (debcff0)
  • Critical code review fixes (81d9c60)
  • critical security and architecture issues found in deep review (69d5838)
  • Deep review fixes for ReviewProcessor refactoring (edef7a7)
  • Enqueue pending threads after voice profile generation completes (5736780)
  • Export ActorType from audit service + mark old plans as superseded (20733c3)
  • Guard against race condition - skip automation if voice profile not ready (fed74fd)
  • make /approve endpoint actually publish the reply (6bf0ce7)
  • Map OpenAI model names to Anthropic equivalents in provider (05fdf82)
  • mock-gbp: Add latlng coordinates to all mock fixtures (d403260)
  • mock-gbp: Add real Google Maps link for McDonald's Mall of Switzerland (76424e0)
  • per-location mode - check location automation for completion (48188e8)
  • Performance improvements and workspace_id filter bug fix (5cd88e9)
  • Phase A review - Add actor tags and run relationship (2ce1dc7)
  • Phase B review - Route failure events through _log_event (7aed22b)
  • playground: Fix AttributeError - VoiceProfile has no location_name (a90cc60)
  • playground: Increase max_tokens - 8192 for generation, 4096 for quick actions (c93c0a9)
  • playground: Strip markdown code fences from LLM response, increase max_tokens (2d88fa3)
  • Preserve NEEDS_REVIEW status during generation completion (bd17b4e)
  • remove unused import, add proper return types (b5f9520)
  • Rename PlaygroundResult to GenerationResult across all imports (ac6c6a8)
  • Return early in reconsider_workspace for non-unified mode (8ce64f3)
  • review: SSE auth and listener cleanup issues (a7bdd63)
  • SAFE mode includes 3-star reviews in approval bucket (1458393)
  • Update AutomationDecisionService for CONSERVATIVE mode (122a849)
  • update review.reply_text when publishing to GBP (7782c8e)
  • Use @property decorators for SubmitResponsesTool (b602877)
  • Use avatar_url in logo upload response for frontend compatibility (777db50)
  • use correct auth pattern (get_current_user from request) (7299af1)
  • Use correct column name workspace_location_id in LocationSettings query (eaed8c4)
  • Use correct EffectiveStyleTraits field names in voice_profile tool (a7a995c)
  • use correct field name for location (name, not location_name) (f59d0d8)
  • Use correct SettingsService method for automation config (4a3cacc)
  • use driver_connection to get raw asyncpg connection (ef39783)
  • use limit(1) for voice profile existence checks (7d8be02)
  • use LocationStatus enum instead of string in settings query (9582dfd)
  • Use os.environ for ANTHROPIC_API_KEY (4c2a131)
  • voice-profile: Fix Phase 2 code review issues (659cf24)
  • wizard back navigation and per-location mode validation (34c9cad)

Features

  • add any_location_inherits_brand to settings response (6552f0d)
  • add brand_defaults_source to track how workspace brand defaults were configured (e0ea8ca)
  • add GET /threads/{thread_id} client endpoint for thread detail (7c7bd83)
  • Add infrastructure improvements - retry, metrics, batch queries (ad1d774)
  • add mode and is_standalone fields for per-location settings (2c93f09)
  • add real-time thread updates via SSE + PostgreSQL NOTIFY (7df7ac8)
  • Add reviews endpoint for agent playground (b68cf67)
  • Add submit_responses tool for structured variation submission (a93e8ea)
  • Add workspace logo upload/delete endpoints (6020943)
  • admin: Add business_summary to BrandIdentity and Voice Profile analysis (793e580)
  • admin: add GET /reviews/by-thread/{thread_id} endpoint (2e0cbcd)
  • admin: Add google_place_id to location details (d9747fe)
  • admin: Add location details endpoint and location_brief field (ab6ee80)
  • admin: add workspace locations endpoint (0bae2e1)
  • admin: Return inherited prompts for location profiles (d1e8faf)
  • admin: Return inherited rules for location profiles (c8a138a)
  • Complete automation infrastructure and wiring (45b19ee)
  • golden standard SSE service with connection pooling (c4d46af)
  • Implement Automation Service (5299971)
  • Include run parameters in run_started event (fecd617)
  • invitations: Include workspace_logo in pending invitations response (6441d0f)
  • LLM selects primary variation as best fit (7ae4065)
  • Major cleanup - Voice Profile system, Review Generator, dead code removal (06cf205)
  • per-field null support for automation overrides (be6120b)
  • Phase 1 - Agent architecture persistence layer (17d74bd)
  • Phase 2 - Agent core with tool calling (388413b)
  • Phase 3 - Streaming layer with SSE (6ca0d62)
  • Phase A - Schema evolution for Unified Thread Architecture (c35e984)
  • Phase B - Write path for Unified Thread Architecture (adfb4c8)
  • Phase C - Backend read path for Unified Thread Architecture (79aa1b2)
  • Phase D - Cleanup Unified Thread Architecture (6a3d14c)
  • phase1: Add ReviewThread database foundation (e6ef9be)
  • phase2: Add ReviewThread service layer (c1994b4)
  • phase3: Link ReviewProcessor runs to threads (5bbdc08)
  • phase4: Add AutomationDecisionService (e66beb2)
  • phase5: Add reviews API routes (1f59b3d)
  • playground: Add debug info to generation response (f6769a6)
  • playground: Implement Phase 1 - Playground infrastructure (622c750)
  • playground: Phase 2 - Quick actions, tools, async lock (d9a39dd)
  • project-clarity: Phase 1 - Detection & Foundation (a89ea7f)
  • project-clarity: Phase 2 - Prevention Guards (fcdda95)
  • project-clarity: Phase 3 - Backend mode detection in settings API (24ee0ff)
  • project-clarity: Phase 4 - Add needs_setup field to location Brand DNA (bb7b2ed)
  • project-clarity: Phase 5 - Documentation & Fix Script (9f87654)
  • restaurant-only business types + multi-location pipeline + LLM optimization (065d7be)
  • review-generator: Unified flow with variation_count and debug output (5a0a529)
  • sse: workspace-scoped threads stream with unified SSE architecture (5835e77)
  • unify threads service architecture (d173a0a)
  • voice-profile: Phase 1 - Foundation for unified architecture (a82fdb0)
  • voice-profile: Phase 2 - Unified architecture implementation (fcb2936)

[API] v0.1.0

Bug Fixes

  • ci: add debug logging for Firebase deploy project (854ed26)
  • ci: hardcode Infisical identity ID (5903c39)
  • ci: use Machine Identity for Infisical auth (cfc9f5b)
  • ci: use OIDC auth for Infisical (26674e1)
  • functions: add config documentation comment (9f873b5)
  • functions: add provider logging for debugging (b0ddb39)
  • functions: downgrade to Node.js 22 for Gen1 compatibility (b536067)
  • functions: improve onDelete logging structure (6c1b0af)
  • functions: improve onDelete logging with null safety (fc528ed)
  • functions: pass raw provider ID directly to backend (75a952d)
  • functions: remove debug console.log and cleanup workflow (15ea259)
  • functions: trigger deploy with updated IAM permissions (5d36962)
  • replace print statements with proper logging in LoggingService (c7802ab)

Features

  • ci: migrate from GitHub Secrets to Infisical for secret management (1ee3253)
  • helm: migrate to Infisical for secret management (9af6317)
  • helm: migrate to Infisical for secret management (e1d7b45)

[API] v1.0.0

Bug Fixes

  • Add 127.0.0.1:3000 to CORS origins for local development (8175741)
  • change domain from .io to .ch (8d2aafa)
  • convert LoggingService to async patterns (679191a)
  • fail if firebase-service-account.json missing, no dummy files (9149a03)
  • made pretty (ee5266e)
  • prevent Docker from creating firebase-service-account.json as directory (e34583e)
  • refactor admin_check.py to use async patterns (c9f9f2e)
  • rename image to threadwork-api (without s) (9412f84)
  • resolve import and UUID type issues (67080e9)
  • small .example.env update (7e4b477)
  • updated star rating and reply rate (85f543d)
  • Use OpenAI client directly in ReviewAnalyticsService (e02f6b2)
  • Use OpenAI function calling for structured analytics output (bf10896)
  • use string for boolean server_default in migrations (901c7ff)
  • use ylabs-action-runner for CI workflows (893184d)
  • Wizard completion and playbook retrieval bugs (76522c7)

Features

  • Add AI-powered review analytics system (f51f1b5)
  • add CI/CD workflows and SOPS encrypted secrets (06ad2f0)
  • Add comprehensive infrastructure monitoring system (3217817)
  • add import of existing replies and disable response generation (7e6dc80)
  • Add load test playbook endpoint for development (330627a)
  • Add Review Reply Composer service with GPT-5 (3765d64)
  • Add Review Reply Service with GPT-5 composer and dev CRUD endpoints (82c72e4)
  • Add Review Reply Service with GPT-5 composer and dev endpoints (d3f8b8b)
  • added celery background task (81188ab)
  • added connector (22f79b0)
  • added location routes (not connected to gbp) (1f1843d)
  • architectual restructuring of provider / connector integration (326a762)
  • Auto-generate wizard first question on place import (0b68172)
  • base setup fastapi and docs (3d38a07)
  • celery background task does only wirte original text of review to database. Also updated migration files (77848f8)
  • fix small issues (b237a0f)
  • helm: add existingSecret support for postgres credentials (2443c3d)
  • Implement comprehensive business data sync from Google Business Profile API (d96cbed)
  • implement flexible places management with selective activation (acba901)
  • Implement GPT-5 wizard with enriched interactions (ask_question, ask_confirm, ask_select) and playbook CRUD endpoints (9adce96)
  • integrated wizard (dfb6fca)
  • partial sync request with full audit trail (2a2faec)
  • remove not needed entpoints for reviews (f0b6f16)
  • stageign (cc00eba)
  • switch minio to firebase storage and fix upload / update of picture (0cc1944)
  • update infrastructure services and database migrations (7a94c40)
  • updated docker compose (8b4d0ec)
  • use external firebase service accounts from /Users/store/threadwork-api/ (34bb0b0)

[Frontend] v1.0.0-dev.1

Bug Fixes

  • fix authguard / connector and add picures (d93c869)
  • fixed some small frontend errors (e85d24f)
  • location image placeholder updated (f6e6808)
  • Organization profile tab validation and fallback (5569f55)
  • resolve TypeScript linting errors in query hooks (b5e0008)
  • updated star rating and reply rate (96ea291)

Features

  • add CI/CD pipelines and Helm chart for frontend apps (e167b06)
  • add import of existing replies and disable response generation (34b017f)
  • Add Load Test Playbook button in Communication Guidelines (e534906)
  • Add place settings page and communication guidelines UI (f85aefd)
  • Add review analytics UI components (053696d)
  • Add system logs page with real-time monitoring (d9964bd)
  • added connectors (d315a0f)
  • added place fetch from backend (8228d8c)
  • implement command palette with search integration and accessibility improvements (3718214)
  • implement location selection and place management UI (a6c27a0)
  • initial commit (ec3ed3e)
  • initial commit (8429ba6)
  • integrated wizard (b70f12a)
  • small fix connector and organization profile (b2745e2)
  • switch minio to firebase storage and fix upload / update of picture (317e276)
  • Update review detail page to use real API data (cf3bd2b)
  • Update to use /playbook_wizard/* endpoints (069e4f0)
  • Update wizard to use GPT-5 V5 API with enriched interactions (ask_question, ask_confirm, ask_select) (5d33e1a)

[Frontend] v1.0.0

Bug Fixes

  • fix authguard / connector and add picures (d93c869)
  • fixed some small frontend errors (e85d24f)
  • location image placeholder updated (f6e6808)
  • Organization profile tab validation and fallback (5569f55)
  • resolve TypeScript linting errors in query hooks (b5e0008)
  • updated star rating and reply rate (96ea291)

Features

  • add CI/CD pipelines and Helm chart for frontend apps (e167b06)
  • add import of existing replies and disable response generation (34b017f)
  • Add Load Test Playbook button in Communication Guidelines (e534906)
  • Add place settings page and communication guidelines UI (f85aefd)
  • Add review analytics UI components (053696d)
  • Add system logs page with real-time monitoring (d9964bd)
  • added connectors (d315a0f)
  • added place fetch from backend (8228d8c)
  • implement command palette with search integration and accessibility improvements (3718214)
  • implement location selection and place management UI (a6c27a0)
  • initial commit (ec3ed3e)
  • initial commit (8429ba6)
  • integrated wizard (b70f12a)
  • small fix connector and organization profile (b2745e2)
  • switch minio to firebase storage and fix upload / update of picture (317e276)
  • Update review detail page to use real API data (cf3bd2b)
  • Update to use /playbook_wizard/* endpoints (069e4f0)
  • Update wizard to use GPT-5 V5 API with enriched interactions (ask_question, ask_confirm, ask_select) (5d33e1a)

[API] v1.0.0-dev.1

Bug Fixes

  • Add 127.0.0.1:3000 to CORS origins for local development (8175741)
  • made pretty (ee5266e)
  • resolve import and UUID type issues (67080e9)
  • small .example.env update (7e4b477)
  • updated star rating and reply rate (85f543d)
  • Use OpenAI client directly in ReviewAnalyticsService (e02f6b2)
  • Use OpenAI function calling for structured analytics output (bf10896)
  • use ylabs-action-runner for CI workflows (893184d)
  • Wizard completion and playbook retrieval bugs (76522c7)

Features

  • Add AI-powered review analytics system (f51f1b5)
  • add CI/CD workflows and SOPS encrypted secrets (06ad2f0)
  • Add comprehensive infrastructure monitoring system (3217817)
  • add import of existing replies and disable response generation (7e6dc80)
  • Add load test playbook endpoint for development (330627a)
  • Add Review Reply Composer service with GPT-5 (3765d64)
  • Add Review Reply Service with GPT-5 composer and dev CRUD endpoints (82c72e4)
  • Add Review Reply Service with GPT-5 composer and dev endpoints (d3f8b8b)
  • added celery background task (81188ab)
  • added connector (22f79b0)
  • added location routes (not connected to gbp) (1f1843d)
  • architectual restructuring of provider / connector integration (326a762)
  • Auto-generate wizard first question on place import (0b68172)
  • base setup fastapi and docs (3d38a07)
  • celery background task does only wirte original text of review to database. Also updated migration files (77848f8)
  • fix small issues (b237a0f)
  • Implement comprehensive business data sync from Google Business Profile API (d96cbed)
  • implement flexible places management with selective activation (acba901)
  • Implement GPT-5 wizard with enriched interactions (ask_question, ask_confirm, ask_select) and playbook CRUD endpoints (9adce96)
  • integrated wizard (dfb6fca)
  • partial sync request with full audit trail (2a2faec)
  • remove not needed entpoints for reviews (f0b6f16)
  • stageign (cc00eba)
  • switch minio to firebase storage and fix upload / update of picture (0cc1944)
  • update infrastructure services and database migrations (7a94c40)
  • updated docker compose (8b4d0ec)