Skip to content

fix: select the MySQL adapter for Trilogy - #28

Merged
cardmagic merged 1 commit into
mainfrom
agent/trilogy-adapter
Aug 10, 2026
Merged

fix: select the MySQL adapter for Trilogy#28
cardmagic merged 1 commit into
mainfrom
agent/trilogy-adapter

Conversation

@cardmagic

Copy link
Copy Markdown
Owner

Fixes the reported UnsupportedDatabase on Trilogy, and the two further defects that running the suite against real Trilogy exposed. Version bumped to 0.10.1.

The reported bug

DatabaseAdapter.for matched the client name, not the protocol:

when /postgres/i  when /mysql/i  when /sqlite/i  else raise UnsupportedDatabase

Trilogy reports "Trilogy", so every Solid Objects call raised UnsupportedDatabase: unsupported database adapter "Trilogy" on a database the gem fully supports.

Adapter names now resolve through one table of families:

FAMILIES = { postgresql: /postgres/i, mysql: /mysql|trilogy/i, sqlite: /sqlite/i }

DatabaseAdapter.family is used by adapter selection, owner-id casting, and wake-up selection alike, so a client cannot be accepted in one place and rejected in another.

That mattered immediately: owner-id casting was a second copy of the same match. Instance#owner_id_cast_type sent Trilogy down the else branch to CAST(x AS TEXT), which is not valid MySQL syntax. That was a latent SQL error, not just a wrong classification.

Two more defects, found by running against real Trilogy

Both are ours, not Trilogy's, and both are reachable on mysql2 too.

Collation mismatch in Instance.orphaned. The query casts owner primary keys and compares them against actor_id. A cast result carries the connection collation, not the column's, and MySQL refuses to compare two collations:

Trilogy::ProtocolError: 1267: Illegal mix of collations
(utf8mb4_0900_ai_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '='

Which collation the connection uses is a property of the client, measured here:

Client collation_connection collation_database
mysql2 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci
Trilogy utf8mb4_general_ci utf8mb4_0900_ai_ci

mysql2 happened to match, which is why this never surfaced. A mysql2 application that sets collation: in database.yml could already hit it — a common setting. The comparison is now pinned to the column's own collation, read from the schema and validated before interpolation.

Deadline interruption unrecognised. A synchronous deadline is enforced by asking the server to interrupt the statement; recognising that interruption is what turns it back into SyncEnqueueTimeout. The match walked the cause chain for mysql2's error_number == 3024. Trilogy exposes error_code, not error_number, so the deadline surfaced as a raw ActiveRecord::StatementTimeout:

[SolidObjects::SyncEnqueueTimeout] exception expected, not ActiveRecord::StatementTimeout

Active Record's own classification is now trusted first, and the raw code fallback reads both names.

Test coverage

New test/unit/deadline_error_test.rb covers both client shapes without needing either gem installed, so this is caught on the default SQLite run rather than only under a Trilogy job. New unit tests pin the family table, and a new test pins the cast collation on the MySQL family.

The skips were part of the problem. Adapter-specific tests skipped on adapter_name.match?(/mysql/i), so a Trilogy run silently skipped every MySQL test while reporting green. All 13 such predicates now key to database_family, and CI runs the MySQL suite against both clients — passing on one proves nothing about the other.

Validation

Run Result
bundle exec rake (SQLite) 378 runs, 1271 assertions, 0 failures, 14 skips
Trilogy (docker MySQL 8) 378 runs, 1234 assertions, 0 failures, 22 skips
mysql2 (docker MySQL 8) 378 runs, 1234 assertions, 0 failures, 22 skips
PostgreSQL 17.6 378 runs, 1251 assertions, 0 failures, 14 skips
Standard, RuboCop, RBS, Steep, Brakeman clean

Confirmed the MySQL-family tests genuinely execute under Trilogy rather than skip, and that reverting the pattern to /mysql/i reproduces UnsupportedDatabase: unsupported database adapter "Trilogy".

Trilogy is a development dependency only; it is not added to the gem's runtime requirements.

Adapter selection matched the client name, not the protocol. Trilogy
reports "Trilogy", so every call raised UnsupportedDatabase on a database
Solid Objects fully supports.

The match now resolves through one table of families used by adapter
selection, owner-id casting, and wake-up selection alike, so a client
cannot be accepted in one place and rejected in another. Owner-id casting
was the second place: Trilogy fell through to CAST(x AS TEXT), which is
not valid MySQL.

Running the suite against real Trilogy found two more, both ours rather
than Trilogy's.

Instance.orphaned compared a cast against a column, and a cast result
carries the connection collation rather than the column's. MySQL refuses
to compare two collations. mysql2 negotiates the database default and
Trilogy negotiates utf8mb4_general_ci, so the query raised Illegal mix of
collations. A mysql2 application setting collation: in database.yml could
already hit this. The comparison is pinned to the column's collation.

A synchronous deadline is enforced by asking the server to interrupt the
statement, and the interruption was matched only through mysql2's
error_number. Trilogy names it error_code, so a deadline surfaced as a
raw StatementTimeout instead of SyncEnqueueTimeout.

CI runs the MySQL suite against both clients, and adapter-specific skips
key to the family, so a Trilogy run no longer silently skips every MySQL
test.
@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds Trilogy as a supported MySQL client and centralizes database-family detection.

  • Uses database families consistently for adapter selection, wake-up selection, owner-ID casting, and adapter-specific tests.
  • Pins MySQL reconciliation casts to the actor_id column collation.
  • Recognizes MySQL deadline interruptions through Active Record classification and both client error-code APIs.
  • Adds Trilogy to development dependencies and runs MySQL CI against both mysql2 and Trilogy.
  • Updates documentation, generated signatures, tests, changelog, and the gem version to 0.10.1.

Confidence Score: 5/5

The PR appears safe to merge with no concrete blocking or independently actionable non-blocking issue identified.

The centralized family selection, Trilogy error handling, and MySQL collation behavior are applied consistently and covered by focused unit and integration tests.

Important Files Changed

Filename Overview
lib/solid_objects/database_adapter.rb Centralizes supported adapter names into PostgreSQL, MySQL, and SQLite families, including Trilogy in the MySQL family.
app/models/solid_objects/instance.rb Selects owner-ID cast types by database family and applies the MySQL actor-ID column collation to reconciliation casts.
lib/solid_objects/database_adapters/mysql.rb Recognizes deadline interruptions through Active Record timeout classes and mysql2 or Trilogy error-code accessors.
lib/solid_objects/wake_up_adapters.rb Selects PostgreSQL wake-up behavior through the centralized database-family resolver.
.github/workflows/ci.yml Expands the MySQL job into mysql2 and Trilogy matrix runs.
test/unit/deadline_error_test.rb Covers mysql2, Trilogy, Active Record timeout classes, unrelated errors, and inactive-deadline behavior.
test/models/instance_reconciliation_test.rb Covers MySQL collation emission and database-family-specific owner-ID cast types.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  C[Active Record connection] --> F[DatabaseAdapter.family]
  F -->|PostgreSQL| P[PostgreSQL adapter and wake-up]
  F -->|Mysql2 or Trilogy| M[MySQL adapter]
  F -->|SQLite| S[SQLite adapter]
  M --> O[CHAR owner-ID cast with actor_id collation]
  M --> D[Deadline interruption classification]
  D --> E[Sync timeout error]
Loading

Reviews (1): Last reviewed commit: "fix: select the MySQL adapter for Trilog..." | Re-trigger Greptile

@cardmagic
cardmagic merged commit efbe93a into main Aug 10, 2026
29 checks passed
@cardmagic
cardmagic deleted the agent/trilogy-adapter branch August 10, 2026 21:36
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