Repository navigation
Conversation
Before the labelled queries, one explicit run ('Use the <skill> skill.') must
load that skill. If it does not, the probe writes status
'invalid: skill not visible', prints it, exits 1 and runs no labelled query,
so a skill the harness never shows cannot read as a 0% trigger rate.
--no-known-positive skips the check (status 'unchecked').
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
CLI interface change detectedThis PR changes dokimi's user-facing CLI surface (commands and/or options): ~ `dokimi catalog trigger-probe` parameters changed:
+ added option `--no-known-positive`Updated on every push; the |
|
✅ OpenCodeReview: Review complete: 0 finding(s) across 7 selected item(s). Review details
|
| return None | ||
| from dokimi.harnesses import trigger_probe as tp | ||
|
|
||
| known = tp.known_positive(args.target or sorted(names)[0], catalog, cfg) |
There was a problem hiding this comment.
Must-fix: names can be empty here. For example, use an empty existing --catalog directory and a trigger set containing {"questions":[{"id":"a","question":"Hello","expected_skill":null}]} with no --target. Discovery returns no skills, and _labelled_queries accepts the explicitly labelled negative query because its acceptable-skill list is empty. The new default guard then raises IndexError at sorted(names)[0], instead of reporting a controlled input error. Reject an empty catalog before selecting the guard skill, and add a regression test for this negative-only set.
There was a problem hiding this comment.
Fixed in 1375814. An empty --catalog is now refused with --catalog holds no skills before the known-positive guard picks its skill, so a negative-only set no longer reaches sorted(names)[0]. Runs with --no-known-positive are unchanged.
Regression tests: test_cli_refuses_an_empty_catalog_before_the_guard_picks_a_skill (red before the fix, IndexError at catalog_probe.py:123), and test_no_known_positive_still_runs_a_negative_only_set_on_an_empty_catalog.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #320 +/- ##
==========================================
- Coverage 94.05% 94.04% -0.01%
==========================================
Files 297 297
Lines 38018 38042 +24
Branches 6424 6427 +3
==========================================
+ Hits 35756 35778 +22
- Misses 1452 1454 +2
Partials 810 810
🚀 New features to boost your workflow:
|
…-positive-guard
1375814 to
48cbd0f
Compare
A negative-only trigger set against a catalog with no skills reached sorted(names)[0] in the known-positive guard and raised IndexError. Refuse the empty catalog as an input error before the guard picks its skill. Runs with --no-known-positive are unchanged. Cover both with regression tests. Thread: PRRT_kwDOVBg7g86yOGu2 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
vlad-perevezentsev
left a comment
There was a problem hiding this comment.
Review at 48cbd0f. The guard does what it says on the happy path: it runs once before any labelled query, its cost is added to the total, and --no-known-positive keeps the old behaviour. The main gap is that a failed run (API error, timeout) is reported as "skill not visible"; the details are in the line comments.
What I ran, at 48cbd0f:
make ci-local --offline: 0 failed, 19 passed, 13 skipped (network/Docker jobs); the test suite has 11,980 passed, 58 skipped.- A fake
claudethat listssum-fastin its init event and then returns anis_errorresult: the probe exits 1 with"status": "invalid: skill not visible".
Checked, no issues
- Empty catalog (the bot's thread): fixed in 48cbd0f; an empty
--catalogis refused beforesorted(names)[0], and both new tests cover it. - Order of checks: bad input, a bad
--outand an unlabelled set still exit before the paid guard run. - CLI snapshot and allowlist:
--no-known-positiveis incli-interface.jsonandcli_flags_allowlist.txt; the changelog fragment is under Added.
| _write(out_path, {"harness": "claude-code", "status": _INVALID, "known_positive": known, | ||
| "mode": "sealed" if args.sealed else "stock", "model": args.model, | ||
| "catalog": str(catalog), "answers": []}) | ||
| print(json.dumps({"status": _INVALID, "known_positive": known}, indent=2)) | ||
| raise SystemExit(f"{_INVALID}: {known['query']!r} did not load {known['skill']!r}" | ||
| + (f" ({known['error']})" if known["error"] else "") + "; no labelled query was run") |
There was a problem hiding this comment.
Any failure of the guard run is written as status: "invalid: skill not visible", including failures that say nothing about visibility.
A timeout, no result event, an API or auth error (result.is_error), or an OSError/RuntimeError from staging all reach this branch, because it only checks known["passed"]. Repro: a fake claude that prints an init event listing sum-fast and then {"type":"result","subtype":"error_during_execution","is_error":true}. The probe exits 1 and probe.json says "status": "invalid: skill not visible", with "error": "error_during_execution" inside known_positive, even though that same run listed the skill. Someone reading the artifact concludes the harness hides the skill when the run simply failed, which is the "an error reads as a result" case dokimi tries to avoid.
Suggestion: when known["error"] is set, write a separate status such as error: known-positive run failed (and say so in the SystemExit message and the docs); keep invalid: skill not visible for a run that finished without an error and did not load the skill. A test with an is_error result would cover it.
| query = f"Use the {skill} skill." | ||
| try: | ||
| r = run_query(query, catalog, cfg, runner=runner, source_env=source_env) | ||
| except (OSError, RuntimeError) as exc: | ||
| return {"skill": skill, "query": query, "passed": False, "loaded": [], "cost_usd": None, | ||
| "error": f"{type(exc).__name__}: {exc}"} | ||
| return {"skill": skill, "query": query, "passed": skill in r["skill"]["loaded"], | ||
| "loaded": r["skill"]["loaded"], "cost_usd": r["cost_usd"], "error": r["error"]} |
There was a problem hiding this comment.
The guard shows that the Skill tool accepts the name from the prompt, not that the harness listed or described the skill.
Use the <skill> skill. names the skill, so the model can call Skill(<skill>) even if the listing budget (--listing-budget-fraction) cut its entry or description. In that case the guard passes and the labelled queries can still score about 0% for the reason the docs say the guard rules out ("the harness never showed it", evaluating-treatments.md:603-604). The guard run already parses the init event, but known_positive drops r["skill"]["listed"].
Suggestion: keep listed in the known_positive record, and either require the skill to be listed when the init event lists any skills, or narrow the docs to "the skill can be loaded". Do you know whether Claude Code accepts a Skill call for a skill it did not list?
| _write(out_path, {"harness": "claude-code", "status": _INVALID, "known_positive": known, | ||
| "mode": "sealed" if args.sealed else "stock", "model": args.model, | ||
| "catalog": str(catalog), "answers": []}) |
There was a problem hiding this comment.
The invalid output has no top-level cost_usd and drops header fields the normal output always has.
The guard run is paid, but its cost is only in known_positive.cost_usd; trials, max_turns, listing_budget_fraction, claude_code_version are missing too. A script that sums out["cost_usd"] over probe files raises KeyError or misses the spend. The header is also rebuilt by hand here, so it will keep drifting from the dict at lines 82-89.
Suggestion: build the shared header (harness, status, known_positive, mode, model, catalog, settings) in one helper used by both writes, and set cost_usd to the guard's cost in the invalid output.
| cost += (known or {}).get("cost_usd") or 0 | ||
| out = { | ||
| "harness": "claude-code", | ||
| "status": "ok" if known else "unchecked", |
There was a problem hiding this comment.
Nit: status is ok whenever the guard passed, even when the same run then exits 1 because not_listed is non-empty.
The output then says "status": "ok" while the CLI raises catalog skills Claude Code did not list: .... A consumer that filters on status == "ok" accepts a run the command rejected.
Suggestion: either set a non-ok status when not_listed is non-empty, or name the field after what it reports (for example known_positive_status).
| labelled query exits 2 before any run. Records are kept in `<out>.partial` while the | ||
| probe runs: | ||
| labelled query exits 2 before any run. Before the labelled queries, one explicit run | ||
| (`Use the <skill> skill.`, for the `--target` skill or the first skill of the catalog) must |
There was a problem hiding this comment.
Nit: "The first skill of the catalog" is the alphabetically first frontmatter name (sorted(names)[0]), not the first directory or listing entry.
With sum-fast/ and io-read/ the guard checks io-read. Also, since 48cbd0f an empty --catalog is refused unless --no-known-positive is passed; before this PR a negative-only set ran on it. Neither the docs nor the changelog fragment say so.
Suggestion: write "the alphabetically first skill name" here and in the changelog fragment, and add a sentence that an empty catalog is refused while the guard is on.
Summary
catalog trigger-probenow checks that the harness can load the skill before it scores the labelled set. A skill the harness never shows scores every query 0%, which reads as a finding.The output keeps every existing key;
statusandknown_positiveare added. The refusal costs one query. The check runs one skill, so it shows that the harness loads skills at all, not that every skill in the catalog is visible;not_listedstill covers skills missing from the init listing.Evidence
New tests in
tests/test_trigger_probe.pyuse a fake runner and no network. Against the base sources they fail, and they pass on this branch.ruff format --checkis not enforced in this repo (the[tool.ruff]comment says so), and the touched files were already unformatted at the base, so the diff keeps the existing layout.Merge Danger
--target) skill is not loaded now exits 1 before any labelled run, where it used to write a 0% report and exit 0. Scripts that expect a report must pass--no-known-positiveor fix the catalog.invalid: skill not visible;known_positive.errorand the stderr message carry the real cause.--no-known-positiveis allowlisted intests/data/cli_flags_allowlist.txt(no registry concept yet) anddocs/reference/cli-interface.jsonis regenerated.🤖 Generated with Claude Code