Skip to content

evals: add 13 new evals across 4 skills - #11

Merged
abhishekkrthakur merged 7 commits into
mainfrom
add-skill-evals
May 18, 2026
Merged

abhishekkrthakur merged 7 commits into
mainfrom
add-skill-evals

Conversation

@abhishekkrthakur

@abhishekkrthakur abhishekkrthakur commented May 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds eval coverage for the four skills that had zero or thin coverage. After this PR, every skill except vespa-cli has ≥3 evals.

Skill Before After
schema-authoring 7 7
app-package 3 5
feed-operations 0 4
pyvespa 0 3
query-builder 0 3
vespa-cli 0 0 (skipped — file-based grading doesn't fit; revisit later)

What's added

data/evals_feed-operations.json (4 evals, new)

  • bulk-feed-jsonl — generate a JSONL feed with PUT/UPDATE/REMOVE, partial-update operators, weightedset vs array add shapes
  • fix-broken-feed-file (diagnose) — single-colon doc ID, bare value in update, remove with extraneous fields, wrong weightedset add shape
  • conditional-write-and-tensor-update — top-level condition, mapped-tensor modify operator, atomic multi-field updates
  • product-partial-updates (lab-inspired) — realistic e-commerce partial updates against a provided product.sd fixture

data/evals_pyvespa.json (3 evals, new)

  • build-app-package-script — ApplicationPackage + Field/HNSW/RankProfile, exercises the tuple-vs-list indexing gotcha and attribute must be a list signature
  • feed-and-query-script — feed_async_iterable + app.syncio() + hybrid YQL with input.query(q)
  • fix-broken-pyvespa-script (diagnose) — app name with hyphen, attribute="fast-search" bare string, embed-indexing as list instead of tuple

data/evals_query-builder.json (3 evals, new)

  • ecommerce-multi-signal-rank-profile (lab-inspired) — append three rank profiles to a fixture schema combining BM25, rating, in-stock bonus, freshness, with match-features
  • hybrid-rrf-global-phase — inherits semantic, function reuse, global-phase with reciprocal_rank_fusion + rerank-count
  • fix-broken-yql (diagnose) — {targetHits=200} (should be :), grouping missing the | all(...) wrapper

data/evals_app-package.json (+2 evals)

  • add-query-profile-with-tensor-type — adds default.xml linked via type="root" and types/root.xml with XML-escaped tensor type
  • deployment-xml-multi-region-with-tests — Cloud <deployment> with <test/>/<staging/> before <prod>, three regions in a single prod block

Fixture & lab strategy

Lab-inspired evals (product-partial-updates, ecommerce-multi-signal-rank-profile, hybrid-rrf-global-phase) draw on the e-commerce patterns from learn_git's labs and university/101/chN/ecommerce_app/ reference solutions, but ship self-contained fixtures under data/fixtures/<eval-name>/ so the repo has no external-path dependencies.

Workflow

Also updates .github/workflows/run-harness.yml to include the three new eval files in the matrix so they actually run when the harness is dispatched.

…up app-package

Adds 13 new evals across four eval files:

- data/evals_feed-operations.json (4 evals, new): bulk-feed-jsonl,
  fix-broken-feed-file, conditional-write-and-tensor-update,
  product-partial-updates (lab-inspired). Exercises JSONL wire format,
  doc-id format, partial-update operator wrapping, weightedset vs array
  add shapes, conditional writes, and tensor modify cells.
- data/evals_pyvespa.json (3 evals, new): build-app-package-script,
  feed-and-query-script, fix-broken-pyvespa-script. Covers
  ApplicationPackage construction, indexing tuple-vs-list gotcha, app
  name rules, attribute=list signature, feed_async_iterable, hybrid
  query with input.query(q).
- data/evals_query-builder.json (3 evals, new): ecommerce-multi-signal-
  rank-profile, hybrid-rrf-global-phase, fix-broken-yql. Exercises
  multi-signal first-phase, global-phase reciprocal_rank_fusion,
  match-features for debug, weakAnd annotation syntax, grouping
  pipe+all wrapper.
- data/evals_app-package.json (+2 evals): add-query-profile-with-tensor-
  type, deployment-xml-multi-region-with-tests. Covers query-profile
  type linking with XML-escaped tensor types and Cloud deployment.xml.

Fixtures live under data/fixtures/<eval-name>/ for diagnose-and-fix
evals. Lab-inspired evals (product-partial-updates, ecommerce-multi-
signal-rank-profile, hybrid-rrf-global-phase) draw on the e-commerce
patterns from learn_git's labs, but ship self-contained fixtures so the
repo does not depend on external paths.
…loyment.xml

Cross-checked technical claims in the new evals against
/Users/abhishek/workspace/documentation/en/ and the pyvespa source at
/Users/abhishek/workspace/pyvespa. Two real errors fixed:

- feed-operations eval 3 (conditional-write-and-tensor-update): the
  tensor `modify` long form uses key `"addresses"` (plural), not
  `"cells"`. `"cells"` is the documented short form for tensors with a
  single mapped dimension (a map of key:value). The prompt now steers
  the agent to the short form for tensor<float>(topic{}); assertions
  accept either short or long form via regex alternation.

- app-package eval 5 (renamed deployment-xml-multi-region-with-tests
  -> deployment-xml-multi-region-rollout): dropped the bogus <test/>
  and <staging/> self-closing siblings — neither form is in the
  documented deployment.xml schema. The eval now exercises the real
  documented constructs: <region>, <delay minutes="N"/>, <parallel>,
  and <block-change days hours time-zone/>, matching the canonical
  staged-rollout-with-parallel-fan-out pattern in the deployment
  reference.

- pyvespa eval 1 (build-app-package-script): removed file_exists
  assertions for ./output/services.xml and ./output/schemas/article.sd
  — these required actual script execution which depends on pyvespa
  being installed in the agent's environment, which is not guaranteed.
  Script correctness is now graded statically.

Verifications performed (all grounded):
- Doc ID double-colon form
- weightedset add object form {"key": weight}
- conditional write "condition" at top-level with <type>.<field> selection
- remove takes only doc ID, no fields block
- tensor modify operations: replace/add/multiply
- grouping | all(group(...) each(...)) wrapper
- YQL annotations use colon: {targetHits: 200}
- rank-profile inherits, match-features, global-phase, rerank-count
- reciprocal_rank_fusion is a documented pseudo-function
- Rank features: bm25, nativeRank, freshness, closeness, attribute
- pyvespa: name rules enforced at __init__ (lowercase a-z0-9, letter-
  start, <=20 chars, no hyphens/underscores)
- pyvespa: Field attribute is Optional[List[str]]; indexing tuple
  renders multiline, list renders pipe-separated
- pyvespa: is_successful() is canonical, is_successfull() is deprecated
- services.xml: document mode required, valid values index/streaming/
  store-only
- redundancy and min-redundancy both work, min-redundancy preferred
- query-profile-type field name ranking.features.query(NAME) with
  XML-entity-escaped tensor type
- deployment.xml: <region>, <delay>, <parallel>, <block-change>
- Vespa Cloud regions: aws-us-east-1c, aws-eu-west-1a, gcp-us-central1-f
@abhishekkrthakur
abhishekkrthakur marked this pull request as draft May 18, 2026 07:25
Five assertions failed on legitimate agent output:
- pyvespa indexing tuple: required single-element single-line tuple; agents legitimately use multi-line and multi-element tuple forms which still render correctly per pyvespa's Field.indexing_to_text
- pyvespa first_phase: required direct string after =; agents legitimately wrap in parens first_phase=("...")
- pyvespa ranking: required body-dict form "ranking":"hybrid"; sess.query accepts kwarg form ranking="hybrid"
- query-builder category filter: required = operator; agent legitimately used contains, both valid in YQL on attribute fields

After this, every assertion passes on real output except one legitimate skill-uplift signal: fix-broken-pyvespa-script without_skill misses the list-vs-tuple gotcha, which is the eval's intended discrimination.
@abhishekkrthakur

Copy link
Copy Markdown
Collaborator Author

Local harness results

Ran all 13 new evals locally against Claude with both Sonnet (default) and Haiku to validate the evals and measure the skill-vs-no-skill delta.

Sonnet (iteration 1)

Skill with_skill without_skill Δ pass Cost (with) Cost (without)
feed-operations 100.0% 100.0% +0.0% $0.1443 $0.1173
pyvespa 100.0% 91.7% +8.3% $0.1787 $0.3655
query-builder 100.0% 100.0% +0.0% $0.1383 $0.1273

Haiku (iteration 2)

Skill with_skill without_skill Δ pass Cost (with) Cost (without)
feed-operations 97.9% 76.5% +21.4% $0.0472 $0.0309
pyvespa 100.0% 69.9% +30.1% $0.0446 $0.0665
query-builder 100.0% 90.5% +9.5% $0.0393 $0.0449

Key findings

  1. Skills carry far more weight on Haiku. Δ pass goes from 0 / +8 / 0 (Sonnet) to +21 / +30 / +9.5 (Haiku). On Sonnet, feed-ops and query-builder look like the skill is "useless" — but that's because Sonnet already knows YQL and the JSON feed format. Drop to Haiku and the skill closes the gap.

  2. Haiku-with-skill basically matches Sonnet-with-skill on quality at ~3× cheaper. All three Haiku-with-skill cells hit 97.9–100% pass rate at $0.04–$0.05 per eval vs Sonnet's $0.14–$0.18.

  3. Genuine signal on the diagnose-and-fix evals. Without the skill, Haiku fails badly on the trickiest evals:

    • fix-broken-feed-file (without skill): 3/6 — missed several wire-format bugs
    • fix-broken-pyvespa-script (without skill): 1/4 — only spotted one of three planted bugs
    • product-partial-updates (without skill): 9/14 — missed array-vs-weightedset add shapes
  4. The one Haiku-with-skill miss is a real wire-format bug that the eval was designed to catch: in bulk-feed-jsonl, Haiku wrote "add": "electronic" (bare string) instead of "add": ["electronic"] (array) for an array<string> field. A small SKILL.md tweak adding an explicit array-add example would push this to 100%.

Bonus: 4 brittle regex assertions fixed (commit a122787)

The first run revealed legitimate alternative output that my regexes didn't account for:

  • pyvespa multi-line / multi-element tuple form for indexing
  • pyvespa first_phase=("...") parenthesized string
  • pyvespa ranking="hybrid" as kwarg vs "ranking": "hybrid" in body dict
  • YQL category contains "Shoes" as a valid alternative to category = "Shoes"

All four were the agent doing something valid that my pattern was too strict to accept.

@abhishekkrthakur
abhishekkrthakur marked this pull request as ready for review May 18, 2026 07:52
Comment thread data/evals_pyvespa.json Resolved
Co-authored-by: Thomas Hjelde Thoresen <thomas.h.thoresen@gmail.com>

@thomasht86 thomasht86 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.

awesome 🔥

@abhishekkrthakur
abhishekkrthakur merged commit 6a3cc8a into main May 18, 2026
2 checks passed
@abhishekkrthakur
abhishekkrthakur deleted the add-skill-evals branch May 18, 2026 10:41
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