cmpnd 0.69.0__tar.gz → 0.71.0__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 (400) hide show
  1. {cmpnd-0.69.0 → cmpnd-0.71.0}/PKG-INFO +1 -1
  2. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/__init__.py +2 -9
  3. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/admin.py +1 -2
  4. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/evals.py +13 -1
  5. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/client.py +10 -23
  6. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/dataset_sync.py +8 -5
  7. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/eval_handler.py +35 -9
  8. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/models.py +13 -3
  9. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/cli.md +14 -7
  10. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/client.md +2 -7
  11. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/sdk-instrumentation.md +2 -0
  12. {cmpnd-0.69.0 → cmpnd-0.71.0}/pyproject.toml +1 -1
  13. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_evals.py +16 -2
  14. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_main.py +22 -0
  15. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_parity.py +10 -5
  16. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_client.py +27 -16
  17. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_client_program_names.py +0 -2
  18. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval.py +1 -1
  19. cmpnd-0.71.0/tests/test_eval_program_id.py +192 -0
  20. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval_start.py +2 -2
  21. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ingest_conformance.py +2 -1
  22. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_id_deprecation.py +0 -1
  23. {cmpnd-0.69.0 → cmpnd-0.71.0}/uv.lock +1 -1
  24. {cmpnd-0.69.0 → cmpnd-0.71.0}/.gitignore +0 -0
  25. {cmpnd-0.69.0 → cmpnd-0.71.0}/AGENTS.md +0 -0
  26. {cmpnd-0.69.0 → cmpnd-0.71.0}/CLAUDE.md +0 -0
  27. {cmpnd-0.69.0 → cmpnd-0.71.0}/README.md +0 -0
  28. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/__init__.py +0 -0
  29. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_assessments.py +0 -0
  30. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_authored_import.py +0 -0
  31. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_deployments.py +0 -0
  32. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_exporter_pool.py +0 -0
  33. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_gepa_patch.py +0 -0
  34. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_http.py +0 -0
  35. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_program_patch.py +0 -0
  36. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_rlm_patch.py +0 -0
  37. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_runtime_tools.py +0 -0
  38. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_timespec.py +0 -0
  39. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_traces.py +0 -0
  40. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/_valsets.py +0 -0
  41. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/authored.py +0 -0
  42. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/callback.py +0 -0
  43. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/api_client.py +0 -0
  44. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/__init__.py +0 -0
  45. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/assessments.py +0 -0
  46. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/auth.py +0 -0
  47. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/datasets.py +0 -0
  48. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/deployments.py +0 -0
  49. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/login.py +0 -0
  50. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/optimizations.py +0 -0
  51. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/org.py +0 -0
  52. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/programs.py +0 -0
  53. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/provider_credentials.py +0 -0
  54. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/tool_servers.py +0 -0
  55. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/top.py +0 -0
  56. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/traces.py +0 -0
  57. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/commands/valsets.py +0 -0
  58. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/credentials.py +0 -0
  59. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/deprecation.py +0 -0
  60. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/pagination.py +0 -0
  61. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/shell.py +0 -0
  62. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/trace_render.py +0 -0
  63. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/tree_help.py +0 -0
  64. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/verbs.py +0 -0
  65. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/cli/views.py +0 -0
  66. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/configuration.py +0 -0
  67. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/context.py +0 -0
  68. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/credentials.py +0 -0
  69. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/datasets.py +0 -0
  70. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/decorators.py +0 -0
  71. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/deployment.py +0 -0
  72. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/deployment_metadata.py +0 -0
  73. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/deployment_runs.py +0 -0
  74. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/execution.py +0 -0
  75. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/exporter.py +0 -0
  76. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/exporter_http.py +0 -0
  77. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/helpers.py +0 -0
  78. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/identity.py +0 -0
  79. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/imaging.py +0 -0
  80. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/__init__.py +0 -0
  81. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/decode.py +0 -0
  82. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/encode.py +0 -0
  83. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/hash.py +0 -0
  84. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/program.py +0 -0
  85. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/reflection.py +0 -0
  86. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/types.py +0 -0
  87. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/ir/xxh64.py +0 -0
  88. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/lm_configuration.py +0 -0
  89. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/mcp_servers.py +0 -0
  90. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/named_programs.py +0 -0
  91. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimization.py +0 -0
  92. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/__init__.py +0 -0
  93. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/gepa.py +0 -0
  94. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/gepa_callback.py +0 -0
  95. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/resume.py +0 -0
  96. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/optimizers/tracker.py +0 -0
  97. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/packaging.py +0 -0
  98. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/programs.py +0 -0
  99. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/references.py +0 -0
  100. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/retry.py +0 -0
  101. {cmpnd-0.69.0 → cmpnd-0.71.0}/cmpnd/traces.py +0 -0
  102. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/2026-04-02-code-review.md +0 -0
  103. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/custom-proposer.md +0 -0
  104. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/plans/2026-04-05-train-val-dataset-capture-design.md +0 -0
  105. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/plans/2026-04-05-train-val-dataset-capture.md +0 -0
  106. {cmpnd-0.69.0 → cmpnd-0.71.0}/docs/reading-traces.md +0 -0
  107. {cmpnd-0.69.0 → cmpnd-0.71.0}/examples/generalizing_proposer.py +0 -0
  108. {cmpnd-0.69.0 → cmpnd-0.71.0}/examples/local_ollama.py +0 -0
  109. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/LINEAGE.md +0 -0
  110. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/README.md +0 -0
  111. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/__init__.py +0 -0
  112. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/bodies.py +0 -0
  113. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/client_floor.py +0 -0
  114. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/exporter_http.py +0 -0
  115. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/program_names.py +0 -0
  116. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/protocols.py +0 -0
  117. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/py.typed +0 -0
  118. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/request_log.py +0 -0
  119. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/retry.py +0 -0
  120. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/cmpnd_ingest/trace_facts.py +0 -0
  121. {cmpnd-0.69.0 → cmpnd-0.71.0}/ingest/pyproject.toml +0 -0
  122. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/audit-sdist.sh +0 -0
  123. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/capture_review_run.py +0 -0
  124. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/check-pip-install.sh +0 -0
  125. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/check_release_artifacts.py +0 -0
  126. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/fixtures/review_run.json.gz +0 -0
  127. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/gepa_resume_bug.py +0 -0
  128. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/install-test-env.sh +0 -0
  129. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/release-gate.sh +0 -0
  130. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/release-real-models.sh +0 -0
  131. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/require_version_bump.py +0 -0
  132. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/seed_review_run.py +0 -0
  133. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/selfhost_compat.py +0 -0
  134. {cmpnd-0.69.0 → cmpnd-0.71.0}/scripts/test-in-linux.sh +0 -0
  135. {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/__init__.pyi +0 -0
  136. {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/primitives/__init__.pyi +0 -0
  137. {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/primitives/prediction.pyi +0 -0
  138. {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/utils/__init__.pyi +0 -0
  139. {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/utils/callback.pyi +0 -0
  140. {cmpnd-0.69.0 → cmpnd-0.71.0}/stubs/dspy/utils/dummies.pyi +0 -0
  141. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/__init__.py +0 -0
  142. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_credential_route.py +0 -0
  143. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_deployment_signature_helpers.py +0 -0
  144. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_exporter_helpers.py +0 -0
  145. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_fake_clock.py +0 -0
  146. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_identity_helpers.py +0 -0
  147. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_resolve_refs.py +0 -0
  148. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/_traced_run.py +0 -0
  149. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/conftest.py +0 -0
  150. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/__init__.py +0 -0
  151. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/committee_task.py +0 -0
  152. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/conftest.py +0 -0
  153. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/continuation_task.py +0 -0
  154. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/data/committee_train.ndjson.gz +0 -0
  155. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/data/committee_val.ndjson.gz +0 -0
  156. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/fake_lm.py +0 -0
  157. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/helpers.py +0 -0
  158. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/target_capabilities.py +0 -0
  159. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_assessments_cli.py +0 -0
  160. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_capture_prompts.py +0 -0
  161. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_composite_module.py +0 -0
  162. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_dataset_auto_creation.py +0 -0
  163. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_deploy_execute.py +0 -0
  164. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_deploy_pandas.py +0 -0
  165. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_deploy_programs.py +0 -0
  166. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_edge_cases.py +0 -0
  167. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_example_hash.py +0 -0
  168. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_gepa_optimization.py +0 -0
  169. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_interpreter_spans.py +0 -0
  170. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_lm_accuracy.py +0 -0
  171. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_module_tracing.py +0 -0
  172. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimization_lineage.py +0 -0
  173. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimization_metric_identity.py +0 -0
  174. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_authored_metric.py +0 -0
  175. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_continuation.py +0 -0
  176. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_custom_proposer.py +0 -0
  177. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_failures.py +0 -0
  178. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_loop.py +0 -0
  179. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_review_committee.py +0 -0
  180. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_optimize_server_owned_completion.py +0 -0
  181. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_parallel_export.py +0 -0
  182. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_project_attribution.py +0 -0
  183. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_react_tool_spans.py +0 -0
  184. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_save_load.py +0 -0
  185. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_trace_structure.py +0 -0
  186. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_traces_read.py +0 -0
  187. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_user_attribution.py +0 -0
  188. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/e2e/test_valsets_cli.py +0 -0
  189. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/01_predict_qa.json +0 -0
  190. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/02_predict_renamed_field.json +0 -0
  191. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/03_chain_of_thought_qa.json +0 -0
  192. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/04_predict_richer_types.json +0 -0
  193. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/05_composite_two_predicts.json +0 -0
  194. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/06_multichaincomparison.json +0 -0
  195. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/07_program_of_thought.json +0 -0
  196. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/08_opaque_module.json +0 -0
  197. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/09_predict_pydantic_field.json +0 -0
  198. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/10_react.json +0 -0
  199. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/11_refine.json +0 -0
  200. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/12_retrieve.json +0 -0
  201. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/13_knn.json +0 -0
  202. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/14_parallel.json +0 -0
  203. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/identity_vectors/README.md +0 -0
  204. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/ingest_conformance.py +0 -0
  205. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/__init__.py +0 -0
  206. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/authored_optimize/judge.py +0 -0
  207. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/authored_optimize/optimize_hosted.py +0 -0
  208. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/conftest.py +0 -0
  209. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/hosted_mcp_tool_optimize_probe.py +0 -0
  210. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/hosted_optimize_probe.py +0 -0
  211. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/optimization_run_probe.py +0 -0
  212. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_cli_deploy_smoketest.py +0 -0
  213. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_logs_renders_traces.py +0 -0
  214. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_optimization_run.py +0 -0
  215. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_optimizing_progress.py +0 -0
  216. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/integration/test_unhappy_path.py +0 -0
  217. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/__init__.py +0 -0
  218. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/__main__.py +0 -0
  219. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/drain.py +0 -0
  220. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/ingest.py +0 -0
  221. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/latency_transport.py +0 -0
  222. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/rlm_shape.py +0 -0
  223. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/rlm_size_report.py +0 -0
  224. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/sweep.py +0 -0
  225. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/test_rlm_shape.py +0 -0
  226. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/load/test_rlm_size_report.py +0 -0
  227. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/__init__.py +0 -0
  228. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/conftest.py +0 -0
  229. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/seed_parity.py +0 -0
  230. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_auth.py +0 -0
  231. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_datasets.py +0 -0
  232. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_deployments.py +0 -0
  233. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_evals.py +0 -0
  234. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_health.py +0 -0
  235. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_modules.py +0 -0
  236. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_optimizations.py +0 -0
  237. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_programs.py +0 -0
  238. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_signatures.py +0 -0
  239. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_trace_streaming.py +0 -0
  240. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/parity/test_traces.py +0 -0
  241. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/__init__.py +0 -0
  242. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_provider.py +0 -0
  243. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_readiness.py +0 -0
  244. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_reliability.py +0 -0
  245. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/_result.py +0 -0
  246. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/mint_bedrock_token.py +0 -0
  247. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_bedrock_converse.py +0 -0
  248. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_deploy_programs.py +0 -0
  249. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_multi_client_stress.py +0 -0
  250. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_client_committee.py +0 -0
  251. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_continuation.py +0 -0
  252. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_loop.py +0 -0
  253. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_loop_wasm.py +0 -0
  254. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_optimize_stress.py +0 -0
  255. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_provider_roles.py +0 -0
  256. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_readiness.py +0 -0
  257. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_real_provider_twins.py +0 -0
  258. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_reliability.py +0 -0
  259. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_reliability_classify.py +0 -0
  260. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_rlm_wasm.py +0 -0
  261. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/real_models/test_trace_search.py +0 -0
  262. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/span_reference_fixture.py +0 -0
  263. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_adapter_reentrancy.py +0 -0
  264. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_assessments_api.py +0 -0
  265. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored.py +0 -0
  266. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_binding_credentials.py +0 -0
  267. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_bundle_collisions.py +0 -0
  268. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_metric_contract.py +0 -0
  269. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_named_models.py +0 -0
  270. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_authored_optimize.py +0 -0
  271. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_callback.py +0 -0
  272. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_candidate_lineage.py +0 -0
  273. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/__init__.py +0 -0
  274. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/conftest.py +0 -0
  275. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_admin.py +0 -0
  276. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_api_client.py +0 -0
  277. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_assessments.py +0 -0
  278. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_auth.py +0 -0
  279. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_credentials.py +0 -0
  280. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_datasets.py +0 -0
  281. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_deployment_runs.py +0 -0
  282. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_deployments.py +0 -0
  283. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_login.py +0 -0
  284. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_optimizations.py +0 -0
  285. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_org.py +0 -0
  286. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_pagination.py +0 -0
  287. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_programs.py +0 -0
  288. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_provider_credentials.py +0 -0
  289. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_schema_sample.py +0 -0
  290. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_shell.py +0 -0
  291. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_tool_servers.py +0 -0
  292. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_top.py +0 -0
  293. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_traces.py +0 -0
  294. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_traces_program_and_module.py +0 -0
  295. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_traces_search_wire.py +0 -0
  296. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_tree_help.py +0 -0
  297. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cli/test_valsets.py +0 -0
  298. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_client_floor.py +0 -0
  299. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/__init__.py +0 -0
  300. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/conftest.py +0 -0
  301. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/test_edge_cases.py +0 -0
  302. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/test_hash_consistency.py +0 -0
  303. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_clustering/test_type_conversion.py +0 -0
  304. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_cmp551_grouping_identity.py +0 -0
  305. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_configuration.py +0 -0
  306. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_context.py +0 -0
  307. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_context_propagation.py +0 -0
  308. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_credential_kwargs.py +0 -0
  309. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_credential_selection.py +0 -0
  310. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_credential_values.py +0 -0
  311. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_dataset_polling.py +0 -0
  312. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_dataset_sync.py +0 -0
  313. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_datasets.py +0 -0
  314. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_decision_client_spans.py +0 -0
  315. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_decorators.py +0 -0
  316. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deploy.py +0 -0
  317. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deploy_mcp_tool_references.py +0 -0
  318. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deploy_program_id.py +0 -0
  319. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deployment_metadata.py +0 -0
  320. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deployment_runs.py +0 -0
  321. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_deployments_read.py +0 -0
  322. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval_example_attribution.py +0 -0
  323. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_eval_trace_grouping.py +0 -0
  324. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exception_paths.py +0 -0
  325. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_execute.py +0 -0
  326. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_execute_run_identity.py +0 -0
  327. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter.py +0 -0
  328. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter_program_names.py +0 -0
  329. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter_queue.py +0 -0
  330. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_exporter_real.py +0 -0
  331. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_fake_lm.py +0 -0
  332. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_callback.py +0 -0
  333. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_integration.py +0 -0
  334. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_output_normalization.py +0 -0
  335. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_gepa_resume.py +0 -0
  336. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_identity.py +0 -0
  337. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_imaging.py +0 -0
  338. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_import_weight.py +0 -0
  339. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ingest_second_producer.py +0 -0
  340. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_integration.py +0 -0
  341. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_interpreter_callback.py +0 -0
  342. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ir_encoder_properties.py +0 -0
  343. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ir_golden_vectors.py +0 -0
  344. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_ir_roundtrip.py +0 -0
  345. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_lm15_native_calls.py +0 -0
  346. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_lm_configuration.py +0 -0
  347. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_lm_usage_shapes.py +0 -0
  348. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_mcp_tools.py +0 -0
  349. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_models.py +0 -0
  350. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_multi_client_stress_readiness.py +0 -0
  351. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimization_progress.py +0 -0
  352. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimization_start.py +0 -0
  353. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize.py +0 -0
  354. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_budget.py +0 -0
  355. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_lift.py +0 -0
  356. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_lms.py +0 -0
  357. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_proposer.py +0 -0
  358. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_reflection_lm.py +0 -0
  359. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_optimize_terminal_failure.py +0 -0
  360. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging.py +0 -0
  361. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging_callable_source.py +0 -0
  362. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging_mcp_tools.py +0 -0
  363. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_packaging_program_source.py +0 -0
  364. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_poll_until.py +0 -0
  365. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_identity.py +0 -0
  366. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_lineage_persist.py +0 -0
  367. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_program_names_in_deploy.py +0 -0
  368. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_programs_create.py +0 -0
  369. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_project_payload.py +0 -0
  370. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_real_provider_twins_readiness.py +0 -0
  371. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_reflector_properties.py +0 -0
  372. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_reflector_smoke.py +0 -0
  373. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_release_gate_script.py +0 -0
  374. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_release_real_models_script.py +0 -0
  375. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_replaced_names.py +0 -0
  376. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_repro_reactv2_bugs.py +0 -0
  377. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_require_version_bump.py +0 -0
  378. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_retry.py +0 -0
  379. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_reversible_failures.py +0 -0
  380. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_rlm_patch.py +0 -0
  381. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_run_attribution_paths.py +0 -0
  382. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_runtime_tools.py +0 -0
  383. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_schemas.py +0 -0
  384. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_seal_lm_credential.py +0 -0
  385. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_seed_review_run.py +0 -0
  386. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_signature_inputs.py +0 -0
  387. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_span_references.py +0 -0
  388. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_span_sent_once.py +0 -0
  389. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_system_one.py +0 -0
  390. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_context_concurrency.py +0 -0
  391. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_fact_wire_contract.py +0 -0
  392. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_facts.py +0 -0
  393. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_trace_render.py +0 -0
  394. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_traces_read.py +0 -0
  395. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_tracked_gepa.py +0 -0
  396. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_tracker_enrich.py +0 -0
  397. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_truncation.py +0 -0
  398. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_upload_auth_headers.py +0 -0
  399. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_valsets_api.py +0 -0
  400. {cmpnd-0.69.0 → cmpnd-0.71.0}/tests/test_xxh64.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cmpnd
3
- Version: 0.69.0
3
+ Version: 0.71.0
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>
@@ -171,15 +171,8 @@ def main() -> None:
171
171
  evals.register(subparsers)
172
172
  datasets.register(subparsers)
173
173
  deployments.register(subparsers)
174
-
175
- # Assessments and valsets CLIs are still in development, hidden behind
176
- # CMPND_CLI_DEV=1 (mirroring the CMPND_CLI_ADMIN gate above). The env var
177
- # only hides the commands from customers; the server still gates each action
178
- # on the assessments:* / valsets:* scope, so this is discoverability, not
179
- # enforcement.
180
- if os.environ.get("CMPND_CLI_DEV") == "1":
181
- assessments.register(subparsers)
182
- valsets.register(subparsers)
174
+ assessments.register(subparsers)
175
+ valsets.register(subparsers)
183
176
 
184
177
  # Top-level Docker-style shortcuts (human-readable by default; --json opts in)
185
178
  top.register(subparsers)
@@ -14,8 +14,7 @@ default limits and feature flags, and `cmpnd admin signup …` sets who may sign
14
14
  and the plan a new account's org lands on. `cmpnd admin feature-flags …` reads and
15
15
  toggles the server's runtime flags. These hit
16
16
  /api/v1/admin/* and require an API key carrying the admin:* scopes — the server
17
- is the real authority. The CMPND_CLI_ADMIN env gate (mirroring CMPND_CLI_DEV)
18
- only keeps these out of customers' --help; it grants nothing.
17
+ is the real authority. The CMPND_CLI_ADMIN env gate only keeps these out of customers' --help; it grants nothing.
19
18
  """
20
19
 
21
20
  from __future__ import annotations
@@ -9,7 +9,18 @@ from .. import api_client, deprecation, pagination
9
9
 
10
10
 
11
11
  def _add_list_args(p: ArgumentParser) -> None:
12
- p.add_argument("--program", dest="program_name", help="Filter by program name")
12
+ p.add_argument(
13
+ "--program",
14
+ dest="program_name",
15
+ metavar="NAME",
16
+ help="Only the runs of the program with this name, current or retired",
17
+ )
18
+ p.add_argument(
19
+ "--module",
20
+ dest="module_class",
21
+ metavar="CLASS",
22
+ help="Only the runs that evaluated this module class, matched exactly (e.g. ReAct)",
23
+ )
13
24
  p.add_argument("--metric", dest="metric_name", help="Filter by metric name")
14
25
  p.add_argument("--status", help="Filter by status (running, completed, failed, cancelled)")
15
26
  pagination.add_args(p, with_page_aliases=True, default_limit=50)
@@ -63,6 +74,7 @@ def handle_list(client: api_client.ApiClient, args: Any) -> Any:
63
74
  body: dict[str, Any] = pagination.wire(args, "page_size")
64
75
  for attr, key in [
65
76
  ("program_name", "program_name"),
77
+ ("module_class", "module_class"),
66
78
  ("metric_name", "metric"),
67
79
  ("status", "status"),
68
80
  ]:
@@ -17,10 +17,6 @@ and propagates to its own eval / parallel threads. It registers nothing global
17
17
  and holds no OS resource: exporters are pooled by credentials at module scope
18
18
  (:mod:`cmpnd._exporter_pool`), so a client may fall out of scope with nothing to
19
19
  release. ``close()`` is an optional alias for end-of-scope flushing.
20
-
21
- The assessment and valset calls are in development. Each raises unless
22
- ``CMPND_CLI_DEV=1`` is set, the switch that hides the in-development
23
- ``cmpnd assessments`` and ``cmpnd valsets`` CLI groups. Tracing needs no flag.
24
20
  """
25
21
 
26
22
  from __future__ import annotations
@@ -111,15 +107,6 @@ class Client:
111
107
  if not self._active:
112
108
  raise RuntimeError("client is closed; create a new cmpnd.Client")
113
109
 
114
- def _check_in_development(self, method: str) -> None:
115
- """Refuse an assessment or valset call unless ``CMPND_CLI_DEV=1`` is set."""
116
- if os.getenv("CMPND_CLI_DEV") != "1":
117
- raise RuntimeError(
118
- f"cmpnd.Client.{method}() is in development and not yet generally available. "
119
- "Set CMPND_CLI_DEV=1 to enable it."
120
- )
121
- self._check_active()
122
-
123
110
  def _scoped_callbacks(self) -> list[Any]:
124
111
  """This client's callback, plus the caller's own non-cmpnd callbacks.
125
112
 
@@ -918,7 +905,7 @@ class Client:
918
905
  e.g. ``annotations=[("output", "/trends/2", "the third trend"),
919
906
  ("span", "a1b2c3", "wrong field")]``.
920
907
  """
921
- self._check_in_development("create_assessment")
908
+ self._check_active()
922
909
  _exporter_pool.flush(self._config) # the referenced trace must be durable first
923
910
  return _assessments.create(
924
911
  trace_id,
@@ -937,7 +924,7 @@ class Client:
937
924
  Pass exactly one of ``program`` (all of that program's assessments, named by
938
925
  its name or ``p_`` id) or ``trace_id`` (one trace's assessments).
939
926
  """
940
- self._check_in_development("list_assessments")
927
+ self._check_active()
941
928
  if program is not None and trace_id is not None:
942
929
  raise ValueError("pass exactly one of program or trace_id")
943
930
  page = _assessments.list(
@@ -952,24 +939,24 @@ class Client:
952
939
 
953
940
  def get_assessment(self, assessment_id: str) -> dict[str, Any]:
954
941
  """Fetch one assessment with its annotations."""
955
- self._check_in_development("get_assessment")
942
+ self._check_active()
956
943
  return _assessments.get(assessment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
957
944
 
958
945
  def delete_assessment(self, assessment_id: str) -> None:
959
946
  """Delete one assessment. Raises if it does not exist."""
960
- self._check_in_development("delete_assessment")
947
+ self._check_active()
961
948
  _assessments.delete(assessment_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
962
949
 
963
950
  def create_valset(self, program: str, *, name: str | None = None) -> dict[str, Any]:
964
951
  """Create a valset owned by ``program``, a program name or ``p_`` id; name auto-assigned when omitted."""
965
- self._check_in_development("create_valset")
952
+ self._check_active()
966
953
  return _valsets.create(
967
954
  self._program_id(program), name=name, api_key=self._config.api_key, endpoint=self._config.endpoint
968
955
  )
969
956
 
970
957
  def list_valsets(self, program: str, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
971
958
  """The valsets of ``program``, a program name or ``p_`` id, newest first (paged by limit/offset)."""
972
- self._check_in_development("list_valsets")
959
+ self._check_active()
973
960
  page = _valsets.list(
974
961
  self._program_id(program),
975
962
  limit=limit,
@@ -981,12 +968,12 @@ class Client:
981
968
 
982
969
  def get_valset(self, valset_id: str) -> dict[str, Any]:
983
970
  """Fetch one valset with its field shape and current version."""
984
- self._check_in_development("get_valset")
971
+ self._check_active()
985
972
  return _valsets.get(valset_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
986
973
 
987
974
  def list_valset_entries(self, valset_id: str, *, limit: int = 50, offset: int = 0) -> list[dict[str, Any]]:
988
975
  """A valset's active entries (paged by limit/offset)."""
989
- self._check_in_development("list_valset_entries")
976
+ self._check_active()
990
977
  page = _valsets.list_entries(
991
978
  valset_id, limit=limit, offset=offset, api_key=self._config.api_key, endpoint=self._config.endpoint
992
979
  )
@@ -1002,7 +989,7 @@ class Client:
1002
989
  ) -> dict[str, Any]:
1003
990
  """Add one entry. Pass exactly one of ``from_assessment`` (the server
1004
991
  derives inputs from its trace) or ``inputs``."""
1005
- self._check_in_development("create_valset_entry")
992
+ self._check_active()
1006
993
  return _valsets.create_entry(
1007
994
  valset_id,
1008
995
  expected_outputs=expected_outputs,
@@ -1014,7 +1001,7 @@ class Client:
1014
1001
 
1015
1002
  def delete_valset_entry(self, entry_id: str) -> dict[str, Any]:
1016
1003
  """Retire an entry (versioned, not a hard delete)."""
1017
- self._check_in_development("delete_valset_entry")
1004
+ self._check_active()
1018
1005
  return _valsets.delete_entry(entry_id, api_key=self._config.api_key, endpoint=self._config.endpoint)
1019
1006
 
1020
1007
  def _run_gepa(
@@ -15,7 +15,7 @@ from . import _http, configuration, identity, models
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
- def check_dataset_exists(dataset_hash: str) -> bool:
18
+ def check_dataset_exists(dataset_hash: str, config: configuration.Config | None = None) -> bool:
19
19
  """Check if a dataset with this hash already exists on the backend.
20
20
 
21
21
  Makes a GET request to /api/v1/datasets/check/{dataset_hash}.
@@ -23,14 +23,17 @@ def check_dataset_exists(dataset_hash: str) -> bool:
23
23
 
24
24
  Args:
25
25
  dataset_hash: The SHA256[:16] hash of the dataset.
26
+ config: The account to ask, which must be the account the run publishes
27
+ to. None asks the process-global account.
26
28
 
27
29
  Returns:
28
30
  True if the dataset exists, False otherwise (including on errors).
29
31
  """
30
- try:
31
- config = configuration.require_config()
32
- except RuntimeError:
33
- return False
32
+ if config is None:
33
+ try:
34
+ config = configuration.require_config()
35
+ except RuntimeError:
36
+ return False
34
37
 
35
38
  url = f"{config.endpoint}/api/v1/datasets/check/{dataset_hash}"
36
39
 
@@ -10,7 +10,7 @@ import logging
10
10
  from datetime import datetime, timezone
11
11
  from typing import Any
12
12
 
13
- from . import context, exporter, helpers, identity, models
13
+ from . import context, helpers, identity, models
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
@@ -85,7 +85,7 @@ class EvalHandler:
85
85
  logger.debug(f"Extracted program: {program}, type: {type(program) if program else None}")
86
86
 
87
87
  if program:
88
- eval_run.program_name = program.__class__.__name__
88
+ eval_run.module_class = program.__class__.__name__
89
89
 
90
90
  # Hash via the IR reflector on the live module so the class tag
91
91
  # discriminates correctly; signature_summary is still derived from
@@ -165,16 +165,23 @@ class EvalHandler:
165
165
  if not input_fields and devset and hasattr(devset[0], "_input_keys"):
166
166
  input_fields = set(devset[0]._input_keys)
167
167
  eval_run._input_fields = input_fields
168
- # Fire pre-flight check (synchronous, short timeout)
168
+ # Fire pre-flight check (synchronous, short timeout). It asks the
169
+ # account the run publishes to: a client's own, else the global one.
169
170
  from . import dataset_sync
170
171
 
171
172
  try:
172
- eval_run._dataset_exists = dataset_sync.check_dataset_exists(eval_run.dataset_hash)
173
+ eval_run._dataset_exists = dataset_sync.check_dataset_exists(
174
+ eval_run.dataset_hash, self._callback._own_config
175
+ )
173
176
  except Exception:
174
177
  eval_run._dataset_exists = None # Will include examples as fallback
175
178
 
179
+ exp = self._callback._current_exporter()
180
+ eval_run.program_id = self._program_id(exp)
181
+
176
182
  logger.info(
177
- f"EvalRun created: program_name={eval_run.program_name}, "
183
+ f"EvalRun created: program_id={eval_run.program_id}, "
184
+ f"module_class={eval_run.module_class}, "
178
185
  f"metric_name={eval_run.metric_name}, "
179
186
  f"dataset_hash={eval_run.dataset_hash}, "
180
187
  f"dataset_size={eval_run.dataset_size}"
@@ -184,7 +191,6 @@ class EvalHandler:
184
191
  # the exporter (serve/observe, or deploy in-Lambda) assigns it. Obtain
185
192
  # it synchronously now, before any eval trace ships, since every
186
193
  # in-flight trace and the dict keys / span below are stamped with it.
187
- exp = exporter.get_exporter()
188
194
  if exp:
189
195
  eval_run.eval_run_id = exp.export_eval_start(eval_run)
190
196
 
@@ -201,13 +207,33 @@ class EvalHandler:
201
207
 
202
208
  # Capture evaluation config in span attributes
203
209
  span.attributes["eval.run_id"] = str(eval_run.eval_run_id)
204
- span.attributes["eval.program_name"] = eval_run.program_name or ""
210
+ span.attributes["eval.module_class"] = eval_run.module_class or ""
205
211
  span.attributes["eval.metric_name"] = eval_run.metric_name or ""
206
212
  span.attributes["eval.dataset_size"] = str(eval_run.dataset_size)
207
213
 
208
214
  self._callback._call_id_to_span[call_id] = span
209
215
  context.push_span(span)
210
216
 
217
+ def _program_id(self, exp: Any) -> str | None:
218
+ """The program id the eval run carries, resolved the way a trace's is.
219
+
220
+ A program name the call declares wins over the callback's program id. The
221
+ exporter resolves the name now, on the caller's thread, because the run's
222
+ start is sent synchronously and must carry the id. The exporter keeps the
223
+ answer for the process, so a name its traces already resolved costs no
224
+ request. A name the exporter cannot resolve leaves the run without an id.
225
+ """
226
+ from . import callback
227
+
228
+ name = callback._declared_program_name()
229
+ if name is None:
230
+ return self._callback._resolve_program_id()
231
+ # Read with getattr because the member is optional: an in-memory collector
232
+ # that resolves no names has none.
233
+ resolve = getattr(exp, "resolve_program_name", None)
234
+ program_id = resolve(name) if callable(resolve) else None
235
+ return program_id if isinstance(program_id, str) else None
236
+
211
237
  def on_evaluate_end(
212
238
  self,
213
239
  call_id: str,
@@ -228,7 +254,7 @@ class EvalHandler:
228
254
  span.status = models.TraceStatus.OK
229
255
  context.pop_span()
230
256
  if self._callback._should_stream_span(span):
231
- exp = exporter.get_exporter()
257
+ exp = self._callback._current_exporter()
232
258
  if exp:
233
259
  exp.export_span(span)
234
260
 
@@ -373,7 +399,7 @@ class EvalHandler:
373
399
  span.attributes["eval.score"] = str(overall_score)
374
400
 
375
401
  # Export the eval run
376
- exp = exporter.get_exporter()
402
+ exp = self._callback._current_exporter()
377
403
  if exp:
378
404
  exp.export_eval_run(eval_run)
379
405
 
@@ -1274,7 +1274,11 @@ class EvalRunBuilder:
1274
1274
  start_time: datetime | None = None
1275
1275
 
1276
1276
  # Eval Identity (defines comparability)
1277
- program_name: str | None = None
1277
+ # The program the run evaluates: the id serve gave the program name the call
1278
+ # declared, or the client's program id. None when the run names no program.
1279
+ program_id: str | None = None
1280
+ # The evaluated module's class, such as "ReAct".
1281
+ module_class: str | None = None
1278
1282
  metric_name: str | None = None
1279
1283
  dataset_hash: str | None = None
1280
1284
  dataset_size: int = 0
@@ -1393,7 +1397,10 @@ class EvalRunBuilder:
1393
1397
  return {
1394
1398
  "eval_run_id": "new",
1395
1399
  "status": EvalRunStatus.RUNNING.value,
1396
- "program_name": self.program_name or "",
1400
+ "program_id": self.program_id,
1401
+ "module_class": self.module_class or "",
1402
+ # Also under the key a serve from before module_class reads.
1403
+ "program_name": self.module_class or "",
1397
1404
  "metric_name": self.metric_name or "",
1398
1405
  "dataset_hash": self.dataset_hash or "",
1399
1406
  "dataset_size": self.dataset_size,
@@ -1411,7 +1418,10 @@ class EvalRunBuilder:
1411
1418
  """Convert to API-compatible dictionary."""
1412
1419
  d = {
1413
1420
  "eval_run_id": str(self.eval_run_id) if self.eval_run_id else None,
1414
- "program_name": self.program_name or "",
1421
+ "program_id": self.program_id,
1422
+ "module_class": self.module_class or "",
1423
+ # Also under the key a serve from before module_class reads.
1424
+ "program_name": self.module_class or "",
1415
1425
  "metric_name": self.metric_name or "",
1416
1426
  "dataset_hash": self.dataset_hash or "",
1417
1427
  "dataset_size": self.dataset_size,
@@ -418,10 +418,7 @@ down or neutral conclusion, an optional prose body and annotations. An
418
418
  annotation attaches a note to a span or to a piece of the output addressed by
419
419
  a JSON pointer.
420
420
 
421
- The group is in development. The CLI registers it only when
422
- `CMPND_CLI_DEV=1` is set, so it does not appear in `cmpnd --help`. The
423
- variable only hides the commands. Serve still checks each action against the
424
- `assessments:*` scopes.
421
+ Serve checks each action against the `assessments:*` scopes.
425
422
 
426
423
  - `cmpnd assessments create <trace-id> [--up|--down|--neutral] [-m "prose"]
427
424
  [--annotate KIND REF NOTE …]` records one judgement.
@@ -458,6 +455,18 @@ program signature hash. `cmpnd programs optimized` commands and
458
455
  optimization result, not a program. Each group's `--help` names the column its
459
456
  IDs come from.
460
457
 
458
+ `cmpnd evals list [--program NAME] [--module CLASS] [--metric] [--status]`
459
+ lists eval runs, newest first. `--program` takes the program's name, current
460
+ or retired, and a name no program answers to is an error that names it.
461
+ `--module` takes the evaluated module's class, such as `ReAct`, and matches it
462
+ exactly. The CLI sends them as `program_name` and `module_class`. Each eval
463
+ run in `evals list`, `evals show` and `programs evals` names what it evaluated
464
+ in three fields, as a trace does. `program_name` is the program's name, empty
465
+ when the program has none or the run names no program. `program_id` is the
466
+ program's `p_` id, and `module_class` is the evaluated module's class. A server
467
+ that predates `module_class` sends the class in `program_name` and filters
468
+ `--program` by class.
469
+
461
470
  `cmpnd deployments openapi <id>` prints the OpenAPI document a deployment
462
471
  serves, which an agent reads before it calls the deployment.
463
472
 
@@ -522,9 +531,7 @@ that lookup, so it creates a valset by the program's name. On a server from befo
522
531
  name fails with an error that says to upgrade the server. Entries live in an
523
532
  `entries` subgroup, the same shape as `cmpnd datasets examples`.
524
533
 
525
- The group is in development. The CLI registers it only when
526
- `CMPND_CLI_DEV=1` is set. Serve still checks each action against the
527
- `valsets:*` scopes.
534
+ Serve checks each action against the `valsets:*` scopes.
528
535
 
529
536
  - `cmpnd valsets create <program> [--name <name>]` creates a validation
530
537
  set for a program. The valset ID is its identity, and the name is a label
@@ -10,11 +10,6 @@ client methods too, and have no form outside a client. A client holds its own ta
10
10
  the global config that `auto_instrument()` reads, so both can run in one
11
11
  process.
12
12
 
13
- The client's assessment and valset calls are in development. Each one raises
14
- `RuntimeError` unless `CMPND_CLI_DEV=1` is set. The same variable reveals the
15
- in-development `cmpnd assessments` and `cmpnd valsets` CLI groups. Tracing
16
- through a client needs no flag.
17
-
18
13
  ## Entry point
19
14
 
20
15
  ```python
@@ -218,12 +213,12 @@ methods:
218
213
  file the deployment stores, or the archive-relative file `path` names.
219
214
  `sdk.get_deployment_signature(deployment_id)` returns the selected
220
215
  artifact's typed metadata. It reads no worker status or executions.
221
- - Assessments, in development behind `CMPND_CLI_DEV=1`:
216
+ - Assessments:
222
217
  `sdk.create_assessment(trace_id, conclusion=..., body=...,
223
218
  annotations=...)`, `sdk.list_assessments(program=... | trace_id=...,
224
219
  limit=..., offset=...)`, `sdk.get_assessment(assessment_id)` and
225
220
  `sdk.delete_assessment(assessment_id)`.
226
- - Valsets, in development behind `CMPND_CLI_DEV=1`:
221
+ - Valsets:
227
222
  `sdk.create_valset(program, name=...)`, `sdk.list_valsets(program,
228
223
  limit=..., offset=...)`, `sdk.get_valset(valset_id)`,
229
224
  `sdk.list_valset_entries(valset_id, limit=..., offset=...)`,
@@ -727,6 +727,8 @@ What it captures beyond the normal span flow:
727
727
  - An `EvalRunBuilder` (constructed at `eval_handler.py:79`) that groups all per-example traces under one eval ID.
728
728
  - The metric name (via `get_metric_name` from `python-sdk/cmpnd/helpers.py`) and inferred provider.
729
729
  - Links to the enclosing optimization run when one exists (`eval_handler.py:85`), so eval runs triggered inside `GEPA.compile` roll up under the optimization in the UI.
730
+ - The program the run evaluates, as `program_id`. A program name the call declares wins: the exporter resolves it with `resolve_program_name`, the same once-per-process answer its traces use, on the caller's thread because the eval start is sent synchronously. Without a declared name, the run takes the callback's program id. A name serve refuses leaves the run without an id. The evaluated module's class goes as `module_class`, and again under `program_name`, the key a serve from before `module_class` reads.
731
+ - The exporter it publishes through: the callback's own (`_current_exporter`), so a client's eval runs go to the client's account.
730
732
  - The dataset — on `on_evaluate_start` it triggers the `dataset_sync` pre-flight described above.
731
733
 
732
734
  Per-example results (scores, statuses, example hashes) are collected in `on_evaluate_end` and shipped as part of the `EvalRunBuilder`'s `to_api_dict()`, which the exporter routes to `/api/v1/eval_runs`.
@@ -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.69.0"
8
+ version = "0.71.0"
9
9
  description = "DSPy observability and deployment SDK for cmpnd"
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.11"
@@ -86,20 +86,34 @@ class TestEvalsList:
86
86
  # own spelling passes while the filter does nothing.
87
87
  def test_minimal_list(self, mock_client):
88
88
  mock_client.post.return_value = {"eval_runs": []}
89
- args = argparse.Namespace(program_name=None, metric_name=None, status=None, limit=50, offset=0)
89
+ args = argparse.Namespace(
90
+ program_name=None, module_class=None, metric_name=None, status=None, limit=50, offset=0
91
+ )
90
92
  handle_list(mock_client, args)
91
93
  body = mock_client.post.call_args[1]["json"]
92
94
  assert body == {"page": 1, "page_size": 50}
93
95
 
94
96
  def test_with_filters(self, mock_client):
95
97
  mock_client.post.return_value = {"eval_runs": []}
96
- args = argparse.Namespace(program_name="RAG", metric_name="accuracy", status="completed", limit=50, offset=0)
98
+ args = argparse.Namespace(
99
+ program_name="RAG", module_class=None, metric_name="accuracy", status="completed", limit=50, offset=0
100
+ )
97
101
  handle_list(mock_client, args)
98
102
  body = mock_client.post.call_args[1]["json"]
99
103
  assert body["program_name"] == "RAG"
100
104
  assert body["metric"] == "accuracy"
101
105
  assert body["status"] == "completed"
102
106
 
107
+ def test_program_names_the_program_and_module_names_the_class(self, mock_client):
108
+ # --program is the program's name; --module is the evaluated module's
109
+ # class, which the server matches exactly under module_class.
110
+ mock_client.post.return_value = {"eval_runs": []}
111
+ args = _build_parser().parse_args(["evals", "list", "--program", "capital-qa", "--module", "ReAct"])
112
+ handle_list(mock_client, args)
113
+ body = mock_client.post.call_args[1]["json"]
114
+ assert body["program_name"] == "capital-qa"
115
+ assert body["module_class"] == "ReAct"
116
+
103
117
  def test_deprecated_search_verb_dispatches_and_is_marked(self, mock_client):
104
118
  # The warning is the dispatcher's job (see test_main.py); the wiring is this one's.
105
119
  parser = _build_parser()
@@ -169,6 +169,28 @@ class TestDevGate:
169
169
  output = json.loads(captured.out)
170
170
  assert "families" in output
171
171
 
172
+ def test_assessments_works_without_flag(self, capsys):
173
+ env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
174
+ env["CMPND_API_KEY"] = "test-key"
175
+ mock_response = {"assessments": [], "total": 0}
176
+ with mock.patch("sys.argv", ["cmpnd", "assessments", "list", "--trace", "t_1"]):
177
+ with mock.patch.dict(os.environ, env, clear=True):
178
+ with mock.patch("cmpnd.cli.api_client.ApiClient.get", autospec=True, return_value=mock_response) as get:
179
+ main()
180
+ assert get.call_args.args[1] == "/api/v1/assessments"
181
+ assert json.loads(capsys.readouterr().out) == mock_response
182
+
183
+ def test_valsets_works_without_flag(self, capsys):
184
+ env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
185
+ env["CMPND_API_KEY"] = "test-key"
186
+ mock_response = {"id": "v_1", "name": "valset-2026-11-02"}
187
+ with mock.patch("sys.argv", ["cmpnd", "valsets", "show", "v_1"]):
188
+ with mock.patch.dict(os.environ, env, clear=True):
189
+ with mock.patch("cmpnd.cli.api_client.ApiClient.get", autospec=True, return_value=mock_response) as get:
190
+ main()
191
+ assert get.call_args.args[1] == "/api/v1/valsets/v_1"
192
+ assert json.loads(capsys.readouterr().out) == mock_response
193
+
172
194
 
173
195
  class TestAdminGate:
174
196
  """CMP-126: `admin` commands gated behind CMPND_CLI_ADMIN=1; the
@@ -16,7 +16,6 @@ from __future__ import annotations
16
16
 
17
17
  import argparse
18
18
  import itertools
19
- import os
20
19
  import re
21
20
  from pathlib import Path
22
21
  from unittest import mock
@@ -26,6 +25,9 @@ from cmpnd.cli.api_client import ApiClient
26
25
  from cmpnd.cli.commands import (
27
26
  admin as _admin,
28
27
  )
28
+ from cmpnd.cli.commands import (
29
+ assessments as _assessments,
30
+ )
29
31
  from cmpnd.cli.commands import (
30
32
  auth as _auth,
31
33
  )
@@ -59,6 +61,9 @@ from cmpnd.cli.commands import (
59
61
  from cmpnd.cli.commands import (
60
62
  traces as _traces,
61
63
  )
64
+ from cmpnd.cli.commands import (
65
+ valsets as _valsets,
66
+ )
62
67
 
63
68
  #: Every module registering a resource-tier noun group. `login` is excluded
64
69
  #: deliberately: `login` / `logout` are task-tier top-level commands with no
@@ -75,6 +80,8 @@ _RESOURCE_MODULES = (
75
80
  _evals,
76
81
  _datasets,
77
82
  _deployments,
83
+ _assessments,
84
+ _valsets,
78
85
  )
79
86
 
80
87
 
@@ -281,10 +288,8 @@ class TestOptimizeBinding:
281
288
  partial revival (CLI but not REPL) is the failure worth catching."""
282
289
 
283
290
  def test_optimize_is_bound_on_both_surfaces(self):
284
- env = {k: v for k, v in os.environ.items() if k != "CMPND_CLI_DEV"}
285
- with mock.patch.dict(os.environ, env, clear=True):
286
- assert "optimize" in _argparse_subcommands()
287
- assert "optimize" in _shell_namespace()
291
+ assert "optimize" in _argparse_subcommands()
292
+ assert "optimize" in _shell_namespace()
288
293
 
289
294
 
290
295
  class TestResourceVocabulary:
@@ -327,11 +327,11 @@ class TestMisuseGuard:
327
327
  sdk5.run_program(a_program(), question="What is the capital of France?")
328
328
 
329
329
 
330
- class TestDevelopmentGate:
331
- """The client's tracing needs no flag. Its assessment and valset calls are in
332
- development, gated behind CMPND_CLI_DEV=1 as their CLI groups are."""
330
+ class TestAssessmentsAndValsetsNeedNoFlag:
331
+ """The client's assessment and valset calls need no environment flag. A closed
332
+ client still refuses each one, as it refuses every other call."""
333
333
 
334
- GATED = {
334
+ CALLS = {
335
335
  "create_assessment": ("t_1",),
336
336
  "list_assessments": ("p_0123456789Ab",),
337
337
  "get_assessment": ("a_1",),
@@ -344,23 +344,19 @@ class TestDevelopmentGate:
344
344
  "delete_valset_entry": ("e_1",),
345
345
  }
346
346
 
347
- def test_construction_needs_no_flag(self, monkeypatch: pytest.MonkeyPatch):
348
- monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
349
- sdk = cmpnd.Client(project_tags=["context-Z"], api_key="k", endpoint="http://x")
350
- assert sdk._active
351
-
352
- @pytest.mark.parametrize("method", sorted(GATED))
353
- def test_an_assessment_or_valset_call_refuses_without_the_flag(self, method, monkeypatch: pytest.MonkeyPatch):
347
+ @pytest.mark.parametrize("method", sorted(CALLS))
348
+ def test_a_closed_client_refuses_an_assessment_or_valset_call(self, method, monkeypatch: pytest.MonkeyPatch):
354
349
  monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
355
350
  sdk = cmpnd.Client(api_key="k", endpoint="http://x")
351
+ sdk.close()
356
352
  kwargs = {"expected_outputs": {}} if method == "create_valset_entry" else {}
357
- with pytest.raises(RuntimeError, match=r"CMPND_CLI_DEV=1"):
358
- getattr(sdk, method)(*self.GATED[method], **kwargs)
353
+ with pytest.raises(RuntimeError, match=r"client is closed"):
354
+ getattr(sdk, method)(*self.CALLS[method], **kwargs)
359
355
 
360
- def test_every_assessment_and_valset_method_is_gated(self):
356
+ def test_every_assessment_and_valset_method_is_listed(self):
361
357
  public = {name for name in dir(cmpnd.Client) if not name.startswith("_")}
362
358
  data = {name for name in public if "assessment" in name or "valset" in name}
363
- assert data == set(self.GATED)
359
+ assert data == set(self.CALLS)
364
360
 
365
361
 
366
362
  # --- Case 7: exceptions and cleanup --------------------------------------
@@ -794,7 +790,7 @@ class TestClientDataSurface:
794
790
  client's own credentials, list_* unwrap to lists, and client.traces warns."""
795
791
 
796
792
  def _client(self, monkeypatch):
797
- monkeypatch.setenv("CMPND_CLI_DEV", "1")
793
+ monkeypatch.delenv("CMPND_CLI_DEV", raising=False)
798
794
  monkeypatch.setattr(cmpnd.client._exporter_pool, "flush", lambda cfg: None)
799
795
  return cmpnd.Client(api_key="k", endpoint="http://x")
800
796
 
@@ -811,6 +807,21 @@ class TestClientDataSurface:
811
807
  assert seen["trace_id"] == "t-1" and seen["conclusion"] == "down"
812
808
  assert seen["api_key"] == "k" and seen["endpoint"] == "http://x"
813
809
 
810
+ @pytest.mark.parametrize(
811
+ ("method", "module", "function", "ref"),
812
+ [
813
+ ("get_assessment", "_assessments", "get", "as_1"),
814
+ ("get_valset", "_valsets", "get", "v_1"),
815
+ ("delete_valset_entry", "_valsets", "delete_entry", "e_1"),
816
+ ],
817
+ )
818
+ def test_a_one_id_call_delegates_with_client_creds(self, method, module, function, ref, monkeypatch):
819
+ fake = mock.create_autospec(getattr(getattr(cmpnd, module), function), return_value={"id": ref})
820
+ monkeypatch.setattr(getattr(cmpnd, module), function, fake)
821
+
822
+ assert getattr(self._client(monkeypatch), method)(ref) == {"id": ref}
823
+ fake.assert_called_once_with(ref, api_key="k", endpoint="http://x")
824
+
814
825
  def test_get_deployment_signature_delegates_with_client_creds(self, monkeypatch):
815
826
  seen: dict = {}
816
827
  answer = object()
@@ -126,7 +126,6 @@ def _provider():
126
126
 
127
127
  @pytest.fixture(autouse=True)
128
128
  def _clean_slate(monkeypatch: pytest.MonkeyPatch):
129
- monkeypatch.delenv("CMPND_CLI_DEV", raising=False) # a client traces with no dev flag
130
129
  monkeypatch.delenv("CMPND_PROGRAM_ID", raising=False)
131
130
  configuration._config = None
132
131
  saved_callbacks = list(dspy.settings.callbacks or [])
@@ -328,7 +327,6 @@ def minting_server(monkeypatch: pytest.MonkeyPatch):
328
327
  def _new_client(**kw: Any) -> httpx.Client:
329
328
  return real_new_client(transport=httpx.MockTransport(srv.handler), **kw)
330
329
 
331
- monkeypatch.setenv("CMPND_CLI_DEV", "1")
332
330
  with (
333
331
  mock.patch("cmpnd._http.new_client", autospec=True, side_effect=_new_client),
334
332
  mock.patch("cmpnd.exporter_http.BatchExporter", autospec=True, side_effect=_factory),