Skip to content

Add Experiment Lifecycle Orchestrator (first long-horizon loop)#7

Merged
DCCA merged 1 commit into
mainfrom
claude/openspec-skills-import-4xj0qo
Jun 22, 2026
Merged

Add Experiment Lifecycle Orchestrator (first long-horizon loop)#7
DCCA merged 1 commit into
mainfrom
claude/openspec-skills-import-4xj0qo

Conversation

@DCCA

@DCCA DCCA commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the Experiment Lifecycle Orchestrator — the first long-horizon loop, built on the longrun primitives (durable state + approval gates + resumable runPlan). It proves the long-horizon model end-to-end.

The plan

design → approve-design (gate) → launch → bake (wait) → readout → decide (gate)
  • advanceExperiment(planId, hypothesis, services, store) runs/resumes the plan; call it repeatedly (e.g. on a schedule). It blocks at human gates, waits during the bake, persists progress, and is a no-op once complete.
  • Injected boundaries: an AI designer (createExperimentDesigner over the OpenRouter provider) and an ExperimentPlatform (launch + results) — adapt to Statsig/Eppo/GrowthBook/LaunchDarkly.
  • A rejected design short-circuits without launching; ship/kill is always human-gated (never auto-ship).

Changes

  • loops/experiment/ — types, plan/steps, advanceExperiment, readout, README, playbook
  • src/ai/providers.tscreateExperimentDesigner
  • test/loops/experiment.test.ts — full lifecycle (design gate → bake wait → decision gate → completion) + rejection short-circuit, via fakes + memory store

OpenSpec

Shipped via proposal → apply → archive; source of truth: openspec/specs/experiment-orchestrator.md.

Validation

  • typecheck / lint — clean
  • npm test111 tests (+3)
  • npm run build — clean (dist/loops/experiment)

Note: programmatic for now — a loopy advance <plan> CLI verb (and non-PR output adapters for the readout/decision) are planned follow-ups.

🤖 Generated with Claude Code

https://claude.ai/code/session_012CrMioorha3QtPUgWbtDbR


Generated by Claude Code

The flagship long-horizon loop, built on the longrun primitives (durable
state + approval gates + resumable runPlan):

- loops/experiment/: a resumable plan design -> approve-design (gate) ->
  launch -> bake (wait) -> readout -> decide (gate), advanced by
  advanceExperiment() which resumes from the last pause and no-ops once
  complete. Injected boundaries: AI designer + ExperimentPlatform. A
  rejected design short-circuits without launching; ship/kill is always
  human-gated.
- src/ai: createExperimentDesigner adapter.
- Full-lifecycle tests (design gate, bake wait, decision gate, completion,
  rejection) with fakes + memory store.

Shipped via the OpenSpec cycle (openspec/specs/experiment-orchestrator.md).
Validated: typecheck, lint, 111 tests, clean build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CrMioorha3QtPUgWbtDbR

@DCCA DCCA left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review

CI green (build success, ~31s); locally typecheck, lint, 111 tests, and build pass.

Strengths

  • Proves the primitives end-to-end. The plan composes runPlan + Gate + StateStore exactly as designed: done advances, gates emit blocked, the bake emits waiting, and progress persists so each advanceExperiment resumes from the last pause. Tests drive the full path (design gate → bake wait → decision gate → completion) and the rejection short-circuit across separate calls sharing one store.
  • Safe by construction. No auto-ship — both design and ship/kill are human gates; bake completes only when the platform reports results (not on a timer), avoiding action on early/noisy data; a rejected design never launches.
  • Idempotent steps. Re-running a step is safe (gate require is idempotent; launch/bake key off persisted memory), which is exactly what the resumption contract requires.
  • Clean boundaries. Designer (AI) and ExperimentPlatform are injected; the AI adapter mirrors the existing provider pattern.

Notes (non-blocking, already scoped as follow-ups)

  • Programmatic only — no loopy advance <plan> CLI verb yet, and the readout/decision aren't emitted to an external system (issue tracker/dashboard). Both are noted follow-ups.
  • The bake's untilIso is informational; the real gate is platform result availability — correctly documented.

Recommend merge.


Generated by Claude Code

@DCCA
DCCA merged commit a4d70d9 into main Jun 22, 2026
1 check passed
DCCA pushed a commit that referenced this pull request Jun 23, 2026
Rank #7 from research deep-dive #3. A long-horizon loop on runPlan + Gate +
StateStore that migrates to a new model version safely:

- loops/model-upgrade-migration/: advanceModelUpgrade() runs a resumable plan
  baseline -> candidate -> diff -> approve (gate) -> apply. It evaluates a
  golden set on the current and candidate models (injected evaluate(modelId)),
  computes regressions + score delta (reusing prompt-eval's Scorecard/
  regressions), blocks at a human approval gate, and on approval emits the
  model-id bump change set (result.bump); on rejection it holds.

Programmatic like the experiment orchestrator (a PR adapter/CLI verb is a
shared follow-up). Shipped via the OpenSpec cycle
(openspec/specs/model-upgrade-migration.md). Validated: typecheck, lint, 174
tests (+2), clean build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CrMioorha3QtPUgWbtDbR
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants