Skip to content

Prepare for next version#43

Draft
numbata wants to merge 89 commits intomainfrom
prepare-for-next-version
Draft

Prepare for next version#43
numbata wants to merge 89 commits intomainfrom
prepare-for-next-version

Conversation

@numbata
Copy link
Owner

@numbata numbata commented Mar 5, 2026

No description provided.

numbata and others added 30 commits March 5, 2026 00:23
- Configuration holds index_prefix, batch_size, auto_indexing,
  async_indexing, and index_job_class settings with sensible defaults
- Registry is a thread-safe Singleton for tracking model-to-index
  mappings with register, find_by_class, find_by_table, all, and reset!
- Add rails-specific spec_helper that loads without ActiveRecord
- Full spec coverage for both classes (20 examples, 0 failures)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement the core index definition classes for Manticore::Rails:
- Index: holds fields, attributes, properties, and associations for a model
- Field: represents a full-text search field with SQL, association, and method detection
- Attribute: extends Field with type mapping (integer->bigint, datetime->timestamp, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create lib/manticore/rails.rb with configuration, registry, and
  auto_indexing helpers plus dedicated Zeitwerk loader
- Create lib/manticore/rails/railtie.rb to load rake tasks in Rails
- Update lib/manticore/client.rb to ignore rails files from main loader

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AssociationProxy captures method_missing chains (tags.name → "tags.name")
  and method calls with args (transcript(:approved_text) → "transcript(approved_text)")
- IndexBuilder provides indexes, has, reindex_on_change, set_property DSL
  methods evaluated via instance_eval, building Index objects with Fields
  and Attributes
- Handles all legacy patterns: bare symbols, association proxies, SQL
  strings, and method calls with arguments
- 15 specs covering all DSL patterns including full Episode-style block

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Schema: generates CREATE/DROP TABLE DDL for ManticoreSearch, executes via UtilsApi
- Indexer: serializes AR records to documents, bulk upsert via IndexApi.bulk NDJSON
- Searcher/Result: lazy-loading search with pagination, filter translation, ordering
- Searchable: ActiveRecord concern with define_manticore_index DSL and callbacks
- Rake tasks: manticore:schema:{create,drop,rebuild} and manticore:index:rebuild
- Fix Field#sql? to detect CAST, IF, CONVERT and other SQL function patterns
- All 141 specs passing
- Define Manticore module before Zeitwerk loader references it
- Parse version from file in gemspec instead of requiring version.rb,
  avoiding Manticore module definition at gem specification time
- WebMock detects `defined?(Manticore)` and tries to load its JRuby
  Manticore HTTP client adapter, which fails with our gem
…core-rails/

- Rename ManticoreSearch -> ManticoreClient across all files to avoid
  namespace collision with JRuby's Manticore HTTP client gem
- Move Rails DSL layer from lib/manticore/rails/ to lib/manticore-rails/
  for cleaner separation (require "manticore-rails")
- Fix Zeitwerk loader push_dir namespace references
- Add manticore:setup task (drop + create + populate all indexes)
- Indexer#reindex_all now includes associations to avoid N+1
- Indexer#reindex_all yields progress count for reporting
- Rake tasks eager-load models so registry is populated
- Fix railtie rake task path after lib/manticore-rails/ move
- Auto-require railtie when Rails is present
Rename ManticoreClient::Rails namespace to top-level ManticoreRails and
add manticore-rails.gemspec alongside manticore-client.gemspec. Two gems,
one repo — the Rails layer depends on manticore-client ~> 1.0.

Adds version.rb, standalone README-rails.md, and fixes indentation
issues introduced during the namespace rename.
Replace N individual API calls with one bulk request, matching
the pattern already used by bulk_replace.
The manticore:schema:create and manticore:schema:drop tasks called
each_index which was never defined, causing NoMethodError at runtime.
Accepts both string and class for index_job_class config, using
ActiveSupport's constantize instead of the unrestricted Object.const_get.
Previously mutated shared Configuration state which affected all threads
in multi-threaded servers like Puma. Now uses thread-local flag so only
the current thread is affected.
Move ManticoreRails::Result to ManticoreRails::Searcher::Result for
clearer ownership. Result is the search subsystem's concern and should
not be a top-level class in the ManticoreRails namespace.
association_name, column_name, and association_path all called
column.to_s.split('.') independently. Extract to a single memoized
private method.
Property values containing single quotes would produce broken SQL.
Use SQL-standard escaping (double single quotes) for safety.
Avoid creating a new IndexApi object on every bulk_replace and
delete_records call. The client is stateless and safe to reuse.
Results from ManticoreSearch are ranked by relevance, but
WHERE IN (...) does not preserve that order. Use index_by
and filter_map to reorder loaded records to match the
original search ranking. Missing records are silently skipped.
Prevent infinite recursion when circular associations are
encountered during field value extraction. Raises an error
if association depth exceeds 10 levels.
Property keys are now validated against /\A[a-z_][a-z0-9_]*\z/i
to ensure only safe identifiers are used in CREATE TABLE DDL.
Values were already escaped; this closes the key injection vector.
Use Mutex to synchronize lazy initialization of @@default class
variables in both ApiClient and Configuration, preventing race
conditions when multiple threads access them concurrently.
…piError

Only set known attributes (code, response_headers, response_body)
instead of blindly setting any key from the options hash as an
instance variable.
batch_size must be positive. index_prefix only accepts
alphanumeric characters and underscores to prevent injection
in table names.
Maintain a secondary @by_table hash index alongside @indexes
to avoid linear scan when looking up indexes by table name.
Replace case/when with a ternary since all non-Symbol branches
produce the same result.
Add on_error callback to Configuration that defaults to warn.
Users can now customize error handling for indexing failures
(e.g. report to error tracking services, raise in test).
Passing nil filters through as-is instead of silently converting
to 0, which would incorrectly match records with value 0.
When wrapping the base query with filters in a bool.must clause,
only pass the relevant query field to QueryFilter to avoid
ambiguous query semantics.
Use MANTICORESEARCH_URI consistently across all workflows.
The release workflow was using MANTICORE_URL which the test
suite does not recognize.
numbata and others added 30 commits March 7, 2026 16:18
Report failed batches via on_error callback and continue reindexing
remaining batches instead of aborting the entire operation.
Emit search.manticore_rails, bulk.manticore_rails, and
delete.manticore_rails events for monitoring search latency
and indexing throughput in production.
Creates a config/initializers/manticore.rb template with all
configuration options and sensible defaults.
When a subclass doesn't have its own index, find_by_class now
checks ancestor classes, enabling STI models to inherit the
parent's search index.
…tation

Cache the constantized job class in Configuration to avoid repeated
string-to-class resolution on every after_commit callback. Add a note
about zero-downtime reindex limitations in the README.
Check circuit_open? in manticore_should_index? to skip indexing when
ManticoreSearch is unresponsive. Call record_success!/record_failure!
after each index/remove operation to track consecutive failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Report via on_error when some requested IDs are not found in the
database, helping diagnose stale callbacks or race conditions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent accidental mutation of Index objects once they are registered
in the Registry. Adding fields, attributes, associations, or properties
after registration raises FrozenError.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support must_not filters via without: option, mirroring the existing
with: inclusion filters. Can be combined for complex queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Setting on_error to :raise converts it to a lambda that re-raises
the original error, making indexing failures visible in development
and test environments instead of silently logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update README with instrumentation events table, circuit breaker
section, without: exclusion filter example, and :raise mode for
on_error. Update CHANGELOG with all new features.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protect @failure_count with @circuit_mutex to prevent races in
multi-threaded servers like Puma. Initialize both at module level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allows tests to restore all configuration defaults with a single call
instead of manually resetting individual attributes in ensure blocks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert doubles for BulkResponse, SearchResponse, SearchResponseHits,
and HitsHits to instance_double to catch API contract drift. Use real
Index objects in registry specs. Re-enable RSpec/VerifiedDoubles for
specs that don't mock ActiveRecord internals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memoize referenced_associations on Index since the object is frozen
after registration. Remove Attribute#sortable? which was defined but
never called anywhere in the codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover the SQL error raise path in Schema.execute and add a test
for single-quote escaping in property values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add commented circuit_breaker_threshold option and enable on_error
:raise mode for local development environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Provides a clear intent method name for manually resetting the circuit
breaker, e.g. after ManticoreSearch recovers from an outage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix generator template: use Rails.env.production? instead of
  Rails.env.local? which requires Rails 7.1+
- Remove unused Field#method_call? method
- Remove exposed attr_readers from IndexBuilder (internal only)
- Complete CHANGELOG with all features added in 0.1.0
- Document rails generator in Installation section
- Document reset_circuit! in Circuit breaker section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The mva/multi type was defined in MANTICORE_TYPE_MAP but no user-facing
type in Attribute::TYPE_MAP maps to :mva, making it unreachable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…SQL responses

- Move record_success! inside sync block so async enqueue does not
  falsely reset the circuit breaker
- Handle beginless/endless Ruby ranges in search filters instead of
  sending nil bounds to ManticoreSearch
- Guard Schema.execute against empty/nil API responses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ering

Reset circuit breaker in before/after hooks to prevent failure count
pollution across test groups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When using manticore_serialize, associations accessed in custom
serialization aren't auto-detected by referenced_associations.
The new includes directive lets models declare extra associations
to eager-load during batch reindex, eliminating N+1 queries.

    define_manticore_index do
      indexes :name
      includes :transcripts, anchors: :dvags
    end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant