terrine 0.1.0a1__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 (578) hide show
  1. terrine-0.1.0a1/.github/CLA.md +154 -0
  2. terrine-0.1.0a1/.github/workflows/ci.yml +287 -0
  3. terrine-0.1.0a1/.github/workflows/cla.yml +61 -0
  4. terrine-0.1.0a1/.github/workflows/docs.yml +42 -0
  5. terrine-0.1.0a1/.github/workflows/durations.yml +40 -0
  6. terrine-0.1.0a1/.github/workflows/release.yml +184 -0
  7. terrine-0.1.0a1/.github/workflows/scale.yml +47 -0
  8. terrine-0.1.0a1/.github/workflows/warehouse-backends.yml +124 -0
  9. terrine-0.1.0a1/.gitignore +22 -0
  10. terrine-0.1.0a1/.kata.toml +4 -0
  11. terrine-0.1.0a1/.pre-commit-config.yaml +16 -0
  12. terrine-0.1.0a1/.python-version +1 -0
  13. terrine-0.1.0a1/.roborev.toml +11 -0
  14. terrine-0.1.0a1/AGENTS.md +376 -0
  15. terrine-0.1.0a1/CHANGELOG.md +865 -0
  16. terrine-0.1.0a1/CLAUDE.md +1 -0
  17. terrine-0.1.0a1/CONTRIBUTING.md +128 -0
  18. terrine-0.1.0a1/LICENSE +202 -0
  19. terrine-0.1.0a1/Makefile +74 -0
  20. terrine-0.1.0a1/NOTICE +4 -0
  21. terrine-0.1.0a1/PKG-INFO +265 -0
  22. terrine-0.1.0a1/README.md +202 -0
  23. terrine-0.1.0a1/THIRD_PARTY_NOTICES.txt +219 -0
  24. terrine-0.1.0a1/benchmarks/README.md +238 -0
  25. terrine-0.1.0a1/benchmarks/report.py +51 -0
  26. terrine-0.1.0a1/benchmarks/results/duckdb-scale-v2-small.json +1 -0
  27. terrine-0.1.0a1/benchmarks/run_cost.py +111 -0
  28. terrine-0.1.0a1/benchmarks/run_duckdb.py +290 -0
  29. terrine-0.1.0a1/benchmarks/run_live.py +361 -0
  30. terrine-0.1.0a1/benchmarks/run_overhead.py +500 -0
  31. terrine-0.1.0a1/benchmarks/workloads/small.json +10 -0
  32. terrine-0.1.0a1/benchmarks/workloads.py +691 -0
  33. terrine-0.1.0a1/docs/guides/backend-compatibility.md +780 -0
  34. terrine-0.1.0a1/docs/guides/candidate-anchors.md +65 -0
  35. terrine-0.1.0a1/docs/guides/capabilities.md +57 -0
  36. terrine-0.1.0a1/docs/guides/common-feature-patterns.md +198 -0
  37. terrine-0.1.0a1/docs/guides/common-stack-interop.md +162 -0
  38. terrine-0.1.0a1/docs/guides/cost-and-residency.md +116 -0
  39. terrine-0.1.0a1/docs/guides/dataset-agent-tools.md +199 -0
  40. terrine-0.1.0a1/docs/guides/design-specs.md +140 -0
  41. terrine-0.1.0a1/docs/guides/design-validation.md +94 -0
  42. terrine-0.1.0a1/docs/guides/first-dataset.md +161 -0
  43. terrine-0.1.0a1/docs/guides/increment-compatibility.md +41 -0
  44. terrine-0.1.0a1/docs/guides/index.md +55 -0
  45. terrine-0.1.0a1/docs/guides/library-handoffs.md +375 -0
  46. terrine-0.1.0a1/docs/guides/limitations.md +101 -0
  47. terrine-0.1.0a1/docs/guides/materialization-runtime.md +298 -0
  48. terrine-0.1.0a1/docs/guides/ml-staging.md +223 -0
  49. terrine-0.1.0a1/docs/guides/orchestrators.md +161 -0
  50. terrine-0.1.0a1/docs/guides/public-api.md +227 -0
  51. terrine-0.1.0a1/docs/guides/semantic-layer-interop.md +30 -0
  52. terrine-0.1.0a1/docs/guides/sequential-panels.md +131 -0
  53. terrine-0.1.0a1/docs/guides/shared-dataset-contract.md +108 -0
  54. terrine-0.1.0a1/docs/guides/stability.md +212 -0
  55. terrine-0.1.0a1/docs/guides/state-panels.md +107 -0
  56. terrine-0.1.0a1/docs/guides/synthetic-worlds.md +70 -0
  57. terrine-0.1.0a1/docs/guides/temporal-attributes.md +75 -0
  58. terrine-0.1.0a1/docs/guides/temporal-engine.md +968 -0
  59. terrine-0.1.0a1/docs/guides/trajectories-survival.md +225 -0
  60. terrine-0.1.0a1/docs/index.md +36 -0
  61. terrine-0.1.0a1/docs/reference/api/data.md +14 -0
  62. terrine-0.1.0a1/docs/reference/api/dataset.md +9 -0
  63. terrine-0.1.0a1/docs/reference/api/errors.md +13 -0
  64. terrine-0.1.0a1/docs/reference/api/recipes.md +15 -0
  65. terrine-0.1.0a1/docs/reference/api/spec.md +77 -0
  66. terrine-0.1.0a1/docs/reference/api/terrine.md +60 -0
  67. terrine-0.1.0a1/docs/reference/api/windows.md +10 -0
  68. terrine-0.1.0a1/docs/reference/refusals.md +591 -0
  69. terrine-0.1.0a1/docs/research/edge-case-designs.md +60 -0
  70. terrine-0.1.0a1/docs/research/landscape.md +167 -0
  71. terrine-0.1.0a1/docs/research/ohdsi-study-design.md +109 -0
  72. terrine-0.1.0a1/docs/research/point-in-time-feature-apis.md +80 -0
  73. terrine-0.1.0a1/evals/agent_dataset_tools.yaml +84 -0
  74. terrine-0.1.0a1/examples/batch_scoring.py +68 -0
  75. terrine-0.1.0a1/examples/bigquery/dataset.py +106 -0
  76. terrine-0.1.0a1/examples/common_stack_interop.py +115 -0
  77. terrine-0.1.0a1/examples/dataset_agent_tools.py +127 -0
  78. terrine-0.1.0a1/examples/event_sequences.py +190 -0
  79. terrine-0.1.0a1/examples/first_dataset.py +14 -0
  80. terrine-0.1.0a1/examples/increment_parity.py +237 -0
  81. terrine-0.1.0a1/examples/materialization_runtime.py +256 -0
  82. terrine-0.1.0a1/examples/ml_staging.py +174 -0
  83. terrine-0.1.0a1/examples/nonadditive_metrics.py +87 -0
  84. terrine-0.1.0a1/examples/orchestrators/airflow_materialization.py +43 -0
  85. terrine-0.1.0a1/examples/orchestrators/dagster_materialization.py +34 -0
  86. terrine-0.1.0a1/examples/orchestrators/dbt_core_after_build.py +85 -0
  87. terrine-0.1.0a1/examples/postgres/dataset.py +105 -0
  88. terrine-0.1.0a1/examples/retention_and_winsorization.py +82 -0
  89. terrine-0.1.0a1/examples/retention_metrics.py +101 -0
  90. terrine-0.1.0a1/examples/sequential_trials.py +128 -0
  91. terrine-0.1.0a1/examples/snowflake/dataset.py +149 -0
  92. terrine-0.1.0a1/examples/state_panel.py +188 -0
  93. terrine-0.1.0a1/examples/table_first_dataset.py +127 -0
  94. terrine-0.1.0a1/examples/trajectories_survival.py +179 -0
  95. terrine-0.1.0a1/examples/unverified_backend.py +150 -0
  96. terrine-0.1.0a1/integration/.test_durations +512 -0
  97. terrine-0.1.0a1/integration/agent/test_dataset_tool_example.py +27 -0
  98. terrine-0.1.0a1/integration/agent/test_dataset_tool_flow.py +80 -0
  99. terrine-0.1.0a1/integration/agent/test_dataset_tool_runtime.py +843 -0
  100. terrine-0.1.0a1/integration/backends/test_duckdb_version.py +160 -0
  101. terrine-0.1.0a1/integration/backends/test_engine_registry.py +25 -0
  102. terrine-0.1.0a1/integration/backends/test_generic.py +800 -0
  103. terrine-0.1.0a1/integration/backends/test_numeric.py +208 -0
  104. terrine-0.1.0a1/integration/compat/test_native_catalog.py +110 -0
  105. terrine-0.1.0a1/integration/compile/test_boolean_outputs.py +365 -0
  106. terrine-0.1.0a1/integration/compile/test_column_runtime_contracts.py +445 -0
  107. terrine-0.1.0a1/integration/compile/test_design_describe.py +474 -0
  108. terrine-0.1.0a1/integration/compile/test_frame_runtime_window_export.py +353 -0
  109. terrine-0.1.0a1/integration/compile/test_ltv.py +148 -0
  110. terrine-0.1.0a1/integration/compile/test_numeric_lowering.py +149 -0
  111. terrine-0.1.0a1/integration/compile/test_retention.py +34 -0
  112. terrine-0.1.0a1/integration/compile/test_time_to_event.py +553 -0
  113. terrine-0.1.0a1/integration/conformance/test_engines.py +550 -0
  114. terrine-0.1.0a1/integration/conftest.py +24 -0
  115. terrine-0.1.0a1/integration/execution/test_generic_provider.py +439 -0
  116. terrine-0.1.0a1/integration/execution/test_native_admission.py +139 -0
  117. terrine-0.1.0a1/integration/handoffs/__init__.py +0 -0
  118. terrine-0.1.0a1/integration/handoffs/conftest.py +83 -0
  119. terrine-0.1.0a1/integration/handoffs/test_causal_grid.py +208 -0
  120. terrine-0.1.0a1/integration/handoffs/test_diff_diff.py +53 -0
  121. terrine-0.1.0a1/integration/handoffs/test_library_handoffs.py +85 -0
  122. terrine-0.1.0a1/integration/handoffs/test_lifelines.py +107 -0
  123. terrine-0.1.0a1/integration/parity/test_increment_panel_parity.py +56 -0
  124. terrine-0.1.0a1/integration/state_panels/test_state_panel_workflows.py +403 -0
  125. terrine-0.1.0a1/integration/temporal/test_aggregate.py +136 -0
  126. terrine-0.1.0a1/integration/temporal/test_retention_bands.py +158 -0
  127. terrine-0.1.0a1/integration/temporal/test_window_quotient_composition.py +317 -0
  128. terrine-0.1.0a1/integration/test_api_check.py +157 -0
  129. terrine-0.1.0a1/integration/test_artifact_corpus_schema.py +69 -0
  130. terrine-0.1.0a1/integration/test_cost_budget.py +202 -0
  131. terrine-0.1.0a1/integration/test_examples.py +42 -0
  132. terrine-0.1.0a1/integration/test_frame.py +153 -0
  133. terrine-0.1.0a1/integration/test_independence.py +32 -0
  134. terrine-0.1.0a1/integration/test_model_from_tables.py +392 -0
  135. terrine-0.1.0a1/integration/test_public_examples.py +58 -0
  136. terrine-0.1.0a1/integration/test_release_upgrade.py +201 -0
  137. terrine-0.1.0a1/integration/warehouse_execution/bigquery_fixtures.py +80 -0
  138. terrine-0.1.0a1/integration/warehouse_execution/ml_staging_fixtures.py +118 -0
  139. terrine-0.1.0a1/integration/warehouse_execution/postgres_fixtures.py +68 -0
  140. terrine-0.1.0a1/integration/warehouse_execution/snowflake_fixtures.py +121 -0
  141. terrine-0.1.0a1/integration/warehouse_execution/test_artifact_identity.py +133 -0
  142. terrine-0.1.0a1/integration/warehouse_execution/test_backend_capabilities.py +540 -0
  143. terrine-0.1.0a1/integration/warehouse_execution/test_bigquery_admission.py +141 -0
  144. terrine-0.1.0a1/integration/warehouse_execution/test_bigquery_execution.py +28 -0
  145. terrine-0.1.0a1/integration/warehouse_execution/test_bigquery_parity.py +276 -0
  146. terrine-0.1.0a1/integration/warehouse_execution/test_duckdb_compiler_scale.py +67 -0
  147. terrine-0.1.0a1/integration/warehouse_execution/test_duckdb_runtime_recovery.py +83 -0
  148. terrine-0.1.0a1/integration/warehouse_execution/test_duckdb_scale.py +34 -0
  149. terrine-0.1.0a1/integration/warehouse_execution/test_incremental_equivalence.py +1029 -0
  150. terrine-0.1.0a1/integration/warehouse_execution/test_live_warehouse_scale.py +34 -0
  151. terrine-0.1.0a1/integration/warehouse_execution/test_materialization_example.py +32 -0
  152. terrine-0.1.0a1/integration/warehouse_execution/test_ml_staging_examples.py +90 -0
  153. terrine-0.1.0a1/integration/warehouse_execution/test_ml_staging_exports.py +871 -0
  154. terrine-0.1.0a1/integration/warehouse_execution/test_ml_staging_reads.py +527 -0
  155. terrine-0.1.0a1/integration/warehouse_execution/test_ml_staging_training.py +735 -0
  156. terrine-0.1.0a1/integration/warehouse_execution/test_orchestrator_adapters.py +883 -0
  157. terrine-0.1.0a1/integration/warehouse_execution/test_planning.py +131 -0
  158. terrine-0.1.0a1/integration/warehouse_execution/test_postgres_admission.py +253 -0
  159. terrine-0.1.0a1/integration/warehouse_execution/test_postgres_execution.py +112 -0
  160. terrine-0.1.0a1/integration/warehouse_execution/test_postgres_shapes.py +837 -0
  161. terrine-0.1.0a1/integration/warehouse_execution/test_postgres_timestamps.py +108 -0
  162. terrine-0.1.0a1/integration/warehouse_execution/test_postgres_windows.py +447 -0
  163. terrine-0.1.0a1/integration/warehouse_execution/test_request_replay_process.py +151 -0
  164. terrine-0.1.0a1/integration/warehouse_execution/test_runtime_api.py +767 -0
  165. terrine-0.1.0a1/integration/warehouse_execution/test_runtime_cli.py +70 -0
  166. terrine-0.1.0a1/integration/warehouse_execution/test_runtime_control.py +51 -0
  167. terrine-0.1.0a1/integration/warehouse_execution/test_runtime_cost_budget.py +83 -0
  168. terrine-0.1.0a1/integration/warehouse_execution/test_saved_plan_restart.py +664 -0
  169. terrine-0.1.0a1/integration/warehouse_execution/test_snapshot_capture_bounds.py +102 -0
  170. terrine-0.1.0a1/integration/warehouse_execution/test_snapshot_partition_consistency.py +235 -0
  171. terrine-0.1.0a1/integration/warehouse_execution/test_snowflake_admission.py +342 -0
  172. terrine-0.1.0a1/integration/warehouse_execution/test_snowflake_execution.py +34 -0
  173. terrine-0.1.0a1/integration/warehouse_execution/test_snowflake_parity.py +648 -0
  174. terrine-0.1.0a1/integration/warehouse_execution/test_winsorization_definition.py +120 -0
  175. terrine-0.1.0a1/mkdocs.yml +54 -0
  176. terrine-0.1.0a1/pyproject.toml +144 -0
  177. terrine-0.1.0a1/scripts/api_check.py +662 -0
  178. terrine-0.1.0a1/scripts/ci_cost.py +104 -0
  179. terrine-0.1.0a1/scripts/ci_scope.py +86 -0
  180. terrine-0.1.0a1/scripts/mutate.py +218 -0
  181. terrine-0.1.0a1/scripts/require_green_ci.py +131 -0
  182. terrine-0.1.0a1/scripts/write_artifact_corpus.py +432 -0
  183. terrine-0.1.0a1/tach.toml +121 -0
  184. terrine-0.1.0a1/terrine/__init__.py +119 -0
  185. terrine-0.1.0a1/terrine/_refusal_codes.py +186 -0
  186. terrine-0.1.0a1/terrine/_time.py +21 -0
  187. terrine-0.1.0a1/terrine/adapters/__init__.py +7 -0
  188. terrine-0.1.0a1/terrine/adapters/increment.py +374 -0
  189. terrine-0.1.0a1/terrine/adapters/opentelemetry.py +70 -0
  190. terrine-0.1.0a1/terrine/agent/__init__.py +10 -0
  191. terrine-0.1.0a1/terrine/agent/definitions.py +150 -0
  192. terrine-0.1.0a1/terrine/agent/design_schema.py +244 -0
  193. terrine-0.1.0a1/terrine/agent/policy.py +166 -0
  194. terrine-0.1.0a1/terrine/agent/schemas.py +298 -0
  195. terrine-0.1.0a1/terrine/agent/tools.py +971 -0
  196. terrine-0.1.0a1/terrine/backends/__init__.py +3 -0
  197. terrine-0.1.0a1/terrine/backends/capabilities.py +64 -0
  198. terrine-0.1.0a1/terrine/backends/dialect.py +839 -0
  199. terrine-0.1.0a1/terrine/backends/engines/__init__.py +0 -0
  200. terrine-0.1.0a1/terrine/backends/engines/bigquery.py +151 -0
  201. terrine-0.1.0a1/terrine/backends/engines/duckdb.py +381 -0
  202. terrine-0.1.0a1/terrine/backends/engines/postgres.py +339 -0
  203. terrine-0.1.0a1/terrine/backends/engines/snowflake.py +222 -0
  204. terrine-0.1.0a1/terrine/backends/extrema.py +25 -0
  205. terrine-0.1.0a1/terrine/backends/joins.py +88 -0
  206. terrine-0.1.0a1/terrine/backends/numeric.py +301 -0
  207. terrine-0.1.0a1/terrine/backends/registry.py +284 -0
  208. terrine-0.1.0a1/terrine/backends/sequences.py +14 -0
  209. terrine-0.1.0a1/terrine/backends/timestamps.py +258 -0
  210. terrine-0.1.0a1/terrine/compile/__init__.py +3 -0
  211. terrine-0.1.0a1/terrine/compile/_asof.py +158 -0
  212. terrine-0.1.0a1/terrine/compile/_predicates.py +134 -0
  213. terrine-0.1.0a1/terrine/compile/anchors.py +541 -0
  214. terrine-0.1.0a1/terrine/compile/columns.py +1462 -0
  215. terrine-0.1.0a1/terrine/compile/cost.py +131 -0
  216. terrine-0.1.0a1/terrine/compile/dispatch.py +160 -0
  217. terrine-0.1.0a1/terrine/compile/layers.py +265 -0
  218. terrine-0.1.0a1/terrine/compile/materialize.py +92 -0
  219. terrine-0.1.0a1/terrine/compile/numeric.py +120 -0
  220. terrine-0.1.0a1/terrine/compile/provenance.py +130 -0
  221. terrine-0.1.0a1/terrine/compile/prune.py +235 -0
  222. terrine-0.1.0a1/terrine/compile/ranges.py +94 -0
  223. terrine-0.1.0a1/terrine/compile/retention.py +129 -0
  224. terrine-0.1.0a1/terrine/compile/shapes/__init__.py +3 -0
  225. terrine-0.1.0a1/terrine/compile/shapes/_observations.py +513 -0
  226. terrine-0.1.0a1/terrine/compile/shapes/calendar_comparison.py +422 -0
  227. terrine-0.1.0a1/terrine/compile/shapes/cohorts.py +388 -0
  228. terrine-0.1.0a1/terrine/compile/shapes/event_panel.py +51 -0
  229. terrine-0.1.0a1/terrine/compile/shapes/event_sequence.py +507 -0
  230. terrine-0.1.0a1/terrine/compile/shapes/life_table.py +236 -0
  231. terrine-0.1.0a1/terrine/compile/shapes/ltv.py +345 -0
  232. terrine-0.1.0a1/terrine/compile/shapes/matched_t0.py +78 -0
  233. terrine-0.1.0a1/terrine/compile/shapes/sequential.py +338 -0
  234. terrine-0.1.0a1/terrine/compile/shapes/state_panel.py +458 -0
  235. terrine-0.1.0a1/terrine/compile/shapes/time_to_event.py +546 -0
  236. terrine-0.1.0a1/terrine/data.py +1998 -0
  237. terrine-0.1.0a1/terrine/dataset/__init__.py +5 -0
  238. terrine-0.1.0a1/terrine/dataset/export.py +479 -0
  239. terrine-0.1.0a1/terrine/dataset/manifest.py +278 -0
  240. terrine-0.1.0a1/terrine/dataset/reference.py +768 -0
  241. terrine-0.1.0a1/terrine/dataset/splits.py +479 -0
  242. terrine-0.1.0a1/terrine/dataset/training.py +115 -0
  243. terrine-0.1.0a1/terrine/dataset/transforms.py +182 -0
  244. terrine-0.1.0a1/terrine/errors.py +149 -0
  245. terrine-0.1.0a1/terrine/execution/__init__.py +9 -0
  246. terrine-0.1.0a1/terrine/execution/_bigquery.py +385 -0
  247. terrine-0.1.0a1/terrine/execution/_generic.py +396 -0
  248. terrine-0.1.0a1/terrine/execution/_metadata.py +47 -0
  249. terrine-0.1.0a1/terrine/execution/_native.py +726 -0
  250. terrine-0.1.0a1/terrine/execution/_postgres.py +549 -0
  251. terrine-0.1.0a1/terrine/execution/_publish.py +299 -0
  252. terrine-0.1.0a1/terrine/execution/_snowflake.py +754 -0
  253. terrine-0.1.0a1/terrine/execution/backend.py +100 -0
  254. terrine-0.1.0a1/terrine/execution/gates.py +340 -0
  255. terrine-0.1.0a1/terrine/execution/inputs.py +1041 -0
  256. terrine-0.1.0a1/terrine/export/__init__.py +35 -0
  257. terrine-0.1.0a1/terrine/export/diff_diff.py +271 -0
  258. terrine-0.1.0a1/terrine/export/lifelines.py +292 -0
  259. terrine-0.1.0a1/terrine/export/preflight.py +321 -0
  260. terrine-0.1.0a1/terrine/export/surrogate.py +206 -0
  261. terrine-0.1.0a1/terrine/frame.py +1267 -0
  262. terrine-0.1.0a1/terrine/metrics.py +228 -0
  263. terrine-0.1.0a1/terrine/model.py +1005 -0
  264. terrine-0.1.0a1/terrine/orchestration/__init__.py +7 -0
  265. terrine-0.1.0a1/terrine/orchestration/airflow.py +134 -0
  266. terrine-0.1.0a1/terrine/orchestration/dagster.py +126 -0
  267. terrine-0.1.0a1/terrine/py.typed +0 -0
  268. terrine-0.1.0a1/terrine/reasons.py +93 -0
  269. terrine-0.1.0a1/terrine/recipes.py +514 -0
  270. terrine-0.1.0a1/terrine/runtime/__init__.py +76 -0
  271. terrine-0.1.0a1/terrine/runtime/api.py +849 -0
  272. terrine-0.1.0a1/terrine/runtime/arrow.py +102 -0
  273. terrine-0.1.0a1/terrine/runtime/backends/base.py +70 -0
  274. terrine-0.1.0a1/terrine/runtime/backends/duckdb.py +599 -0
  275. terrine-0.1.0a1/terrine/runtime/changes.py +71 -0
  276. terrine-0.1.0a1/terrine/runtime/cli.py +108 -0
  277. terrine-0.1.0a1/terrine/runtime/control.py +370 -0
  278. terrine-0.1.0a1/terrine/runtime/cost.py +211 -0
  279. terrine-0.1.0a1/terrine/runtime/events.py +185 -0
  280. terrine-0.1.0a1/terrine/runtime/execute.py +844 -0
  281. terrine-0.1.0a1/terrine/runtime/gc.py +43 -0
  282. terrine-0.1.0a1/terrine/runtime/graph.py +200 -0
  283. terrine-0.1.0a1/terrine/runtime/layers.py +61 -0
  284. terrine-0.1.0a1/terrine/runtime/leases.py +149 -0
  285. terrine-0.1.0a1/terrine/runtime/materialize.py +60 -0
  286. terrine-0.1.0a1/terrine/runtime/owner.py +57 -0
  287. terrine-0.1.0a1/terrine/runtime/planner.py +449 -0
  288. terrine-0.1.0a1/terrine/runtime/planning.py +381 -0
  289. terrine-0.1.0a1/terrine/runtime/saved_plan.py +353 -0
  290. terrine-0.1.0a1/terrine/runtime/schema.py +216 -0
  291. terrine-0.1.0a1/terrine/runtime/snapshot.py +548 -0
  292. terrine-0.1.0a1/terrine/runtime/state.py +510 -0
  293. terrine-0.1.0a1/terrine/runtime/status.py +282 -0
  294. terrine-0.1.0a1/terrine/runtime/synchronization.py +15 -0
  295. terrine-0.1.0a1/terrine/semantic/__init__.py +3 -0
  296. terrine-0.1.0a1/terrine/semantic/attributes.py +86 -0
  297. terrine-0.1.0a1/terrine/semantic/bind.py +433 -0
  298. terrine-0.1.0a1/terrine/semantic/io.py +239 -0
  299. terrine-0.1.0a1/terrine/semantic/models.py +384 -0
  300. terrine-0.1.0a1/terrine/semantic/predicates.py +244 -0
  301. terrine-0.1.0a1/terrine/semantic/rules.py +118 -0
  302. terrine-0.1.0a1/terrine/semantic/sql.py +250 -0
  303. terrine-0.1.0a1/terrine/semantic/time.py +42 -0
  304. terrine-0.1.0a1/terrine/simulate/__init__.py +28 -0
  305. terrine-0.1.0a1/terrine/simulate/baseline.yaml +57 -0
  306. terrine-0.1.0a1/terrine/simulate/generate.py +182 -0
  307. terrine-0.1.0a1/terrine/simulate/scale.py +251 -0
  308. terrine-0.1.0a1/terrine/simulate/world.py +75 -0
  309. terrine-0.1.0a1/terrine/spec/__init__.py +140 -0
  310. terrine-0.1.0a1/terrine/spec/_columns.py +134 -0
  311. terrine-0.1.0a1/terrine/spec/anchors.py +335 -0
  312. terrine-0.1.0a1/terrine/spec/dataset.py +350 -0
  313. terrine-0.1.0a1/terrine/spec/describe.py +750 -0
  314. terrine-0.1.0a1/terrine/spec/design.py +502 -0
  315. terrine-0.1.0a1/terrine/spec/expressions.py +1112 -0
  316. terrine-0.1.0a1/terrine/spec/io.py +1003 -0
  317. terrine-0.1.0a1/terrine/spec/panels.py +641 -0
  318. terrine-0.1.0a1/terrine/spec/sequence.py +220 -0
  319. terrine-0.1.0a1/terrine/spec/state_panel.py +339 -0
  320. terrine-0.1.0a1/terrine/spec/trajectory.py +237 -0
  321. terrine-0.1.0a1/terrine/spec/transforms.py +296 -0
  322. terrine-0.1.0a1/terrine/spec/validate.py +1042 -0
  323. terrine-0.1.0a1/terrine/temporal/__init__.py +3 -0
  324. terrine-0.1.0a1/terrine/temporal/aggregate.py +828 -0
  325. terrine-0.1.0a1/terrine/temporal/attributes.py +413 -0
  326. terrine-0.1.0a1/terrine/temporal/daily.py +335 -0
  327. terrine-0.1.0a1/terrine/temporal/first.py +224 -0
  328. terrine-0.1.0a1/terrine/temporal/lookup.py +195 -0
  329. terrine-0.1.0a1/terrine/temporal/nonadditive.py +504 -0
  330. terrine-0.1.0a1/terrine/temporal/prefix.py +184 -0
  331. terrine-0.1.0a1/terrine/temporal/ranges.py +123 -0
  332. terrine-0.1.0a1/terrine/temporal/readiness.py +47 -0
  333. terrine-0.1.0a1/terrine/temporal/retention.py +226 -0
  334. terrine-0.1.0a1/terrine/temporal/sequence.py +910 -0
  335. terrine-0.1.0a1/terrine/temporal/sessionize.py +137 -0
  336. terrine-0.1.0a1/terrine/temporal/sketches.py +316 -0
  337. terrine-0.1.0a1/terrine/windows.py +246 -0
  338. terrine-0.1.0a1/tests/.test_durations +2371 -0
  339. terrine-0.1.0a1/tests/__init__.py +0 -0
  340. terrine-0.1.0a1/tests/_float_bound.py +21 -0
  341. terrine-0.1.0a1/tests/_timing.py +3 -0
  342. terrine-0.1.0a1/tests/_worlds.py +126 -0
  343. terrine-0.1.0a1/tests/adapters/test_airflow.py +262 -0
  344. terrine-0.1.0a1/tests/adapters/test_dagster.py +225 -0
  345. terrine-0.1.0a1/tests/adapters/test_dbt_core_after_build.py +240 -0
  346. terrine-0.1.0a1/tests/agent/conftest.py +76 -0
  347. terrine-0.1.0a1/tests/agent/fixtures/catalog.yaml +19 -0
  348. terrine-0.1.0a1/tests/agent/test_inspect_design.py +341 -0
  349. terrine-0.1.0a1/tests/agent/test_materialize.py +133 -0
  350. terrine-0.1.0a1/tests/agent/test_plan_authorization.py +225 -0
  351. terrine-0.1.0a1/tests/agent/test_policy.py +126 -0
  352. terrine-0.1.0a1/tests/agent/test_requests.py +61 -0
  353. terrine-0.1.0a1/tests/agent/test_schemas.py +212 -0
  354. terrine-0.1.0a1/tests/artifacts/1/arrow_metadata.json +4 -0
  355. terrine-0.1.0a1/tests/artifacts/1/catalog.yaml +59 -0
  356. terrine-0.1.0a1/tests/artifacts/1/data/customers.parquet +0 -0
  357. terrine-0.1.0a1/tests/artifacts/1/data/orders.parquet +0 -0
  358. terrine-0.1.0a1/tests/artifacts/1/definition.json +1 -0
  359. terrine-0.1.0a1/tests/artifacts/1/design.json +1 -0
  360. terrine-0.1.0a1/tests/artifacts/1/design.yaml +28 -0
  361. terrine-0.1.0a1/tests/artifacts/1/event_panel/definition.json +1 -0
  362. terrine-0.1.0a1/tests/artifacts/1/event_panel/design.json +1 -0
  363. terrine-0.1.0a1/tests/artifacts/1/event_panel/design.yaml +22 -0
  364. terrine-0.1.0a1/tests/artifacts/1/event_panel/expected_schema.json +143 -0
  365. terrine-0.1.0a1/tests/artifacts/1/event_sequence/definition.json +1 -0
  366. terrine-0.1.0a1/tests/artifacts/1/event_sequence/design.json +1 -0
  367. terrine-0.1.0a1/tests/artifacts/1/event_sequence/design.yaml +22 -0
  368. terrine-0.1.0a1/tests/artifacts/1/event_sequence/expected_schema.json +203 -0
  369. terrine-0.1.0a1/tests/artifacts/1/expected_schema.json +273 -0
  370. terrine-0.1.0a1/tests/artifacts/1/life_table/definition.json +1 -0
  371. terrine-0.1.0a1/tests/artifacts/1/life_table/design.json +1 -0
  372. terrine-0.1.0a1/tests/artifacts/1/life_table/design.yaml +25 -0
  373. terrine-0.1.0a1/tests/artifacts/1/life_table/expected_schema.json +428 -0
  374. terrine-0.1.0a1/tests/artifacts/1/ltv/definition.json +1 -0
  375. terrine-0.1.0a1/tests/artifacts/1/ltv/design.json +1 -0
  376. terrine-0.1.0a1/tests/artifacts/1/ltv/design.yaml +23 -0
  377. terrine-0.1.0a1/tests/artifacts/1/ltv/expected_schema.json +218 -0
  378. terrine-0.1.0a1/tests/artifacts/1/manifest.json +1 -0
  379. terrine-0.1.0a1/tests/artifacts/1/receipt.json +1 -0
  380. terrine-0.1.0a1/tests/artifacts/1/state_panel/definition.json +1 -0
  381. terrine-0.1.0a1/tests/artifacts/1/state_panel/design.json +1 -0
  382. terrine-0.1.0a1/tests/artifacts/1/state_panel/design.yaml +32 -0
  383. terrine-0.1.0a1/tests/artifacts/1/state_panel/expected_schema.json +278 -0
  384. terrine-0.1.0a1/tests/artifacts/1/survival/definition.json +1 -0
  385. terrine-0.1.0a1/tests/artifacts/1/survival/design.json +1 -0
  386. terrine-0.1.0a1/tests/artifacts/1/survival/design.yaml +17 -0
  387. terrine-0.1.0a1/tests/artifacts/1/survival/expected_schema.json +308 -0
  388. terrine-0.1.0a1/tests/artifacts/1/time_series/definition.json +1 -0
  389. terrine-0.1.0a1/tests/artifacts/1/time_series/design.json +1 -0
  390. terrine-0.1.0a1/tests/artifacts/1/time_series/design.yaml +39 -0
  391. terrine-0.1.0a1/tests/artifacts/1/time_series/expected_schema.json +188 -0
  392. terrine-0.1.0a1/tests/artifacts/1/trial_panel/definition.json +1 -0
  393. terrine-0.1.0a1/tests/artifacts/1/trial_panel/design.json +1 -0
  394. terrine-0.1.0a1/tests/artifacts/1/trial_panel/design.yaml +34 -0
  395. terrine-0.1.0a1/tests/artifacts/1/trial_panel/expected_schema.json +233 -0
  396. terrine-0.1.0a1/tests/artifacts/RELEASES +0 -0
  397. terrine-0.1.0a1/tests/artifacts/surface/0.1.0a1.txt +546 -0
  398. terrine-0.1.0a1/tests/backends/__init__.py +0 -0
  399. terrine-0.1.0a1/tests/backends/test_duckdb_dialect.py +21 -0
  400. terrine-0.1.0a1/tests/backends/test_engine_registry.py +180 -0
  401. terrine-0.1.0a1/tests/backends/test_generic.py +630 -0
  402. terrine-0.1.0a1/tests/backends/test_numeric.py +166 -0
  403. terrine-0.1.0a1/tests/backends/test_sequences.py +14 -0
  404. terrine-0.1.0a1/tests/backends/test_timestamps.py +193 -0
  405. terrine-0.1.0a1/tests/compat/__init__.py +0 -0
  406. terrine-0.1.0a1/tests/compat/fixtures/catalog.yaml +103 -0
  407. terrine-0.1.0a1/tests/compat/fixtures/increment.yaml +109 -0
  408. terrine-0.1.0a1/tests/compat/fixtures/same-name-collision.yaml +19 -0
  409. terrine-0.1.0a1/tests/compat/fixtures/unsupported-metric.yaml +13 -0
  410. terrine-0.1.0a1/tests/compat/test_increment_semantics.py +156 -0
  411. terrine-0.1.0a1/tests/compat/test_semantic_interop.py +28 -0
  412. terrine-0.1.0a1/tests/compile/__init__.py +0 -0
  413. terrine-0.1.0a1/tests/compile/test_anchors.py +647 -0
  414. terrine-0.1.0a1/tests/compile/test_cohorts.py +332 -0
  415. terrine-0.1.0a1/tests/compile/test_columns.py +1119 -0
  416. terrine-0.1.0a1/tests/compile/test_completeness_columns.py +280 -0
  417. terrine-0.1.0a1/tests/compile/test_cost_estimates.py +29 -0
  418. terrine-0.1.0a1/tests/compile/test_event_sequence.py +1110 -0
  419. terrine-0.1.0a1/tests/compile/test_ltv.py +505 -0
  420. terrine-0.1.0a1/tests/compile/test_matched_t0.py +150 -0
  421. terrine-0.1.0a1/tests/compile/test_nonadditive.py +381 -0
  422. terrine-0.1.0a1/tests/compile/test_numeric.py +17 -0
  423. terrine-0.1.0a1/tests/compile/test_panels.py +583 -0
  424. terrine-0.1.0a1/tests/compile/test_persisted_layers.py +527 -0
  425. terrine-0.1.0a1/tests/compile/test_predicates.py +42 -0
  426. terrine-0.1.0a1/tests/compile/test_prune.py +49 -0
  427. terrine-0.1.0a1/tests/compile/test_range_scaling.py +225 -0
  428. terrine-0.1.0a1/tests/compile/test_retention.py +281 -0
  429. terrine-0.1.0a1/tests/compile/test_state_panel.py +875 -0
  430. terrine-0.1.0a1/tests/compile/test_survival_bounds.py +39 -0
  431. terrine-0.1.0a1/tests/compile/test_time_to_event.py +463 -0
  432. terrine-0.1.0a1/tests/compile/test_winsorization.py +99 -0
  433. terrine-0.1.0a1/tests/conftest.py +74 -0
  434. terrine-0.1.0a1/tests/dataset/__init__.py +0 -0
  435. terrine-0.1.0a1/tests/dataset/test_definition.py +281 -0
  436. terrine-0.1.0a1/tests/dataset/test_export.py +17 -0
  437. terrine-0.1.0a1/tests/dataset/test_label_support.py +128 -0
  438. terrine-0.1.0a1/tests/dataset/test_manifest.py +228 -0
  439. terrine-0.1.0a1/tests/dataset/test_runtime_staging.py +55 -0
  440. terrine-0.1.0a1/tests/dataset/test_splits.py +213 -0
  441. terrine-0.1.0a1/tests/dataset/test_staging.py +44 -0
  442. terrine-0.1.0a1/tests/dataset/test_training_view.py +344 -0
  443. terrine-0.1.0a1/tests/dataset/test_winsorization_definition.py +80 -0
  444. terrine-0.1.0a1/tests/documentation.py +277 -0
  445. terrine-0.1.0a1/tests/execution/__init__.py +0 -0
  446. terrine-0.1.0a1/tests/execution/test_backend_provider.py +374 -0
  447. terrine-0.1.0a1/tests/execution/test_gates.py +392 -0
  448. terrine-0.1.0a1/tests/execution/test_generic.py +326 -0
  449. terrine-0.1.0a1/tests/execution/test_inputs.py +725 -0
  450. terrine-0.1.0a1/tests/execution/test_native.py +87 -0
  451. terrine-0.1.0a1/tests/execution/test_snowflake_session.py +204 -0
  452. terrine-0.1.0a1/tests/execution/test_sql_verification.py +106 -0
  453. terrine-0.1.0a1/tests/export/conftest.py +100 -0
  454. terrine-0.1.0a1/tests/export/test_diff_diff.py +139 -0
  455. terrine-0.1.0a1/tests/export/test_lifelines.py +256 -0
  456. terrine-0.1.0a1/tests/export/test_preflight.py +129 -0
  457. terrine-0.1.0a1/tests/export/test_surrogate.py +134 -0
  458. terrine-0.1.0a1/tests/export/test_warehouse_preflight.py +145 -0
  459. terrine-0.1.0a1/tests/fixtures/__init__.py +0 -0
  460. terrine-0.1.0a1/tests/fixtures/baseline.py +263 -0
  461. terrine-0.1.0a1/tests/fixtures/interop.py +117 -0
  462. terrine-0.1.0a1/tests/fixtures/materialized_frame_v1.json +1 -0
  463. terrine-0.1.0a1/tests/fixtures/pre_rename_plan_request.json +1 -0
  464. terrine-0.1.0a1/tests/fixtures/readme.py +76 -0
  465. terrine-0.1.0a1/tests/fixtures/test_baseline.py +71 -0
  466. terrine-0.1.0a1/tests/fixtures/winsorization.py +98 -0
  467. terrine-0.1.0a1/tests/integration/__init__.py +0 -0
  468. terrine-0.1.0a1/tests/integration/distribution_smoke.py +243 -0
  469. terrine-0.1.0a1/tests/integration/postgres_scratch.py +122 -0
  470. terrine-0.1.0a1/tests/integration/study_api_smoke.py +233 -0
  471. terrine-0.1.0a1/tests/integration/test_benchmark_failure_reporting.py +167 -0
  472. terrine-0.1.0a1/tests/integration/test_live_scale_gate.py +169 -0
  473. terrine-0.1.0a1/tests/parity/__init__.py +0 -0
  474. terrine-0.1.0a1/tests/parity/test_increment_frames.py +225 -0
  475. terrine-0.1.0a1/tests/reference/__init__.py +0 -0
  476. terrine-0.1.0a1/tests/reference/baseline.py +135 -0
  477. terrine-0.1.0a1/tests/reference/nonadditive.py +13 -0
  478. terrine-0.1.0a1/tests/reference/panels.py +133 -0
  479. terrine-0.1.0a1/tests/reference/ranges.py +42 -0
  480. terrine-0.1.0a1/tests/reference/retention.py +69 -0
  481. terrine-0.1.0a1/tests/reference/scale_metrics.py +94 -0
  482. terrine-0.1.0a1/tests/reference/test_baseline.py +120 -0
  483. terrine-0.1.0a1/tests/reference/test_event_sequences.py +155 -0
  484. terrine-0.1.0a1/tests/reference/test_panels.py +80 -0
  485. terrine-0.1.0a1/tests/runtime/__init__.py +0 -0
  486. terrine-0.1.0a1/tests/runtime/test_api.py +614 -0
  487. terrine-0.1.0a1/tests/runtime/test_arrow_output.py +40 -0
  488. terrine-0.1.0a1/tests/runtime/test_backend_capabilities.py +241 -0
  489. terrine-0.1.0a1/tests/runtime/test_batch_cleanup.py +51 -0
  490. terrine-0.1.0a1/tests/runtime/test_cancel_publication.py +161 -0
  491. terrine-0.1.0a1/tests/runtime/test_cli.py +255 -0
  492. terrine-0.1.0a1/tests/runtime/test_control.py +37 -0
  493. terrine-0.1.0a1/tests/runtime/test_control_ipc.py +122 -0
  494. terrine-0.1.0a1/tests/runtime/test_control_recovery.py +148 -0
  495. terrine-0.1.0a1/tests/runtime/test_cost_estimates.py +372 -0
  496. terrine-0.1.0a1/tests/runtime/test_duckdb_publication.py +399 -0
  497. terrine-0.1.0a1/tests/runtime/test_execute.py +1239 -0
  498. terrine-0.1.0a1/tests/runtime/test_gc.py +133 -0
  499. terrine-0.1.0a1/tests/runtime/test_graph.py +117 -0
  500. terrine-0.1.0a1/tests/runtime/test_imports.py +22 -0
  501. terrine-0.1.0a1/tests/runtime/test_input_refusals.py +194 -0
  502. terrine-0.1.0a1/tests/runtime/test_invalidation.py +118 -0
  503. terrine-0.1.0a1/tests/runtime/test_layers.py +430 -0
  504. terrine-0.1.0a1/tests/runtime/test_leases.py +74 -0
  505. terrine-0.1.0a1/tests/runtime/test_opentelemetry.py +86 -0
  506. terrine-0.1.0a1/tests/runtime/test_planner.py +437 -0
  507. terrine-0.1.0a1/tests/runtime/test_planning.py +280 -0
  508. terrine-0.1.0a1/tests/runtime/test_recovery_lease.py +27 -0
  509. terrine-0.1.0a1/tests/runtime/test_request_replay.py +195 -0
  510. terrine-0.1.0a1/tests/runtime/test_run_events.py +213 -0
  511. terrine-0.1.0a1/tests/runtime/test_run_status.py +151 -0
  512. terrine-0.1.0a1/tests/runtime/test_saved_plan.py +423 -0
  513. terrine-0.1.0a1/tests/runtime/test_schema.py +163 -0
  514. terrine-0.1.0a1/tests/runtime/test_snapshot.py +356 -0
  515. terrine-0.1.0a1/tests/runtime/test_snapshot_lifecycle.py +297 -0
  516. terrine-0.1.0a1/tests/runtime/test_state.py +122 -0
  517. terrine-0.1.0a1/tests/semantic/__init__.py +0 -0
  518. terrine-0.1.0a1/tests/semantic/test_catalog.py +551 -0
  519. terrine-0.1.0a1/tests/semantic/test_from_tables.py +1131 -0
  520. terrine-0.1.0a1/tests/semantic/test_metric_rules.py +57 -0
  521. terrine-0.1.0a1/tests/semantic/test_rules_import.py +33 -0
  522. terrine-0.1.0a1/tests/semantic/test_sql.py +94 -0
  523. terrine-0.1.0a1/tests/simulate/__init__.py +0 -0
  524. terrine-0.1.0a1/tests/simulate/test_scale_generator.py +213 -0
  525. terrine-0.1.0a1/tests/simulate/test_world.py +98 -0
  526. terrine-0.1.0a1/tests/spec/__init__.py +0 -0
  527. terrine-0.1.0a1/tests/spec/test_calendar_comparison.py +93 -0
  528. terrine-0.1.0a1/tests/spec/test_describe.py +438 -0
  529. terrine-0.1.0a1/tests/spec/test_design_io.py +535 -0
  530. terrine-0.1.0a1/tests/spec/test_expressions.py +65 -0
  531. terrine-0.1.0a1/tests/spec/test_nonadditive_spec.py +125 -0
  532. terrine-0.1.0a1/tests/spec/test_panels.py +195 -0
  533. terrine-0.1.0a1/tests/spec/test_recipes.py +626 -0
  534. terrine-0.1.0a1/tests/spec/test_record_replace.py +128 -0
  535. terrine-0.1.0a1/tests/spec/test_refusals.py +629 -0
  536. terrine-0.1.0a1/tests/spec/test_retention.py +51 -0
  537. terrine-0.1.0a1/tests/spec/test_sequence.py +116 -0
  538. terrine-0.1.0a1/tests/spec/test_sketch_refusal.py +71 -0
  539. terrine-0.1.0a1/tests/spec/test_state_panel.py +110 -0
  540. terrine-0.1.0a1/tests/spec/test_validate.py +1141 -0
  541. terrine-0.1.0a1/tests/temporal/__init__.py +0 -0
  542. terrine-0.1.0a1/tests/temporal/test_first_occurrence.py +297 -0
  543. terrine-0.1.0a1/tests/temporal/test_nonadditive.py +66 -0
  544. terrine-0.1.0a1/tests/temporal/test_prefix.py +25 -0
  545. terrine-0.1.0a1/tests/temporal/test_prefix_lookup.py +409 -0
  546. terrine-0.1.0a1/tests/temporal/test_range_scaling.py +243 -0
  547. terrine-0.1.0a1/tests/temporal/test_readiness.py +21 -0
  548. terrine-0.1.0a1/tests/temporal/test_retention.py +386 -0
  549. terrine-0.1.0a1/tests/temporal/test_scd2_attributes.py +368 -0
  550. terrine-0.1.0a1/tests/temporal/test_semantic_binding.py +451 -0
  551. terrine-0.1.0a1/tests/temporal/test_sequence.py +293 -0
  552. terrine-0.1.0a1/tests/temporal/test_sessionize.py +206 -0
  553. terrine-0.1.0a1/tests/temporal/test_sketches.py +85 -0
  554. terrine-0.1.0a1/tests/temporal/test_sparse_state.py +585 -0
  555. terrine-0.1.0a1/tests/temporal/test_window_aggregates.py +807 -0
  556. terrine-0.1.0a1/tests/test_api_check.py +425 -0
  557. terrine-0.1.0a1/tests/test_artifact_corpus.py +150 -0
  558. terrine-0.1.0a1/tests/test_benchmarks_import.py +24 -0
  559. terrine-0.1.0a1/tests/test_ci_cost.py +36 -0
  560. terrine-0.1.0a1/tests/test_ci_scope.py +28 -0
  561. terrine-0.1.0a1/tests/test_common_stack_interop.py +32 -0
  562. terrine-0.1.0a1/tests/test_data.py +53 -0
  563. terrine-0.1.0a1/tests/test_distribution.py +21 -0
  564. terrine-0.1.0a1/tests/test_documentation.py +90 -0
  565. terrine-0.1.0a1/tests/test_engine_dispatch.py +401 -0
  566. terrine-0.1.0a1/tests/test_errors.py +23 -0
  567. terrine-0.1.0a1/tests/test_frame.py +339 -0
  568. terrine-0.1.0a1/tests/test_frame_runtime.py +363 -0
  569. terrine-0.1.0a1/tests/test_metadata.py +690 -0
  570. terrine-0.1.0a1/tests/test_mutation_runner.py +33 -0
  571. terrine-0.1.0a1/tests/test_optional_dependencies.py +49 -0
  572. terrine-0.1.0a1/tests/test_public_api.py +172 -0
  573. terrine-0.1.0a1/tests/test_public_docstrings.py +94 -0
  574. terrine-0.1.0a1/tests/test_reasons.py +52 -0
  575. terrine-0.1.0a1/tests/test_release_gate.py +193 -0
  576. terrine-0.1.0a1/tests/test_reprs.py +107 -0
  577. terrine-0.1.0a1/tests/test_windows.py +117 -0
  578. terrine-0.1.0a1/uv.lock +6801 -0
@@ -0,0 +1,154 @@
1
+ # terrine Individual Contributor License Agreement
2
+
3
+ Version 1.0 · effective 2026-10-20
4
+
5
+ The signature record stores the commit at which you signed, so the exact text
6
+ you agreed to is always recoverable from this file's git history. If this
7
+ Agreement is revised, the version above changes and existing signatures remain
8
+ bound to the version in force when they were made.
9
+
10
+ Thank you for your interest in contributing to terrine (the "Project"),
11
+ owned by Kyle Caron ("Owner", "we", "us").
12
+
13
+ This agreement clarifies the intellectual property license granted with
14
+ Contributions from any person or entity. It protects both you and the Owner;
15
+ it does **not** change your rights to use your own Contributions for any other
16
+ purpose.
17
+
18
+ **You keep the copyright in everything you contribute.** This is a license, not
19
+ an assignment. You are free to use, sell, relicense, and redistribute your own
20
+ Contributions however you wish, with no obligation to us.
21
+
22
+ You accept and agree to the following terms for your present and future
23
+ Contributions to the Project.
24
+
25
+ ## 1. Definitions
26
+
27
+ "You" (or "Your") means the copyright owner, or the legal entity authorized by
28
+ the copyright owner, entering into this Agreement.
29
+
30
+ "Contribution" means any original work of authorship, including any
31
+ modifications to or additions to an existing work, that is or previously has
32
+ been intentionally submitted by You to the Owner for inclusion in, or
33
+ documentation of, the Project. "Submitted" means any form of electronic,
34
+ verbal, or written communication sent to the Owner or its representatives,
35
+ including but not limited to communication on electronic mailing lists, source
36
+ code control systems, and issue tracking systems that are managed by, or on
37
+ behalf of, the Owner for the purpose of discussing and improving the Project,
38
+ but excluding communication that is conspicuously marked or otherwise
39
+ designated in writing by You as "Not a Contribution."
40
+
41
+ ## 2. Grant of Copyright License
42
+
43
+ Subject to the terms and conditions of this Agreement, You hereby grant to the
44
+ Owner and to recipients of software distributed by the Owner a perpetual,
45
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable, **transferable
46
+ and assignable** copyright license to reproduce, prepare derivative works of,
47
+ publicly display, publicly perform, **sublicense**, and distribute Your
48
+ Contributions and such derivative works.
49
+
50
+ The Owner may assign this Agreement, and the licenses granted under it, to a
51
+ successor in interest to the Project, including by merger, reorganization, or
52
+ sale of the assets to which the Project relates. This Agreement binds and
53
+ benefits the Owner's successors and assigns.
54
+
55
+ ## 3. Right to License Under Any Terms
56
+
57
+ You acknowledge and agree that the Owner may license, sublicense, and
58
+ distribute Your Contributions — alone or as part of the Project — **under any
59
+ license terms the Owner chooses**, including open source licenses, source
60
+ available licenses, and proprietary or commercial licenses, and that the Owner
61
+ may offer the Project under multiple licenses simultaneously (dual licensing).
62
+
63
+ The Owner is under no obligation to distribute Your Contributions under the
64
+ license currently applied to the Project.
65
+
66
+ This clause exists so that the Owner can sustain the Project commercially. It
67
+ does not restrict You: the rights You grant here are non-exclusive, and Your
68
+ own rights in Your Contributions are unaffected.
69
+
70
+ ## 4. Grant of Patent License
71
+
72
+ Subject to the terms and conditions of this Agreement, You hereby grant to the
73
+ Owner and to recipients of software distributed by the Owner a perpetual,
74
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as
75
+ stated in this section) patent license to make, have made, use, offer to sell,
76
+ sell, import, and otherwise transfer the Project, where such license applies
77
+ only to those patent claims licensable by You that are necessarily infringed by
78
+ Your Contribution(s) alone or by combination of Your Contribution(s) with the
79
+ Project to which such Contribution(s) was submitted.
80
+
81
+ If any entity institutes patent litigation against You or any other entity
82
+ (including a cross-claim or counterclaim in a lawsuit) alleging that Your
83
+ Contribution, or the Project to which You have contributed, constitutes direct
84
+ or contributory patent infringement, then any patent licenses granted to that
85
+ entity under this Agreement for that Contribution or Project shall terminate as
86
+ of the date such litigation is filed.
87
+
88
+ ## 5. You Represent That You Are Entitled To Grant This License
89
+
90
+ You represent that You are legally entitled to grant the above license. If Your
91
+ employer(s) has rights to intellectual property that You create that includes
92
+ Your Contributions, You represent that You have received permission to make
93
+ Contributions on behalf of that employer, that You will have received
94
+ permission from Your current and future employers for all future
95
+ Contributions, that Your employer has waived such rights for all of Your
96
+ current and future Contributions to the Owner, or that Your employer has
97
+ executed a Corporate Contributor License Agreement with the Owner.
98
+
99
+ ## 6. You Represent That Each Contribution Is Your Original Creation
100
+
101
+ You represent that each of Your Contributions is Your original creation. You
102
+ represent that Your Contribution submissions include complete details of any
103
+ third-party license or other restriction (including, but not limited to,
104
+ related patents and trademarks) of which You are personally aware and which are
105
+ associated with any part of Your Contributions.
106
+
107
+ ## 7. Third-Party Work
108
+
109
+ Should You wish to submit work that is not Your original creation, You may
110
+ submit it to the Owner separately from any Contribution, identifying the
111
+ complete details of its source and of any license or other restriction
112
+ (including, but not limited to, related patents, trademarks, and license
113
+ agreements) of which You are personally aware, and conspicuously marking the
114
+ work as "Submitted on behalf of a third-party: [named here]".
115
+
116
+ ## 8. No Obligation of Support or Warranty
117
+
118
+ You are not expected to provide support for Your Contributions, except to the
119
+ extent You desire to provide support. You may provide support for free, for a
120
+ fee, or not at all. Unless required by applicable law or agreed to in writing,
121
+ You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR
122
+ CONDITIONS OF ANY KIND, either express or implied, including, without
123
+ limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
124
+ MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
125
+
126
+ ## 9. Notification of Changed Circumstances
127
+
128
+ You agree to notify the Owner of any facts or circumstances of which You become
129
+ aware that would make these representations inaccurate in any respect.
130
+
131
+ ## Signing
132
+
133
+ Contributions are accepted only from signers of this Agreement, except for
134
+ automated accounts and coding agents named in the workflow allowlist, which
135
+ cannot themselves sign; the human opening the pull request remains responsible
136
+ for the representations above.
137
+
138
+ Sign electronically by commenting the following on your pull request, exactly:
139
+
140
+ ```
141
+ I have read the CLA Document and I hereby sign the CLA
142
+ ```
143
+
144
+ You sign once; the signature covers all of Your Contributions to the Project,
145
+ past and future.
146
+
147
+ **Record kept.** Signing stores your GitHub username, the text of your comment,
148
+ and a timestamp in the `cla-signatures` branch of this repository. That record
149
+ is retained for as long as the Project exists, because it is the evidence of
150
+ the licenses granted above. It is public if this repository is public.
151
+
152
+ If you are contributing on behalf of a company and your employer requires its
153
+ own agreement rather than the representations in section 5, contact
154
+ kyle.j.caron@gmail.com before opening a pull request.
@@ -0,0 +1,287 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+
8
+ # A newer push supersedes an in-flight run of the same ref.
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+
14
+ jobs:
15
+ # Each pushed commit runs every job once. A branch push defers to the
16
+ # pull-request run of the same commit when one exists; GitHub runs none for a
17
+ # pull request with merge conflicts, so an open pull request alone does not
18
+ # defer. Other events and tag pushes always run every job.
19
+ scope:
20
+ runs-on: ubuntu-latest
21
+ timeout-minutes: 3
22
+ permissions:
23
+ contents: read
24
+ actions: read
25
+ outputs:
26
+ defer: ${{ steps.scope.outputs.defer }}
27
+ steps:
28
+ - if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/')
29
+ uses: actions/checkout@v4
30
+ - id: scope
31
+ env:
32
+ GH_TOKEN: ${{ github.token }}
33
+ LOOKUP: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/heads/') }}
34
+ run: |
35
+ set -euo pipefail
36
+ if [ "$LOOKUP" = true ]; then
37
+ python3 scripts/ci_scope.py --sha "$GITHUB_SHA" --repo "$GITHUB_REPOSITORY"
38
+ else
39
+ echo "defer=false" >> "$GITHUB_OUTPUT"
40
+ fi
41
+ checks:
42
+ needs: scope
43
+ if: needs.scope.outputs.defer != 'true'
44
+ runs-on: ubuntu-latest
45
+ timeout-minutes: 30
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - uses: astral-sh/setup-uv@v5
49
+ with:
50
+ enable-cache: true
51
+ - uses: actions/setup-python@v5
52
+ with:
53
+ python-version: "3.14"
54
+ - run: uv sync --locked --group dev --group docs --all-extras
55
+ - run: make lint
56
+ - run: make typecheck
57
+ unit:
58
+ needs: scope
59
+ if: needs.scope.outputs.defer != 'true'
60
+ runs-on: ubuntu-latest
61
+ timeout-minutes: 30
62
+ strategy:
63
+ fail-fast: false
64
+ matrix:
65
+ python-version: ["3.12", "3.14"]
66
+ group: [1, 2]
67
+ steps:
68
+ - uses: actions/checkout@v4
69
+ - uses: astral-sh/setup-uv@v5
70
+ with:
71
+ enable-cache: true
72
+ - uses: actions/setup-python@v5
73
+ with:
74
+ python-version: "${{ matrix.python-version }}"
75
+ - run: uv sync --locked --group dev --all-extras
76
+ - run: >-
77
+ /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -q tests
78
+ -n auto --splits 2 --group ${{ matrix.group }}
79
+ --splitting-algorithm least_duration
80
+ --durations-path tests/.test_durations
81
+ --ignore=tests/temporal/test_sketches.py
82
+ --ignore=tests/spec/test_sketch_refusal.py
83
+ --ignore=tests/compile/test_nonadditive.py
84
+ --ignore=tests/compat
85
+ --ignore=tests/parity
86
+ integration:
87
+ needs: scope
88
+ if: needs.scope.outputs.defer != 'true'
89
+ runs-on: ubuntu-latest
90
+ timeout-minutes: 30
91
+ strategy:
92
+ fail-fast: false
93
+ matrix:
94
+ # Groups are balanced from integration/.test_durations; tests without a
95
+ # stored duration get the average and are still assigned to a group.
96
+ python-version: ["3.12", "3.14"]
97
+ group: [1, 2, 3, 4]
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - uses: astral-sh/setup-uv@v5
101
+ with:
102
+ enable-cache: true
103
+ - uses: actions/setup-python@v5
104
+ with:
105
+ python-version: "${{ matrix.python-version }}"
106
+ - run: uv sync --locked --group dev --all-extras
107
+ - run: >-
108
+ /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -q integration
109
+ -n auto --dist loadscope --splits 4 --group ${{ matrix.group }}
110
+ --splitting-algorithm duration_based_chunks
111
+ --durations-path integration/.test_durations
112
+ --ignore=integration/parity
113
+ --ignore=integration/handoffs
114
+ # The same known answers compiled through the portable base expression
115
+ # policy; about twenty seconds beside the native run.
116
+ - if: matrix.group == 1
117
+ run: /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -q -n auto integration/conformance --generic-dialect
118
+ docs-and-examples:
119
+ needs: scope
120
+ if: needs.scope.outputs.defer != 'true'
121
+ runs-on: ubuntu-latest
122
+ timeout-minutes: 30
123
+ steps:
124
+ - uses: actions/checkout@v4
125
+ - uses: astral-sh/setup-uv@v5
126
+ with:
127
+ enable-cache: true
128
+ - uses: actions/setup-python@v5
129
+ with:
130
+ python-version: "3.12"
131
+ - run: uv sync --locked --group dev --group docs --all-extras
132
+ - run: uv run --group docs python -m tests.documentation --build
133
+ - run: uv build
134
+ # Builds once per resolution and installs those distributions on every
135
+ # supported Python in turn.
136
+ distributions:
137
+ needs: scope
138
+ if: needs.scope.outputs.defer != 'true'
139
+ runs-on: ubuntu-latest
140
+ strategy:
141
+ fail-fast: false
142
+ matrix:
143
+ resolution: [highest, lowest-direct]
144
+ steps:
145
+ - uses: actions/checkout@v4
146
+ - uses: astral-sh/setup-uv@v5
147
+ with:
148
+ enable-cache: true
149
+ - uses: actions/setup-python@v5
150
+ with:
151
+ python-version: |
152
+ 3.12
153
+ 3.13
154
+ 3.14
155
+ - run: uv build
156
+ - env:
157
+ RESOLUTION: ${{ matrix.resolution }}
158
+ run: |
159
+ set -euo pipefail
160
+ for python in 3.12 3.13 3.14; do
161
+ uv run --no-project --python "$python" python \
162
+ -m tests.integration.distribution_smoke \
163
+ --wheel dist/*.whl --sdist dist/*.tar.gz \
164
+ --python "$python" --resolution "$RESOLUTION"
165
+ done
166
+
167
+ # Suites for optional extras, in turn. Each re-syncs with exactly its own
168
+ # extras, so every extra is proven without the others installed.
169
+ optional-suites:
170
+ needs: scope
171
+ if: needs.scope.outputs.defer != 'true'
172
+ runs-on: ubuntu-latest
173
+ steps:
174
+ - uses: actions/checkout@v4
175
+ - uses: astral-sh/setup-uv@v5
176
+ with:
177
+ enable-cache: true
178
+ - uses: actions/setup-python@v5
179
+ with:
180
+ python-version: "3.12"
181
+ - name: Sync sketches extras
182
+ run: uv sync --group dev --extra duckdb --extra pandas --extra sketches
183
+ - run: /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -n auto tests/temporal/test_sketches.py tests/spec/test_sketch_refusal.py tests/compile/test_nonadditive.py -q
184
+ - name: Sync increment compatibility extras
185
+ run: uv sync --locked --group dev --extra duckdb --extra increment
186
+ - run: /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -n auto tests/compat tests/parity
187
+ - run: /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -n auto integration/parity
188
+ - name: Sync library hand-off extras
189
+ run: uv sync --locked --group dev --extra duckdb --extra doubleml --extra dowhy --extra duckreg --extra lifelines --extra diff-diff
190
+ - run: /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -q -n auto integration/handoffs
191
+
192
+ postgres:
193
+ needs: scope
194
+ if: needs.scope.outputs.defer != 'true'
195
+ uses: ./.github/workflows/warehouse-backends.yml
196
+ with:
197
+ backend_mode: postgres
198
+
199
+ conformance-newest-python:
200
+ needs: scope
201
+ if: needs.scope.outputs.defer != 'true'
202
+ runs-on: ubuntu-latest
203
+ env:
204
+ UV_PYTHON: "3.14"
205
+ steps:
206
+ - uses: actions/checkout@v4
207
+ - uses: astral-sh/setup-uv@v5
208
+ with:
209
+ enable-cache: true
210
+ - run: uv sync --locked --group dev --extra duckdb
211
+ - run: /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest -q -n auto integration/conformance
212
+
213
+ # Validates stable exports and annotations, then compares signatures with the
214
+ # newest versioned snapshot; differences are informational during 0.x.
215
+ api-compat:
216
+ needs: scope
217
+ if: needs.scope.outputs.defer != 'true'
218
+ runs-on: ubuntu-latest
219
+ timeout-minutes: 10
220
+ steps:
221
+ - uses: actions/checkout@v4
222
+ with:
223
+ fetch-depth: 0
224
+ fetch-tags: true
225
+ - uses: astral-sh/setup-uv@v5
226
+ with:
227
+ enable-cache: true
228
+ - uses: actions/setup-python@v5
229
+ with:
230
+ python-version: "3.12"
231
+ - run: uv sync --locked --group dev
232
+ - name: Check stable API against release tags
233
+ run: uv run python scripts/api_check.py
234
+ - name: Compare stable API snapshot
235
+ run: |
236
+ set -euo pipefail
237
+ snapshot=$(uv run python -c '
238
+ from pathlib import Path
239
+ from packaging.version import Version
240
+ snapshots = list(Path("tests/artifacts/surface").glob("*.txt"))
241
+ print(max(snapshots, key=lambda path: Version(path.stem.removeprefix("v"))) if snapshots else "")
242
+ ')
243
+ if [ -z "$snapshot" ]; then
244
+ uv run python scripts/api_check.py --compare tests/artifacts/surface/.no-snapshot-yet.txt
245
+ exit $?
246
+ fi
247
+ uv run python scripts/api_check.py --compare "$snapshot"
248
+
249
+ # Single check to require in branch protection. Matrix jobs report one check
250
+ # per entry, so requiring them individually means editing the ruleset every
251
+ # time a matrix changes. GitHub reports a job skipped by a condition as
252
+ # successful, so a deferred run renames this job and never reports a check
253
+ # named exactly `ci-ok`; the pull-request run reports it instead.
254
+ ci-ok:
255
+ name: ${{ needs.scope.outputs.defer == 'true' && 'ci-ok (checked by the pull request run)' || 'ci-ok' }}
256
+ runs-on: ubuntu-latest
257
+ timeout-minutes: 5
258
+ needs:
259
+ - scope
260
+ - checks
261
+ - unit
262
+ - integration
263
+ - docs-and-examples
264
+ - distributions
265
+ - optional-suites
266
+ - postgres
267
+ - conformance-newest-python
268
+ - api-compat
269
+ if: always()
270
+ permissions: {}
271
+ steps:
272
+ - name: Require every job to succeed
273
+ env:
274
+ DEFER: ${{ needs.scope.outputs.defer }}
275
+ NEEDS: ${{ toJSON(needs) }}
276
+ run: |
277
+ set -euo pipefail
278
+ if [ "$DEFER" = true ]; then
279
+ echo "The pull-request run of this commit runs and checks every job."
280
+ exit 0
281
+ fi
282
+ echo "$NEEDS" | jq -r 'to_entries[] | "\(.key): \(.value.result)"'
283
+ failed=$(echo "$NEEDS" | jq -r '[to_entries[] | select(.value.result != "success") | .key] | join(", ")')
284
+ if [ -n "$failed" ]; then
285
+ echo "::error::jobs did not succeed: $failed"
286
+ exit 1
287
+ fi
@@ -0,0 +1,61 @@
1
+ name: cla
2
+
3
+ # Signatures are committed to the `cla-signatures` branch of this repo using
4
+ # the job's GITHUB_TOKEN, which is why `contents: write` below is required.
5
+
6
+ on:
7
+ issue_comment: {types: [created]}
8
+ pull_request_target: {types: [opened, closed, reopened, synchronize]}
9
+
10
+ concurrency:
11
+ # Recording a signature is a read-modify-write on one JSON file guarded by a
12
+ # SHA precondition; concurrent signings would race and one would 409.
13
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.issue.number }}
14
+ cancel-in-progress: false
15
+
16
+ permissions: {}
17
+
18
+ jobs:
19
+ cla:
20
+ runs-on: ubuntu-latest
21
+ timeout-minutes: 10
22
+ permissions:
23
+ actions: write
24
+ contents: write
25
+ pull-requests: write
26
+ statuses: write
27
+ # Write scopes on a pull_request_target job are safe only while nothing
28
+ # here checks out or executes PR-controlled content. Don't add a checkout
29
+ # or build step.
30
+ steps:
31
+ # Maintained fork of the archived contributor-assistant/github-action,
32
+ # pinned by SHA because this job holds write scopes under
33
+ # pull_request_target.
34
+ - uses: iainmcgin/cla-github-action@0d27e5a16278d4adb6b0c4b92f08ad27b0a21dc8 # v3.2.0
35
+ # Without this guard the action runs on every comment on every plain
36
+ # issue, where there is no pull request to resolve, and fails the check.
37
+ if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
38
+ env:
39
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40
+ with:
41
+ path-to-document: ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.event.repository.default_branch }}/.github/CLA.md
42
+ path-to-signatures: signatures/v1/cla.json
43
+ branch: cla-signatures
44
+ # AI coding agents add Co-authored-by trailers; they are counted as
45
+ # committers but cannot comment to sign, so they must be allowlisted
46
+ # or every agent-assisted PR blocks permanently.
47
+ # Name automated accounts explicitly; a wildcard such as bot* would also
48
+ # exempt human accounts whose names start with "bot".
49
+ allowlist: kylejcaron,dependabot[bot],renovate[bot],github-actions[bot],copilot,Copilot,Codex,Cursor,noreply@anthropic.com,cursoragent@cursor.com,codex@openai.com
50
+ # Fail the check when the PR opener authored none of the commits.
51
+ require-opener-as-author: true
52
+ lock-pullrequest-aftermerge: false
53
+ custom-pr-sign-comment: I have read the CLA Document and I hereby sign the CLA
54
+ custom-notsigned-prcomment: >
55
+ Thanks for the pull request. Before it can be merged, please read
56
+ the [Contributor License Agreement](${{ github.server_url }}/${{ github.repository }}/blob/${{ github.event.repository.default_branch }}/.github/CLA.md)
57
+ and sign it by posting the comment below. You keep the copyright in
58
+ your work; the CLA grants terrine's owner the right to license it,
59
+ including commercially. You sign once and it covers all your future
60
+ contributions.
61
+ custom-allsigned-prcomment: CLA signed by all contributors. Thank you.
@@ -0,0 +1,42 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: pages
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ build:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: astral-sh/setup-uv@v5
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+ - run: uv sync --group docs
25
+ - run: uv run --group docs python -m tests.documentation --build
26
+ - uses: actions/upload-pages-artifact@v3
27
+ with:
28
+ path: site
29
+
30
+ deploy:
31
+ if: github.ref == 'refs/heads/main'
32
+ environment:
33
+ name: github-pages
34
+ url: ${{ steps.deployment.outputs.page_url }}
35
+ runs-on: ubuntu-latest
36
+ needs: build
37
+ permissions:
38
+ pages: write
39
+ id-token: write
40
+ steps:
41
+ - id: deployment
42
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,40 @@
1
+ name: durations
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ refresh:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: astral-sh/setup-uv@v5
15
+ with:
16
+ enable-cache: true
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+ - run: uv sync --locked --group dev --all-extras
21
+ - name: Store unit test durations
22
+ run: >-
23
+ /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest tests -n auto
24
+ --store-durations --durations-path tests/.test_durations
25
+ --ignore=tests/temporal/test_sketches.py
26
+ --ignore=tests/spec/test_sketch_refusal.py
27
+ --ignore=tests/compile/test_nonadditive.py
28
+ --ignore=tests/compat --ignore=tests/parity
29
+ - name: Store integration test durations
30
+ run: >-
31
+ /usr/bin/time -f "terrine-pytest-cpu %U %S" uv run pytest integration -n auto
32
+ --store-durations --durations-path integration/.test_durations
33
+ --ignore=integration/parity --ignore=integration/handoffs
34
+ - uses: actions/upload-artifact@v4
35
+ with:
36
+ name: stored-test-durations
37
+ path: |
38
+ tests/.test_durations
39
+ integration/.test_durations
40
+ include-hidden-files: true