Compare commits

...

10 Commits

Author SHA1 Message Date
Donal McBreen 53131b61f0 Merge pull request #2891 from basecamp/dependabot/bundler/net-imap-0.6.4
CI (SaaS) / Test (OSS) (push) Has been cancelled
CI (SaaS) / Test (SaaS) (push) Has been cancelled
Build and publish container image to GHCR / Build and push image (amd64) (push) Has been cancelled
Build and publish container image to GHCR / Build and push image (arm64) (push) Has been cancelled
Build and publish container image to GHCR / Create multi-arch manifest and sign (push) Has been cancelled
Bump net-imap from 0.6.3 to 0.6.4
2026-05-15 11:33:02 +01:00
Matthew Kent 068b886802 Merge pull request #2897 from basecamp/add-maint-mode-note
Add our standard section on setting maintenance mode
2026-05-13 13:38:31 -07:00
Matthew Kent 661ee9c2ae Add our standard section on setting maintenance mode. 2026-05-13 13:34:27 -07:00
github-actions[bot] d5e366bcfc Sync Gemfile.saas.lock 2026-05-04 22:06:23 +00:00
dependabot[bot] ab78162f39 Bump net-imap from 0.6.3 to 0.6.4
Bumps [net-imap](https://github.com/ruby/net-imap) from 0.6.3 to 0.6.4.
- [Release notes](https://github.com/ruby/net-imap/releases)
- [Commits](https://github.com/ruby/net-imap/compare/v0.6.3...v0.6.4)

---
updated-dependencies:
- dependency-name: net-imap
  dependency-version: 0.6.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-04 22:06:12 +00:00
Mike Dalessio 5f45e54a07 dep: update nokogiri to v1.19.3 (#2887) 2026-04-27 18:07:26 -04:00
Mike Dalessio e6c5cd51a0 dep: update queenbee and audits1984 to avoid deprecation warnings (#2875) 2026-04-22 16:17:27 -04:00
dependabot[bot] f9daf091d7 Bump the github-actions group across 1 directory with 3 updates (#2856)
Bumps the github-actions group with 3 updates in the / directory: [ruby/setup-ruby](https://github.com/ruby/setup-ruby), [docker/login-action](https://github.com/docker/login-action) and [docker/build-push-action](https://github.com/docker/build-push-action).


Updates `ruby/setup-ruby` from 1.295.0 to 1.300.0
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](https://github.com/ruby/setup-ruby/compare/319994f95fa847cf3fb3cd3dbe89f6dcde9f178f...e65c17d16e57e481586a6a5a0282698790062f92)

Updates `docker/login-action` from 4.0.0 to 4.1.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/b45d80f862d83dbcd57f89517bcf500b2ab88fb2...4907a6ddec9925e35a0a9e82d7399ccc52663121)

Updates `docker/build-push-action` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/d08e5c354a6adb9ed34480a06d141179aa583294...bcafcacb16a39f128d818304e6c9c0c18556b85f)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.300.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/login-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: docker/build-push-action
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-18 17:04:01 -07:00
dependabot[bot] b5ea94e99f Bump selenium-webdriver from 4.41.0 to 4.43.0 in the development-dependencies group (#2855)
* Bump selenium-webdriver in the development-dependencies group

Bumps the development-dependencies group with 1 update: [selenium-webdriver](https://github.com/SeleniumHQ/selenium).


Updates `selenium-webdriver` from 4.41.0 to 4.43.0
- [Release notes](https://github.com/SeleniumHQ/selenium/releases)
- [Changelog](https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES)
- [Commits](https://github.com/SeleniumHQ/selenium/compare/selenium-4.41.0...selenium-4.43.0)

---
updated-dependencies:
- dependency-name: selenium-webdriver
  dependency-version: 4.43.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* Sync Gemfile.saas.lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-18 17:03:49 -07:00
Mike Dalessio 466b215ef8 Add SearchReindexJob to repopulate the search index (#2850)
Rebuilds search records for every published Card and every Comment on a
published Card. Intended for manual invocation after a search-index loss
event — not a recurring job.

Uses ActiveJob::Continuable so the work survives worker restarts and
resumes from the last-processed id. The job is idempotent.

Removes script/maintenance/reindex_stale_search_records.rb, which was
written against a different hypothesis (a date-cutoff backfill) and is
superseded by this unconditional repair job.
2026-04-16 19:40:02 -04:00
11 changed files with 189 additions and 71 deletions
+3 -3
View File
@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0 - uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1.300.0
with: with:
ruby-version: .ruby-version ruby-version: .ruby-version
bundler-cache: true bundler-cache: true
@@ -31,7 +31,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0 - uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1.300.0
with: with:
ruby-version: .ruby-version ruby-version: .ruby-version
bundler-cache: true bundler-cache: true
@@ -53,7 +53,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0 - uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1.300.0
with: with:
ruby-version: .ruby-version ruby-version: .ruby-version
bundler-cache: true bundler-cache: true
@@ -17,7 +17,7 @@ jobs:
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # zizmor: ignore[artipacked] -- credentials needed for git push - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # zizmor: ignore[artipacked] -- credentials needed for git push
- uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0 - uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1.300.0
with: with:
ruby-version: .ruby-version ruby-version: .ruby-version
+3 -3
View File
@@ -49,7 +49,7 @@ jobs:
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to GHCR - name: Log in to GHCR
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
@@ -84,7 +84,7 @@ jobs:
- name: Build and push (${{ matrix.platform }}) - name: Build and push (${{ matrix.platform }})
id: build id: build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with: with:
context: . context: .
file: Dockerfile file: Dockerfile
@@ -125,7 +125,7 @@ jobs:
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to GHCR - name: Log in to GHCR
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
+1 -1
View File
@@ -61,7 +61,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0 - uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1.300.0
with: with:
ruby-version: .ruby-version ruby-version: .ruby-version
bundler-cache: true bundler-cache: true
+10 -10
View File
@@ -291,7 +291,7 @@ GEM
msgpack (1.8.0) msgpack (1.8.0)
net-http-persistent (4.0.8) net-http-persistent (4.0.8)
connection_pool (>= 2.2.4, < 4) connection_pool (>= 2.2.4, < 4)
net-imap (0.6.3) net-imap (0.6.4)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@@ -306,21 +306,21 @@ GEM
net-protocol net-protocol
net-ssh (7.3.2) net-ssh (7.3.2)
nio4r (2.7.5) nio4r (2.7.5)
nokogiri (1.19.2-aarch64-linux-gnu) nokogiri (1.19.3-aarch64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-aarch64-linux-musl) nokogiri (1.19.3-aarch64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-arm-linux-gnu) nokogiri (1.19.3-arm-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-arm-linux-musl) nokogiri (1.19.3-arm-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-arm64-darwin) nokogiri (1.19.3-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-x86_64-darwin) nokogiri (1.19.3-x86_64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-x86_64-linux-gnu) nokogiri (1.19.3-x86_64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-x86_64-linux-musl) nokogiri (1.19.3-x86_64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
openssl (4.0.0) openssl (4.0.0)
ostruct (0.6.3) ostruct (0.6.3)
@@ -414,7 +414,7 @@ GEM
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rubyzip (3.2.2) rubyzip (3.2.2)
securerandom (0.4.1) securerandom (0.4.1)
selenium-webdriver (4.41.0) selenium-webdriver (4.43.0)
base64 (~> 0.2) base64 (~> 0.2)
logger (~> 1.4) logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
+1 -1
View File
@@ -8,7 +8,7 @@ gem "actionpack-xml_parser" # needed by queenbee for XML request body parsing
gem "queenbee", bc: "queenbee-plugin" gem "queenbee", bc: "queenbee-plugin"
gem "fizzy-saas", path: "saas" gem "fizzy-saas", path: "saas"
gem "console1984", bc: "console1984" gem "console1984", bc: "console1984"
gem "audits1984", bc: "audits1984", branch: "flavorjones/coworker-api" gem "audits1984", bc: "audits1984"
# Native push notifications (iOS/Android) # Native push notifications (iOS/Android)
gem "action_push_native" gem "action_push_native"
+12 -13
View File
@@ -1,7 +1,6 @@
GIT GIT
remote: https://github.com/basecamp/audits1984 remote: https://github.com/basecamp/audits1984
revision: 422b8ff25820c828b7cf09aff4923fd8cc2c6795 revision: 4271a8e1f02f0f35d749c938bf4dcccf902b4190
branch: flavorjones/coworker-api
specs: specs:
audits1984 (0.1.7) audits1984 (0.1.7)
console1984 console1984
@@ -23,7 +22,7 @@ GIT
GIT GIT
remote: https://github.com/basecamp/queenbee-plugin remote: https://github.com/basecamp/queenbee-plugin
revision: 14312a940471e20617b38cdec7c092a01567d18b revision: c0119be5940edb3739d4bb591c1a5c7064881638
specs: specs:
queenbee (3.2.0) queenbee (3.2.0)
activeresource activeresource
@@ -407,7 +406,7 @@ GEM
uri (>= 0.11.1) uri (>= 0.11.1)
net-http-persistent (4.0.8) net-http-persistent (4.0.8)
connection_pool (>= 2.2.4, < 4) connection_pool (>= 2.2.4, < 4)
net-imap (0.6.3) net-imap (0.6.4)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@@ -422,21 +421,21 @@ GEM
net-protocol net-protocol
net-ssh (7.3.2) net-ssh (7.3.2)
nio4r (2.7.5) nio4r (2.7.5)
nokogiri (1.19.2-aarch64-linux-gnu) nokogiri (1.19.3-aarch64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-aarch64-linux-musl) nokogiri (1.19.3-aarch64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-arm-linux-gnu) nokogiri (1.19.3-arm-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-arm-linux-musl) nokogiri (1.19.3-arm-linux-musl)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-arm64-darwin) nokogiri (1.19.3-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-x86_64-darwin) nokogiri (1.19.3-x86_64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-x86_64-linux-gnu) nokogiri (1.19.3-x86_64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.2-x86_64-linux-musl) nokogiri (1.19.3-x86_64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
openssl (4.0.0) openssl (4.0.0)
os (1.1.4) os (1.1.4)
@@ -571,7 +570,7 @@ GEM
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rubyzip (3.2.2) rubyzip (3.2.2)
securerandom (0.4.1) securerandom (0.4.1)
selenium-webdriver (4.41.0) selenium-webdriver (4.43.0)
base64 (~> 0.2) base64 (~> 0.2)
logger (~> 1.4) logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
+60
View File
@@ -0,0 +1,60 @@
# Repair task — reindexes every searchable Card and Comment in the database.
# Intended to be invoked manually after a search-index loss event. Not a recurring job.
#
# Idempotent: Searchable#reindex upserts by (searchable_type, searchable_id).
# Continuable: if the worker is interrupted, the job resumes from the last-processed id.
#
# `rich_text_limit` is a safety valve against unbounded bodies: records whose rich text
# exceeds the limit (in bytes) are filtered out at the SQL level, so they never materialize
# in Ruby. Without it, a single pathological body can stall the batch query or OOM the
# worker during preload, which has happened in practice.
#
# Usage:
# SearchReindexJob.perform_later
# SearchReindexJob.perform_later(batch_size: 500, log_every: 100, rich_text_limit: 50_000)
class SearchReindexJob < ApplicationJob
include ActiveJob::Continuable
queue_as :backend
def perform(batch_size: 100, log_every: 1000, rich_text_limit: 100_000)
step :cards do |step|
processed = 0
Card.published
.left_joins(:rich_text_description)
.where("action_text_rich_texts.body IS NULL OR OCTET_LENGTH(action_text_rich_texts.body) <= ?", rich_text_limit)
.includes(:rich_text_description)
.find_each(start: step.cursor, batch_size: batch_size) do |card|
safely_reindex(card)
processed += 1
log_progress(:cards, processed, card.id) if (processed % log_every).zero?
step.advance! from: card.id
end
end
step :comments do |step|
processed = 0
Comment.joins(:card).merge(Card.published)
.left_joins(:rich_text_body)
.where("action_text_rich_texts.body IS NULL OR OCTET_LENGTH(action_text_rich_texts.body) <= ?", rich_text_limit)
.includes(:rich_text_body, :card)
.find_each(start: step.cursor, batch_size: batch_size) do |comment|
safely_reindex(comment)
processed += 1
log_progress(:comments, processed, comment.id) if (processed % log_every).zero?
step.advance! from: comment.id
end
end
end
private
def safely_reindex(record)
record.reindex
rescue StandardError => e
Rails.error.report(e, context: { record_type: record.class.name, record_id: record.id })
end
def log_progress(step_name, count, cursor)
Rails.logger.info { "SearchReindexJob: step=#{step_name} processed=#{count} cursor=#{cursor}" }
end
end
+16
View File
@@ -89,6 +89,22 @@ Staging is primarily intended for testing infrastructure changes. It uses produc
- https://app.fizzy-staging.com/ - https://app.fizzy-staging.com/
## Maintenance mode
To take production offline for maintenance, run `kamal-proxy stop` on the load balancers via `knife ssh`:
```bash
knife ssh 'hostname:fizzy-lb-*' "sudo docker exec fizzy-load-balancer kamal-proxy stop fizzy --message='Sorry! Fizzy is undergoing some maintenance and will be back shortly.'"
```
Verify maintenance is enabled by visiting https://app.fizzy.do/.
To lift maintenance mode:
```bash
knife ssh 'hostname:fizzy-lb-*' 'sudo docker exec fizzy-load-balancer kamal-proxy resume fizzy'
```
## License ## License
fizzy-saas is released under the [O'Saasy License](LICENSE.md). fizzy-saas is released under the [O'Saasy License](LICENSE.md).
@@ -1,39 +0,0 @@
# Reindex cards and comments that may be missing from the search index.
#
# The data import path (Account::DataTransfer) uses insert_all! which bypasses
# ActiveRecord callbacks, so imported cards and comments never get search records
# created. This script reindexes cards and comments created before a cutoff date.
#
# Usage:
# bin/rails runner script/maintenance/reindex_stale_search_records.rb # default cutoff: 2025-11-13
# bin/rails runner script/maintenance/reindex_stale_search_records.rb 2026-01-01 # custom cutoff
cutoff = Date.parse(ARGV[0] || "2025-11-13")
puts "Reindexing cards and comments created before #{cutoff}..."
cards = Card.published.where("created_at < ?", cutoff).includes(:rich_text_description)
card_count = cards.count
puts "Found #{card_count} cards to reindex"
reindexed_cards = 0
cards.find_each do |card|
card.reindex
reindexed_cards += 1
print "\rCards: #{reindexed_cards}/#{card_count}" if reindexed_cards % 100 == 0
end
puts "\rCards: #{reindexed_cards}/#{card_count}"
comments = Comment.joins(:card).merge(Card.published).where("comments.created_at < ?", cutoff).includes(:rich_text_body, :card)
comment_count = comments.count
puts "Found #{comment_count} comments to reindex"
reindexed_comments = 0
comments.find_each do |comment|
comment.reindex
reindexed_comments += 1
print "\rComments: #{reindexed_comments}/#{comment_count}" if reindexed_comments % 100 == 0
end
puts "\rComments: #{reindexed_comments}/#{comment_count}"
puts "Done! Reindexed #{reindexed_cards} cards and #{reindexed_comments} comments."
+82
View File
@@ -0,0 +1,82 @@
require "test_helper"
class SearchReindexJobTest < ActiveJob::TestCase
test "reindexes cards and comments after their search records are nuked" do
card = cards(:logo)
comment = comments(:logo_1)
card.reindex
comment.reindex
card_shard = Search::Record.for(card.account_id)
comment_shard = Search::Record.for(comment.account_id)
assert card_shard.exists?(searchable_type: "Card", searchable_id: card.id)
assert comment_shard.exists?(searchable_type: "Comment", searchable_id: comment.id)
card_shard.delete_all
comment_shard.delete_all unless comment_shard == card_shard
assert_not card_shard.exists?(searchable_type: "Card", searchable_id: card.id)
assert_not comment_shard.exists?(searchable_type: "Comment", searchable_id: comment.id)
SearchReindexJob.perform_now
assert card_shard.exists?(searchable_type: "Card", searchable_id: card.id)
assert comment_shard.exists?(searchable_type: "Comment", searchable_id: comment.id)
end
test "skips records whose rich text exceeds rich_text_limit" do
Current.account = accounts(:"37s")
Current.session = Session.new(identity: identities(:david))
big_card = boards(:writebook).cards.create!(
creator: users(:david),
title: "too big to index",
status: :published,
description: "x" * 5_000
)
nuke_search_records
SearchReindexJob.perform_now(rich_text_limit: 1_000)
shard = Search::Record.for(big_card.account_id)
assert_not shard.exists?(searchable_type: "Card", searchable_id: big_card.id)
end
test "does not index drafted cards or their comments" do
Current.account = accounts(:"37s")
Current.session = Session.new(identity: identities(:david))
card = boards(:writebook).cards.create!(
creator: users(:david),
title: "will be drafted",
status: :published
)
comment = card.comments.create!(creator: users(:david), body: "on a card that will be drafted")
card.update!(status: :drafted)
nuke_search_records
SearchReindexJob.perform_now
shard = Search::Record.for(card.account_id)
assert_not shard.exists?(searchable_type: "Card", searchable_id: card.id)
assert_not shard.exists?(searchable_type: "Comment", searchable_id: comment.id)
end
private
def sqlite?
ActiveRecord::Base.connection.adapter_name == "SQLite"
end
def nuke_search_records
if sqlite?
ActiveRecord::Base.connection.execute("DELETE FROM search_records")
ActiveRecord::Base.connection.execute("DELETE FROM search_records_fts")
else
Search::Record::Trilogy::SHARD_CLASSES.each(&:delete_all)
end
end
end