Add CI pipeline for SDK skill-efficacy evaluation#222
Conversation
Adds a GitHub Actions workflow and supporting scripts to evaluate the cosmosdb-sdk skill set using MSBench. The pipeline: - Runs 15 Harbor task instances (3 scenarios × 5 SDKs) with 3 repeats - Uses pass@k metrics to measure skill reliability - Creates GitHub issues mapping failures to specific sdk-* rules New files: - .github/workflows/msbench-eval.yaml (workflow_dispatch trigger) - scripts/msbench-eval.py (orchestration: submit, poll, report) - scripts/create-skills-issue.py (failure → rule mapping → issue) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds a manually-triggered GitHub Actions pipeline plus helper scripts to run MSBench-based evaluations for Cosmos DB SDK skill guidance, generate a merged pass@k report, and (optionally) open a tracking issue when results fall below a threshold.
Changes:
- Adds a
workflow_dispatchGitHub Actions workflow to authenticate via Azure OIDC, installmsbench-cli, run the evaluation, and uploadresults.json. - Adds
scripts/msbench-eval.pyto orchestrate MSBench runs, poll for completion, generate a merged report, and evaluate per-instance pass rates. - Adds
scripts/create-skills-issue.pyto parse results, map failing tests to sdk-* rules, and create a GitHub issue viagh issue create.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
.github/workflows/msbench-eval.yaml |
New manual CI workflow to run MSBench evaluation, optionally create an issue, and upload artifacts. |
scripts/msbench-eval.py |
New orchestrator script for running MSBench, merging reports, parsing pass rates, and flagging failing instances. |
scripts/create-skills-issue.py |
New issue-creation script to summarize failures and map them to rule files. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use masked env var for pip token instead of persisting in pip config - Guard issue creation step on results.json existence - Fix normalize_rate to correctly handle '0.9%' as 0.009 not 0.9 - Remove duplicate issue creation from msbench-eval.py (workflow handles it) - Make labels optional in create-skills-issue.py with fallback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Moves the cosmos-sdk-skills benchmark into benchmarks/cosmos-sdk-skills/: - 15 Harbor tasks (3 scenarios × 5 SDKs): mosaic, ticketing, IoT - Shared verifier with 5 check files (pytest-based SDK best practice tests) - runner.sh entrypoint (emulator startup, app build/run, pytest execution) - runner-with-skills.sh (custom runner that loads cosmosdb-sdk skill) - dataset.jsonl (15 MSBench instances) - publish-benchmark.yaml workflow (auto-rebuild on benchmarks/ changes) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The actual tool for building/publishing benchmark images is harbor-format-curation, not msbench-cli. Updated the workflow to use the correct commands: import, build, update-database, publish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The verifier graded best-practice rules mostly by regex-scanning agent source (check_source.py / check_advanced_source.py). Per the MSBench lessons doc, those static checks are gameable and prove nothing about runtime behavior. This adds a behavioral grader driven by the live app plus independent emulator reads, for the mosaic scenario (all 5 SDKs). - check_behavior.py (NEW, wired into runner.sh): builds/runs the app, drives the HTTP API, then re-reads the Cosmos emulator with the verifier's own client and asserts they agree: persistence is real (no in-memory/SQLite fakes), API read matches the stored doc, duplicate POST -> 409 with exactly one persisted doc, partition-key value == user id with a working point read, and city filter == emulator query set. - conftest.py: independent-emulator-read helpers/fixtures (emulator_docs_for_id, persisted_docs, users_partition_key_field). - check_source.py: honest docstring — these remain STATIC client-config signals the single-node emulator cannot prove (retry, Direct mode, preferred regions, diagnostics, singleton), kept for A/B coverage. - 5x mosaic instruction.md: grading section now states live behavior is primary and symmetric across arms. - README.md + docs/benchmark-coverage.md: document the behavioral layer. Note: emulator not runnable on Windows host; re-validate gold in WSL and regenerate the dataset prompt (instruction.md changed). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Validated the behavioral verifier end-to-end by running the mosaic-python gold reference against the vNext Cosmos emulator. The run surfaced two real reference bugs that had never been exercised, plus a gold/agent asymmetry that prevented fix_validation from ever reaching reward=1: - reference/requirements.txt: add email-validator (app.py uses pydantic EmailStr, so the service failed to boot without it). - reference/app.py: drop enable_cross_partition_query from the async query_items call. The azure-cosmos v4 async SDK removed that kwarg (cross-partition is automatic); passing it raised TypeError -> 500 on GET /users?city=. Caught by both check_api and the new check_behavior. - check_skills.py TestAgentReadSkills: skip (instead of fail) when no agent transcript exists. Gold/fix_validation runs have no Copilot agent, so the transcript is never written; a present-but-empty transcript still fails (real infra signal). - .gitignore: ignore the locally staged skills build-context artifact. Gold now passes: 41 passed, 3 skipped, reward=1. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The vnext emulator's gateway serves static endpoints (/, emulator.pem) before the pgcosmos data-plane extension finishes initializing. The old readiness probe only checked that :8081 answered, so runner.sh proceeded while real Cosmos calls still returned HTTP 503 'pgcosmos extension is still starting'. SDK clients that connect eagerly at process start (dotnet/java/nodejs/go) crashed at boot; the python reference only survived because the emulator was already warm. Add a dataplane_ready() check that issues a signed GET /dbs and a wait_dataplane() loop that blocks until the data plane answers with a non-5xx status. Both the already-running fast path and the post-launch path now wait on it. Validated: mosaic-nodejs gold goes from reward=0 to reward=1, and the other SDKs now reach their apps instead of dying on the startup 503. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tives All five mosaic SDK gold references now pass local emulator gold runs (reward=1): python, nodejs, dotnet, java, go. Reference fixes (emulator integration; production literals preserved so check_source static rules still pass): - dotnet: use ConnectionMode.Gateway when the endpoint is the local emulator (emulator has no Direct/rntbd backend), keep Direct for real accounts. - java: break a Spring bean cycle by moving the CosmosClient @bean into a nested @configuration class; use gatewayMode + endpointDiscoveryEnabled( false) and drop preferredRegions for the emulator (single-region emulator advertises no regional endpoints, so discovery tried to resolve localhost-WestUS2). The Java v4 SDK always uses TLS for the gateway, so this instance runs the emulator in https mode and trusts its self-signed root CA in run.sh. - go: azcosmos v1.2.0 has no NewCrossPartitionQueryItemsPager; use NewQueryItemsPager with an empty PartitionKey for the cross-partition query. Add the missing go.sum (go mod tidy). Harness fix: - start-emulator.sh: the data-plane readiness probe now skips TLS verification when COSMOS_PROTOCOL=https (self-signed emulator cert). Verifier false-positive fixes (baked into base image): - conftest.py: skip the dotnet build output dir (out/) when scanning source, and strip XML comments (<!-- -->) so a commented-out package id in a .csproj no longer trips package checks. - check_source.py: the "no Azure.Cosmos preview package" check no longer matches inside the legit Microsoft.Azure.Cosmos id (negative lookbehind). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rewrite the 'How you will be graded' section of all 15 task instruction.md files so the agent gets no mention or hint of skills, an agent skill set, or Cosmos DB best-practice criteria. Remove the enumerated best-practice categories (retry, preferred regions, Direct mode, diagnostics, client reuse, indexing policy, throughput) and the mosaic-go transparency rubric. Grading is now described purely functionally: a verifier drives the HTTP API and independently reads the emulator to confirm endpoints behave per the API contract and returned data matches stored data. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The instruction scrub removed all agent-facing hints about a skill set, so the Go/Node.js 'missing-guidance transparency' rubric is now undiscoverable (an agent can't know to write 'borrowed from ...'). The skills-read gate (did the agent open SKILL.md / a rule file) is also out of scope for this benchmark. Remove both: - check_skills.py: drop TestGoMissingGuidanceTransparency, TestNoOverstatedCertainty, TestNodejsNoOverstatedCertainty, and TestAgentReadSkills plus their helpers/constants; unused imports removed; module retitled to 'Source anti-pattern checks'. - conftest.py: drop the now-unused source_text_with_comments and docs_text fixtures. - README.md / docs/benchmark-coverage.md: remove the transparency and skill-engagement descriptions, matrix rows, and legend so the docs match the graders that actually run. The remaining source anti-pattern checks (hardcoded key, endpoint from env, forbidden packages, sync-over-async blocking, async client) are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eting + iot
Refactor the shared verifier (check_api/behavior/cosmos/source, conftest) to
drive all generic checks off declarative per-scenario contracts instead of the
hardcoded mosaic contract. Each root-entity sub-check (create/get/list,
persistence, duplicate rejection, partition key, indexing, throughput, document
shape) is toggled by the contract so mosaic, ticketing, and iot each get exactly
the checks they declare.
- shared/contracts/{mosaic,ticketing,iot}.json: declarative contracts baked
into the base image (SCENARIO env selects the active one).
- conftest.py: loads the contract, exposes ROOTS/CHILDREN + shared helpers and
fixtures (container resolution, emulator doc lookup, root seeding/persistence).
- check_source.py: provision-count bound is now contract-aware (1 database +
one create-container per declared container) so multi-container scenarios pass.
- Per-scenario /tests/checks.py grade the child entities the generic engine does
not model: ticket purchase/duplicate/ETag-cancel, reading ingest/time-range/
device-summary. Copied to all 5 SDK dirs each.
- Python reference apps for ticketing (events+tickets, ETag cancel) and iot
(devices+readings, time-range + summary), mirroring mosaic-python.
- Task Dockerfiles set per-scenario env; python tasks wire in the reference.
Gold-validated locally: all 5 mosaic SDKs, ticketing-python, and iot-python
report reward=1.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ends The CES backend writes instance_id into /drop/metadata.json, but the local Docker backend writes run-level metadata (instance_ids, plural) and passes the id via the instanceId env var. entry.sh hard-read ['instance_id'] under set -e, so on the local backend the python KeyError aborted the whole script before the agent ran (gold runs never exercised this path — they call solve.sh/test.sh directly). Prefer the instanceId env var, fall back to metadata.json, default to 'unknown', mirroring parse.py's existing logic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Convert the 6 structurally-complete tasks to the proven harbor-format-curation
layout so CES runs the baked verifier and produces real 0/1 scores (not "error").
Per task: git mv reference -> environment/reference; rewrite environment/Dockerfile
to pre-install which/zip/unzip via tdnf + dnf->tdnf shim (CES agent harness skips
installs for tools already present on Azure Linux), use relative COPY reference,
keep per-language toolchain installs, and drop harbor-baked tests/solution/
instruction/metadata COPY lines.
Pipeline reads authoritative scores from eval.json inside output.zip instead of
msbench-cli report (which mis-parses harbor eval.json). Regenerate all 15
metadata.json with the full harbor contract; add harbor-generated dataset.jsonl
and benchmark_loaders.toml.
Validated on CES: ticketing-python (run 28973765143) and mosaic-python
(run 28975682758) both graded end-to-end with 0 errors/0 eval-errors.
Deferred: iot-{dotnet,go,java,nodejs} and ticketing-{dotnet,go,java,nodejs}
need reference apps + language toolchains authored before they can grade.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Narrow the PR and weekly MSBench run to the single, CES-validated
mosaic-python task (run 28975682758 graded 0/1 with 0 errors).
- Remove the other 14 task dirs (mosaic-{dotnet,go,java,nodejs},
ticketing-*, iot-*); their full work is preserved on branch
yumnahussain/all-15-tasks-backup for later expansion.
- Reduce dataset.jsonl and msbench-registration/dataset.jsonl to the
single mosaic-python row (pipeline reads the top-level dataset).
- Update README.md + docs/benchmark-coverage.md with a scope banner and
corrected counts (1 task, Python-only); the shared verifier keeps its
per-language checks (gated by SDK), so no shared/ changes are needed.
The workflow and scripts/msbench-eval.py are already task-count agnostic
(they iterate the dataset), so no logic changes are required.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Normalize pass-rate fractions before rendering, preserve aggregated repeat counts in generated issue analysis, forward selected Copilot models into CES runs, and remove unused issue creation helper. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…arsed status msbench-cli run (without --no-wait) blocks to completion, so its output already contains report/analysis prose that mis-parses harbor eval.json and emits a bogus 'error' status token. The early terminal-failure guard scraped that token and aborted with exit 2 before reaching the authoritative build_results_from_eval grader -- so every completed real run crashed the pipeline instead of writing results.json, checking the threshold, and filing the skills issue. - msbench-eval.py: don't hard-abort on a failure-looking status from the already-completed run output; only use status to decide whether to keep polling. Make wait_for_completion defer a scraped TERMINAL_FAILURE to eval.json grading (genuine failures still surface via the report fallback). - create-skills-issue.py: map TestPythonAsyncClient -> sdk-python-async-deps (the real async verifier class that failed in a live run was unmapped). Verified end-to-end against a real run (29036621569): 0/1 resolved now grades as a clean threshold FAIL (exit 1 -> issue creation) instead of exit 2 crash. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The runner previously forced a custom-agent persona (--agent cosmosdb-best-practices) whose routing table explicitly told the agent-under-test to read the skill rules. That contaminated the benchmark: it measured a hinted agent, not the skill's organic effect. Replace the custom-agent staging with a plain skill install into ~/.copilot/skills/ (the personal skills directory @github/copilot auto-discovers). The default agent now runs the task with no hint -- it only sees the skill's name+description and decides on its own whether to consult it, exactly as a real user's setup would. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…runner Parse a single COSMOS connection string (AccountEndpoint + AccountKey) into COSMOS_ENDPOINT + COSMOS_KEY before live-mode detection, so passing --encrypted-env COSMOS alone switches the grader off the bundled emulator and onto a live account. Order-independent; base64 keys preserved. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: yumnahussain <161499581+yumnahussain@users.noreply.github.com>
Forward live-account credentials (COSMOS connection string, or split COSMOS_ENDPOINT/COSMOS_KEY) via --encrypted-env when present so the verifier grades against a real Cosmos account instead of the bundled emulator. When unset, the pipeline runs against the emulator as before. Also fix an --encrypted-env argparse bug: msbench-cli's --encrypted-env is nargs='+', so repeating the flag kept only the last value and silently dropped the rest. Emit all names under one flag. The workflow now surfaces an optional COSMOS secret to the run step. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Wire --no-wait through to msbench-cli so the driver submits and returns immediately with the server-assigned run_id instead of blocking on the full graded run, and assert that run_id in main() as the CES-acceptance proof. Add .github/workflows/msbench-ces-preflight.yaml: a workflow_dispatch job that logs in as the Azure service principal via OIDC, installs msbench-cli, and runs the --no-wait submit. A returned run_id proves the SP authenticated to CES and cleared MSBench entitlement; no run_id fails the job with the CLI error. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
New skill rule sdk-python-client-kwargs: in azure-cosmos v4 all CosmosClient config is passed as keyword arguments; constructing documents.ConnectionPolicy and mutating its attributes (e.g. policy.RequestTimeout = 10000) is a legacy v3/pydocumentdb pattern the SDK replaces with _build_connection_policy(). New verifier test TestClientConfigViaKwargs in check_source.py (python-gated, static) flags ConnectionPolicy() construction and legacy attribute assignments (RequestTimeout/PreferredLocations/RetryOptions/...). Scoped to ConnectionPolicy only so SSLConfiguration/ProxyConfiguration objects are not false-flagged. Regenerated AGENTS.md (npm run build). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The new skill rule and its AGENTS.md regeneration now live in a separate PR (AzureCosmosDB#225). This PR keeps only the verifier test TestClientConfigViaKwargs in check_source.py, which cites the rule id. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
cb851df to
31522cb
Compare
Add a preflight job to msbench-eval.yaml that submits one --no-wait run as the Azure service principal and asserts a CES run_id. The evaluate job now needs: preflight and only runs when the preflight succeeded (or was skipped), so the full ~16-min graded run never starts if the SP cannot submit to CES. Add a skip_preflight workflow_dispatch input to bypass the gate once the SP path is proven and avoid the extra throwaway submission. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Review: cosmos-sdk-skills benchmark (Python slice)Really nice work here — the architecture is sound and the behavioral core is the strongest part. Below is a consolidated review focused on the Python ( What's strong (keep it)
Things to fix (internal consistency — a benchmark that contradicts itself is hard to trust)
Test-design notes
Suggested next steps (by impact)
Future directions (out of the current Python scope — roadmap)
Bottom line: the behavioral core is strong and worth building on. The two highest-value moves are (1) making the framework internally consistent and (2) adding a skill-on/off A/B with per-check reporting so it measures the skill's effect, not just whether agents pass. |
Replace the service-principal OIDC login (and the SP preflight gate) with an interactive 'az login --use-device-code' step so the manually-triggered eval runs as whoever dispatches it, using their own MSBench entitlement. This matches how MSBench authenticates a developer locally and needs no SP to be provisioned first. The workflow stays workflow_dispatch-only (no schedule). Adds a tenant_id input and a 60-minute timeout to bound the interactive sign-in. Removes the standalone SP submit preflight workflow; SP setup for unattended runs is tracked in a separate issue. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Addresses PR review (things-to-fix 1-5 + test-design notes): - Delete dead check_advanced_source.py (never in pytest target list) - Delete hinted runner-with-skills.sh; document shared/ces/runner.sh as the canonical organic (un-hinted) agent runner in README - Fix skill-name drift cosmosdb-sdk -> cosmosdb-best-practices (README, create-skills-issue.py PREFERRED_RULES_DIR) - Fix rule-ID drift sdk-retry-throttled -> sdk-retry-429 (check_source.py, reference README) and prune TEST_TO_RULE_MAP keys for deleted tests - Unify app port to 9080 across runner.sh, conftest.py, reference/run.sh; correct stale :8080 comments in start-emulator.sh - Tighten loose static regexes to require code-adjacency (retry, preferred_locations) and document that string literals are not stripped Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Addressed the things to fix and test-design notes from the review in 0fc1c23. Things to fix
Test-design notes
Validated: |
Move the internal Azure Artifacts feed path, AAD token resource GUID, CES ACR name, and CES execution backend out of the committed workflows/scripts and into GitHub repo variables so only placeholders appear in the public repo. Mechanism is unchanged. - msbench-eval.yaml / publish-benchmark.yaml: feed + token resource now read from vars.MSBENCH_FEED / vars.MSBENCH_TOKEN_RESOURCE (auth URL + trusted-host derived at runtime); ACR login uses vars.CES_ACR; backend passed via vars.MSBENCH_BACKEND env. - publish-benchmark.yaml: [docker.prod] profile is materialized at publish time from vars.CES_ACR instead of hardcoding the registry in mosaic.toml. - mosaic.toml: drop the committed [docker.prod] registry name; document CI injection + local override. - msbench-eval.py: DEFAULT_BACKEND now reads MSBENCH_BACKEND env (empty default). - README / benchmark_loaders.toml: genericize devdiv-microsoft/MicrosoftSweBench and msbench-benchmarks references. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Scrubbed the internal MSBench identifiers out of the public repo (feed path, AAD token resource GUID, CES ACR name, CES backend). Mechanism is unchanged — the values now come from GitHub repo variables (Settings → Secrets and variables → Actions → Variables), so only placeholders appear in the YAML/scripts. Repo variables to create before running the pipelines:
Notes:
|
Replace the internal tool name (MSBench) and remote-service name (CES) in human-readable prose (comments, docstrings, help text, README, workflow display name) with generic 'skill-efficacy evaluation' / 'remote execution backend' wording. Functional tokens (msbench-cli, filenames, cache paths, image tags, labels) are intentionally retained. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Print the run-analysis URL (https://msbenchapp.azurewebsites.net/run-analysis/<run_id>) as soon as the run_id is known, again after the summary, and in the --no-wait preflight path so the run is viewable regardless of pass/fail. Also record run_id and analysis_url in the results.json payload. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
TheovanKraay
left a comment
There was a problem hiding this comment.
This looks great, just a couple of things...
publish-benchmark.yaml runs on push to main under benchmarks/**, so merging this will trigger it immediately (and on every benchmarks change after). It needs CES_ACR and the Azure OIDC secrets to publish, and those aren't set up in this repo yet, so it'll fail every time, harmlessly but leaving a red run on main. Can we switch it to workflow_dispatch only for now so it just runs when we manually kick it off? Once the registry and OIDC are configured we can add the auto-trigger back. (Or leave the trigger and make the missing-CES_ACR check exit 0 and skip instead of failing, same result.).
Also msbench-eval.py still hardcodes the internal msbenchapp.azurewebsites.net URL, move that to a repo var like the others.
And a question on the eval, was leaving out the skill-on/off comparison intentional? Right now the pipeline only runs the skill-on path, so we're measuring compliance rather than efficacy and there's no delta to point at. I can see runner-no-agent.sh is already there as a baseline but not wired in, so was that planned for a follow-up, or worth adding here?
sajeetharan
left a comment
There was a problem hiding this comment.
Looks good to me overall. I agree with Theo’s comments and don’t have any additional concerns beyond those, the rest would just be nits (just added them in lines)
…ning - Wire in the skill-off baseline (runner-no-agent.sh) via --baseline so the pipeline reports the skill-on vs skill-off pass-rate delta (efficacy), not just compliance. Adds a comparison table + results-comparison.json artifact. Gated behind the compare_baseline workflow input (default true); timeout doubled. - Move the run-analysis URL out of the script into the MSBENCH_RUN_ANALYSIS_URL repo variable, matching MSBENCH_BACKEND/MSBENCH_FEED. Link is omitted when unset. - publish-benchmark.yaml: manual (workflow_dispatch) trigger only until CES_ACR + Azure OIDC are configured, so it no longer fails on every push to main. - Drop unnecessary pip --trusted-host from both workflows (Azure Artifacts is HTTPS with valid certs; the flag only weakened TLS verification). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Thanks Theo, good calls — all three are in the latest push. Flipped Pulled the hardcoded URL out into a And yeah, you're right about the skill-on/off thing — I'd assumed someone else had that experiment, but it really does belong here. So I wired |
Summary
Adds a manually-triggered GitHub Actions workflow and supporting scripts to evaluate the
cosmosdb-best-practicesskill set using an internal skill-efficacy evaluation harness. The pipeline measures whether the skills help an agent produce Cosmos DB SDK best-practice-compliant code, grading the generated app both behaviorally (drive its HTTP API + independently read the data store) and via static source checks.Current scope
Scoped to a single Harbor task instance (
mosaic-python) while the end-to-end pipeline is validated. The harness (shared base image, remote-backend runner, verifier, contracts) already supports additional scenarios × SDKs, which will be added in follow-up PRs.What's included
.github/workflows/msbench-eval.yamlworkflow_dispatchjob that signs in as the triggering user via device code, installsmsbench-cli, runs the eval, and opens an issue on failure.github/workflows/publish-benchmark.yamlharbor-format-curationscripts/msbench-eval.pymsbench-cli run --repeat N, runs a remote-backend submit preflight, polls, reads harboreval.json, computes pass@k, checks thresholdscripts/create-skills-issue.pysdk-*rules, opens a tracking issuebenchmarks/cosmos-sdk-skills/**mosaic-pythontask, shared remote-backend runner, and pytest verifier that independently reads the store to confirm real persistenceAuthentication (changed)
The pipeline no longer uses an Azure OIDC service principal. Instead it authenticates to Azure / the remote execution backend as the person who dispatches the run, via an interactive device-code sign-in — the same identity used for a local eval. The job prints a URL + one-time code to its logs; the dispatcher completes the browser sign-in, and all subsequent
az/msbench-clicalls run as that account (which is what authorizes the backend submission and the Azure Artifacts feed read).tenant_idworkflow input (blank = az default tenant).Live Cosmos account (optional)
An optional
COSMOSconnection-string secret. When set,msbench-eval.pyforwards it (encrypted) so the verifier grades against a real Cosmos DB account instead of the bundled emulator. Leave it unset to grade against the emulator. This enables checks that a single-node emulator can't prove (e.g. multi-region routing).Verifier: Python client-config check
check_source.pyaddsTestClientConfigViaKwargs— a Python-gated static check that flags the legacydocuments.ConnectionPolicy(...)construction / attribute-mutation pattern (e.g.policy.RequestTimeout = ...) and steers toward passing config as keyword arguments toCosmosClient(...). The skill rule this test cites (sdk-python-client-kwargs) lives in companion PR #225 (one-rule-per-PR); the test references the rule id as a string, so the two PRs are independent and can merge in either order.How it works
run_idbefore the real run.--repeatindependent attempts (default 3).eval.json.sdk-*rules with suggested skill improvements.Inputs
benchmark— benchmark name (defaultcosmos-sdk-skills)repeat— independent attempts per instance (default 3)threshold— pass-rate threshold 0–1 (default 0.9, tentative)model— overrides the in-container@github/copilotCLI (blank = runner defaultclaude-sonnet-4.6); forwarded asCOPILOT_MODEL, while the eval CLI's own--modelstays on a valid plugin model-map keytenant_id— Azure tenant to sign into (blank = az default)Prerequisites
MSBENCH_FEED,MSBENCH_TOKEN_RESOURCE,CES_ACR,MSBENCH_BACKEND(Settings → Secrets and variables → Actions → Variables).COPILOT_GITHUB_TOKENsecret — a github.com token for an account with a Copilot subscription (the default Actions token has no Copilot access); forwarded into the remote-backend container via--encrypted-env GITHUB_TOKEN.COSMOSsecret — a Cosmos DB connection string to grade against a live account instead of the emulator.az logined (or the SP path).Companion benchmark repo
The Harbor tasks and verifier were originally authored in a separate registration repo (
cosmos-sdk-skills-bench). The in-scope task + verifier are vendored intobenchmarks/cosmos-sdk-skills/here so CI can build and grade directly.Tentative decisions (feedback welcome)