cmpnd 0.85.0__tar.gz → 0.85.1__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 (413) hide show
  1. {cmpnd-0.85.0 → cmpnd-0.85.1}/PKG-INFO +1 -1
  2. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/sdk-instrumentation.md +12 -0
  3. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/exporter_http.py +68 -7
  4. {cmpnd-0.85.0 → cmpnd-0.85.1}/pyproject.toml +1 -1
  5. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/seed_review_run.py +19 -3
  6. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_project_attribution.py +0 -73
  7. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_traces_read.py +3 -1
  8. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_trace_search.py +7 -1
  9. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_exporter.py +123 -0
  10. {cmpnd-0.85.0 → cmpnd-0.85.1}/uv.lock +1 -1
  11. {cmpnd-0.85.0 → cmpnd-0.85.1}/.gitignore +0 -0
  12. {cmpnd-0.85.0 → cmpnd-0.85.1}/AGENTS.md +0 -0
  13. {cmpnd-0.85.0 → cmpnd-0.85.1}/CLAUDE.md +0 -0
  14. {cmpnd-0.85.0 → cmpnd-0.85.1}/README.md +0 -0
  15. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/__init__.py +0 -0
  16. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_assessments.py +0 -0
  17. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_authored_import.py +0 -0
  18. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_deployments.py +0 -0
  19. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_exporter_pool.py +0 -0
  20. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_gepa_patch.py +0 -0
  21. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_http.py +0 -0
  22. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_program_patch.py +0 -0
  23. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_rlm_patch.py +0 -0
  24. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_runtime_tools.py +0 -0
  25. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_timespec.py +0 -0
  26. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_traces.py +0 -0
  27. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/_valsets.py +0 -0
  28. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/authored.py +0 -0
  29. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/callback.py +0 -0
  30. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/__init__.py +0 -0
  31. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/api_client.py +0 -0
  32. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/__init__.py +0 -0
  33. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/admin.py +0 -0
  34. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/assessments.py +0 -0
  35. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/auth.py +0 -0
  36. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/datasets.py +0 -0
  37. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/deployments.py +0 -0
  38. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/evals.py +0 -0
  39. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/login.py +0 -0
  40. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/optimizations.py +0 -0
  41. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/org.py +0 -0
  42. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/programs.py +0 -0
  43. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/provider_credentials.py +0 -0
  44. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/tool_servers.py +0 -0
  45. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/top.py +0 -0
  46. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/traces.py +0 -0
  47. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/commands/valsets.py +0 -0
  48. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/credentials.py +0 -0
  49. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/deprecation.py +0 -0
  50. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/pagination.py +0 -0
  51. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/shell.py +0 -0
  52. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/trace_render.py +0 -0
  53. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/tree_help.py +0 -0
  54. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/verbs.py +0 -0
  55. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/cli/views.py +0 -0
  56. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/client.py +0 -0
  57. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/configuration.py +0 -0
  58. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/context.py +0 -0
  59. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/credentials.py +0 -0
  60. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/dataset_sync.py +0 -0
  61. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/datasets.py +0 -0
  62. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/decorators.py +0 -0
  63. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/deployment.py +0 -0
  64. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/deployment_metadata.py +0 -0
  65. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/deployment_runs.py +0 -0
  66. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/eval_handler.py +0 -0
  67. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/execution.py +0 -0
  68. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/exporter.py +0 -0
  69. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/exporter_http.py +0 -0
  70. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/helpers.py +0 -0
  71. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/identity.py +0 -0
  72. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/imaging.py +0 -0
  73. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/__init__.py +0 -0
  74. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/decode.py +0 -0
  75. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/encode.py +0 -0
  76. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/hash.py +0 -0
  77. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/program.py +0 -0
  78. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/reflection.py +0 -0
  79. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/types.py +0 -0
  80. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/ir/xxh64.py +0 -0
  81. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/lm_configuration.py +0 -0
  82. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/mcp_servers.py +0 -0
  83. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/models.py +0 -0
  84. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/named_programs.py +0 -0
  85. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/optimization.py +0 -0
  86. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/optimizers/__init__.py +0 -0
  87. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/optimizers/gepa.py +0 -0
  88. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/optimizers/gepa_callback.py +0 -0
  89. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/optimizers/resume.py +0 -0
  90. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/optimizers/tracker.py +0 -0
  91. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/packaging.py +0 -0
  92. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/program_naming.py +0 -0
  93. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/programs.py +0 -0
  94. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/references.py +0 -0
  95. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/retry.py +0 -0
  96. {cmpnd-0.85.0 → cmpnd-0.85.1}/cmpnd/traces.py +0 -0
  97. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/2026-04-02-code-review.md +0 -0
  98. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/cli.md +0 -0
  99. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/client.md +0 -0
  100. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/custom-proposer.md +0 -0
  101. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  102. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  103. {cmpnd-0.85.0 → cmpnd-0.85.1}/docs/reading-traces.md +0 -0
  104. {cmpnd-0.85.0 → cmpnd-0.85.1}/examples/generalizing_proposer.py +0 -0
  105. {cmpnd-0.85.0 → cmpnd-0.85.1}/examples/local_ollama.py +0 -0
  106. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/LINEAGE.md +0 -0
  107. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/README.md +0 -0
  108. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/__init__.py +0 -0
  109. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/bodies.py +0 -0
  110. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/client_floor.py +0 -0
  111. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/program_names.py +0 -0
  112. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/protocols.py +0 -0
  113. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/py.typed +0 -0
  114. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/request_log.py +0 -0
  115. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/retry.py +0 -0
  116. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/span_context.py +0 -0
  117. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  118. {cmpnd-0.85.0 → cmpnd-0.85.1}/ingest/pyproject.toml +0 -0
  119. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/audit-sdist.sh +0 -0
  120. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/capture_review_run.py +0 -0
  121. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/check-pip-install.sh +0 -0
  122. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/check_release_artifacts.py +0 -0
  123. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/fixtures/review_run.json.gz +0 -0
  124. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/gepa_resume_bug.py +0 -0
  125. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/install-test-env.sh +0 -0
  126. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/release-gate.sh +0 -0
  127. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/release-real-models.sh +0 -0
  128. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/require_version_bump.py +0 -0
  129. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/selfhost_compat.py +0 -0
  130. {cmpnd-0.85.0 → cmpnd-0.85.1}/scripts/test-in-linux.sh +0 -0
  131. {cmpnd-0.85.0 → cmpnd-0.85.1}/stubs/dspy/__init__.pyi +0 -0
  132. {cmpnd-0.85.0 → cmpnd-0.85.1}/stubs/dspy/primitives/__init__.pyi +0 -0
  133. {cmpnd-0.85.0 → cmpnd-0.85.1}/stubs/dspy/primitives/prediction.pyi +0 -0
  134. {cmpnd-0.85.0 → cmpnd-0.85.1}/stubs/dspy/utils/__init__.pyi +0 -0
  135. {cmpnd-0.85.0 → cmpnd-0.85.1}/stubs/dspy/utils/callback.pyi +0 -0
  136. {cmpnd-0.85.0 → cmpnd-0.85.1}/stubs/dspy/utils/dummies.pyi +0 -0
  137. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/__init__.py +0 -0
  138. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_credential_route.py +0 -0
  139. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_deployment_signature_helpers.py +0 -0
  140. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_exporter_helpers.py +0 -0
  141. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_fake_clock.py +0 -0
  142. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_identity_helpers.py +0 -0
  143. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_resolve_refs.py +0 -0
  144. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/_traced_run.py +0 -0
  145. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/conftest.py +0 -0
  146. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/__init__.py +0 -0
  147. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/committee_task.py +0 -0
  148. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/conftest.py +0 -0
  149. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/continuation_task.py +0 -0
  150. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  151. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  152. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/fake_lm.py +0 -0
  153. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/helpers.py +0 -0
  154. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/target_capabilities.py +0 -0
  155. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_assessments_cli.py +0 -0
  156. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_capture_prompts.py +0 -0
  157. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_composite_module.py +0 -0
  158. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_dataset_auto_creation.py +0 -0
  159. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_deploy_execute.py +0 -0
  160. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_deploy_pandas.py +0 -0
  161. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_deploy_programs.py +0 -0
  162. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_edge_cases.py +0 -0
  163. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_example_hash.py +0 -0
  164. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_gepa_optimization.py +0 -0
  165. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_interpreter_spans.py +0 -0
  166. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_lm_accuracy.py +0 -0
  167. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_module_tracing.py +0 -0
  168. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimization_lineage.py +0 -0
  169. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimization_metric_identity.py +0 -0
  170. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_authored_metric.py +0 -0
  171. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_continuation.py +0 -0
  172. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_custom_proposer.py +0 -0
  173. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_failures.py +0 -0
  174. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_loop.py +0 -0
  175. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_review_committee.py +0 -0
  176. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  177. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_parallel_export.py +0 -0
  178. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_react_tool_spans.py +0 -0
  179. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_save_load.py +0 -0
  180. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_trace_structure.py +0 -0
  181. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_user_attribution.py +0 -0
  182. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/e2e/test_valsets_cli.py +0 -0
  183. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/01_predict_qa.json +0 -0
  184. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  185. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  186. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  187. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  188. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  189. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/07_program_of_thought.json +0 -0
  190. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/08_opaque_module.json +0 -0
  191. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  192. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/10_react.json +0 -0
  193. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/11_refine.json +0 -0
  194. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/12_retrieve.json +0 -0
  195. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/13_knn.json +0 -0
  196. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/14_parallel.json +0 -0
  197. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/identity_vectors/README.md +0 -0
  198. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/ingest_conformance.py +0 -0
  199. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/__init__.py +0 -0
  200. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/authored_optimize/judge.py +0 -0
  201. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  202. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/conftest.py +0 -0
  203. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  204. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/hosted_optimize_probe.py +0 -0
  205. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/optimization_run_probe.py +0 -0
  206. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  207. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/test_logs_renders_traces.py +0 -0
  208. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/test_optimization_run.py +0 -0
  209. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/test_optimizing_progress.py +0 -0
  210. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/integration/test_unhappy_path.py +0 -0
  211. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/lm15_prompt_fixture.py +0 -0
  212. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/lm15_prompts/four_turn_predict.json +0 -0
  213. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/lm15_prompts/rlm_six_turns.json +0 -0
  214. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/__init__.py +0 -0
  215. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/__main__.py +0 -0
  216. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/drain.py +0 -0
  217. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/ingest.py +0 -0
  218. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/latency_transport.py +0 -0
  219. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/rlm_shape.py +0 -0
  220. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/rlm_size_report.py +0 -0
  221. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/sweep.py +0 -0
  222. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/test_rlm_shape.py +0 -0
  223. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/load/test_rlm_size_report.py +0 -0
  224. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/__init__.py +0 -0
  225. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/conftest.py +0 -0
  226. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/seed_parity.py +0 -0
  227. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_auth.py +0 -0
  228. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_datasets.py +0 -0
  229. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_deployments.py +0 -0
  230. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_evals.py +0 -0
  231. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_health.py +0 -0
  232. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_modules.py +0 -0
  233. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_optimizations.py +0 -0
  234. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_programs.py +0 -0
  235. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_signatures.py +0 -0
  236. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_trace_streaming.py +0 -0
  237. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/parity/test_traces.py +0 -0
  238. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/__init__.py +0 -0
  239. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/_provider.py +0 -0
  240. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/_readiness.py +0 -0
  241. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/_reliability.py +0 -0
  242. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/_result.py +0 -0
  243. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/mint_bedrock_token.py +0 -0
  244. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_bedrock_converse.py +0 -0
  245. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_deploy_programs.py +0 -0
  246. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_multi_client_stress.py +0 -0
  247. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_optimize_client_committee.py +0 -0
  248. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_optimize_continuation.py +0 -0
  249. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_optimize_loop.py +0 -0
  250. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_optimize_loop_wasm.py +0 -0
  251. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_optimize_stress.py +0 -0
  252. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_provider_roles.py +0 -0
  253. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_readiness.py +0 -0
  254. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_real_provider_twins.py +0 -0
  255. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_reliability.py +0 -0
  256. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_reliability_classify.py +0 -0
  257. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/real_models/test_rlm_wasm.py +0 -0
  258. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/span_reference_fixture.py +0 -0
  259. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_adapter_reentrancy.py +0 -0
  260. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_assessments_api.py +0 -0
  261. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_authored.py +0 -0
  262. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_authored_binding_credentials.py +0 -0
  263. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_authored_bundle_collisions.py +0 -0
  264. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_authored_metric_contract.py +0 -0
  265. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_authored_named_models.py +0 -0
  266. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_authored_optimize.py +0 -0
  267. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_callback.py +0 -0
  268. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_candidate_lineage.py +0 -0
  269. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/__init__.py +0 -0
  270. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/conftest.py +0 -0
  271. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_admin.py +0 -0
  272. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_api_client.py +0 -0
  273. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_assessments.py +0 -0
  274. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_auth.py +0 -0
  275. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_credentials.py +0 -0
  276. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_datasets.py +0 -0
  277. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_deployment_runs.py +0 -0
  278. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_deployments.py +0 -0
  279. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_evals.py +0 -0
  280. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_login.py +0 -0
  281. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_main.py +0 -0
  282. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_optimizations.py +0 -0
  283. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_org.py +0 -0
  284. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_pagination.py +0 -0
  285. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_parity.py +0 -0
  286. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_programs.py +0 -0
  287. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_provider_credentials.py +0 -0
  288. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_schema_sample.py +0 -0
  289. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_shell.py +0 -0
  290. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_tool_servers.py +0 -0
  291. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_top.py +0 -0
  292. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_traces.py +0 -0
  293. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_traces_program_and_module.py +0 -0
  294. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_traces_search_wire.py +0 -0
  295. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_tree_help.py +0 -0
  296. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cli/test_valsets.py +0 -0
  297. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_client.py +0 -0
  298. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_client_floor.py +0 -0
  299. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_client_program_names.py +0 -0
  300. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_clustering/__init__.py +0 -0
  301. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_clustering/conftest.py +0 -0
  302. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_clustering/test_edge_cases.py +0 -0
  303. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_clustering/test_hash_consistency.py +0 -0
  304. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_clustering/test_type_conversion.py +0 -0
  305. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_cmp551_grouping_identity.py +0 -0
  306. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_configuration.py +0 -0
  307. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_context.py +0 -0
  308. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_context_propagation.py +0 -0
  309. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_credential_kwargs.py +0 -0
  310. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_credential_selection.py +0 -0
  311. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_credential_values.py +0 -0
  312. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_dataset_polling.py +0 -0
  313. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_dataset_sync.py +0 -0
  314. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_datasets.py +0 -0
  315. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_decision_client_spans.py +0 -0
  316. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_decorators.py +0 -0
  317. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_deploy.py +0 -0
  318. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_deploy_mcp_tool_references.py +0 -0
  319. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_deploy_program_id.py +0 -0
  320. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_deployment_metadata.py +0 -0
  321. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_deployment_runs.py +0 -0
  322. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_deployments_read.py +0 -0
  323. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_eval.py +0 -0
  324. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_eval_example_attribution.py +0 -0
  325. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_eval_program_id.py +0 -0
  326. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_eval_start.py +0 -0
  327. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_eval_trace_grouping.py +0 -0
  328. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_exception_paths.py +0 -0
  329. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_execute.py +0 -0
  330. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_execute_run_identity.py +0 -0
  331. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_exporter_program_names.py +0 -0
  332. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_exporter_queue.py +0 -0
  333. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_exporter_real.py +0 -0
  334. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_fake_lm.py +0 -0
  335. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_gepa_callback.py +0 -0
  336. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_gepa_integration.py +0 -0
  337. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_gepa_output_normalization.py +0 -0
  338. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_gepa_resume.py +0 -0
  339. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_identity.py +0 -0
  340. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_imaging.py +0 -0
  341. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_import_weight.py +0 -0
  342. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_ingest_conformance.py +0 -0
  343. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_ingest_second_producer.py +0 -0
  344. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_integration.py +0 -0
  345. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_interpreter_callback.py +0 -0
  346. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_ir_encoder_properties.py +0 -0
  347. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_ir_golden_vectors.py +0 -0
  348. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_ir_roundtrip.py +0 -0
  349. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_lm15_native_calls.py +0 -0
  350. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_lm15_prompt_fixtures.py +0 -0
  351. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_lm15_prompt_references.py +0 -0
  352. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_lm_configuration.py +0 -0
  353. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_lm_usage_shapes.py +0 -0
  354. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_mcp_tools.py +0 -0
  355. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_models.py +0 -0
  356. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_multi_client_stress_readiness.py +0 -0
  357. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_no_signature_hash_on_the_wire.py +0 -0
  358. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimization_phase_callback.py +0 -0
  359. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimization_program_names.py +0 -0
  360. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimization_progress.py +0 -0
  361. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimization_start.py +0 -0
  362. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize.py +0 -0
  363. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize_budget.py +0 -0
  364. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize_lift.py +0 -0
  365. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize_lms.py +0 -0
  366. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize_proposer.py +0 -0
  367. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize_reflection_lm.py +0 -0
  368. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_optimize_terminal_failure.py +0 -0
  369. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_packaging.py +0 -0
  370. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_packaging_callable_source.py +0 -0
  371. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_packaging_mcp_tools.py +0 -0
  372. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_packaging_program_source.py +0 -0
  373. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_poll_until.py +0 -0
  374. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_program_id_deprecation.py +0 -0
  375. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_program_identity.py +0 -0
  376. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_program_lineage_persist.py +0 -0
  377. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_program_names_in_deploy.py +0 -0
  378. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_program_naming.py +0 -0
  379. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_programs_create.py +0 -0
  380. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_project_payload.py +0 -0
  381. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_real_provider_twins_readiness.py +0 -0
  382. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_reflector_properties.py +0 -0
  383. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_reflector_smoke.py +0 -0
  384. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_release_gate_script.py +0 -0
  385. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_release_real_models_script.py +0 -0
  386. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_replaced_names.py +0 -0
  387. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_repro_reactv2_bugs.py +0 -0
  388. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_require_version_bump.py +0 -0
  389. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_retry.py +0 -0
  390. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_reversible_failures.py +0 -0
  391. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_rlm_patch.py +0 -0
  392. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_run_attribution_paths.py +0 -0
  393. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_runtime_tools.py +0 -0
  394. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_schemas.py +0 -0
  395. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_seal_lm_credential.py +0 -0
  396. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_seed_review_run.py +0 -0
  397. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_signature_inputs.py +0 -0
  398. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_span_references.py +0 -0
  399. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_span_sent_once.py +0 -0
  400. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_span_submission.py +0 -0
  401. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_span_submission_wire_contract.py +0 -0
  402. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_system_one.py +0 -0
  403. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_trace_context_concurrency.py +0 -0
  404. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_trace_fact_wire_contract.py +0 -0
  405. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_trace_facts.py +0 -0
  406. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_trace_render.py +0 -0
  407. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_traces_read.py +0 -0
  408. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_tracked_gepa.py +0 -0
  409. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_tracker_enrich.py +0 -0
  410. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_truncation.py +0 -0
  411. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_upload_auth_headers.py +0 -0
  412. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_valsets_api.py +0 -0
  413. {cmpnd-0.85.0 → cmpnd-0.85.1}/tests/test_xxh64.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cmpnd
3
- Version: 0.85.0
3
+ Version: 0.85.1
4
4
  Summary: DSPy observability and deployment SDK for cmpnd
5
5
  Project-URL: Homepage, https://cmpnd.ai
6
6
  Author-email: cmpnd <hello@cmpnd.ai>
@@ -331,6 +331,18 @@ Each `_send_*` method routes a failed delivery to one of two counters: a `429` (
331
331
 
332
332
  Tolerating is never silent. A send that recovered logs a warning naming what it rode through (`rode through 3 transient responses over 12.4s (503=3) to POST /api/v1/traces`), and an exhausted budget raises `ExportRetriesExhausted` with the same count and window in its message. `BatchExporter.failure_summary()` reports the distribution of non-2xx statuses observed, how many transient answers were ridden through, and a sample error body — that's what the stress lane prints when it fails, so a red lane says *what* the wire answered rather than only how many errors there were.
333
333
 
334
+ Trace delivery failures log at ERROR on `cmpnd.exporter`. The message names the
335
+ operation and the number of records the exporter will not resend. HTTP failures
336
+ include the status, route and serve's string `error`, `error_code`, `upgrade` and
337
+ `field` values when present. The exporter bounds each value and escapes control
338
+ characters. It omits other body fields and non-JSON responses. Exhausted retries
339
+ include the last server message as well as the attempt count and elapsed time.
340
+
341
+ A non-retryable 422 discards the submission. Upgrade the SDK when serve asks for
342
+ it, then emit fresh telemetry. An upgrade cannot recover discarded records.
343
+ Background failures keep the application running and increment the existing
344
+ error counters. They do not raise an exception in the instrumented program.
345
+
334
346
  ### The retryable-error contract
335
347
 
336
348
  The server tells a client when a failed write is worth re-sending, in three signals carrying one fact:
@@ -59,6 +59,31 @@ logger = logging.getLogger("cmpnd.exporter")
59
59
  _GZIP_HEADERS = {"Content-Encoding": "gzip"}
60
60
 
61
61
 
62
+ def _export_error_detail(exc: Exception) -> str:
63
+ """Keep delivery errors useful in background logs without dumping response bodies."""
64
+
65
+ def text(value: str, limit: int = 300) -> str:
66
+ return json.dumps(value[:limit], ensure_ascii=True)[1:-1]
67
+
68
+ cause = exc.__cause__ if isinstance(exc, ExportRetriesExhausted) else exc
69
+ if not isinstance(cause, httpx.HTTPStatusError):
70
+ return text(str(exc), 600)
71
+ response = cause.response
72
+ detail = f"HTTP {response.status_code} for {cause.request.method} {cause.request.url.path}"
73
+ if cause is not exc:
74
+ detail = f"{text(str(exc), 600)}; {detail}"
75
+ try:
76
+ body = response.json()
77
+ except (ValueError, httpx.ResponseNotRead):
78
+ return detail
79
+ if isinstance(body, dict):
80
+ for key in ("error", "error_code", "upgrade", "field"):
81
+ value = body.get(key)
82
+ if isinstance(value, str) and value:
83
+ detail += f"; {key}={text(value)}"
84
+ return detail
85
+
86
+
62
87
  def _send_json(client: httpx.Client, method: str, path: str, payload: Any) -> httpx.Response:
63
88
  """POST/PATCH/PUT ``payload`` as gzipped JSON.
64
89
 
@@ -1581,15 +1606,30 @@ class BatchExporter:
1581
1606
  # drop call for opposite responses from the caller.
1582
1607
  self._record_drop("trace", "server_shed", count=len(traces_to_send), log=False)
1583
1608
  else:
1584
- logger.error(f"Failed to export traces batch: {e}")
1609
+ logger.error(
1610
+ "Failed to export traces batch. Records will not be resent (count=%s, traces=%s, spans=%s): %s",
1611
+ len(traces_to_send) + total_spans,
1612
+ len(traces_to_send),
1613
+ total_spans,
1614
+ _export_error_detail(e),
1615
+ )
1585
1616
  with self._stats_lock:
1586
1617
  self._error_count += len(traces_to_send)
1587
1618
  except Exception as e:
1588
- logger.error(f"Failed to export traces batch: {e}")
1619
+ logger.error(
1620
+ "Failed to export traces batch. Records will not be resent (count=%s, traces=%s, spans=%s): %s",
1621
+ len(traces_to_send) + total_spans,
1622
+ len(traces_to_send),
1623
+ total_spans,
1624
+ _export_error_detail(e),
1625
+ )
1589
1626
  with self._stats_lock:
1590
1627
  self._error_count += len(traces_to_send)
1591
1628
 
1592
1629
  def _send_encoded_trace(self, trace: EncodedTraceBody) -> None:
1630
+ # The body stays compressed end to end, so the exporter never learns how
1631
+ # many spans it embeds. A failure names the one trace and says the span
1632
+ # count is unknown, rather than understating the loss as one record.
1593
1633
  client = self._require_client()
1594
1634
  try:
1595
1635
  self._send_retrying(
@@ -1601,11 +1641,19 @@ class BatchExporter:
1601
1641
  if e.response.status_code == 429:
1602
1642
  self._record_drop("trace", "server_shed", count=1)
1603
1643
  else:
1604
- logger.error(f"Failed to export encoded trace {trace.trace_id}: {e}")
1644
+ logger.error(
1645
+ "Failed to export encoded trace %s. Records will not be resent (traces=1, spans=unknown): %s",
1646
+ trace.trace_id,
1647
+ _export_error_detail(e),
1648
+ )
1605
1649
  with self._stats_lock:
1606
1650
  self._error_count += 1
1607
1651
  except Exception as e:
1608
- logger.error(f"Failed to export encoded trace {trace.trace_id}: {e}")
1652
+ logger.error(
1653
+ "Failed to export encoded trace %s. Records will not be resent (traces=1, spans=unknown): %s",
1654
+ trace.trace_id,
1655
+ _export_error_detail(e),
1656
+ )
1609
1657
  with self._stats_lock:
1610
1658
  self._error_count += 1
1611
1659
 
@@ -1619,7 +1667,11 @@ class BatchExporter:
1619
1667
  self._exported_count += 1
1620
1668
  logger.debug(f"Started trace {trace_id}")
1621
1669
  except Exception as e:
1622
- logger.error(f"Failed to start trace {trace_id}: {e}")
1670
+ logger.error(
1671
+ "Failed to start trace %s. Records will not be resent (count=1): %s",
1672
+ trace_id,
1673
+ _export_error_detail(e),
1674
+ )
1623
1675
  with self._stats_lock:
1624
1676
  self._error_count += 1
1625
1677
 
@@ -1651,7 +1703,12 @@ class BatchExporter:
1651
1703
  self._exported_count += len(span_list)
1652
1704
  logger.debug(f"Exported {len(span_list)} spans for trace {trace_id}")
1653
1705
  except Exception as e:
1654
- logger.error(f"Failed to export spans for trace {trace_id}: {e}")
1706
+ logger.error(
1707
+ "Failed to export spans for trace %s. Records will not be resent (count=%s): %s",
1708
+ trace_id,
1709
+ len(span_list),
1710
+ _export_error_detail(e),
1711
+ )
1655
1712
  with self._stats_lock:
1656
1713
  self._error_count += len(span_list)
1657
1714
 
@@ -1667,7 +1724,11 @@ class BatchExporter:
1667
1724
  self._exported_count += 1
1668
1725
  logger.debug(f"Finalized trace {trace_id}")
1669
1726
  except Exception as e:
1670
- logger.error(f"Failed to finalize trace {trace_id}: {e}")
1727
+ logger.error(
1728
+ "Failed to finalize trace %s. Records will not be resent (count=1): %s",
1729
+ trace_id,
1730
+ _export_error_detail(e),
1731
+ )
1671
1732
  with self._stats_lock:
1672
1733
  self._error_count += 1
1673
1734
 
@@ -5,7 +5,7 @@ name = "cmpnd"
5
5
  # it's new) — no git tags. Bump with `uv version --bump {minor,patch}` or by
6
6
  # hand. Runtime `cmpnd.__version__` reads installed metadata, so it tracks
7
7
  # this automatically. See docs/plans/2026-07-02-sdk-pypi-tag-free-publish.md.
8
- version = "0.85.0"
8
+ version = "0.85.1"
9
9
  description = "DSPy observability and deployment SDK for cmpnd"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.11"
@@ -46,11 +46,15 @@ import logging
46
46
  import os
47
47
  import pathlib
48
48
  import re
49
+ import sys
49
50
  import urllib.error
50
51
  import urllib.parse
51
52
  import urllib.request
52
53
  import uuid
53
54
 
55
+ # The captured fixtures already depend on this repository's serve scripts.
56
+ sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "serve" / "scripts" / "seed_fixtures"))
57
+
54
58
  logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
55
59
  log = logging.getLogger("seed_review_run")
56
60
 
@@ -673,6 +677,14 @@ def _ensure_program(endpoint: str, api_key: str, name: str) -> str | None:
673
677
 
674
678
 
675
679
  def _post(endpoint: str, path: str, payload, api_key: str, method: str = "POST"):
680
+ if path.startswith("/api/v1/traces"):
681
+ from submission import prepare_trace_submission
682
+
683
+ if path == "/api/v1/traces/batch":
684
+ for trace in payload:
685
+ prepare_trace_submission(trace)
686
+ elif path.startswith("/api/v1/traces/") and path.endswith("/spans"):
687
+ prepare_trace_submission(payload, path.split("/")[-2])
676
688
  body = json.dumps(payload).encode("utf-8")
677
689
  req = urllib.request.Request(
678
690
  endpoint + path,
@@ -680,9 +692,13 @@ def _post(endpoint: str, path: str, payload, api_key: str, method: str = "POST")
680
692
  method=method,
681
693
  headers={"Content-Type": "application/json", "X-API-Key": api_key},
682
694
  )
683
- with urllib.request.urlopen(req, timeout=30) as resp: # noqa: S310 - fixed https endpoint from env
684
- raw = resp.read()
685
- return resp.status, (json.loads(raw) if raw else {})
695
+ try:
696
+ with urllib.request.urlopen(req, timeout=30) as resp: # noqa: S310 - fixed https endpoint from env
697
+ raw = resp.read()
698
+ return resp.status, (json.loads(raw) if raw else {})
699
+ except urllib.error.HTTPError as exc:
700
+ detail = exc.read().decode("utf-8", "replace")[:400]
701
+ raise RuntimeError(f"{method} {path} returned HTTP {exc.code}: {detail!r}") from exc
686
702
 
687
703
 
688
704
  def _reserve_optimization(endpoint: str, api_key: str) -> str | None:
@@ -10,13 +10,11 @@ block so subsequent tests in the same pytest invocation are not affected.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- import datetime
14
13
  import uuid
15
14
  from collections.abc import Callable
16
15
  from typing import Any
17
16
 
18
17
  import dspy
19
- import httpx
20
18
  import pytest
21
19
 
22
20
  import cmpnd
@@ -121,77 +119,6 @@ def test_project_stamped_on_trace_and_spans(server_client, trace_capture):
121
119
  _restore_session_config()
122
120
 
123
121
 
124
- def test_streaming_spans_inherit_full_project_tags(server_client):
125
- """Spans added via the streaming path (POST /traces/:id/spans) inherit all
126
- project_tags from the parent trace, not just the first tag.
127
-
128
- This bypasses the SDK exporter and calls the API directly to simulate
129
- an old SDK that sends project but not project_tags on spans. Serve must
130
- preserve both tags from the parent trace.
131
- """
132
- trace_id = str(uuid.uuid4())
133
- tag_a = f"e2e-stream-a-{uuid.uuid4().hex[:8]}"
134
- tag_b = f"e2e-stream-b-{uuid.uuid4().hex[:8]}"
135
- now = datetime.datetime.now(datetime.timezone.utc).isoformat()
136
- headers = {
137
- "X-API-Key": CMPND_E2E_API_KEY or "",
138
- "Content-Type": "application/json",
139
- }
140
-
141
- # 1. Start trace with two tags
142
- start_resp = httpx.post(
143
- f"{E2E_ENDPOINT}/api/v1/traces/{trace_id}/start",
144
- headers=headers,
145
- json={
146
- "module_class": "StreamTest",
147
- "start_time": now,
148
- "project": tag_a,
149
- "project_tags": [tag_a, tag_b],
150
- },
151
- timeout=30.0,
152
- )
153
- assert start_resp.status_code == 202, f"start_trace failed: {start_resp.status_code} {start_resp.text}"
154
-
155
- # 2. Add a span WITHOUT project_tags — simulates old SDK behavior
156
- span_id = str(uuid.uuid4())
157
- spans_resp = httpx.post(
158
- f"{E2E_ENDPOINT}/api/v1/traces/{trace_id}/spans",
159
- headers=headers,
160
- json={
161
- "spans": [
162
- {
163
- "span_id": span_id,
164
- "trace_id": trace_id,
165
- "name": "predict",
166
- "span_type": "predict",
167
- "start_time": now,
168
- "end_time": now,
169
- # project and project_tags intentionally omitted
170
- }
171
- ]
172
- },
173
- timeout=30.0,
174
- )
175
- assert spans_resp.status_code == 200, f"add_spans failed: {spans_resp.status_code} {spans_resp.text}"
176
-
177
- # 3. Poll for ingestion, then fetch the trace. The trace row and its spans
178
- # become visible independently and asynchronously. Read the endpoint
179
- # directly to keep the wait bounded by one retry loop (CMP-843).
180
- def _spans():
181
- resp = server_client._client.get(f"/api/v1/traces/{trace_id}")
182
- return resp.json().get("spans", []) if resp.status_code == 200 else []
183
-
184
- spans = poll_until(_spans, timeout=60.0, interval=3.0)
185
-
186
- assert spans, "trace has no spans after streaming add"
187
- for span in spans:
188
- span_tags = span.get("project_tags", [])
189
- assert tag_a in span_tags and tag_b in span_tags, (
190
- f"span {span.get('span_id')} should inherit both tags from trace, "
191
- f"got {span_tags!r} — expected {[tag_a, tag_b]!r}"
192
- )
193
-
194
-
195
122
  def test_project_null_when_unset(server_client, trace_capture):
196
123
  """Without configure(project=...), the trace and spans land with NULL project."""
197
124
  try:
@@ -29,7 +29,9 @@ class TestTracesReadE2E:
29
29
  trace_id = trace_capture.last_trace_id
30
30
  assert trace_id is not None, "no trace captured"
31
31
 
32
- # Detail reads the ingested source without waiting for collection projection.
32
+ # Trace headers and spans publish independently. Wait until both are visible
33
+ # before checking the SDK's detail read.
34
+ server_client.get_trace(trace_id)
33
35
  detail = cmpnd.traces.show(trace_id, api_key=CMPND_E2E_API_KEY, endpoint=E2E_ENDPOINT)
34
36
  assert detail["trace"]["trace_id"] == trace_id
35
37
  assert isinstance(detail["spans"], list)
@@ -78,8 +78,11 @@ def test_cross_trace_q_search_finds_the_span_token():
78
78
 
79
79
  # One trace, one span whose name carries the unique token. The write path
80
80
  # indexes that name in the span transaction, and the read below waits for
81
- # the projected search collection to publish it.
81
+ # the projected search collection to publish it. Both records are
82
+ # self-contained submissions: each declares its schema version, and the span
83
+ # carries its own tags rather than inheriting the trace's.
82
84
  trace = {
85
+ "schema_version": 1,
83
86
  "trace_id": trace_id,
84
87
  "start_time": _iso(),
85
88
  "end_time": _iso(),
@@ -89,8 +92,11 @@ def test_cross_trace_q_search_finds_the_span_token():
89
92
  "span_count": 1,
90
93
  "spans": [
91
94
  {
95
+ "schema_version": 1,
92
96
  "span_id": span_id,
93
97
  "trace_id": trace_id,
98
+ "project_tags": [tag],
99
+ "tags": {},
94
100
  "name": token,
95
101
  "span_type": "tool",
96
102
  "start_time": _iso(),
@@ -14,6 +14,7 @@ from uuid import uuid4
14
14
 
15
15
  import httpx
16
16
  import pytest
17
+ from cmpnd_ingest.bodies import EncodedTraceBody
17
18
 
18
19
  from cmpnd import retry
19
20
  from cmpnd.configuration import Config
@@ -1179,3 +1180,125 @@ def test_failure_summary_is_quiet_when_nothing_failed():
1179
1180
  exporter._flush_batch([ExportItem(item_type="trace", data=_make_trace(), timestamp=0.0)])
1180
1181
 
1181
1182
  assert "no non-2xx" in exporter.failure_summary()
1183
+
1184
+
1185
+ @pytest.mark.parametrize(
1186
+ "kind,count",
1187
+ [("trace", 1), ("trace", 2), ("trace_start", 1), ("span", 2), ("trace_finalize", 1), ("encoded_trace", 1)],
1188
+ )
1189
+ def test_trace_rejection_logs_server_guidance_and_delivery_loss(kind, count, caplog):
1190
+ body = {
1191
+ "error": "schema_version must be 1",
1192
+ "error_code": "trace_submission_contract",
1193
+ "field": "schema_version",
1194
+ "upgrade": "Upgrade with uv add cmpnd --upgrade",
1195
+ "retryable": False,
1196
+ "unrelated": "private response detail",
1197
+ }
1198
+ capture = ContractCapture([(422, body, {})])
1199
+ exporter = _make_seq_exporter(capture)
1200
+ tid = uuid4()
1201
+ batch = []
1202
+ for _ in range(count):
1203
+ data = (
1204
+ _make_span(trace_id=tid)
1205
+ if kind == "span"
1206
+ else EncodedTraceBody(str(tid), "gzip", gzip.compress(b"{}"))
1207
+ if kind == "encoded_trace"
1208
+ else _make_trace()
1209
+ )
1210
+ batch.append(ExportItem(item_type=kind, data=data, timestamp=0.0))
1211
+ try:
1212
+ with caplog.at_level(logging.ERROR, logger="cmpnd.exporter"):
1213
+ exporter._flush_batch(batch)
1214
+ assert len(capture.requests) == 1
1215
+ assert exporter._error_count == count
1216
+ assert exporter._exported_count == 0
1217
+ assert "422" in caplog.text
1218
+ assert "schema_version must be 1" in caplog.text
1219
+ assert "trace_submission_contract" in caplog.text
1220
+ assert "Upgrade with uv add cmpnd --upgrade" in caplog.text
1221
+ if kind == "encoded_trace":
1222
+ # The exporter never inflates an encoded trace, so it cannot count the
1223
+ # spans the trace embeds and must not report the trace as one record.
1224
+ assert "traces=1, spans=unknown" in caplog.text
1225
+ assert "count=" not in caplog.text
1226
+ else:
1227
+ assert f"count={count}" in caplog.text
1228
+ assert "Records will not be resent" in caplog.text
1229
+ assert "private response detail" not in caplog.text
1230
+ finally:
1231
+ exporter.shutdown()
1232
+
1233
+
1234
+ @pytest.mark.parametrize(
1235
+ "body", [[], {"error": {"secret": "private response detail"}}, {"error": "bad\nforged log\r\x1b[31m" + "x" * 5000}]
1236
+ )
1237
+ def test_trace_rejection_handles_unexpected_or_long_error_bodies(body, caplog):
1238
+ requests = []
1239
+
1240
+ def handle(request):
1241
+ requests.append(request)
1242
+ return httpx.Response(400, json=body)
1243
+
1244
+ exporter = _make_exporter(RequestCapture())
1245
+ exporter._client = httpx.Client(base_url=_make_config().endpoint, transport=httpx.MockTransport(handle))
1246
+ try:
1247
+ with caplog.at_level(logging.ERROR, logger="cmpnd.exporter"):
1248
+ exporter._flush_batch([ExportItem(item_type="trace", data=_make_trace(), timestamp=0.0)])
1249
+ messages = [r.getMessage() for r in caplog.records if r.levelno == logging.ERROR]
1250
+ assert len(requests) == 1
1251
+ assert len(messages) == 1
1252
+ assert "400" in messages[0]
1253
+ assert "count=1" in messages[0]
1254
+ assert len(messages[0]) < 2000
1255
+ assert "private response detail" not in messages[0]
1256
+ assert "\nforged log" not in messages[0]
1257
+ assert "\x1b" not in messages[0]
1258
+ finally:
1259
+ exporter.shutdown()
1260
+
1261
+
1262
+ def test_trace_rejection_handles_non_json_response(caplog):
1263
+ exporter = _make_exporter(RequestCapture())
1264
+ exporter._client = httpx.Client(
1265
+ base_url=_make_config().endpoint,
1266
+ transport=httpx.MockTransport(lambda _: httpx.Response(413, text="<html>private response detail</html>")),
1267
+ )
1268
+ try:
1269
+ with caplog.at_level(logging.ERROR, logger="cmpnd.exporter"):
1270
+ exporter._flush_batch([ExportItem(item_type="trace", data=_make_trace(), timestamp=0.0)])
1271
+ assert "413" in caplog.text
1272
+ assert "count=1" in caplog.text
1273
+ assert "private response detail" not in caplog.text
1274
+ finally:
1275
+ exporter.shutdown()
1276
+
1277
+
1278
+ def test_retry_exhaustion_logs_last_server_message(caplog):
1279
+ capture = ContractCapture([(503, {"error": "database temporarily unavailable", "retryable": True}, {})])
1280
+ exporter = _make_seq_exporter(capture)
1281
+ try:
1282
+ with caplog.at_level(logging.ERROR, logger="cmpnd.exporter"):
1283
+ exporter._flush_batch([ExportItem(item_type="trace", data=_make_trace(), timestamp=0.0)])
1284
+ assert len(capture.requests) == retry.MAX_ATTEMPTS
1285
+ assert "database temporarily unavailable" in caplog.text
1286
+ assert "transient responses over" in caplog.text
1287
+ assert "count=1" in caplog.text
1288
+ finally:
1289
+ exporter.shutdown()
1290
+
1291
+
1292
+ def test_rejected_full_trace_logs_embedded_span_loss(caplog):
1293
+ capture = ContractCapture([(422, {"error": "invalid span", "retryable": False}, {})])
1294
+ exporter = _make_seq_exporter(capture)
1295
+ payload = _make_trace().to_api_dict()
1296
+ payload["spans"] = [_make_span().to_api_dict(), _make_span().to_api_dict()]
1297
+ try:
1298
+ with caplog.at_level(logging.ERROR, logger="cmpnd.exporter"):
1299
+ exporter._send_traces([payload])
1300
+ assert "count=3, traces=1, spans=2" in caplog.text
1301
+ assert exporter._exported_count == 0
1302
+ assert len(capture.requests) == 1
1303
+ finally:
1304
+ exporter.shutdown()
@@ -505,7 +505,7 @@ wheels = [
505
505
 
506
506
  [[package]]
507
507
  name = "cmpnd"
508
- version = "0.85.0"
508
+ version = "0.85.1"
509
509
  source = { editable = "." }
510
510
  default-groups = ["dspy-3-4-1"]
511
511
  dependencies = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes