Skip to content

fix(catalog): flag name conflicts, fail an empty root, keep spec errors out of routing - #328

Merged
xaleryb merged 19 commits into
intel:mainfrom
napetrov:fix/rescan-catalog
Nov 3, 2026
Merged

xaleryb merged 19 commits into
intel:mainfrom
napetrov:fix/rescan-catalog

Conversation

@napetrov

Copy link
Copy Markdown
Contributor

Summary

A rescan of public skill catalogs found three catalog-side gaps: a name that two different skills share was silent in catalog scan and aborted novelty routing --catalog, a root with no SKILL.md exited 0 without a word, and a skill with a spec error (a description over 1024 characters) went into the routing field.

catalog scan
  two skills, one name, different SKILL.md   -> warn name-conflict on each, naming the other path
  root with no SKILL.md (kind skills or all) -> "no SKILL.md found under ROOT" on stderr, exit 1
                                                (tasks-only root under kind all: warn; --strict fails)

novelty routing --catalog
  a name whose loaded copies differ          -> the name leaves the field, stderr names every path
                                                (routing exits 0; it no longer aborts with exit 2)
  a skill with a spec error                  -> left out, stderr names the error; --include-invalid keeps it
                                                (the saved result records include_invalid under field)

The conflict check runs over every loaded copy before the disabled and spec-error filters, so the routing field and the name-conflict warnings agree: a name the scan warns about is never in the field.

Shape tests in #327 (tests/test_skill_repo_shapes.py) that this PR flips. Each is a strict xfail on main (OPEN_BUGS). With this PR they XPASS, so their marks must come off when #327 is rebased on this change:

shape dimension this PR fixes #327 xfail
drifted_mirror routing flips
same_name_distinct_dirs routing flips
zero_skill scan and strict exit flips
description_too_long field flips
name_not_dir field flips
title_case_name field flips

The last three are labelled fixed by fix/rescan-routing in #327. This PR also makes their field dimension hold, through the spec-error exclusion; the two changes overlap there, so whichever lands second should rebase on the other.

Evidence

Tests were written first and fail on the base code (base run: 10 failed, 105 passed on the touched test files before the fix).

Full suite on the branch head ec204a14, and on intel/main:

branch   pytest -n auto -q   13 failed, 12000 passed, 27 skipped
intel/main                   the same 13 failures, all tests/test_pipeline_question_set.py

The 13 failures are in the question-set pipeline and fail the same way without this change, so they are not part of this PR.

Local checks on this branch:

ruff check dokimi tests                  All checks passed!
mypy dokimi                              4 errors, all in dokimi/mcp/mcp_protocol.py (the mcp client API);
                                         the same 4 on intel/main, file not touched here
python -m dokimi.schema_check ...        exit 0
python -m dokimi.config_check            exit 0

docs/reference/cli-interface.json is regenerated for --include-invalid, and the flag is in tests/data/cli_flags_allowlist.txt.

Self-review (local mode, plain pass and edge pass on each round): round 1 found a conflict check that ran after the disabled and spec-error filters, so the scan warning could be false, and a note that omitted copies; both fixed with a red test each. Round 2 found that the saved field rule did not record include_invalid; fixed with a red test. Blocking findings left: 0.

Merge Danger

Door: two-way. The only new surface is novelty routing --include-invalid (default off). The saved routing result gains one additive key, field.include_invalid. Reverting restores the old field and the abort.

Blast Radius: medium for routing and for CI, small elsewhere.

Ramifications:

  • Routing fields shrink. A catalog with a spec-error skill loses that skill from --catalog by default. A non-kebab-case name (MyTool) or a name that is not its directory name is a spec error too, so it leaves the field as well. Numbers over such catalogs move; rerun to compare.
  • A name with different content leaves the field whole, including the copy that is disabled or has a spec error. That is the rule catalog scan already warns about.
  • Conflicts no longer abort. novelty routing --catalog exits 0 with a warning where it used to exit 2. The field then lacks the conflicting name, and the warning says how to route it: dedupe or rename.
  • catalog scan on a root with no SKILL.md (for --kind skills and --kind all without tasks) exits 1. Checked against the pinned uxl-skills commit used by the agent-quality workflow (6feb3f3a, 8 SKILL.md files): exit 0, so that job is not affected. A tasks-only root under --kind all only warns unless --strict.
  • Changelog fragment changelog.d/20261031_120000_napetrov_rescan-catalog.md lists the three items.

Decisions for the author to confirm:

  • A disabled or spec-error copy of a name removes an enabled same-name skill from the field. This is the reading of "skip the conflicting names" used here.
  • --include-invalid does not keep a spec-error skill whose name conflicts; the name still leaves the field.
  • No --strict flag on routing for conflicts; the warning is the signal.
  • CRLF and LF copies of one skill count as different content (byte comparison, as before).

Checklist

  • Tests added/updated and pytest passes (13 failures are pre-existing on intel/main, see above)
  • ruff, mypy, and schema checks pass (mypy has the 4 pre-existing mcp errors)
  • Docs updated (or N/A) — docs/external-content.md, docs/skill-novelty.md, CLI snapshot
  • No ad-hoc run artifacts committed
  • New files carry the SPDX license header (or are exempt in .github/.licenserc.yaml) — no new source files; the changelog fragment is Markdown

🤖 Generated with Claude Code

…spec errors from routing

Three catalog-side bugs from the 10-30 rescan of public skill catalogs:

- Two skills with one name and different content aborted `novelty routing
  --catalog` for the whole repo (exit 2). The routing field now skips that
  name, with a warning naming every path, and keeps the rest of the field.
  `catalog scan` reports each such skill as a `name-conflict` warning with the
  other path, where it used to say ok.
- `catalog scan` on a root with no SKILL.md exited 0 silently. It now prints
  `no SKILL.md found under <root>` and exits 1. With `--kind all` a tasks-only
  root only warns, and `--strict` makes that a failure.
- A skill with a spec error (for example a description over 1024 characters)
  entered the routing field. It is now left out with a warning naming the
  error; `novelty routing --include-invalid` keeps it.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…r its copies

catalog scan warns on every copy of a name whose SKILL.md files differ, including a copy
that is disabled or has a spec error. Routing checked the conflict only after dropping
those copies, so a name could stay in the field while the scan said it was skipped.

The conflict is now found over the loaded, non-excluded copies before the disabled and
spec-error filters. The note names every path of the name. The spec-error wording in the
changelog and the docs now says it is an example list, not the whole list.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The saved routing result states the field rule, and it recorded include_disabled but not
include_invalid, so a run that kept spec-error skills looked the same as a default run.

The default exclusion of a spec-error skill is a change in what the field holds, so the
changelog lists it under Changed. The docs list the flag with the other field-rule keys.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…-invalid

The unreleased routing-catalog-manifest fragment still said same-name catalog skills are
refused. They now leave the field with a warning. The --include-invalid entry and the docs
say that a conflicting name stays out whatever the flag says.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
@napetrov
napetrov requested a review from a team as a code owner October 31, 2026 17:39
@github-actions github-actions Bot added the cli-interface-change Changes dokimi's user-facing CLI surface label Oct 31, 2026
@github-actions

Copy link
Copy Markdown

CLI interface change detected

This PR changes dokimi's user-facing CLI surface (commands and/or options):

~ `dokimi novelty routing` parameters changed:
    + added option `--include-invalid`

Updated on every push; the cli-interface-change label is on while the diff is non-empty.

@exai-bot

exai-bot commented Oct 31, 2026 •

Copy link
Copy Markdown

OpenCodeReview: Commit b8ac2a6 was not reviewed. This PR has reached its review limit (6 reviews).

To review this commit: re-request review from exai-bot in the Reviewers list.

Last review (51ce87b): no findings

Open threads from the bot: 1

@codecov-commenter

codecov-commenter commented Oct 31, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 95.06173% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.32%. Comparing base (41b3d8d) to head (b8ac2a6).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
dokimi/dokimi/novelty/routing.py 92.98% 1 Missing and 3 partials ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #328      +/-   ##
==========================================
+ Coverage   94.29%   94.32%   +0.02%     
==========================================
  Files         308      309       +1     
  Lines       39322    39535     +213     
  Branches     6651     6693      +42     
==========================================
+ Hits        37079    37290     +211     
- Misses       1430     1433       +3     
+ Partials      813      812       -1     
Files with missing lines Coverage Δ
dokimi/dokimi/commands/catalog.py 97.87% <100.00%> (+0.05%) ⬆️
dokimi/dokimi/commands/novelty.py 95.16% <100.00%> (-0.16%) ⬇️
dokimi/dokimi/external/validate.py 94.54% <100.00%> (+0.60%) ⬆️
dokimi/dokimi/novelty/all_vs_all.py 99.17% <ø> (ø)
dokimi/dokimi/novelty/routing.py 96.03% <92.98%> (-0.61%) ⬇️

... and 12 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vlad-perevezentsev vlad-perevezentsev 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.

Review at ec204a1. The three fixes work as described: a same-name conflict no longer aborts routing, catalog scan warns about it and fails on an empty root, and spec-error skills leave the --catalog field. One point needs your decision: a disabled or spec-error copy of a name now also drops the enabled skill a harness still lists. The rest are small and in the line comments.

What I ran, at ec204a1:

  • make ci-local --offline: 0 failed, 19 passed, 13 skipped (network and Docker steps).
  • The PR's four touched test files on the merge-base 05f9d62: 14 of the new tests fail there, so they cover the change.
  • Repro on a scratch catalog (skills/db enabled, legacy/db disabled with other text; perf with a differing plugin copy): catalog_competitors drops both db and perf; catalog scan warns name-conflict on all four copies.
  • catalog scan --kind skills on a root whose skills.yaml lists no skill: exit 1 with no SKILL.md found.

Checked, no issues

  • Empty field: when every catalog name is skipped, check_field still refuses a run with no competitors, so a conflict cannot turn into a 100% selection rate.
  • Mirrors and spec errors: a byte-identical copy is not a conflict, and a spec-error copy is filtered before the keeper is picked, so a valid deeper copy still stands for the card.
  • Saved field rule: field.include_invalid is written for both the single-artifact and the all-vs-all runs; the CLI snapshot and the flag allowlist are updated.
  • Docs: external-content.md and skill-novelty.md describe the new exit code, the warning and the flag.

Comment thread dokimi/dokimi/novelty/routing.py Outdated
notes.append(f"left out catalog skill {skill.name!r}: "
"disable-model-invocation (--include-disabled keeps it)")
loaded.append((skill, hashlib.sha256(skill.path.read_bytes()).hexdigest(), review))
conflicting = _conflicting_names([(skill, digest) for skill, digest, _ in loaded], notes)

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.

A disabled copy of a name now removes the enabled skill of that name from the field, though a harness still lists that skill.

Repro: a catalog with skills/db/SKILL.md (enabled) and legacy/db/SKILL.md (different text, disable-model-invocation: true). catalog_competitors returns no db, with the note skipped catalog name 'db'. On the base it returned db: the hidden copy was filtered first, and the one card a harness lists stayed. The field now lacks a real sibling, so the artifact's selection rate is measured against a smaller field than the one the model sees. The same holds for a copy with only a spec error under the default --include-invalid off.

The PR lists this as a decision to confirm; I think the conflict should be about the copies that can be in the field. Suggestion: run _left_out_by_flag first and _conflicting_names over what is left (so --include-disabled / --include-invalid bring the conflict back), and in catalog scan do not count a disable-model-invocation copy as a name-conflict (or say in the warning that routing skips the name only while both copies are listed).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending the maintainer's decision; no change in this push. The field rule (a disabled copy of a name and an enabled copy) is the open item already listed in the PR body.
Options: (a) keep the current rule, the field drops a name whose copies differ, whatever the flags; (b) run the flag filters first and the conflict check over what is left. I will apply whichever the maintainer picks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainer chose option (b): the flag filters run first, and the conflict check runs over what is left. Fixed in c848aec.
A disabled copy no longer makes its name a conflict, so the enabled skill stays in the field. --include-disabled brings the copy back into the check.
catalog scan now names only the listed copies in name-conflict (not disabled, not spec-error), so routing and scan agree. Tests: test_a_disabled_copy_of_a_name_is_no_conflict_with_the_enabled_copies, test_include_disabled_brings_the_disabled_copy_back_into_the_conflict, test_a_disabled_copy_of_a_name_is_not_a_name_conflict.

Comment on lines +9 to +21
- **`novelty routing --catalog` leaves out a skill with a spec error by default** (for example a
description over 1024 characters, or a name that is not kebab-case or not its directory name), with
a warning on stderr naming the error. Before, such a skill was in the field. `--include-invalid`
keeps it.
- **`catalog scan` reports a same-name skill with different content as a `name-conflict` warning**
naming the other path. Before, each of the two skills was reported `ok`. It is a warning, not an
error, so `--strict` does not fail on it.

### Fixed

- **`novelty routing --catalog` skips a name that two different skills share, with a warning,
instead of aborting the whole run** (`catalog has X at A and B with different content`, exit 2).
Every copy of that name leaves the field, the rest of it stays, and stderr names every path.

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.

The fragment does not say that earlier --catalog routing results stop being comparable, and its Fixed entry fixes an abort that no release had.

Leaving spec-error skills out by default, and dropping a name whose other copy is disabled, change the field for the same command, so the selection rates move (the PR body says "rerun to compare", the fragment does not). Under the project rules that is a change to defaults that moves published numbers. The abort catalog has X at A and B with different content came with the 20261021 fragment, which is not released yet and which this PR already rewrites, so the release notes would tell the same change twice.

Suggestion: add to the Changed entry "Rerun earlier --catalog results before comparing them", and drop the first Fixed bullet (the 20261021 fragment already says it).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d3ba18b. The changelog fragment now says a routing result saved before this change is not comparable, and the abort note is kept under Changed: it was refused (exit 2) in the unreleased 20261021 entry, and now it is a warning.

Comment thread dokimi/dokimi/commands/novelty.py Outdated
Comment on lines +866 to +867
routing_p.add_argument("--include-invalid", action="store_true", dest="include_invalid",
help="Keep catalog skills with a spec error in the field")

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.

The spec-error filter covers only --catalog, so the same invalid skill is in the field or out of it depending on how it is passed.

--catalog cat/ leaves out cat/skills/long (description over 1024 characters) with a warning; --competitors skill:cat/skills/long keeps it with no warning. Both saved results record include_invalid: false. --include-disabled, by contrast, is applied to --competitors too.

Suggestion: either check skill: competitors the same way (review_skills on a one-entry list), or say in the help and in skill-novelty.md that --include-invalid and the filter are about --catalog only, so field.include_invalid is not read as covering the explicit competitors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending the maintainer's decision; no change in this push. skill: competitors and --catalog skills follow different filters, which the PR body lists as open.
Options: (a) apply the spec-error filter to explicit skill: competitors too (warn and drop); (b) keep it, and say in the help and skill-novelty.md that --include-invalid covers --catalog only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainer chose option (a): an explicit skill: competitor with a spec error is skipped with a warning, as a catalog skill is. Fixed in c848aec.
The warning names the error and --include-invalid; the entry goes into the saved left_out list.
Tests: test_an_explicit_spec_error_competitor_is_skipped_with_a_warning; test_a_spec_error_copy_is_no_conflict_with_a_valid_copy_of_the_name (with --include-invalid: test_include_invalid_makes_the_spec_error_copy_a_conflict_again).

Comment thread dokimi/dokimi/novelty/routing.py Outdated
Comment on lines +539 to +577
reviews = review_skills(entries)
loaded: list[tuple[Skill, str, SkillReview | None]] = []
for entry, review in zip(entries, reviews, strict=True):
skill = entry.skill
if skill is None or not entry.loaded:
if notes is not None:
notes.append(f"skipped catalog entry {entry.name!r}: {entry.error}")
continue
if skill.name in exclude:
continue
if not include_disabled and disables_model_invocation(skill.path):
if notes is not None:
notes.append(f"left out catalog skill {skill.name!r}: "
"disable-model-invocation (--include-disabled keeps it)")
loaded.append((skill, hashlib.sha256(skill.path.read_bytes()).hexdigest(), review))
conflicting = _conflicting_names([(skill, digest) for skill, digest, _ in loaded], notes)
eligible: list[tuple[Skill, str]] = []
for skill, digest, review in loaded:
if skill.name in conflicting or _left_out_by_flag(
skill, review, include_disabled, include_invalid, notes):
continue
eligible.append((skill, hashlib.sha256(skill.path.read_bytes()).hexdigest()))
eligible.append((skill, digest))
return eligible


def _refuse_conflicting_names(eligible: list[tuple[Skill, str]]) -> None:
"""Two skills with one name and different bytes cannot both stand for the card.
def _left_out_by_flag(skill: Skill, review: SkillReview | None, include_disabled: bool,
include_invalid: bool, notes: list[str] | None) -> bool:
"""Whether a disabled or spec-error skill is left out, with the note that says why."""
if not include_disabled and disables_model_invocation(skill.path):
if notes is not None:
notes.append(f"left out catalog skill {skill.name!r}: "
"disable-model-invocation (--include-disabled keeps it)")
return True
if not include_invalid and review is not None and review.state == "error":
if notes is not None:
problems = "; ".join(f.message for f in review.findings if f.level == "error")
notes.append(f"left out catalog skill {skill.name!r} at {skill.path}: "
f"spec error ({problems}; --include-invalid keeps it)")
return True
return False


def _conflicting_names(loaded: list[tuple[Skill, str]], notes: list[str] | None) -> set[str]:

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.

Routing now calls review_skills and then redoes what it computed: the digest, the disabled flag and the name-conflict check.

review_skills already holds content_sha256 and disable_model_invocation for each skill and adds the name-conflict findings; routing hashes each SKILL.md again (line 549), re-parses its frontmatter in disables_model_invocation (line 563), and has its own _conflicting_names. Two implementations of the rule the scan warns about can drift, which is what this PR is fixing.

Suggestion: use review.content_sha256 and review.disable_model_invocation, and take the conflicting names from the reviews (or move the grouping into one helper both use).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d3ba18b. Routing takes the digest, the disabled flag and the name-conflict set from review_skills (content_sha256, disable_model_invocation, name-conflict findings), so it no longer hashes or re-parses each SKILL.md. catalog scan and the field read one implementation.

Comment thread dokimi/dokimi/commands/catalog.py Outdated
if args.kind in ("skills", "all") and not report["skills"]:
# Nothing to scan is a wrong root or an empty checkout, so a skills scan fails on it. A
# --kind all scan of a tasks-only catalog is a warning, which --strict makes a failure.
print(f"no SKILL.md found under {root}", file=sys.stderr)

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.

Nit: The message says no SKILL.md found when there are SKILL.md files but the manifest lists none.

A root with skills/a/SKILL.md and skills.yaml set to skills: [] prints no SKILL.md found under <root> and exits 1. The exit is right; the message sends the user looking for missing files.

Suggestion: when a skills.yaml is present, say skills.yaml under <root> declares no skill.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d3ba18b. A root with a skills.yaml that has no skill that can be scanned now says so, instead of no SKILL.md found. Test: test_catalog_scan_with_a_manifest_that_declares_no_skill_says_so_and_exits_1.

Comment thread dokimi/dokimi/external/validate.py Outdated
"warn",
"name-conflict",
f"name {name!r} is also used by {', '.join(others)}, with different content; "
"routing skips this name until one is renamed or removed",

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.

Nit: The name-conflict warning says routing skips the name, but it does not when one copy is the artifact.

novelty routing --artifact skill:cat/skills/db --catalog cat/ with a different plugins/x/skills/db: the name is in exclude, so the fork is dropped by name before the conflict check, with no note and nothing in left_out, while the scan says routing skips db.

Suggestion: word it as "novelty routing --catalog leaves this name out of the field", or note in left_out a same-name catalog copy that differs from the artifact.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d3ba18b. The warning now says novelty routing --catalog leaves the name out of the field, which is what happens when the artifact is one of the copies.

…eview; reword the conflict and no-skill messages

- Routing reads content_sha256, disable_model_invocation and the name-conflict
  findings of review_skills instead of hashing and re-parsing each SKILL.md
  again, so catalog scan and the field cannot drift (Thread: PRRT_kwDOVBg7g86yVfRA).
- The name-conflict warning says `novelty routing --catalog` leaves the name out
  of the field, which is what happens when the artifact is one of the copies
  (Thread: PRRT_kwDOVBg7g86yVfRH).
- A root whose skills.yaml declares no skill says so, instead of `no SKILL.md
  found` (Thread: PRRT_kwDOVBg7g86yVfRD).
- The changelog fragment says a routing result saved before this change is not
  comparable, and drops the Fixed entry for an abort no release had
  (Thread: PRRT_kwDOVBg7g86yVfQ8).

Thread: PRRT_kwDOVBg7g86yVfRA
Thread: PRRT_kwDOVBg7g86yVfRH
Thread: PRRT_kwDOVBg7g86yVfRD
Thread: PRRT_kwDOVBg7g86yVfQ8
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Copilot AI balanced review requested due to automatic review settings November 1, 2026 05:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues block the catalog diagnostics and routing eligibility changes.

No open issues 🎉

What changed in this PR

0 new findings; nothing to fix.

This PR aligns dokimi’s catalog diagnostics with routing eligibility, so conflicting names and invalid skills are handled consistently without unnecessarily aborting routing.

Changes:

  • Warn about same-name skills with different content and exclude those names from catalog-derived routing fields.
  • Exclude spec-error skills by default, add --include-invalid, and record that flag in saved routing results.
  • Fail empty skill scans, with a tasks-only exception under non-strict --kind all, and update tests and documentation.
File Description
dokimi/​tests/​test_novelty_routing_field.py Tests conflict exclusion, invalid-skill filtering, warnings, and saved flags.
dokimi/​tests/​test_novelty_routing_all_vs_all.py Updates the expected saved field metadata.
dokimi/​tests/​test_catalog_validate.py Tests name-conflict warnings and affected paths.
dokimi/​tests/​test_catalog_command.py Tests empty catalogs and tasks-only scan behavior.
dokimi/​tests/​data/​cli_flags_allowlist.txt Registers --include-invalid in the flag allowlist.
dokimi/​dokimi/​novelty/​routing.py Uses catalog reviews to filter conflicts and spec-error skills.
dokimi/​dokimi/​external/​validate.py Adds name-conflict findings for differing same-name skills.
dokimi/​dokimi/​commands/​novelty.py Wires --include-invalid into routing and saved metadata.
dokimi/​dokimi/​commands/​catalog.py Adds empty-scan diagnostics and failure rules.
dokimi/​docs/​skill-novelty.md Documents routing exclusions and saved field rules.
dokimi/​docs/​reference/​cli-interface.json Adds the new flag to the CLI snapshot.
dokimi/​docs/​external-content.md Documents empty scans and name-conflict warnings.
dokimi/​changelog.d/​20261031_120000_napetrov_rescan-catalog.md Records the catalog and routing behavior changes.
dokimi/​changelog.d/​20261021_130000_napetrov_routing-catalog-manifest.md Updates the earlier fragment to describe conflict skipping.

Review effort: Balanced

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

Review at d3ba18b. I found no new bug or risk. The merge waits on two design points that @vlad-perevezentsev raised and the author has handed back for a maintainer's decision.

Open until decided:

  • @vlad-perevezentsev's point on routing.py (a disabled or spec-error copy of a name removes the enabled same-name skill from the field) is unchanged at this head. The conflict check still runs over every loaded copy before the --include-disabled / --include-invalid filters (_eligible_catalog_skills, by a reading of the code). It waits for a decision.
  • @vlad-perevezentsev's point on commands/novelty.py (--include-invalid and the spec-error filter cover --catalog only, while skill: competitors are kept unfiltered) is unchanged: include_invalid is passed only to catalog_competitors. The saved result still records include_invalid: false for such a run. It waits for a decision.

What I ran, on a Linux review host at d3ba18b:

  • make ci-local: 30 passed, 0 failed, 7 skipped (jobs that need a PR context, Docker or network).
  • 26 deliberate mutants of the new code against the four touched test files: 23 are caught. The 3 that pass change only the order of paths in a message, or are equivalent code (args.kind == "skills" is implied by not report["tasks"]).
  • The touched tests run against the base modules: 15 fail there, so they cover the change.
  • Reproductions of catalog scan on an empty root, a tasks-only root, --strict, and an empty skills.yaml, and of catalog_competitors with mirrors, disabled and spec-error copies, and exclude, all offline.

Checked, no issues

  • Conflict rule: routing takes the conflicting names from the name-conflict findings of review_skills, so the scan warning and the field agree. Identical mirrors are not a conflict.
  • Exit codes: --kind skills on an empty root exits 1; --kind all on a tasks-only root exits 0 and 1 under --strict; the pinned catalog in the agent-quality workflow has SKILL.md files, so it is not affected.
  • Saved field rule: include_invalid is recorded for single-artifact and all-vs-all runs; the CLI snapshot and flag allowlist are updated.
  • Repo rules: changelog fragment present, commits signed off, no generated artifacts, no schema change.

…icit spec errors

- The disable-model-invocation and spec-error filters now run before
  the same-name conflict check, so a copy no harness lists does not
  make its name a conflict. --include-disabled and --include-invalid
  bring the copy back into the check.
- catalog scan names only the listed copies (not disabled, not a spec
  error) in name-conflict warnings, so routing and scan agree.
- An explicit skill: competitor with a spec error is skipped with a
  warning, as a catalog skill is (competitor_left_out), instead of
  being kept silently.
- growth_baseline.json lowered for novelty.py after the move.

Covered by red-then-green tests in test_novelty_routing_field.py and
test_catalog_validate.py.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Comment on lines +12 to +13
keeps it. A name with two different copies, or a copy that is `disable-model-invocation`, also changes
the field, so a routing result saved before this change is not comparable with one saved now for the

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation · low
Nit: this still says a disabled copy changes the routing field, but the latest implementation filters disabled copies before checking conflicts. For example, an enabled skills/db/SKILL.md and a different-content disabled plugins/db/SKILL.md now keep the enabled db in the default field, just as before this PR. Remove the disabled-copy clause, or qualify it with --include-disabled, so the compatibility warning describes the current behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a283eed. The changelog now says a copy that is disable-model-invocation counts only with --include-disabled. With the default flags it does not change the field, as you describe.

Comment thread dokimi/dokimi/novelty/routing.py Outdated
Comment on lines +467 to +468
entry = SkillCatalogEntry(name=skill.name, status=None, path=path.parent,
source_root=path.parent.parent, skill=skill)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug · medium
Must-fix: the spec-error filter depends on how the same path is written. From /tmp/checkout with SKILL.md declaring name: db, competitor_left_out('skill:SKILL.md', include_disabled=False, include_invalid=False) keeps the skill, but the same call with skill:/tmp/checkout/SKILL.md drops it for name-mismatch. For the relative reference, both path.parent and path.parent.parent are ., so review_skills treats it as a root skill and exempts the directory-name check; the absolute reference does not get that exemption. Normalize the path before deriving the review root and apply a consistent root-skill policy. Add a regression comparing relative and absolute references (including skill:.) so path spelling cannot change the measured field.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a283eed. competitor_left_out now reads the absolute path, so skill:SKILL.md, skill:. and the absolute reference get the same verdict and the directory-name check applies to all three. Regression: test_the_spelling_of_an_explicit_competitor_does_not_change_its_verdict (relative gave None before).

Comment thread dokimi/dokimi/novelty/routing.py Outdated
Comment on lines +557 to +559
A name whose loaded copies differ in content leaves the field whole. That check runs
before the disabled and spec-error filters, so it sees the copies ``catalog scan`` warns
about, and the note names all of them.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation · low
Nit: this describes the previous filter order. The implementation now removes disabled and spec-error copies before checking conflicts, so a valid enabled db remains when its only differing copy is excluded. Update this docstring and catalog_competitors (which still says disabled and spec-error copies participate) to describe conflicts among copies admitted by the flags.

Suggestion:

Suggested change
A name whose loaded copies differ in content leaves the field whole. That check runs
before the disabled and spec-error filters, so it sees the copies ``catalog scan`` warns
about, and the note names all of them.
Disabled and spec-error copies are filtered according to the flags first. A name whose
remaining copies differ in content leaves the field whole, with a note naming every
remaining path of that name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a283eed. The docstrings of catalog_competitors and _eligible_catalog_skills now describe the flag-first order: conflicts are checked among the copies the flags admit, with a note naming every remaining path.

…elling

competitor_left_out reads the absolute path. A relative skill:SKILL.md had
parent.parent == "." and was taken for a root skill, so the directory-name
check was skipped and the same skill got a different verdict.

Also: the catalog_competitors and _eligible_catalog_skills docstrings and the
changelog describe the flag-first order (a disabled copy counts only with
--include-disabled). test_skill_repo_shapes drops its open-bug xfail table:
the six entries XPASS on this branch, so the marks came off.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Comment thread dokimi/docs/external-content.md Outdated
Comment on lines +128 to +129
another skill's, is a `warn`. So is a skill whose `name` another skill shares with
different content (`name-conflict`): the finding names the other path, and

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation · low
Nit: qualify this as a conflict between enabled skills without spec errors. _name_conflicts excludes disabled and spec-invalid copies, so skills/x plus a different-content plugins/x with disable-model-invocation: true produces no name-conflict warning and keeps the enabled x in default routing (as test_a_disabled_copy_of_a_name_is_not_a_name_conflict verifies). The unqualified wording promises a warning for that input. Apply the same qualification to the catalog scan entry in changelog.d/20261031_120000_napetrov_rescan-catalog.md; routing inclusion flags can admit additional copies, but scan has no corresponding flags.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c936c71. The paragraph and the changelog entry now say name-conflict counts only among listed skills (no disable-model-invocation, no spec error).

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

Review at a283eed. The flag-first order from c848aec holds: the scan warning and the routing field name the same copies, and the path-spelling fix works for relative references. One thing is worth fixing before merge: the same fix now rejects a root-level SKILL.md that --catalog keeps. One nit on the changelog.

What I ran, on a Linux review host at a283eed:

  • make ci-local: 30 passed, 0 failed, 7 skipped (jobs that need a PR context, Docker or network). Changed-line coverage gate passes.
  • 31 deliberate mutants of the new code against the four touched test files: 29 are caught. The 2 that pass are equivalent code (args.kind == "skills" is implied by not report["tasks"]; the review is None guard) and one message-only filter in _name_conflicts.
  • Reproductions with the LLM transport mocked: catalog scan on empty, tasks-only and empty-manifest roots; catalog_competitors with mirrors, disabled and spec-error copies; competitor_left_out with file, directory, relative and skill:. spellings.

Checked, no issues

  • Conflict rule: disabled and spec-error copies are filtered first, then conflicts are taken over what is left. With default flags, an enabled db next to a different disabled db stays in the field and gets no scan warning; --include-disabled brings the conflict back.
  • Spelling: skill:SKILL.md, skill:., skill:dir and the absolute path give one verdict inside a skill directory.
  • Exit codes: empty root exits 1 for --kind skills and --kind all, 0 for --kind tasks; a tasks-only root under --kind all warns and fails only with --strict.
  • Repo rules: all 7 non-merge commits are signed off, no generated artifacts, CLI snapshot and flag allowlist updated, changelog fragment present.

Comment thread dokimi/dokimi/novelty/routing.py Resolved
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
Comment thread dokimi/docs/external-content.md Outdated
| Command | Root missing | Exit |
|---|---|---|
| `catalog scan --root <missing>` | `--root is not a directory: <path>` | 1 |
| `catalog scan --root <no SKILL.md>` | `no SKILL.md found under <path>` | 1 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation · low
Nit: this row promises exit 1 for every root without SKILL.md, but the default --kind all scan of a healthy tasks-only root prints this message and exits 0 without --strict (as the new tasks-only regression test verifies). Add --kind skills to this command, or qualify the exit column with the tasks-only exception.

Suggestion:

Suggested change
| `catalog scan --root <no SKILL.md>` | `no SKILL.md found under <path>` | 1 |
| `catalog scan --root <no SKILL.md> --kind skills` | `no SKILL.md found under <path>` | 1 |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c936c71: the row runs catalog scan --root <no SKILL.md> --kind skills, which exits 1 (checked on this branch). With --kind all a tasks-only root still only warns, as the paragraph says.

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

I pushed a commit per nit, up to c3d32a1, which fix the nit from my review:

  • c3d32a1: dokimi/changelog.d/20261031_120000_napetrov_rescan-catalog.md:11: added that a --competitors skill:<path> with a spec error is skipped the same way.

make ci-local at c3d32a1: 30 passed, 0 failed, 7 skipped.

Not approving yet. Still open: the risk from my review.

…kind skills

The scan's name-conflict warning skips a disable-model-invocation copy and a copy
with a spec error (validate._name_conflicts), so the docs and the changelog say
so. The root-missing table row names --kind skills: with --kind all, a tasks-only
root only warns.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>

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

Review at c936c71. The commits since my last review change docs only (external-content.md, the changelog fragment), and the doc fixes read right. The merge still waits on my earlier thread about a root-level SKILL.md, which this head leaves unchanged. One nit inline.

What I ran, on a Linux review host at c936c71:

  • make ci-local: 30 passed, 0 failed, 7 skipped (jobs that need a PR context, Docker or network).
  • 30 deliberate mutants of the new code against the five touched test files: 27 are caught. The 3 that pass change only note text or the scan warning for a spec-error copy (the nit inline).
  • Reproductions with the LLM transport mocked: catalog_competitors and competitor_left_out on a root-level SKILL.md; catalog scan on empty, tasks-only and empty-manifest roots; flag-first conflict checks with --include-disabled and --include-invalid.

Still open from my earlier review:

  • dokimi/dokimi/novelty/routing.py:472: a root-level SKILL.md is kept by --catalog but dropped as an explicit skill: competitor. At c936c71, checkout/SKILL.md with name: db: catalog_competitors("checkout", set(), notes) returns db; competitor_left_out("skill:<abs>/checkout", ...) returns spec error (name 'db' is not the directory name 'checkout'; --include-invalid keeps it). The author's option (a) calls this "the spec rule", but the catalog applies the same rule with the root exemption (validate.py:207), so the two paths still give different verdicts for one skill, and the checkout directory name decides the field. Please take option (b) in the narrow form from the thread: read a SKILL.md with no skills/ parent as a root skill for the name check, and add a test for skill:<dir> and skill:SKILL.md on a root-level skill.

Checked, no issues

  • Exit codes: an empty root exits 1 for --kind skills and --kind all; a tasks-only root under --kind all warns and exits 1 only with --strict; the new row in external-content.md uses --kind skills.
  • Conflict rule: disabled and spec-error copies are filtered first; the scan warns about the same copies routing drops. Verified with and without --include-disabled / --include-invalid.
  • Repo rules: both changelog fragments present, all 9 non-merge commits signed off, CLI snapshot and flag allowlist updated, no schema change, no generated artifacts.
Bot points I checked that no longer apply at this head (1)
  • exai-bot's point on the path spelling of skill: references does not apply: skill:SKILL.md, skill:. and the absolute path now give one verdict (a283eed). The root-skill policy it also mentions is the thread above.

Comment thread dokimi/dokimi/external/validate.py Resolved

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

Review at 5a61b4a. The merge still waits on my earlier point about a root-level SKILL.md, which this head leaves unchanged. The commits since c3d32a1 touch the docs and the changelog only, apart from merges of main, and the doc changes read right. I found no new bug or risk.

What I ran, on a Linux review host at 5a61b4a:

  • make ci-local: 28 passed, 2 failed, 7 skipped. The 2 failures are the gitleaks install and the commit scan, which need a download that is not available here; the PR does not cause them. 12,262 tests passed, 59 skipped; changed-line coverage 98%.
  • Reproductions with the LLM transport mocked: catalog_competitors and competitor_left_out on a root-level SKILL.md.
  • One mutant of _name_conflicts against the three touched test files (124 tests): it passes (the second point under "Still open").

Still open from my earlier review:

  • dokimi/dokimi/novelty/routing.py:472: a root-level SKILL.md is kept by --catalog but dropped as an explicit skill: competitor. At 5a61b4a, checkout/SKILL.md with name: db: catalog_competitors("checkout", set(), notes) returns db and no note. competitor_left_out on skill:<abs>/checkout and on skill:<abs>/checkout/SKILL.md returns spec error (name 'db' is not the directory name 'checkout'; --include-invalid keeps it). The checkout directory name still decides whether a single-skill repo is in the field. The author's option (a) keeps the check as "the spec rule", but the catalog applies the same rule with the root exemption (validate.py:207). Please take the narrow form of (b): read a SKILL.md with no skills/ parent as a root skill for the name check, with a test for skill:<dir> and skill:SKILL.md.
  • dokimi/dokimi/external/validate.py:245: nothing pins the state != "error" clause in _name_conflicts. Removing it passes the touched test files (124 passed). The test from my thread, test_a_spec_error_copy_of_a_name_is_not_a_name_conflict, is still not in tests/test_catalog_validate.py.

Checked, no issues

  • Delta: git diff c3d32a1..HEAD for the PR's files is the changelog wrapping and the name-conflict qualification in external-content.md and the changelog, plus the --kind skills table row. They match _name_conflicts and the exit codes.
  • Repo rules: all 9 non-merge commits are signed off, CLI snapshot and flag allowlist are current (cli-surface passes), docs build, no schema change, no generated artifacts.
Bot points I checked that no longer apply at this head (1)
  • exai-bot's point on the path spelling of skill: references does not apply: skill:SKILL.md, skill:. and the absolute path give one verdict (a283eed). The root-skill policy it also mentions is the open point above.

Signed-off-by: Anton Volkov <antonwolfy@gmail.com>

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

I pushed a commit per nit, up to 33d7692, which fix the nit from my review:

  • 33d7692: dokimi/tests/test_catalog_validate.py:154: added test_a_spec_error_copy_of_a_name_is_not_a_name_conflict after the disabled-copy test, as suggested.

make ci-local at 33d7692: 30 passed, 0 failed, 7 skipped.

Not approving yet. Still open: the earlier thread of mine above nit level.

…n explicit competitor's name check

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Comment on lines +253 to +254
field = _routing_field(args, {"perf"}, left_out)
assert [c.name for c in field] == ["cache"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test · low
Nit (non-blocking): this regression now stops at _routing_field, so it no longer verifies the advertised change from command refusal to successful routing. A refusal introduced after field construction, or failure to persist the conflict in field.left_out, would still pass. Keep these filtering assertions, then call args.func(args) and inspect the saved JSON for status == "ok", field.competitors == ["cache"], and the conflict note in field.left_out. No other routing conflict test exercises that complete command path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6387fe6. The conflict test now runs the whole command: it checks the saved result is ok, competitors is [cache], and the conflict note is in field.left_out.

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

The root-skill fix is right, and my earlier thread on it is closed. One test gap came with it, and it is worth fixing before merge.

What I ran, on a Linux review host at c0bae6d:

  • make ci-local: 30 passed, 0 failed, 7 skipped (jobs that need Docker, network or a PR context).
  • 6 deliberate mutants of the root = ... line against test_novelty_routing_field.py (36 tests): all 5 that change the rule are caught. The one that removes the abspath line passes (the inline comment).
  • Reproductions with the LLM transport mocked: competitor_left_out on checkout/SKILL.md (name db) by file, directory, skill:SKILL.md and skill:.; on skills/checkout and plugins/x/skills/checkout.

Checked, no issues

  • Root-skill rule: a SKILL.md with no skills/ parent gets no name-vs-directory error for any spelling; under skills/ the check stays. Both match catalog_competitors for those layouts.
  • Repo rules: all non-merge commits are signed off, CLI snapshot and flag allowlist current, changelog fragments present, no schema change.
Bot points I checked that no longer apply at this head (1)
  • exai-bot's point on the path spelling of skill: references does not apply: skill:SKILL.md, skill:. and the absolute path now give one verdict, and the root-skill policy it also mentions is the one now applied.

@vlad-perevezentsev vlad-perevezentsev 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.

Review at c0bae6d. The name check now works the same as --catalog for a skill at the root and under skills/. One more layout still differs; it is in the line comment.

Agreed with @antonwolfy on the missing relative-path test for the abspath line.

Agreed with @exai-bot on the conflict test that does not reach the saved JSON.

skill = load_skill(path)
# A SKILL.md with no ``skills/`` parent is a root skill, as the catalog reads one at its scan root:
# its directory name says nothing about the skill, so the name check is skipped for it.
root = path.parent.parent if path.parent.parent.name == "skills" else path.parent

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.

The skills/ parent rule from @antonwolfy's thread closes the root-level case, but a skill outside a skills/ directory now skips the name check only when passed explicitly.

The root-level and skills/ layouts agree with --catalog, as @antonwolfy checked; a third layout does not. Repro at c0bae6d: cat/tools/database/SKILL.md with name: db. catalog_competitors("cat", ...) leaves db out (name 'db' is not the directory name 'database'), and catalog scan reports the same error. competitor_left_out("skill:cat/tools/database", ...) returns None, so the same file is in the field as --competitors and out of it as --catalog. Any layout without skills/ (plugins/x/<dir>, tools/<dir>) gets this.

Suggestion: read a SKILL.md as a root skill only when nothing above it looks like a catalog, e.g. when its parent directory holds no other skill directory (a single-skill checkout), or when the directory is the top of a git checkout; and add the tools/database case to test_a_skill_under_a_skills_directory_keeps_the_directory_name_check. If the heuristic is meant to stay, say in skill-novelty.md which explicit skills are name-checked.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainer decision: keep the directory-name rule for explicit skill: outside skills/. Such a skill is read as a root skill and is not name-checked when passed explicitly.
Documented in docs/skill-novelty.md and pinned by a test. Done in 51ce87b.

napetrov and others added 3 commits November 2, 2026 08:11
…ative spelling under skills/

The conflict regression stopped at the field; it now runs the command and
checks the saved result is ok, with the same note in left_out.

A relative skill: reference under a skills/ directory is checked as its
absolute one is, so removing the abspath in competitor_left_out fails it.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
A skill: competitor outside a skills/ tree is read as a root skill, so its
name is not checked against its directory. Document that, and pin it with a
test, so an explicit reference and a catalog scan are not read as agreeing.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…ield

The refusal for queries naming a skill outside the field only pointed at
--include-disabled, which does nothing for the spec-error and name-conflict
leave-outs this PR adds. Name all three, and say in the changelog that
--all-vs-all still refuses such a query file.

Signed-off-by: Alexander Rybkin <alexander.rybkin@intel.com>
@xaleryb

xaleryb commented Nov 3, 2026

Copy link
Copy Markdown
Contributor
  • Ran: the full suite, lint, types, security and the benchmark gate on the head merged with main, plus novelty routing --all-vs-all --catalog on catalogs where a queried skill is left out of the field.
  • --all-vs-all with a query file that names a skill left out for a spec error (description over 1024 chars), or a name with two different copies, gets exit 2 and the advice "left out unless you pass --include-disabled". Following that advice changes nothing: still exit 2. Expected: the refusal stays (docs/skill-novelty.md says all-vs-all refuses a query file naming a skill outside the field), but the message should name the real reasons. Also, the changelog's "instead of refusing the run" does not hold under --all-vs-all.
  • Pushed b8ac2a6: the refusal now names all three ways a skill leaves the field (--include-disabled, --include-invalid, a name with conflicting copies), with a parametrized CLI test and a changelog clause.
  • Left for the author: nothing blocking.

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

Approving b8ac2a6: CI green, and the automated review of this head raised nothing new. The findings from the comment above are fixed by the pushed commits, each with a test or a doc change.

@xaleryb
xaleryb merged commit 1cc9663 into intel:main Nov 3, 2026
16 checks passed
xaleryb added a commit to napetrov/dokimi that referenced this pull request Nov 3, 2026
Keeps intel#328's field rules (spec errors and name conflicts leave the field) and
intel#329's estimate-only, all-vs-all repeats and cost; the refusal of a query file
naming a left-out skill now names each skill with every reason that applies.

Signed-off-by: Alexander Rybkin <alexander.rybkin@intel.com>
napetrov added a commit to napetrov/dokimi that referenced this pull request Nov 3, 2026
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>

intel#328's competitor rules (disable-model-invocation, spec errors, name conflicts) now live in routing_field, the module this branch moved them to. Routing tests follow main's notes and the InputError exit path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli-interface-change Changes dokimi's user-facing CLI surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants