Conversation
|
assigned to @whymath |
mrshu
left a comment
There was a problem hiding this comment.
⚒️ review-anvil report
Review decision: COMMENT — The converter has four confirmed data-quality and partial-conversion risks.
Result: Four focused changes would make repeated and partial conversions safer while preserving the PR's aggregate-only design.
Scope: This PR adds a sayf-eval aggregate results-record converter, CLI route, documentation, fixtures, and offline tests.
Checks: 8 single-reviewer concerns checked; 0 confirmed, 0 ruled out, 8 set aside because exact-head verification did not complete.
Second check: targeted, 2 reviewers; 3 kept, 1 clarified, 0 set aside, 0 removed.
Earlier review comments
No earlier review comments were present.
What I noticed
- RAV-RUN1-R1-F001 [high] source-provenance
every_eval_ever/converters/sayf_eval/adapter.py:184— The adapter puts a task slug insource_data.dataset_name. This replaces upstream names such asCTI-Bench MCQ, while the empty default prefix routes data into bare task collections. (inline) - RAV-RUN1-R1-F003 [high] record-identity
every_eval_ever/converters/sayf_eval/adapter.py:364—evaluation_idcontains the current retrieval time. Re-converting the same source run creates a new logical evaluation each time. (inline) - RAV-RUN1-R1-F005 [high] partial-conversion
every_eval_ever/converters/sayf_eval/adapter.py:418-422— One invalid task raises after earlier task logs were built. The file-level failure path then discards those valid sibling logs. (inline) - RAV-RUN1-R1-F007 [medium] judge-metadata
every_eval_ever/converters/sayf_eval/adapter.py:164—LlmScoring.input_promptreceives scoring prose or an invented fallback sentence. The record therefore presents a description as the actual judge prompt. (inline)
Non-blocking low findings (1 item)
- RAV-RUN1-R1-F013 [low] tests — The publish test checks Pydantic validation but does not run the repository semantic validation gate on final paths.
Things to try (4 items)
- [high] source-provenance — Upstream dataset names can stay in
source_data, while an explicit sayf-eval collection override handles routing. (RAV-RUN1-R1-P001; coversRAV-RUN1-R1-F001) - [high] record-identity — A stable source-run token can occupy the timestamp segment of
evaluation_id; retrieval time can remain inretrieved_timestamp. (RAV-RUN1-R1-P002; coversRAV-RUN1-R1-F003) - [high] partial-conversion — A task-level error boundary can keep valid task logs and record each rejected task in failure accounting. (
RAV-RUN1-R1-P003; coversRAV-RUN1-R1-F005) - [medium] judge-metadata —
llm_scoringcan be present only when the source supplies the real prompt template. Otherwise, supported score data can remain without invented prompt text. (RAV-RUN1-R1-P004; coversRAV-RUN1-R1-F007)
Set aside / Outside this change (8 items)
- RAV-RUN1-R1-F002 [high] score-validation — We set this aside because the verification run could not inspect the exact PR head.
- RAV-RUN1-R1-F004 [high] empty-record-accounting — We set this aside because the zero-output CLI path was not reproduced.
- RAV-RUN1-R1-F006 [medium] model-metadata — We set this aside because the model classification path was not reproduced at the exact PR head.
- RAV-RUN1-R1-F008 [medium] source-provenance — We set this aside because malformed provenance behavior was not reproduced.
- RAV-RUN1-R1-F009 [medium] timestamp-handling — We set this aside because malformed timestamp behavior was not reproduced.
- RAV-RUN1-R1-F010 [medium] source-type — We set this aside because the source artifact classification was not confirmed against the exact PR head.
- RAV-RUN1-R1-F011 [medium] failure-accounting — We set this aside because the source-record unit used by
total_recordswas not confirmed. - RAV-RUN1-R1-F012 [medium] failure-reporting — We set this aside because publication failure behavior was not reproduced.
Run details
- Target: PR #220 (
feat/sayf-eval-converter, 7 files, +928/-1) - Run ordinal: 1
- Rounds: 1/1 completed; adaptive off; material findings remain
- Mix: 3 codex-exec
- Focus: correctness, maintainability, simplicity, production blast-radius, and constructive positive review language
- Earlier review comments: none
- Finding counts: 0 critical, 3 high, 1 medium, 1 low, 0 nit
- Checks: concerns=8; confirmed=0/ruled-out=0/set-aside=8/lowered=0
- Second check: targeted; reviewers=2; kept=3/clarified=1/set-aside=0/removed=0; approval changed no
- Set aside: 8 items; reason=verification could not access the exact PR head
Reviewed with review-anvil.
|
Hey @Aymen311 it looks like the sayf-eval repo is a closed repo, and I wasn't able to find any published eval results generated using this harness either. Is there a plan to open-source the harness and generate a lot of open/public results using it? If that's the case then we can continue looking into this converter approach for the harness itself. On the other hand, if the plan is to continue to keep the harness closed but only publish some eval results, then maybe an adapter might be more appropriate so that we can still get the data in into the EEE datastore without having to make all the structural changes needed for a converter. |
|
Hello again @whymath, Thanks for the review. I've addressed all four confirmed points in Sayf-eval is now open source (https://github.com/qcri/sayf-eval), and the repo now ships a public leaderboard. Those are aggregate-only results records for 10 models across 24 cybersecurity sub-tasks, in exactly the schema this converter ingests. Surfacing them on HF Community-Evals through this converter is the immediate use case for the new domain. |
|
Small follow-up in |
|
@mrshu or @nelaturuharsha can you help here ? |
Add `every_eval_ever convert sayf_eval`, converting a sayf-eval results record (https://pypi.org/project/sayf-eval/) into the unified schema. - converters/sayf_eval/: SayfEvalAdapter builds one EvaluationLog per task (accuracy, plus CVSS MAD for VSP and micro-F1 for ATE). The judge is recorded under metric_config.llm_scoring, decoding/pipeline settings under generation_config, and per-task provenance as the matching source_data variant. It reads the record as JSON and does not import sayf-eval. - cli.py: register `sayf_eval` as a convert source + dispatch. - Aggregate-only by design: sayf-eval per-sample item text is dual-use and kept private, so no instance-level _samples.jsonl is emitted (detailed results are optional in the schema). - tests + fixture: tests/test_sayf_eval_adapter.py, tests/data/sayf_eval/. - docs: converters/README.md sayf-eval section.
…ersion, judge prompt Respond to the PR review of the sayf-eval converter: - source-provenance: keep the upstream dataset name in source_data.dataset_name (e.g. "CTI-Bench MCQ"); route to the datastore via an explicit --collection override (default "sayf-eval") instead of overwriting the name with a slug. - record-identity: derive the evaluation_id's run segment from the record's created_at so re-converting the same run is idempotent; wall-clock time stays in retrieved_timestamp. - partial-conversion: a per-task error boundary keeps valid sibling logs and records each rejected task in failure accounting. - judge-metadata: populate llm_scoring only from the record's real judge prompt template (now embedded by sayf-eval); when absent, omit llm_scoring and record the judge model in metric_config.additional_details rather than inventing text. - tests: refresh the fixture (adds judge_prompt_templates); add stable-id, partial-conversion and no-template cases; run the repo's semantic validation gate (validate_file) on published paths.
Publish one collection per task (data/<prefix><task>/..., default prefix "sayf-eval-") instead of a single "sayf-eval" collection, so EEE's per-collection Community-Evals tooling maps one collection to one benchmark sub-leaderboard. Upstream dataset names remain in each log's source_data. - cli.py: replace --collection with --collection-prefix; publish each task log with its own collection_override (task = evaluation_id stem). - converters/sayf_eval/__main__.py, converters/README.md: match the new flag. - tests: assert per-task collections via publish and end-to-end via the CLI.
sayf-eval removed the private CISSP task (never released or benchmarked), so its 'other'/private source no longer appears in a sayf-eval record. Remove cissp from the results fixture and the adapter tests (now 3 tasks: ate, athena_vsp, mcq), and cover the adapter's 'other' -> SourceDataPrivate mapping with a direct unit test instead of relying on a fixture task.
tests/test_documentation_commands.py rejects a bare pip install in any documented command.
2809238 to
fb40fdf
Compare
|
Rebased onto current main so this can get CI. One conflict, in Also added one commit. Rebased branch locally: 1350 passed, 1 skipped, ruff clean. |
|
Thanks @borgr for the tweaks! In the meantime, we've released the writeup paper behind the harness: https://arxiv.org/pdf/2609.08765 (it includes results, failure modes...etc) |
borgr
left a comment
There was a problem hiding this comment.
Rechecked all four of mrshu's findings against the rebased branch. Three are fixed and I've resolved them with the line each one landed on. F001 keeps the upstream dataset_name and falls back to the task slug only when the record has no name, F005 gives each task its own error boundary so one bad task no longer discards its siblings, and F007 emits llm_scoring only when the record carries the real judge template.
F003 is the one still open, and only in its fallback. The created_at-derived run_token is right. run_token or retrieved_timestamp then mints a wall-clock id for a record with no created_at, and the bare except Exception above it does the same for an unparseable one, so those records still get a fresh identity per conversion. I left a suggested replacement on that thread, which raises instead of guessing — the F005 boundary in this same PR is what makes that safe, since the failure now costs one task rather than the file. If sayf-eval always writes created_at, say so on the thread and I'll resolve it as unreachable.
Everything else here reads well, and the local run on the rebase was 1350 passed, 1 skipped with ruff clean. Two things outside your control before this can land. The CI run needs a maintainer to release the fork gate, and I can't click that from where I'm working, so it's queued with the others. Thanks for the writeup link as well — worth citing from the converter README once this is in.
…a clock id Addresses the remaining F003 point. `run_token or retrieved_timestamp` minted a wall-clock evaluation_id for a record with no (or unparseable) created_at, so that record became a new logical evaluation on every conversion. Raise a ValueError instead; the per-task error boundary from F005 files the failure and keeps the record's valid siblings. Add tests for the missing and unparseable created_at branches (each asserts the failure lands in the report, not a published log).
|
Thanks again @borgr, and appreciate you rebasing and sorting out the docs test. I pushed the F003 fallback fix you suggested in |
|
Thanks @Aymen311 — verified Congratulations on the paper. One optional thing you asked about, and it is genuinely optional — nothing blocks on it. The converter takes additional_details={
'paper': 'https://arxiv.org/abs/2609.08765',
},Note The only thing left on this PR is the CI approval click, since fork runs sit at |
Per @borgr's suggestion, SourceMetadata now carries the sayf-eval paper in additional_details.paper, so a consumer reading a record has a route back to the methodology. Uses the arXiv landing page (abs), matching the rest of the repo. Adds a test asserting the link is present.
|
Added it in |
Add the arXiv paper link next to the source link in the sayf-eval section so the docs also point back to the methodology (per @borgr's suggestion).
|
Also linked it from the converter README in |
|
Thanks — both commits look right, and the abs-vs-PDF distinction landed correctly. One correction to my own suggestion, though. I wrote It appears as This is worth changing before merge rather than after. A consumer filtering Three lines. In -_PAPER = 'https://arxiv.org/abs/2609.08765'
+_PAPER_URL = 'https://arxiv.org/abs/2609.08765'- additional_details={'paper': _PAPER},
+ additional_details={'paper_url': _PAPER_URL},and the assertion in - assert (details or {})['paper'] == 'https://arxiv.org/abs/2609.08765'
+ assert (details or {})['paper_url'] == 'https://arxiv.org/abs/2609.08765'The leading underscore matches this file's own constants ( Push that and #220 is ready to merge — nothing else outstanding from my side. The fork CI run needs a maintainer to release it, which we will do on the new head. |
Rename additional_details.paper -> paper_url (constant _PAPER -> _PAPER_URL) to match the repo's established key, used across nine adapters, so a consumer filtering source_metadata.additional_details.paper_url does not silently skip sayf_eval. Per @borgr's correction; worth doing pre-merge since a published record is immutable under its UUID.
|
Done in |
What
Adds a converter for sayf-eval — a model-agnostic cybersecurity LLM-evaluation framework — so its results can be ingested into the Every Eval Ever schema:
sayf-eval writes a canonical results record per run that embeds the full pipeline configuration (decoding params,
<think>handling, denominator policy, judge model) and per-task dataset provenance alongside the scores. The converter maps that record onto the schema.Design
EvaluationLogper task, mirroring the lm-eval converter. Each task contributesaccuracy, plus a secondevaluation_resultsentry where applicable — CVSS MAD for vuln-scoring tasks (lower_is_better: true,[0,10]) and micro-F1 for ATT&CK-extraction tasks.metric_config.llm_scoring; decoding/pipeline settings undergeneration_config.generation_args(+additional_detailsfor the rest); provenance as the matchingsource_datavariant (HF / URL / other)._samples.jsonl(detailed_evaluation_resultsis optional in the schema). The results record contains no prompt/gold/response text.Changes
every_eval_ever/converters/sayf_eval/—adapter.py(SayfEvalAdapter),__main__.py,__init__.py.every_eval_ever/cli.py— registersayf_evalas aconvertsource + dispatch.tests/test_sayf_eval_adapter.py+tests/data/sayf_eval/results_fixture.json.every_eval_ever/converters/README.md— sayf-eval section.Testing
validate_filechecks.every_eval_ever convert sayf_eval→every_eval_ever validate: one aggregate JSON per task, zero_samples.jsonl, correctlower_is_betterper metric, judge + pipeline config present, no item text.