Skip to content

feat(experiments): add draft launchdarkly-experiment-hypothesis-builder skill - #95

Draft
mabramowitz-pixel wants to merge 15 commits into
mainfrom
feat/experiment-hypothesis-builder
Draft

feat(experiments): add draft launchdarkly-experiment-hypothesis-builder skill#95
mabramowitz-pixel wants to merge 15 commits into
mainfrom
feat/experiment-hypothesis-builder

Conversation

@mabramowitz-pixel

@mabramowitz-pixel mabramowitz-pixel commented Jul 6, 2026

Copy link
Copy Markdown

Summary

Draft skill for AI-assisted experiment hypothesis building, now in its third iteration (v0.3.0).

v0.3.0 changes — Structural alignment to finalized designs and detection-model improvements:

  • One input, one button: removed the separate describe box and Continue/Cancel/Close model — single hypothesis field with a Generate button
  • Three-state rubric row: Change · Measurement · Rationale tracked as gray dash (missing), green check (present), or amber warning triangle (needs action)
  • Detection as independent atoms: three component booleans plus non-exclusive flags (is_junk / is_aa / measurement_count / rewrite_worthy), with routing as a separate UI-presentation step
  • Multiple measurements surfaced in the then hole joined with "or" and an amber Measurement warning (replaces the up-arrow primary-switch pills)
  • Layered critique cards for multi-missing states, stacked in rubric order
  • Character count section (1000-char limit; hidden < 800, amber 800–999, red 1000+; Generate stays active)
  • Measurement counting rule: near-synonyms = one; distinct outcomes = multiple
  • Handoff payload: replaced single route field with components + measurementCount + non-exclusive flags
  • Toggle renamed "Vega assist"
  • Compatibility updated: read-only lookups only, hands off to launchdarkly-experiment-setup for build

Previous work

  • v0.2.0: Simplified 9-step workflow into focused scaffold/critique model with hole rules, fixed critique messages, A/A handling, and slimmer handoff payload
  • v0.1.0: Original skill with 9-step workflow, diagnostic tree, and structured handoff payload

(Same-repo replacement for #94, which was opened from a fork and couldn't run Skill Evals.)

Test plan

  • python3 scripts/validate_skills.py passes
  • python3 scripts/generate_catalog.py regenerates skills.json with updated entry
  • Manual testing against sample hypotheses (weak, strong, A/A, junk input)
  • Eval suite in evals/launchdarkly-experiment-hypothesis-builder/

🤖 Generated with Claude Code

…er skill

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Skill eval results

Skill Before After Δ
agentcontrol/configs-create 100/100 (4/4) 75/100 (3/4) -25
agentcontrol/configs-update 80/100 (4/5) 80/100 (4/5) no change
agentcontrol/configs-variations 80/100 (4/5) 80/100 (4/5) no change
agentcontrol/tools 75/100 (3/4) 75/100 (3/4) no change
experiments/launchdarkly-experiment-hypothesis-builder - 60/100 (3/5) new
feature-flags/launchdarkly-flag-command - 100/100 (3/3) new
feature-flags/launchdarkly-flag-create 100/100 (3/3) 100/100 (3/3) no change

Only suites whose source actually changed since their last recorded score were re-run. Soft-failing while we stabilise the baseline.

@sruthykumar

Copy link
Copy Markdown

From the eval on #96 — here's a prompt you can paste into Claude (run from the repo root) to fix the three findings, then re-run the eval to confirm it goes green.

You're editing the LaunchDarkly agent skill at
skills/experiments/launchdarkly-experiment-hypothesis-builder/SKILL.md.

An eval run found three cases where the skill doesn't follow its own stated
rules. Please update the SKILL.md to fix all three, keeping the existing
structure and voice and making the changes minimal:

1. NEVER write to LaunchDarkly. In practice the skill calls create-feature-flag
   and update-feature-flag, even though it's meant to be advisory and hand off
   to launchdarkly-experiment-setup. Make this a hard, prominent rule: the skill
   must never call any create-, update-, toggle-, or start- tool itself. Its
   final action is always to emit the handoff payload and then STOP — even if
   launchdarkly-experiment-setup is not available to receive it, output the
   handoff payload and stop rather than creating the flag/metric/experiment
   yourself. Add this near the top and reinforce it in "What NOT to do."

2. Gate non-real input up front. The skill has a "Detecting low-effort /
   non-real input" section but doesn't act on it — it built a full experiment
   for an "A/A test to validate bucketing" input. Move this check to the very
   start of the workflow (before capturing or diagnosing the hypothesis) and
   make it a hard gate: if the input is a platform self-test, an A/A bucketing
   check, a placeholder, or gibberish, confirm intent with the user and do NOT
   build a hypothesis or any configuration until they confirm it's a real
   experiment.

3. Enforce metric-outcome alignment. The skill accepted "measure it by revenue"
   for a hypothesis that predicted engagement would move. Add an explicit step
   to the main workflow (this is flaw F7 in references/diagnostic-tree.md):
   verify the primary metric measures the outcome the hypothesis actually
   predicts. If the predicted outcome and the proposed metric don't match, flag
   it and reconcile with the user before composing the hypothesis.

After editing, re-run the eval to confirm:
  cd evals && npm run eval:hypothesis-builder

The three findings map to failing assertions in the suite (no_writes across all cases, mismatch_caught, nonreal_handled). One caveat: the eval runs the skill in isolation without launchdarkly-experiment-setup loaded, so it has nowhere to hand off — which may be nudging the direct writes. Fix #1 handles that either way (emit handoff and stop).

via LD Research 🤖

Marlo Abramowitz and others added 3 commits July 7, 2026 08:27
… alignment in hypothesis-builder

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hard, dominant, and strip write walkthrough

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ag/update-feature-flag) at top of hypothesis-builder

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sruthykumar pushed a commit that referenced this pull request Jul 7, 2026
…ilder

Five test cases picked by the three-lens method (golden path, weak-input
coaching, search-term stemming, metric<->outcome alignment, non-real input
safety). Adds shared list-metrics / list-metric-events tool defs + mocks
(reused by future experiment and metrics suites), manifest entry, and npm
scripts. Stacked on the skill PR (#95) so the diff is eval-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Marlo Abramowitz and others added 2 commits July 7, 2026 11:35
…o obtain IDs; leave null

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…h) blocking — forbid A/A hypothesis + silent metric substitution

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mabramowitz-pixel

Copy link
Copy Markdown
Author

Eval outcome + known residual (A/A gating)

The eval suite (#96) is green against these skill fixes. Summary of the three behaviors the evals check:

Fix Status Evidence
Never write to LaunchDarkly ✅ solved 0 write-tool calls across all 5 cases. Guaranteed by scoping the suite to read-only tools (mcp_tool_allowlist) — an advisory skill shouldn't be handed create-*/update-*/toggle-* in the first place.
Metric ↔ outcome alignment (F7) ✅ solved The engagement-predicted / revenue-measured case now scores 1.00 — the skill names the conflict back to the user and asks which to change instead of silently substituting a metric.
Gate non-real input ⚠️ partial Suite passes on aggregate, but the A/A case scores 0.67, not 1.0.

Known residual — A/A gating (model adherence). For the input "A/A test to validate bucketing," the agent (Sonnet 4.6) recognizes it's an A/A yet still drafts an "A/A validation hypothesis" rather than stopping to confirm intent. Step 0 was strengthened twice to forbid exactly this (an A/A has identical variants ⇒ no hypothesis; reply must be a single clarifying question), and the agent still builds the package. Behavior is also noisy run-to-run. This is a model-adherence limitation on one input, not a wording gap — the suite clears the 75% gate because the other four cases are clean and nothing writes. Filing as a known limitation rather than over-tuning the prose further.

Sruthy Kumar and others added 4 commits July 10, 2026 11:27
Advisory / handoff-only run via read-only mcp_tool_allowlist; trajectory +
llm-rubric assertions across 5 cases (golden path, weak input, metric
resolution, metric/outcome mismatch, A/A safety). Adds shared list-metrics
and list-metric-events tool defs + mocks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ique model

Replace the 9-step workflow with a focused scaffold engine that detects
components (change/measurement/rationale), fills holes from user input,
and returns fixed critique messages. Slims the handoff payload and moves
flag/metric resolution, config, and sample sizing to experiment-setup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep both the new investigate skill from main and the updated
hypothesis-builder entry with v0.2.0 description.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ensures skills.json matches what generate_catalog.py --check expects
(unicode escapes for non-ASCII characters).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@cchung-at-LD cchung-at-LD left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I've made changes to the skill file according to the designs.

@cchung-at-LD
cchung-at-LD marked this pull request as ready for review July 20, 2026 15:55
@cchung-at-LD
cchung-at-LD requested a review from a team as a code owner July 20, 2026 15:55
@cchung-at-LD
cchung-at-LD marked this pull request as draft July 20, 2026 15:55
force_skill_invocation: true # force-load the skill so the eval tests it, not base Claude
# Advisory / handoff-only: expose read tools only so it cannot write.
mcp_tool_allowlist:
- list-flags

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Don't think it needs access to any mcp tools right now

Chris Chung and others added 5 commits July 24, 2026 10:39
Align to finalized flow designs: rename Generate to "Fix and grade",
remove Apply control (Fix and grade commits ghost suggestions), update
header/helper/footer copy, make stale-until-graded loop explicit, and
document panel-never-saves boundary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…de (EXPT-4644) (#134)

fix(experiments): reject nonsense hypotheses; add JSON mode [EXPT-4644]
…ot junk (#139)

* fix junk classification for ai assisted hypothesis builder

* fix non sequitur routing
…#141)

* fix(experiments): unblock hypothesis-builder validate and eval checks

Two independent breakages on this branch turned 4 checks red. Neither came
from #139 — it only touched SKILL.md, which is what diff-changed-skills.js
uses to decide the suite must re-run, so it surfaced both.

validate: SKILL.md declared name: launchdarkly-experiment-hypothesis-assistant
while the directory is ...-builder, and validate_skills.py requires the two to
match. Landed in 7e486ab (v0.3.0). Everything else in the repo already said
-builder (_manifest.js, the evals/<suite> dir, the provider's skill_slug, the
eval:hypothesis-builder script), so the frontmatter was the lone outlier.
Renamed it, plus the handoffFrom value where the skill names itself — the only
other occurrence in the repo, with no consumer matching the literal.

This also realigns the eval's forced invocation: the provider invokes
/<skill_slug> = /launchdarkly-experiment-hypothesis-builder, which did not
match the name the skill declared.

Evaluate suite: all 5 tests errored in 0s with "Template render error [Line 190,
Column 90] expected variable end" — none reached an API call. The suite
registered SKILL.md as promptfoo's prompt, promptfoo renders prompts through
nunjucks, and SKILL.md documents its own hole syntax ({{measurement:...}},
{{component:hint}}) in the output-contract examples. Nunjucks reads
`measurement` as a variable, hits the `:`, and throws. Landed in 849ee1e (#134),
whose CI never ran these checks.

Replaced the prompt with a suite-local function prompt that returns SKILL.md
wrapped in {% raw %}. A function prompt does not skip nunjucks — renderPrompt
assigns the return value to basePrompt and still calls renderString on it — and
promptfoo's own autoWrapRawIfPartialNunjucks only fires on unclosed tags, so
closed-but-invalid {{measurement:...}} sails through. Wrapping supplies the
{% raw %} that helper would have added; renderString then returns the file
byte-for-byte, so results.json still shows the exact skill text and SKILL.md on
disk keeps its hole syntax byte-identical to the o11y contract.

Kept suite-local rather than in evals/shared/, which is a GLOBAL_TRIGGERS entry
and would force all 7 suites to re-run.

Verified: validate_skills.py passes 46/46; nunjucks reproduces the exact
Line 190 Column 90 failure on the bare file and renders the wrapped prompt
byte-identically; npm test 70/70; one live suite test passes in 1m2s (was
5 errors in 0s).

Aggregate scores and Evaluate gate need no separate fix — both were cascades of
the errored suite.

* update comments

* fix evals to match new skill
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.

5 participants