ExperimentSpec v1: versioned schema with result gating against real stage-14 metrics - #324
Draft
DermotOBrien-EC wants to merge 9 commits into
Draft
ExperimentSpec v1: versioned schema with result gating against real stage-14 metrics#324DermotOBrien-EC wants to merge 9 commits into
DermotOBrien-EC wants to merge 9 commits into
Conversation
PIVOT/REFINE rollback re-enters execute_pipeline with a fresh frame; the outer frame later overwrites pipeline_summary.json with only its own degradation list, so records made during the recursive run were lost. Thread one shared accumulator through the recursive call.
The outcome hook read run_dir/results.json, which production never writes, so every remembered outcome carried metric 0.0. Aggregate the actual stage-*/runs artifacts via _collect_experiment_results and record the contract metric mean, matching condition-prefixed keys.
UniversalExperimentPlan gains a versioned v1 schema with round-trip YAML serialization and validation, and the legacy exp_plan converter now preserves every contract metric (first as primary, the rest as secondary). The runner replaces the dead inline researchclaw.pipeline.experiment_spec hooks with real gates: after EXPERIMENT_DESIGN the plan is converted and written as experiment_spec.yaml; after RESULT_ANALYSIS the contract metrics are validated against the freshly written stage-14/experiment_summary.json metrics_summary, matching condition-prefixed keys (e.g. ppo/accuracy) and accepting either the standard aggregate dicts (validated via mean) or bare numeric values. A missing summary or missing/empty metrics_summary defers to stage-15 diagnosis with a once-per-run degradation record instead of failing the stage; unreadable or malformed summaries and contract violations fail the stage with a spec_violations.json artifact.
max_budget_usd defaults to 5.0 and researchclaw.cost_tracker does not exist, so the budget check has always been a silent no-op. Instead of failing CLI-agent runs (the rejected PR 302 behavior) or staying silent, record a once-per-run cost_budget_unenforced degradation when a CLI agent runs with a configured budget and no tracker, keep the pure-LLM path silent, preserve the stop-on-exceeded path when a tracker exists, and record tracker errors instead of swallowing them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resubmission of #301, with the result gate reworked to resolve the three blockers from the #301/#302 closing reviews. Stacked on #323: the first 7 commits here belong to that PR; this PR adds the last 2 (
Evolve ExperimentSpec v1 schema and gate spec violations in the runner,Record unenforced cost budgets as a degradation). Kept as a draft until #323 lands, then I will rebase so the diff shows only the schema and gate work.The three blockers, resolved
1. The result gate now validates the artifact the pipeline actually writes. The old gate read
run_dir/results.json, which production never creates, so stage 14 hard-failed every real run. The reworked gate readsstage-14/experiment_summary.json(the file the just-completed stage writes; thestage-14_vNdirectories are pre-rollback snapshots, since_version_rollback_stagesrenames the old directory before a re-run) and validates the contract metrics against itsmetrics_summary:accuracymatchesppo/accuracyas well as a bareaccuracykey.{min, max, mean, count}aggregates; themeanmust be finite and numeric. Bare numeric values are also accepted, mirroring the BUG-09 tolerance in_analysis.pyfor metrics that do not use the standard shape.metrics_summary, DEFERS: the stage result is returned unchanged and a once-per-runresult_gate_deferreddegradation is recorded inpipeline_summary.json(stage 15 diagnosis and the R6-4 tolerance already handle the empty-metrics situation downstream).spec_violations.jsonartifact: an unreadable or invalid-JSON summary, a non-objectmetrics_summary, a contract metric with no matching key, or a non-finite value.2. The cost budget can no longer hard-fail a run.
max_budget_usddefaults to 5.0 andresearchclaw/cost_tracker.pydoes not exist in the repo, so the old #302 change failed every CLI-agent run at the first stage. Now a missing tracker records a once-per-runcost_budget_unenforceddegradation for CLI-agent providers (silent for providerllm, where the knob is inert by design), the stop-on-exceeded path is preserved unchanged when a tracker is importable, and tracker errors are recorded once instead of swallowed.3. No
importlib.util.find_spec. The missing-import bug is gone structurally: tracker availability is detected with try/except ImportError.Also in the schema commit
UniversalExperimentPlangains the v1 contract fields (schema_version,mode,budget,seeds, preregisteredprediction), strictfrom_dictparsing that rejects unknown keys, YAML round-trip (to_yaml_v1/from_yaml_v1), andvalidate(strict=...).from_legacy_exp_plannow preserves every contract metric: the first becomes the primary, the rest becomesecondary_metrics(previously they were silently dropped, so a plan withmetrics: [accuracy, loss]never enforcedloss).stage-09/experiment_spec.yaml; the gate skips with a warning when that file is absent (pre-v1 runs).Testing
The old gate tests manually created
run_dir/results.json, which is what masked blocker 1; no test does that anymore. The rewritten tests build the real artifact layout (stage-14/experiment_summary.jsonwith condition-prefixedmetrics_summary) and every behavioral change was verified red-first against the pre-fix code. Coverage includes: prefixed and exact metric matching, a missing secondary metric failing the stage, non-finite means failing, empty and absent summaries deferring with exactly one degradation record, a non-objectmetrics_summaryfailing as malformed, the gate validating the currentstage-14/rather than a stale_v2snapshot, budget degradation recorded once for CLI-agent runs and not forllm, the preserved stop-on-exceeded path, schema round-trip and validation, and the converter keeping secondary metrics in both dict and list forms.Full suite:
2976 passed, 56 skipped(the skips are the env-gated live suites).