ferrum-orm 0.1.17__tar.gz → 0.1.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/Cargo.lock +8 -8
  2. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/Cargo.toml +1 -1
  3. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/PKG-INFO +64 -10
  4. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/README.md +62 -8
  5. ferrum_orm-0.1.20/crates/ferrum-core/benches/hydrate.rs +384 -0
  6. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/ir/metadata.rs +6 -0
  7. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/ir/mod.rs +4 -0
  8. ferrum_orm-0.1.20/crates/ferrum-sql/benches/compile.rs +813 -0
  9. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/emit.rs +13 -5
  10. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/pyproject.toml +5 -11
  11. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/__init__.py +11 -3
  12. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/_native.pyi +66 -11
  13. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/app.py +69 -0
  14. ferrum_orm-0.1.20/python/ferrum/cli/check_schema_cmd.py +148 -0
  15. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/migrate_cmd.py +142 -51
  16. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/migrations_cmd.py +0 -1
  17. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/connection.py +465 -27
  18. ferrum_orm-0.1.20/python/ferrum/contrib/__init__.py +12 -0
  19. ferrum_orm-0.1.20/python/ferrum/contrib/fastapi.py +554 -0
  20. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/mysql.py +60 -18
  21. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/postgres.py +250 -26
  22. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/protocol.py +52 -0
  23. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/sqlite.py +65 -12
  24. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/echo.py +2 -2
  25. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/errors.py +391 -27
  26. ferrum_orm-0.1.20/python/ferrum/expressions.py +176 -0
  27. ferrum_orm-0.1.20/python/ferrum/ext/__init__.py +17 -0
  28. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/ext/pgvector.py +132 -41
  29. ferrum_orm-0.1.20/python/ferrum/hooks.py +499 -0
  30. ferrum_orm-0.1.20/python/ferrum/migrations/autodiff.py +665 -0
  31. ferrum_orm-0.1.20/python/ferrum/migrations/base.py +85 -0
  32. ferrum_orm-0.1.20/python/ferrum/migrations/coordinator.py +1031 -0
  33. ferrum_orm-0.1.20/python/ferrum/migrations/drift.py +1488 -0
  34. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/ledger.py +138 -5
  35. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/loader.py +69 -0
  36. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/operations.py +17 -3
  37. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/orchestrator.py +906 -22
  38. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/models.py +860 -8
  39. ferrum_orm-0.1.20/python/ferrum/observability.py +554 -0
  40. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/queryset.py +388 -50
  41. ferrum_orm-0.1.20/python/ferrum/registry.py +116 -0
  42. ferrum_orm-0.1.20/python/ferrum/relations.py +683 -0
  43. ferrum_orm-0.1.20/python/ferrum/routing.py +376 -0
  44. ferrum_orm-0.1.20/python/ferrum/runtime.py +433 -0
  45. ferrum_orm-0.1.20/python/ferrum/session.py +344 -0
  46. ferrum_orm-0.1.17/crates/ferrum-core/benches/hydrate.rs +0 -101
  47. ferrum_orm-0.1.17/crates/ferrum-sql/benches/compile.rs +0 -162
  48. ferrum_orm-0.1.17/python/ferrum/contrib/__init__.py +0 -5
  49. ferrum_orm-0.1.17/python/ferrum/contrib/fastapi.py +0 -75
  50. ferrum_orm-0.1.17/python/ferrum/expressions.py +0 -82
  51. ferrum_orm-0.1.17/python/ferrum/ext/__init__.py +0 -5
  52. ferrum_orm-0.1.17/python/ferrum/hooks.py +0 -270
  53. ferrum_orm-0.1.17/python/ferrum/migrations/base.py +0 -50
  54. ferrum_orm-0.1.17/python/ferrum/migrations/drift.py +0 -377
  55. ferrum_orm-0.1.17/python/ferrum/observability.py +0 -159
  56. ferrum_orm-0.1.17/python/ferrum/registry.py +0 -55
  57. ferrum_orm-0.1.17/python/ferrum/relations.py +0 -378
  58. ferrum_orm-0.1.17/python/ferrum/runtime.py +0 -240
  59. ferrum_orm-0.1.17/python/ferrum/session.py +0 -171
  60. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/LICENSE +0 -0
  61. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/Cargo.toml +0 -0
  62. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/compile/mod.rs +0 -0
  63. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/error.rs +0 -0
  64. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/hydrate/mod.rs +0 -0
  65. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/lib.rs +0 -0
  66. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-core/src/migrate/mod.rs +0 -0
  67. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-pyo3/Cargo.toml +0 -0
  68. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-pyo3/src/lib.rs +0 -0
  69. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/Cargo.toml +0 -0
  70. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/dialect.rs +0 -0
  71. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/fts/mod.rs +0 -0
  72. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/fts/mssql.rs +0 -0
  73. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/fts/mysql.rs +0 -0
  74. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/fts/postgres.rs +0 -0
  75. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/fts/sqlite.rs +0 -0
  76. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/crates/ferrum-sql/src/lib.rs +0 -0
  77. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/__init__.py +0 -0
  78. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/bootstrap.py +0 -0
  79. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/init.py +0 -0
  80. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/inspectdb_cmd.py +0 -0
  81. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/makemigrations_cmd.py +0 -0
  82. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/resetdb_cmd.py +0 -0
  83. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/revert_cmd.py +0 -0
  84. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/showmigrations_cmd.py +0 -0
  85. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/cli/sqlmigrate_cmd.py +0 -0
  86. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/config.py +0 -0
  87. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/__init__.py +0 -0
  88. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/mssql.py +0 -0
  89. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/drivers/streaming.py +0 -0
  90. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/ext/fts.py +0 -0
  91. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/__init__.py +0 -0
  92. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/fts/__init__.py +0 -0
  93. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/fts/mssql.py +0 -0
  94. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/fts/mysql.py +0 -0
  95. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/fts/postgres.py +0 -0
  96. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/fts/sqlite.py +0 -0
  97. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/gates.py +0 -0
  98. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/introspect.py +0 -0
  99. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/migrations/tokens.py +0 -0
  100. {ferrum_orm-0.1.17 → ferrum_orm-0.1.20}/python/ferrum/py.typed +0 -0
@@ -25,9 +25,9 @@ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
25
25
 
26
26
  [[package]]
27
27
  name = "anyhow"
28
- version = "1.0.102"
28
+ version = "1.0.104"
29
29
  source = "registry+https://github.com/rust-lang/crates.io-index"
30
- checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
30
+ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
31
31
 
32
32
  [[package]]
33
33
  name = "autocfg"
@@ -223,7 +223,7 @@ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
223
223
 
224
224
  [[package]]
225
225
  name = "ferrum-core"
226
- version = "0.1.17"
226
+ version = "0.1.20"
227
227
  dependencies = [
228
228
  "criterion",
229
229
  "proptest",
@@ -234,7 +234,7 @@ dependencies = [
234
234
 
235
235
  [[package]]
236
236
  name = "ferrum-migrate"
237
- version = "0.1.17"
237
+ version = "0.1.20"
238
238
  dependencies = [
239
239
  "ferrum-core",
240
240
  "serde",
@@ -243,7 +243,7 @@ dependencies = [
243
243
 
244
244
  [[package]]
245
245
  name = "ferrum-pyo3"
246
- version = "0.1.17"
246
+ version = "0.1.20"
247
247
  dependencies = [
248
248
  "ferrum-core",
249
249
  "ferrum-sql",
@@ -255,7 +255,7 @@ dependencies = [
255
255
 
256
256
  [[package]]
257
257
  name = "ferrum-sql"
258
- version = "0.1.17"
258
+ version = "0.1.20"
259
259
  dependencies = [
260
260
  "criterion",
261
261
  "ferrum-core",
@@ -750,9 +750,9 @@ dependencies = [
750
750
 
751
751
  [[package]]
752
752
  name = "rustix"
753
- version = "1.1.4"
753
+ version = "1.1.6"
754
754
  source = "registry+https://github.com/rust-lang/crates.io-index"
755
- checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
755
+ checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa"
756
756
  dependencies = [
757
757
  "bitflags",
758
758
  "errno",
@@ -3,7 +3,7 @@ members = ["crates/ferrum-core", "crates/ferrum-sql", "crates/ferrum-pyo3"]
3
3
  resolver = "2"
4
4
 
5
5
  [workspace.package]
6
- version = "0.1.17"
6
+ version = "0.1.20"
7
7
  edition = "2021"
8
8
  authors = ["Ferrum Contributors"]
9
9
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ferrum-orm
3
- Version: 0.1.17
3
+ Version: 0.1.20
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Framework :: AsyncIO
6
6
  Classifier: Intended Audience :: Developers
@@ -25,7 +25,7 @@ Requires-Dist: ferrum-orm[cli] ; extra == 'all'
25
25
  Requires-Dist: ferrum-orm[dotenv] ; extra == 'all'
26
26
  Requires-Dist: typer>=0.12 ; extra == 'cli'
27
27
  Requires-Dist: rich>=13 ; extra == 'cli'
28
- Requires-Dist: ferrum-orm[pg,cli,dotenv] ; extra == 'dev'
28
+ Requires-Dist: ferrum-orm[pg,mysql,sqlite,mssql,cli,dotenv] ; extra == 'dev'
29
29
  Requires-Dist: maturin>=1.7,<2 ; extra == 'dev'
30
30
  Requires-Dist: pytest>=8 ; extra == 'dev'
31
31
  Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
@@ -96,12 +96,25 @@ Ferrum aims to provide all four.
96
96
  - Pydantic-first models
97
97
  - Django-inspired ORM experience
98
98
  - Rust-powered query engine
99
- - PostgreSQL-first architecture (MySQL, SQLite, and SQL Server via optional extras)
99
+ - PostgreSQL-first architecture. MySQL, SQLite, and SQL Server extras are best-effort thin parity — not production-supported and not production-readiness release gates
100
100
  - Type-safe query construction
101
101
  - Automatic migrations
102
102
  - High-performance result hydration
103
103
  - Production-ready observability
104
104
 
105
+ ### Production-readiness execution
106
+
107
+ Ferrum is still alpha. The remaining production work for Ticket Analyzer and an
108
+ async-refactored Org AI Platform is tracked in
109
+ [the production-readiness plan](.cursor/plans/ferrum-production-readiness_6b5f422d.plan.md).
110
+ Execution is wave-based and supports parallel agents through disjoint file ownership,
111
+ per-workstream state, immutable evidence logs, and an independent verification gate.
112
+
113
+ Every task follows `Specify → Plan → Tasks → Implement`; every executor run follows
114
+ `Load → Execute → Validate executor output → Verify independently → Update state`.
115
+ See [.agent-work/production-readiness/](.agent-work/production-readiness/) for the durable
116
+ execution contract and current aggregate state.
117
+
105
118
  ---
106
119
 
107
120
  ## Quick Example
@@ -285,7 +298,9 @@ This allows Ferrum to maintain a Pythonic API without sacrificing performance.
285
298
  ### Cross-Driver Full-Text Search
286
299
 
287
300
  Native full-text search across PostgreSQL, MySQL, SQLite FTS5, and SQL Server — one
288
- QuerySet API, dialect-specific SQL emit and migration DDL.
301
+ QuerySet API, dialect-specific SQL emit and migration DDL. Cross-dialect FTS on
302
+ MySQL / SQLite / SQL Server is a **thin-extra** capability, not a P0
303
+ production-readiness release gate. PostgreSQL FTS is the production-readiness target.
289
304
 
290
305
  **Query modes** (filter lookups and ranking):
291
306
 
@@ -366,7 +381,7 @@ and [API Reference](docs/api-reference.md) for per-dialect DDL and operator mapp
366
381
  - [x] Migrations (schema diff, apply, revert, CLI)
367
382
  - [x] Relationships (ForeignKey, OneToOne, ManyToMany)
368
383
  - [x] pgvector KNN search and HNSW/IVFFLAT index DDL
369
- - [x] Full-text search (cross-dialect: PostgreSQL, MySQL, SQLite FTS5, SQL Server)
384
+ - [x] Full-text search (PostgreSQL is the P0 gate; MySQL/SQLite/SQL Server FTS is thin-extra)
370
385
  - [x] Observability hooks (Tier A/B/C)
371
386
  - [x] CLI (`makemigrations`, `migrate`, `revert`, `showmigrations`, `inspectdb`, `resetdb`)
372
387
 
@@ -397,7 +412,11 @@ and [API Reference](docs/api-reference.md) for per-dialect DDL and operator mapp
397
412
 
398
413
  Ferrum is currently in active development.
399
414
 
400
- The API is not yet stable and breaking changes should be expected until the first public release.
415
+ The API is not yet stable. **0.x has no compatibility guarantee**: SemVer MINOR and PATCH
416
+ may both break. After 1.0, public API and migration-ops breaks require a deprecation
417
+ window of at least one minor release and 90 days, whichever is longer. Generated SQL is
418
+ never a compatibility surface. Compatibility policy: `AGENTS.md` §5a. Thin extras:
419
+ `AGENTS.md` §2.6. See also `CHANGELOG.md`.
401
420
 
402
421
  ## Installation
403
422
 
@@ -430,10 +449,45 @@ pip install ferrum-orm
430
449
  Bare `ferrum-orm` installs Pydantic and the Rust core only. Choose a driver extra
431
450
  (`pg`, `mysql`, `sqlite`, or `mssql`) before calling `ferrum.connect()`.
432
451
 
433
- MySQL, SQLite, and SQL Server are **thin-parity** backends: they support core CRUD
434
- and migrations but not transactions, upsert, `bulk_update`, RLS, or pgvector
435
- (PostgreSQL only). SQL Server connects via `aioodbc`/`pyodbc` and requires a system
436
- ODBC driver such as `msodbcsql18`; DSNs use the `mssql://` or `sqlserver://` scheme.
452
+ MySQL, SQLite, and SQL Server are **best-effort thin-parity** backends: they are **not
453
+ production-supported** and are **not production-readiness release gates**. Core CRUD is
454
+ exercised across all four drivers; advanced behavior is capability-gated rather than
455
+ emulated with incompatible SQL. The integration-suite registry
456
+ (`tests/python/integration/backends.py`) is the coverage matrix — what is tested,
457
+ not a stability or production-support claim. PostgreSQL claims every capability.
458
+ MySQL and SQL Server claim full-text search and composite primary keys only.
459
+ SQLite claims `RETURNING`, full-text search, and composite primary keys.
460
+
461
+ | Capability | PostgreSQL | MySQL | SQLite | SQL Server |
462
+ | ---------- | :--------: | :---: | :----: | :--------: |
463
+ | Transactions | ✅ | — | — | — |
464
+ | Savepoints | ✅ | — | — | — |
465
+ | Cursor streaming | ✅ | — | — | — |
466
+ | Bulk update | ✅ | — | — | — |
467
+ | Aggregates / grouping | ✅ | — | — | — |
468
+ | Upsert | ✅ | — | — | — |
469
+ | Returning rows | ✅ | — | ✅ | — |
470
+ | Row-level security helpers | ✅ | — | — | — |
471
+ | pgvector | ✅ | — | — | — |
472
+ | Full-text search | ✅ | ✅ | ✅ | ✅ |
473
+ | JSON operators | ✅ | — | — | — |
474
+ | Case-insensitive `ILIKE` | ✅ | — | — | — |
475
+ | Array columns | ✅ | — | — | — |
476
+ | Alter column | ✅ | — | — | — |
477
+ | Composite primary keys | ✅ | ✅ | ✅ | ✅ |
478
+ | Stored-function calls | ✅ | — | — | — |
479
+
480
+ Unsupported capabilities fail with a typed Ferrum error before backend SQL is
481
+ executed. Transactions, savepoints, aggregates, upsert, alter-column, and
482
+ stored-function calls are PostgreSQL-only in this matrix; thin extras raise at
483
+ the Python/compiler boundary rather than sending Postgres SQL. Pull requests
484
+ exercise PostgreSQL and SQLite, while the nightly integration matrix runs
485
+ PostgreSQL, MySQL, SQLite, and SQL Server independently. SQLite on PRs is CI
486
+ coverage, not a production-readiness gate. Cross-dialect FTS in the matrix is
487
+ thin-extra coverage, not a P0 release gate.
488
+
489
+ SQL Server connects via `aioodbc`/`pyodbc` and requires a system ODBC driver such
490
+ as `msodbcsql18`; DSNs use the `mssql://` or `sqlserver://` scheme.
437
491
 
438
492
  ### Wire format (advanced)
439
493
 
@@ -24,12 +24,25 @@ Ferrum aims to provide all four.
24
24
  - Pydantic-first models
25
25
  - Django-inspired ORM experience
26
26
  - Rust-powered query engine
27
- - PostgreSQL-first architecture (MySQL, SQLite, and SQL Server via optional extras)
27
+ - PostgreSQL-first architecture. MySQL, SQLite, and SQL Server extras are best-effort thin parity — not production-supported and not production-readiness release gates
28
28
  - Type-safe query construction
29
29
  - Automatic migrations
30
30
  - High-performance result hydration
31
31
  - Production-ready observability
32
32
 
33
+ ### Production-readiness execution
34
+
35
+ Ferrum is still alpha. The remaining production work for Ticket Analyzer and an
36
+ async-refactored Org AI Platform is tracked in
37
+ [the production-readiness plan](.cursor/plans/ferrum-production-readiness_6b5f422d.plan.md).
38
+ Execution is wave-based and supports parallel agents through disjoint file ownership,
39
+ per-workstream state, immutable evidence logs, and an independent verification gate.
40
+
41
+ Every task follows `Specify → Plan → Tasks → Implement`; every executor run follows
42
+ `Load → Execute → Validate executor output → Verify independently → Update state`.
43
+ See [.agent-work/production-readiness/](.agent-work/production-readiness/) for the durable
44
+ execution contract and current aggregate state.
45
+
33
46
  ---
34
47
 
35
48
  ## Quick Example
@@ -213,7 +226,9 @@ This allows Ferrum to maintain a Pythonic API without sacrificing performance.
213
226
  ### Cross-Driver Full-Text Search
214
227
 
215
228
  Native full-text search across PostgreSQL, MySQL, SQLite FTS5, and SQL Server — one
216
- QuerySet API, dialect-specific SQL emit and migration DDL.
229
+ QuerySet API, dialect-specific SQL emit and migration DDL. Cross-dialect FTS on
230
+ MySQL / SQLite / SQL Server is a **thin-extra** capability, not a P0
231
+ production-readiness release gate. PostgreSQL FTS is the production-readiness target.
217
232
 
218
233
  **Query modes** (filter lookups and ranking):
219
234
 
@@ -294,7 +309,7 @@ and [API Reference](docs/api-reference.md) for per-dialect DDL and operator mapp
294
309
  - [x] Migrations (schema diff, apply, revert, CLI)
295
310
  - [x] Relationships (ForeignKey, OneToOne, ManyToMany)
296
311
  - [x] pgvector KNN search and HNSW/IVFFLAT index DDL
297
- - [x] Full-text search (cross-dialect: PostgreSQL, MySQL, SQLite FTS5, SQL Server)
312
+ - [x] Full-text search (PostgreSQL is the P0 gate; MySQL/SQLite/SQL Server FTS is thin-extra)
298
313
  - [x] Observability hooks (Tier A/B/C)
299
314
  - [x] CLI (`makemigrations`, `migrate`, `revert`, `showmigrations`, `inspectdb`, `resetdb`)
300
315
 
@@ -325,7 +340,11 @@ and [API Reference](docs/api-reference.md) for per-dialect DDL and operator mapp
325
340
 
326
341
  Ferrum is currently in active development.
327
342
 
328
- The API is not yet stable and breaking changes should be expected until the first public release.
343
+ The API is not yet stable. **0.x has no compatibility guarantee**: SemVer MINOR and PATCH
344
+ may both break. After 1.0, public API and migration-ops breaks require a deprecation
345
+ window of at least one minor release and 90 days, whichever is longer. Generated SQL is
346
+ never a compatibility surface. Compatibility policy: `AGENTS.md` §5a. Thin extras:
347
+ `AGENTS.md` §2.6. See also `CHANGELOG.md`.
329
348
 
330
349
  ## Installation
331
350
 
@@ -358,10 +377,45 @@ pip install ferrum-orm
358
377
  Bare `ferrum-orm` installs Pydantic and the Rust core only. Choose a driver extra
359
378
  (`pg`, `mysql`, `sqlite`, or `mssql`) before calling `ferrum.connect()`.
360
379
 
361
- MySQL, SQLite, and SQL Server are **thin-parity** backends: they support core CRUD
362
- and migrations but not transactions, upsert, `bulk_update`, RLS, or pgvector
363
- (PostgreSQL only). SQL Server connects via `aioodbc`/`pyodbc` and requires a system
364
- ODBC driver such as `msodbcsql18`; DSNs use the `mssql://` or `sqlserver://` scheme.
380
+ MySQL, SQLite, and SQL Server are **best-effort thin-parity** backends: they are **not
381
+ production-supported** and are **not production-readiness release gates**. Core CRUD is
382
+ exercised across all four drivers; advanced behavior is capability-gated rather than
383
+ emulated with incompatible SQL. The integration-suite registry
384
+ (`tests/python/integration/backends.py`) is the coverage matrix — what is tested,
385
+ not a stability or production-support claim. PostgreSQL claims every capability.
386
+ MySQL and SQL Server claim full-text search and composite primary keys only.
387
+ SQLite claims `RETURNING`, full-text search, and composite primary keys.
388
+
389
+ | Capability | PostgreSQL | MySQL | SQLite | SQL Server |
390
+ | ---------- | :--------: | :---: | :----: | :--------: |
391
+ | Transactions | ✅ | — | — | — |
392
+ | Savepoints | ✅ | — | — | — |
393
+ | Cursor streaming | ✅ | — | — | — |
394
+ | Bulk update | ✅ | — | — | — |
395
+ | Aggregates / grouping | ✅ | — | — | — |
396
+ | Upsert | ✅ | — | — | — |
397
+ | Returning rows | ✅ | — | ✅ | — |
398
+ | Row-level security helpers | ✅ | — | — | — |
399
+ | pgvector | ✅ | — | — | — |
400
+ | Full-text search | ✅ | ✅ | ✅ | ✅ |
401
+ | JSON operators | ✅ | — | — | — |
402
+ | Case-insensitive `ILIKE` | ✅ | — | — | — |
403
+ | Array columns | ✅ | — | — | — |
404
+ | Alter column | ✅ | — | — | — |
405
+ | Composite primary keys | ✅ | ✅ | ✅ | ✅ |
406
+ | Stored-function calls | ✅ | — | — | — |
407
+
408
+ Unsupported capabilities fail with a typed Ferrum error before backend SQL is
409
+ executed. Transactions, savepoints, aggregates, upsert, alter-column, and
410
+ stored-function calls are PostgreSQL-only in this matrix; thin extras raise at
411
+ the Python/compiler boundary rather than sending Postgres SQL. Pull requests
412
+ exercise PostgreSQL and SQLite, while the nightly integration matrix runs
413
+ PostgreSQL, MySQL, SQLite, and SQL Server independently. SQLite on PRs is CI
414
+ coverage, not a production-readiness gate. Cross-dialect FTS in the matrix is
415
+ thin-extra coverage, not a P0 release gate.
416
+
417
+ SQL Server connects via `aioodbc`/`pyodbc` and requires a system ODBC driver such
418
+ as `msodbcsql18`; DSNs use the `mssql://` or `sqlserver://` scheme.
365
419
 
366
420
  ### Wire format (advanced)
367
421