Skip to content

Trim technology-selection skill cost via gated progressive disclosure#931

Open
luisquintanilla wants to merge 1 commit into
dotnet:mainfrom
luisquintanilla:trim-technology-selection-889
Open

Trim technology-selection skill cost via gated progressive disclosure#931
luisquintanilla wants to merge 1 commit into
dotnet:mainfrom
luisquintanilla:trim-technology-selection-889

Conversation

@luisquintanilla

@luisquintanilla luisquintanilla commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Proposal: trim the technology-selection skill (dotnet/skills #889) — measured, not guessed

Skill: plugins/dotnet-ai/skills/technology-selection
Issue: dotnet/skills#889 — flagged TRIM-COST (P1),
"Address first"
: passes but heavy (+208,946 tok, +3.73 turns, +3.47 tools), passes on GPT only
(1/5 families), Impact 0.57.
Owners: @luisquintanilla, @artl93

TL;DR

We did not guess. We reproduced the eval offline with @microsoft/vally-cli, calibrated the
current skill (V1) to confirm our harness reproduces the report's direction, then ran candidate
rewrites head-to-head at runs = 3 on the full scorecard (deterministic behavior graders, the
LLM judge rubric, and tokens/turns/tools). The winner is V6 — "gated progressive disclosure":
a lean decision core with per-branch detail in references/, read only when writing implementation
code
. Measured against the current skill and three other rewrites, V6:

  • cuts the plan-only task cost ~3–4.5× (back to the cheapest variant's floor: ~29K tok / 2 turns)
    by not reading references for "show me a plan / do not write code" requests;
  • eliminates the sk- key leak and posts the best LLM-guardrail and ML.NET judge scores by
    re-reading the branch reference exactly where code is written;
  • has the best overall reliability (16/18 trials) — no behavior, judge, or reliability regression
    versus the current skill on any task.

A cheaper rewrite (V2) that trimmed more tokens but regressed the judge to 0/3 and still leaked
sk-
was rejected by the numbers — the "not in a vacuum" guarantee in action.

Root cause: the cost is induced behavior, not the 22 KB body

The skill body is ~5.5K tokens. The +208K overhead comes from what the skill makes the agent do.
Its Step 6 "Validate the implementation" mandates, on every task:

dotnet build -c Release -warnaserror   # any warning fails the build
dotnet test -c Release

and repeats dotnet build -c Release -warnaserror completes cleanly in the Validation checklist.
-warnaserror turns any warning into a hard failure, triggering fix→rebuild loops. The skill also
walks all four technology branches (classic ML / LLM / agentic / RAG) even when only one applies,
and pushes full implement+build+test even on stimuli that explicitly say "show me your plan and
architecture only — do not write any code."

Measured proof (V1, claude-haiku-4.5, LLM-summarization stimulus — one representative run;
runs = 3 median 1,273,780 tok / 44 turns / 63 tool calls):

  • 1,562,404 tokens, 46 turns, 48 tool calls (41 bash), of which 8 were dotnet build — a
    build-fix-rebuild loop that rewrote Program.cs/.csproj repeatedly.
  • Baseline (no skill) on the same stimulus: 220,239 tokens — the skill adds a ~7× overhead here.
  • And the expensive run still failed behavior: used the OpenAI SDK directly (grader
    output-contains: IChatClient → FAIL) and leaked sk- (grader output-not-contains: sk-
    FAIL). The cost bought a wrong answer. Across runs = 3, V1's LLM task leaks sk- in 1/3 runs
    and the judge passes only 2/3.
  • On the mid tier the loop times out (>6 min) on the heavy stimuli (Agentic 0/3, ML.NET 1/3).

This is exactly the report's "passes GPT only, cost not justified," reproduced and explained.

Where the tokens actually go (turn-driven cache reads)

Decomposing the token totals (input+output, from each trial's session.shutdown usage) shows the
overhead is ~98 % cache-read tokens, not fresh computation:

V1 stimulus total tok fresh tok (new input+output) cache-read tok
LLM-summarization 1,562,404 25,796 (1.7 %) 1,484,494
RAG-pipeline (plan-only) 34,038 3,906 20,248

Cache reads accumulate per turn — every extra agent turn re-reads the growing context. So the
real cost lever is turn count, and the build-fix-rebuild loop is what inflates turns (V1's
LLM run: 46 turns). Removing the mandatory build/test loop cuts turns → cuts cache-read volume →
cuts total tokens, and removes the loop's opportunities to go wrong (the sk- leak happened deep
in that loop). Cost, reliability, and correctness move together. (We report total tokens for
#889-comparability, but track turns + fresh tokens as the load-bearing, lower-variance cost axes.)

Method (measure, don't guess)

  • Harness: eng/vally-adapter/run-vally-evals.sh dotnet-ai technology-selection over
    tests/dotnet-ai/technology-selection/eval.vally.yaml (6 stimuli; deterministic graders
    output-contains/-not-contains/exit-success plus an LLM prompt rubric). baseline =
    no skill; skilled = the one skill dir under test.
  • Cross-family, reduced matrix (approved):
    • Mid leg: executor claude-haiku-4.5, judge gpt-5.5.
    • Frontier leg: executor gpt-5.5, judge claude-opus-4.6.
  • Variants swap only the skill body (identical frontmatter description, so discovery is held
    constant — Call% is already 100%, not the problem). Each variant = its own skill dir + a literal
    skilled.environment.skills path.
  • Decision rule: pick the largest ΔTok/ΔTurns/ΔTools reduction subject to no regression
    in deterministic behavior graders, no Impact/judge drop, no new timeouts
    . Cost is optimized on a
    multi-dimensional objective, never alone.

Candidate ladder

Variant SKILL.md Design Status
V1 355 lines current (verbose; walks all 4 branches; Step 6 -warnaserror build/test loop) calibration
V2 130 lines single-file trim: scope to selected branch, compact guardrails, drop the build/test loop, "if plan asked, plan only" tested
V3 81 + 4 refs progressive disclosure: lean decision core; per-branch depth in references/{classic-ml,llm,agentic,rag}.md, read for the selected branch tested
V5 30 + 4 refs aggressive floor: pure decision tree + references rejected (too aggressive: LLM judge regressed 3/5, no cost win)
V6 101 + 4 refs gated progressive disclosure: V3 core + inline per-branch "plan essentials"; read a reference only when writing implementation code, never for plan-only requests ✅ WINNER

All variants preserve the deterministic grader tokens (new MLContext(seed:, TrainTestSplit,
IChatClient, Temperature, no sk-, MaximumIterations, Microsoft.Agents.AI,
Microsoft.Extensions.AI, chunk, embedding) in the branch that emits them, and keep the
frontmatter description byte-identical to V1 (discovery held constant).

Results — HAIKU (mid) leg, runs = 3

Executor claude-haiku-4.5, judge gpt-5.5, 3 runs/stimulus. Verdict = all-graders-pass
(deterministic and the LLM prompt rubric). Tokens/turns are per-stimulus medians.
(Numbers from vally's own report.md; sk- leak = the output-not-contains grader failing.)

Reliability / behavior (pass rate out of 3): V1 from the calibration run; V2/V3/V6
co-measured in one run (baseline v2) so the V6-vs-V2-vs-V3 comparison has no cross-run drift.

Stimulus V1 V2 V3 V6
Agentic workflow (heavy) ❌ 0/3 ❌ 0/3 ❌ 0/3 ❌ 0/3
LLM integration (heavy) ❌ 0/3 · leaks sk- · judge 2/3 ❌ 0/3 · leaks sk- 2/3 · judge 0/3 🟡 1/3 · leaks 1/3 · judge 2/3 🟡 1/3 · no leak (3/3) · judge 2/3
ML.NET classification (heavy) ❌ 0/3 (2 errored) ❌ 0/3 (exit 1/3, judge 1/3) ❌ 0/3 (exit 1/3, judge 1/3) ❌ 0/3 (exit 3/3, judge 3/3) †
NL scenario → RAG chatbot (plan-only) ✅ 3/3 ✅ 3/3 ✅ 3/3 ✅ 3/3
RAG pipeline (plan-only) ✅ 3/3 ✅ 3/3 ✅ 3/3 ✅ 3/3
Reject LLM for tabular 🟡 2/3 ✅ 3/3 ✅ 3/3 ✅ 3/3
Clean passes / total complete 2 · 12/18 3 · 14/18 3 · 15/18 3 · 16/18

† The ML.NET output-contains grader inspects the literal last assistant message for
new MLContext(seed: / TrainTestSplit; a run that finished with a prose summary fails it even
though the code was written. All four variants fail it (0/3) — it is a grader-brittleness
constant, not a V6 regression. On the load-bearing signals V6 is best: it completes ML.NET 3/3
and the judge passes 3/3 (every other variant completes ≤1/3, judge ≤1/3).

Cost on the 3 light / plan-only tasks (all variants pass — apples-to-apples), median tokens / turns:

Stimulus V1 V2 V3 V6
NL → RAG chatbot 32.6K / 2 29.0K / 2 92.5K / 6 28.8K / 2
RAG pipeline 33.3K / 2 30.2K / 2 136.7K / 9 29.9K / 2
Reject LLM 31.4K / 2 27.7K / 2 87.2K / 6 27–124K / 2–8 ‡

‡ V6 removes V3's reference tax on the two explicit plan-only tasks completely (back to the V2
floor: 28.8K/2 and 29.9K/2 vs V3's 92.5K/6 and 136.7K/9 — a ~3–4.5× reduction). The
Reject LLM task is borderline (it says "I want to use GPT…", not "plan only"), so V6 sometimes
writes the ML.NET alternative in code (one of three runs spiked to 1.69M); it still passes 3/3.
This is the residual cost variance, called out honestly.

Decision & winner: V6 (gated progressive disclosure)

Applying the decision rule — largest cost cut subject to no regression in behavior graders, judge,
or reliability
V6 wins, and the losers are rejected by the numbers, not by taste:

  • V2 (cheapest single-file trim) — REJECTED. It buys the lowest cost by regressing the
    security guardrail: on the LLM task the judge fails all 3 runs (prompt 0/3, vs V1's 2/3)
    and it leaks sk- in 2/3 runs. "Trims tokens but quality suffers" is exactly the tradeoff
    we were told to reject.
  • V3 (progressive disclosure) — good, but dominated. It fixes safety (stops the leak) but pays
    a 3–4.5× token/turn tax on plan-only tasks by reading a reference it doesn't need — and V2
    proves those plan rubrics pass with no reference at all, so the tax is pure waste.
  • V5 (aggressive floor) — REJECTED earlier (LLM judge regressed to 3/5, no cost win).
  • V6 keeps V3's structure but gates the reference read to implementation only. Result: it
    matches V2's cost floor on the plan-only tasks and matches-or-beats V3's safety on
    implementation (LLM 0 leaks, best output-contains 2/3, judge 2/3), while posting the best
    overall reliability (16/18)
    and the best ML.NET outcome (completes 3/3, judge 3/3). No axis
    regresses versus V1; safety, quality, and reliability all improve.

Mechanism confirmed: the sk- leak happens deep in the implementation loop, so the fix is to
re-anchor the guardrail exactly there (read llm.md when writing LLM code) — not to pay for a
reference on a plan the agent will never code. V6 does precisely that, and the measured numbers
confirm it: safety preserved where code is written, cost cut where it isn't.

Results — FRONTIER (GPT) leg — the "no regression where V1 already passes" check

The report says the skill "passes on GPT only." So the frontier leg is a regression guard:
executor gpt-5.5, cross-family judge claude-opus-4.6, V1 vs V6, runs = 2. On GPT the heavy
tasks actually complete (both variants 12/12 trials complete, 0 leaks).

Verdicts are identical V1↔V6 on every task (cross-family judge agrees): NL ✅, RAG ✅, Reject ✅,
LLM 🟡 (output-not-contains 2/2 — no leak — prompt 2/2), Agentic ❌ and ML.NET ❌ only on the
brittle output-contains grader while exit-success 2/2 and the judge prompt 2/2 both pass. No
task V1 passes on GPT regresses under V6.

And V6 still cuts cost on GPT — the trim is not a haiku artifact:

Stimulus (GPT) V1 tok / turns V6 tok / turns Δ
LLM integration 2.11M / 47.5 1.32M / 37 −37% tok, −10 turns
NL → RAG chatbot (plan-only) 27.6K / 2 24.6K / 2 −11%
RAG pipeline (plan-only) 28.2K / 2 24.9K / 2 −12%
ML.NET 610K / 25 546K / 25.5 −10%
Agentic 2.12M / 39 1.94M / 49 −9% tok

V6's LLM output-contains also improves to 5/5 on GPT (V1: 3/5). Net: on the family where the
skill already passes, V6 preserves every pass and reduces the LLM task's cost by more than a third.

Validity caveats (stated honestly)

  • Discovery not measured here: the experiment force-loads the skill, so description changes
    don't surface as Call%. We kept description byte-identical across variants; any triggering
    change needs a separate discovery probe. (Call% is already 100% — discovery is not the problem.)
  • Reduced matrix ≠ full CI grid: absolute numbers differ from the report; inference rests on
    relative within-harness comparison (same tasks/judge/harness across variants).
  • Heavy stimuli (Agentic, ML.NET "full implementation") hit the 6-min cap for baseline and every
    variant on the mid (haiku) tier — haiku is too weak to finish them regardless of skill, so
    Agentic is non-discriminating there; the frontier (GPT) leg is where those tasks actually
    complete. ML.NET's output-contains grader is brittle to prose-summary endings across all
    variants (see †).
  • runs = 3 on the mid leg (report avgN was 3.6); the frontier leg uses runs = 2 as a regression
    check. Token totals on heavy tasks are cache-read-dominated and noisy (§ "Where the tokens go"),
    so cost claims lean on turns and the low-variance plan-only tasks.
  • The sk-/quality wins are the load-bearing result; they reproduce across two independent
    haiku runs (v123 and v236). V2's leak and V3's tax both replicated.

What ships (PR-ready)

plugins/dotnet-ai/skills/technology-selection/:

  • SKILL.md: 355 → 101 lines (git diff --stat: +85 / −339).
  • New references/: classic-ml.md, llm.md, agentic.md, rag.md (182 lines total),
    read only when implementing the selected branch.
  • Frontmatter description byte-identical to the current skill (discovery unchanged; Call% is
    already 100%).
  • Passes the repo's markdownlint-cli2 config (0 issues).

Net effect vs the current skill, by the numbers: removes the dotnet build -warnaserror /
dotnet test loop that was the cost driver; answers plan-only requests from the lean core (~29K
tok / 2 turns, a 3–4.5× cut); re-reads the branch reference while writing code, which stops the
sk- key leak
and yields the best LLM/ML.NET judge scores; best overall reliability (16/18) on
haiku and −37% tokens on the LLM task on GPT — with no task regressing on either family.

Reproduce

# from the dotnet/skills repo root, with @microsoft/vally-cli installed and GITHUB_TOKEN set
vally experiment run <experiment.yaml> \
  --eval-filter tests/dotnet-ai/technology-selection/eval.vally.yaml --workers 6

Experiment files used (variants swap only environment.skills): mid leg
claude-haiku-4.5×gpt-5.5, runs 3 (V2/V3/V6 co-measured); frontier leg gpt-5.5×claude-opus-4.6,
runs 2 (V1 vs V6). Scorecards were recomputed directly from each trial's events.jsonl and matched
vally's own report.md exactly.


PR scope

This PR is scoped to one of the five skills tracked in
#889: the TRIM-COST (P1) "address first" item
for technology-selection. Issue #889 is a dotnet-ai portfolio tracker and stays open for
the remaining four mcp-csharp-* skills (STRENGTHEN / EFFICIENT-WIN) — this PR is a partial step,
not the whole issue.

The change touches only the skill body (SKILL.md 355 → 101 lines + new references/); the
frontmatter description is byte-identical, so discovery/triggering is unchanged.

Copilot AI review requested due to automatic review settings July 22, 2026 19:29
@luisquintanilla
luisquintanilla requested a review from artl93 as a code owner July 22, 2026 19:29
Cuts SKILL.md from 355 to 101 lines and moves per-branch depth into
references/ (classic-ml, llm, agentic, rag), read only when writing
implementation code. Removes the Step 6 `dotnet build -warnaserror` +
`dotnet test` mandate that induced build-fix-rebuild loops -- the root
cost driver flagged in dotnet#889 (measured: 1.56M tok / 46 turns / 8 builds
vs a 220K no-skill baseline on the LLM stimulus).

Selected by offline head-to-head Vally runs (runs=3, two model families),
not guessed. Versus the current skill: plan-only cost cut ~3-4.5x,
eliminates the sk- key leak, best reliability 16/18 on haiku, -37% tokens
on the LLM task on GPT, and zero task regression on either family. A
cheaper single-file trim was rejected because its judge score dropped to
0/3 and it still leaked sk-. Frontmatter description is unchanged so
discovery is held constant (Call% already 100%).

Part of dotnet#889 (the dotnet-ai portfolio tracker): this implements the
TRIM-COST (P1) "address first" item for technology-selection only. The
four mcp-csharp-* skills tracked in dotnet#889 remain separate work.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a78b17bd-5e28-4e85-b248-38626ebb5eee
@luisquintanilla
luisquintanilla force-pushed the trim-technology-selection-889 branch from 9d4172f to 4516118 Compare July 22, 2026 19:31

Copilot AI left a comment

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.

Pull request overview

This PR trims the plugins/dotnet-ai/skills/technology-selection skill by moving deep per-branch guidance into references and gating those reference reads to implementation-only scenarios, reducing token/turn/tool overhead for plan-only requests.

Changes:

  • Rewrites SKILL.md into a shorter decision-core with “plan-only vs implementation” gating guidance.
  • Adds per-branch reference docs (classic-ml, llm, agentic, rag) to hold implementation details and minimal code shapes.
  • Updates validation/anti-pattern checklists to align with the progressive disclosure approach.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
plugins/dotnet-ai/skills/technology-selection/SKILL.md Replaces verbose workflow with a compact decision tree + gated reference usage.
plugins/dotnet-ai/skills/technology-selection/references/classic-ml.md Adds ML.NET packages/guardrails + minimal example.
plugins/dotnet-ai/skills/technology-selection/references/llm.md Adds MEAI LLM integration packages/guardrails + minimal example.
plugins/dotnet-ai/skills/technology-selection/references/agentic.md Adds Agent Framework packages/guardrails + minimal example.
plugins/dotnet-ai/skills/technology-selection/references/rag.md Adds RAG packages/guardrails + minimal query shape + planning checklist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +30 to +32
var queryEmbedding = await embeddingGenerator.GenerateAsync(question, ct);
var hits = await collection.SearchAsync(queryEmbedding, top: 5, new() { }, ct);
var grounded = hits.Where(h => h.Score >= 0.75); // minimum similarity threshold
Comment on lines +33 to +36
.AsBuilder()
.UseFunctionInvocation()
.Use(inner => new RetryingChatClient(inner, maxRetries: 3))
.Build());
Comment on lines +9 to +11
<PackageReference Include="Microsoft.Extensions.AI" Version="9.*" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.*" /> <!-- or OpenAI / Azure.AI.Inference / OllamaSharp -->
<PackageReference Include="Microsoft.ML.Tokenizers" Version="2.*" /> <!-- client-side token budgeting -->
Comment on lines +9 to +11
<PackageReference Include="Microsoft.Extensions.AI" Version="9.*" />
<PackageReference Include="Microsoft.Agents.AI" Version="1.*-*" /> <!-- prerelease: dotnet add --prerelease -->
<PackageReference Include="Azure.AI.OpenAI" Version="2.*" /> <!-- or another MEAI provider -->
Copilot AI review requested due to automatic review settings July 22, 2026 19:32

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

plugins/dotnet-ai/skills/technology-selection/references/rag.md:32

  • The sample mixes a named argument (top: 5) with positional arguments that follow (new() { }, ct), which is invalid C# syntax. Use either all positional arguments or name the remaining arguments as well so the snippet compiles.
var queryEmbedding = await embeddingGenerator.GenerateAsync(question, ct);
var hits = await collection.SearchAsync(queryEmbedding, top: 5, new() { }, ct);
var grounded = hits.Where(h => h.Score >= 0.75);   // minimum similarity threshold

plugins/dotnet-ai/skills/technology-selection/references/llm.md:35

  • This reference is scoped to “no tools”, but the minimal shape enables function/tool invocation (UseFunctionInvocation()). Either remove it here or move this snippet under the agentic reference to keep the guidance consistent.
        .AsBuilder()
        .UseFunctionInvocation()
        .Use(inner => new RetryingChatClient(inner, maxRetries: 3))

plugins/dotnet-ai/skills/technology-selection/references/llm.md:11

  • The package list doesn’t include Azure.Identity, but the minimal example uses DefaultAzureCredential which comes from that package. Adding it avoids a copy/paste compilation failure.
<PackageReference Include="Microsoft.Extensions.AI" Version="9.*" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.*" />   <!-- or OpenAI / Azure.AI.Inference / OllamaSharp -->
<PackageReference Include="Microsoft.ML.Tokenizers" Version="2.*" />  <!-- client-side token budgeting -->

plugins/dotnet-ai/skills/technology-selection/references/agentic.md:11

  • The package list doesn’t include Azure.Identity, but the minimal example uses DefaultAzureCredential. Adding Azure.Identity prevents a copy/paste compilation failure.
<PackageReference Include="Microsoft.Extensions.AI" Version="9.*" />
<PackageReference Include="Microsoft.Agents.AI" Version="1.*-*" />  <!-- prerelease: dotnet add --prerelease -->
<PackageReference Include="Azure.AI.OpenAI" Version="2.*" />        <!-- or another MEAI provider -->

@AbhitejJohn

Copy link
Copy Markdown
Collaborator

Cross-family Vally evaluation — technology-selection

Ran the cross-family skill evaluation on the single skill changed by this PR (plugins/dotnet-ai/skills/technology-selection) — SKILL.md + references/{agentic,classic-ml,llm,rag}.md.

  • Run: https://github.com/dotnet/skills/actions/runs/29985588613
  • Dispatch: cross-family evaluation-run.yml on a throwaway branch = PR head (4516118) + the cross-family workflow commit; scoped plugins=dotnet-ai skills=technology-selection, executors=opus,gpt,sonnet46,haiku,mai, runs=3 workers=3.
  • Judge rule (verified): judge is never the executor's family — GPT judges Opus, Opus judges everyone else.

Skilled (treatment) vs baseline, per executor

Executor Model Judge Result Win rate (W/T/L) Mean preference Trials
opus claude-opus-4.8 gpt-5.5 ❌ inconclusive 100% (12/0/0) +65.0% [45.4, 84.6] 12 (3 unmatched)
gpt gpt-5.5 claude-opus-4.8 ✅ credibly better 94.4% (17/1/0) +67.8% [50.7, 84.9] 18
sonnet46 claude-sonnet-4.6 claude-opus-4.8 ❌ inconclusive 100% (14/0/0) +78.6% [61.3, 95.8] 14 (1 unmatched)
haiku claude-haiku-4.5 claude-opus-4.8 ✅ credibly better 77.8% (14/3/1) +58.9% [35.6, 82.1] 18
mai mai-code-1-flash-picker claude-opus-4.8 ❌ inconclusive 66.7% (8/3/1) +33.3% [7.7, 58.9] 12 (6 unmatched)

Cross-family pass rate: 2/5 (40%) at the strict conclusive bar (gpt, haiku).

Interpretation

The trimmed skill is directionally preferred over baseline in all 5 executors — win rate 67–100%, mean preference +33% to +79%. The three non-passes are flagged inconclusive due to unmatched trajectories (3 / 1 / 6 unmatched trials), not losses — the treatment did not lose a single conclusive comparison against baseline anywhere.

Against the 12% dotnet-ai pass rate that motivated #889, this is a strong positive signal: where the comparison is conclusive the trimmed skill is credibly better, and no executor prefers the baseline. The remaining action is reducing unmatched trajectories (opus/sonnet46/mai) so those cells reach conclusiveness rather than any concern about skill quality.

@AbhitejJohn

AbhitejJohn commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

@luisquintanilla Thanks for taking this on — the progressive-disclosure restructure is a genuinely nice win. Trimming the top-level skill from ~263 to ~102 lines and moving per-branch detail into references that only load at implementation time directly targets the cost problem this was meant to fix.

I ran the change two ways to sanity-check it: a cross-family evaluation (five different models each doing the task, with a separate model scoring them), and several independent AI code reviews plus an automated skill-quality check. Sharing what came back in case it's useful.

Evaluation results were encouraging. Across all five models, the trimmed skill was preferred over the current version. Two cleared the strict "credibly better" bar; the other three are positive-but-inconclusive due to unmatched trajectories, not losses — no model preferred the baseline in any conclusive comparison. Full run: https://github.com/dotnet/skills/actions/runs/29985588613

Executor model Judge Result Win rate (W/T/L) Mean preference [95% CI]
Opus GPT inconclusive (unmatched) 100% (12/0/0) +65.0% [+45.4, +84.6]
GPT Opus ✅ credibly better 94.4% (17/1/0) +67.8% [+50.7, +84.9]
Sonnet 4.6 Opus inconclusive (unmatched) 100% (14/0/0) +78.6% [+61.3, +95.8]
Haiku Opus ✅ credibly better 77.8% (14/3/1) +58.9% [+35.6, +82.1]
MAI Flash Opus inconclusive (unmatched) 66.7% (8/3/1) +33.3% [+7.7, +58.9]

A few things worth a look before merging, grouped by severity.

🔴 Blocking

  • Some technology branches lost their guidance. The decision tree still points people to ONNX Runtime, OllamaSharp, and the GitHub Copilot SDK, but the implementation step only offers four reference files (ML.NET, LLM, agentic, RAG) and the old inline package versions for those three were removed. An agent picking one of those paths now has nothing to open and no package versions to go on, so it may guess. Worth either adding short references or keeping their package versions somewhere reachable.

🟡 Non-blocking

  • The "Hybrid" path is under-routed. The gate says to read "the one matching reference," but a hybrid ML.NET-scoring-plus-LLM implementation needs both the classic-ml and llm references. Suggest wording it as "read the matching reference(s) — for Hybrid, read both."
  • RAG planning guidance is behind a closed door. Plan/architecture requests are told to answer from the top-level file and not open a reference, but the RAG planning checklist lives in references/rag.md. Either hoist that checklist up, or allow opening it for RAG planning.

⚪ Minor (from the automated skill-quality check — wording being a touch too absolute)

  • Saying Microsoft.SemanticKernel is superseded for all new projects is stronger than warranted — it's still an active, supported option; conditional guidance reads better than a blanket ban.
  • "Never hand-roll tool loops on IChatClient" pushes everyone to the prerelease Agent Framework even for simple, bounded function calls. A short "use plain MEAI for simple cases, Agent Framework for durable multi-step/multi-agent work" would help.
  • One eval scenario asks only what to use for churn prediction but the scoring expects a full implementation — that can penalize a correct, concise recommendation. Worth aligning the prompt and the rubric.
  • A couple of scenarios check output text rather than a built/run result, and the "do not use for" exclusion has no scenario testing that it correctly stays inactive.

(Three other compile-level items — the SearchAsync argument order in rag.md, the missing Azure.Identity package in llm.md/agentic.md, and the UseFunctionInvocation contradiction in llm.md — are already covered by the automated reviewer's inline comments, so I won't repeat them here. They're worth fixing too and I'd count the first two as Blocking.)

None of this is blocking on capability — the direction is clearly right. The branch-routing gap above is the highest-value fix; the rest is polish. Thanks again for pushing this forward!

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.

3 participants