Canonical Artifact Flow#
This is the smallest deterministic example that still crosses the full ecosystem boundary:
design_research.problemsloads a packaged benchmark.design_research.agentssupplies the public seeded baseline agent.design_research.experimentsbuilds and runs the study, then exports canonical artifacts.design_research.analysisvalidates and reads those artifacts.
It is the compatibility smoke path for the examples workflow: no live model, no network dependency, and no umbrella-owned orchestration logic.
Run it with:
python examples/canonical_artifact_flow.py
Code#
examples/canonical_artifact_flow.py# 1"""Smallest deterministic problems-agents-experiments-analysis handoff."""
2
3from __future__ import annotations
4
5from pathlib import Path
6from statistics import mean
7
8import design_research as dr
9
10PROBLEM_ID = "decision_laptop_design_profit_maximization"
11AGENT_ID = "SeededRandomBaselineAgent"
12STUDY_ID = "canonical_artifact_flow"
13OUTPUT_DIR = Path("artifacts") / "examples" / STUDY_ID
14PRIMARY_METRIC = "primary_outcome"
15
16
17def main() -> None:
18 """Run one packaged problem through the public umbrella stack."""
19 # Start with a packaged benchmark from design-research-problems. The umbrella
20 # import keeps the example focused on the workflow instead of package wiring.
21 problem = dr.problems.get_problem(PROBLEM_ID)
22
23 # Build the smallest useful study: one problem, one public agent, and two
24 # deterministic replicates so the analysis layer has real rows to consume.
25 study = dr.experiments.build_strategy_comparison_study(
26 dr.experiments.StrategyComparisonConfig(
27 study_id=STUDY_ID,
28 title="Canonical Artifact Flow",
29 description="Run the minimal composed ecosystem path and validate its artifacts.",
30 bundle=dr.experiments.BenchmarkBundle(
31 bundle_id="canonical-artifact-flow",
32 name="Canonical Artifact Flow",
33 description="One packaged benchmark and one public baseline agent.",
34 problem_ids=(PROBLEM_ID,),
35 agent_specs=(AGENT_ID,),
36 ),
37 run_budget=dr.experiments.RunBudget(replicates=2, parallelism=1, max_runs=2),
38 output_dir=OUTPUT_DIR,
39 )
40 )
41
42 # Materialize the abstract recipe into condition rows, then execute those
43 # rows through design-research-experiments.
44 conditions = dr.experiments.build_design(study)
45 results = dr.experiments.run_study(
46 study,
47 conditions=conditions,
48 checkpoint=False,
49 show_progress=False,
50 )
51
52 # Export canonical analysis tables. This is the main ecosystem handoff:
53 # experiments writes artifacts that analysis can read directly.
54 artifacts = dr.experiments.export_analysis_tables(
55 study,
56 conditions=conditions,
57 run_results=results,
58 output_dir=study.output_dir / "analysis",
59 validate_with_analysis_package=True,
60 )
61
62 # Validate the exported event table and build the metric summary directly
63 # from artifacts, without asking the user to load the CSV tables.
64 event_report = dr.analysis.validate_experiment_events(artifacts["events.csv"])
65 metric_rows = dr.analysis.build_condition_metric_table_from_artifacts(
66 artifacts["events.csv"],
67 metric=PRIMARY_METRIC,
68 condition_column="agent_id",
69 )
70
71 # Reporting helpers live with experiments because they know the study shape,
72 # while analysis owns the statistical and tabular transforms.
73 summary_path = dr.experiments.write_markdown_report(
74 study.output_dir,
75 "canonical_artifact_flow_summary.md",
76 dr.experiments.render_markdown_summary(study, results),
77 )
78
79 values = [float(row["value"]) for row in metric_rows]
80 successes = sum(result.status.value == "success" for result in results)
81
82 # Keep terminal output compact: enough to confirm the packages worked
83 # together and point readers at the generated artifacts.
84 print("Canonical artifact flow:", study.study_id)
85 print("Package path: problems -> agents -> experiments -> analysis")
86 print("Problem:", problem.metadata.title)
87 print("Agent:", AGENT_ID)
88 print("Runs:", len(results), f"({successes} success)")
89 print(f"Mean {PRIMARY_METRIC}:", f"{mean(values):.4f}")
90 print("Event rows valid:", event_report.is_valid, f"(rows={event_report.n_rows})")
91 print("Summary report:", summary_path.name)
92 print("Artifacts directory:", artifacts["events.csv"].parent)
93
94
95if __name__ == "__main__":
96 main()