Skip to content

fix(routing): triage queries skip code fences, zero-query runs say why - #168

Merged
antonwolfy merged 10 commits into
intel:mainfrom
napetrov:fix/skill-gap-W3
Oct 23, 2026
Merged

antonwolfy merged 10 commits into
intel:mainfrom
napetrov:fix/skill-gap-W3

Conversation

@napetrov

Copy link
Copy Markdown
Contributor

Part of #4.
Depends on #164: both append tests to tests/test_novelty_routing.py, so this rebases cleanly only after #164 merges.

Summary

novelty routing --queries-from-headings stops reading code-block lines as requests, and a run with no usable query says why.

 headings_as_queries(body)
+  _outside_fences(body)                  # drop ``` and ~~~ blocks first
   headings: ^#{2,3}[ \t]+(.+)$           # a bare "##" line no longer takes the next line
 cmd_novelty_routing
-  if not queries: exit "no usable queries"
+  zero scored queries:
+    write routing.json  {"status": "no_queries", "reason": ...}
+    exit 1, naming the reason and --queries
   rate lines
+    n_queries N given, ...  triage: self-derived
+    WARNING if fewer than 5 scored

Evidence

Nine new tests in tests/test_novelty_routing.py. Against intel/main (commands/novelty.py and novelty/routing.py reverted, rest of the branch kept), nine fail:

before: intel/main routing.py + novelty.py
  FAILED test_a_heading_inside_a_code_fence_is_not_a_query[```]
  FAILED test_a_heading_inside_a_code_fence_is_not_a_query[~~~]
  FAILED test_a_fence_closes_only_on_its_own_character_and_length
  FAILED test_a_bare_hash_line_does_not_take_the_next_line_as_its_heading
  FAILED test_headings_inside_code_only_refuse_the_run_and_say_why
  FAILED test_a_query_file_with_nothing_in_it_refuses_the_run
  FAILED test_queries_without_a_content_word_refuse_the_run
  FAILED test_every_rate_line_carries_its_query_count_and_triage_tag
  FAILED test_fewer_than_five_scored_queries_are_warned_about_on_stdout
  9 failed, 48 passed

after: this branch, full suite below

Local checks on the rebased head:

uv run ruff check .                              All checks passed!
uv run mypy dokimi                               Success: no issues found in 222 source files
uv run python -m dokimi.schema_check             exit 0
uv run python -m dokimi.config_check             exit 0
uv run pytest -n auto -q                         6951 passed, 22 skipped

Merge Danger

Door: two-way. The exit-code change is the only one that a script can see, and it is reversible by reverting the commit.

Blast Radius: low, limited to novelty routing.

  • Exit code 1 on no scored query. A run whose queries are non-empty but all filtered out (no content word) used to exit 0 with null rates. It now exits 1 and writes "status": "no_queries" with a reason. Scripts that read the null rates as a result must check the exit code or status. This is the one change to existing behaviour.
  • Result file on the failure path. The no-query case now writes routing.json before exiting. A batch run finds a record instead of nothing.
  • Fenced headings are no longer queries. --queries-from-headings offers fewer, and different, self-derived queries on artifacts with code blocks. They remain triage only and stay stamped queries_self_derived.
  • Stdout format. Each rate line now reads n_queries N given, ... and carries triage: self-derived when the queries came from headings. Line-parsers need updating.
  • Warning, not failure, under five queries. A run that scores fewer than five queries prints a warning on stdout.
  • Merge order. Merge after feat(novelty): usage and cost block for routing --model #164 (see the first line).

Checklist

  • Tests added/updated and pytest passes
  • ruff, mypy, and schema checks pass
  • Docs updated: docs/skill-novelty.md (routing section)
  • No ad-hoc run artifacts committed
  • New code and test files carry the SPDX license header (no new code files; the changelog fragment follows the existing fragments, which carry none)

🤖 Generated with Claude Code

--queries-from-headings read a `## comment` inside a fenced code block as a
request. Headings inside fences are now skipped (backtick and tilde fences,
closed only by the same character at least as long).

A run with no usable query exited with a bare "no usable queries" and wrote
nothing. It now names the cause, suggests --queries, and writes the result
with "status": "no_queries" and a "reason"; a successful result carries
"status": "ok".

Every routing rate line prints its n_queries, with "triage: self-derived"
beside it when the queries come from the artifact's headings. Fewer than five
scored queries draw a warning on stdout.

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The heading pattern used \s+ after the hashes, which also matches a newline,
so a bare "##" line read the next line as its heading. The separator is now
[ \t]+, and a test pins "##\nfoo bar\n" to no queries.

Changelog: the zero-scored routing exit (status no_queries, exit 1 where it
used to exit 0 with null rates) is listed under Changed.

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 52d90cc. The fence skipping works for the plain cases, and the new rate lines and the no_queries record behave as described. Four points are worth fixing before merge: one bug in the fence matcher, two risks (a model-row count that does not match the lexical one, and tests that miss the fence-closing rules), and one nit.

What I ran, on a Linux review host at 52d90cc:

  • make ci-local: 20 passed, 8 failed, 7 skipped. The 8 failures are ruff, zizmor, pre-commit, bandit, mypy, deptry, mkdocs build and pip-audit, all exit 127: the tools are missing from my venv because make dev stops at the tools install on this base, which #179 fixed on main. Static checks, mypy and the strict docs build pass on GitHub's CI at this head. Tests: 6952 passed, 21 skipped; changed-lines coverage gate passed; schema-compat, wheel build and smoke, and gitleaks passed.
  • Reproductions for the code findings, with the LLM transport mocked.
  • Mutation runs on _outside_fences: 8 mutants, 3 of which pass the full test_novelty_routing.py.

Checked, no issues

  • Fence closing: closers need the opener's character and at least its length; trailing spaces, CRLF and unclosed fences behave as CommonMark.
  • Heading regex: ##\n foo bar no longer takes the next line; ##\tTabbed heading is accepted; #### stays excluded.
  • Consumers: nothing in the tree parses the old over N of M queries line, no schema covers routing.json, and the one test that reads it (test_novelty_journey.py) uses lexical.n_queries, which is unchanged.
  • No-query path: it exits before any model call, and it overwrites a stale status: ok file at --out.

Comment thread dokimi/dokimi/novelty/routing.py Outdated
Comment thread dokimi/tests/test_novelty_routing.py
Comment thread dokimi/dokimi/commands/novelty.py Outdated
Comment thread dokimi/dokimi/commands/novelty.py Outdated
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
@codecov-commenter

codecov-commenter commented Oct 22, 2026 •

Copy link
Copy Markdown

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

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.80%. Comparing base (5064dc2) to head (6125691).
⚠️ Report is 11 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #168      +/-   ##
==========================================
+ Coverage   91.64%   91.80%   +0.15%     
==========================================
  Files         222      223       +1     
  Lines       27409    27638     +229     
  Branches     4508     4553      +45     
==========================================
+ Hits        25118    25372     +254     
+ Misses       1620     1604      -16     
+ Partials      671      662       -9     
Files with missing lines Coverage Δ
dokimi/dokimi/commands/novelty.py 95.84% <100.00%> (+2.30%) ⬆️
dokimi/dokimi/novelty/routing.py 98.85% <100.00%> (+0.09%) ⬆️

... and 15 files with indirect coverage changes

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

@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 46a0897, which fix the nit from my review:

  • 46a0897: dokimi/dokimi/commands/novelty.py:373: the warning now says 'query' for a count of one and 'queries' otherwise.

make ci-local at 46a0897: 20 passed, 8 failed (all exit 127, tools missing on host), 7 skipped.

Not approving yet. Still open: the bug and the two risks from my review.

napetrov and others added 6 commits October 22, 2026 11:40
…es is of all given

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…hore(growth): raise commands/novelty.py for W3

Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…baseline after the extraction

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

A closer indented 1-3 spaces (fences in list items) could stop matching, hiding every
heading after it, and no test went red. Also pin "status": "ok" on a successful result,
the triage tag on the model row, the warning at 4 scored queries, and a tab after "##".

Signed-off-by: Alexander Rybkin <alexander.rybkin@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 fc0539e. The three points from my earlier review are fixed: the fence matcher follows CommonMark on the indent and the info string, the model row says n_queries N given, and the tests I asked for are there. One test gap is left before merge.

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

  • make ci-local: 28 passed, 1 failed, 7 skipped. The failure is pip-audit on the lock files, which this PR does not touch. Tests: 7223 passed, 1 skipped; changed-lines coverage gate, schema-compat, docs build, wheel build and smoke, and gitleaks passed.
  • Mutation runs on _FENCE, _outside_fences and the heading regex: 18 mutants; some pass the full test_novelty_routing.py. The ones that matter are on the inline comment.

Checked, no issues

  • Fence rules: a tab indent, a 4-space indent, a backtick in a backtick opener's info string, a ~~~ line inside a backtick block, a ```js line inside a block, trailing spaces/tab and CRLF on the closer all behave as CommonMark; each of the first five now has a test that fails when the rule is removed.
  • No-query path: all-fenced headings, a blank queries file, an empty JSON list and an all-stopword file each exit 1 with a reason and write status: no_queries; the model is not called.
  • Consumers: the only reader of routing.json in the tree is test_novelty_journey.py, which uses lexical.n_queries; the added status key breaks nothing.
  • Growth ratchet: novelty.py is 863 lines, matching the raised baseline, and cmd_novelty_routing complexity is lowered to 12.

Comment thread dokimi/tests/test_novelty_routing.py
@xaleryb

xaleryb commented Oct 23, 2026

Copy link
Copy Markdown
Contributor
  • Ran: full suite, ruff, mypy strict and bandit at the head, a CommonMark differential on fenced documents, and a mutation pass over the new fence and output code.
  • Open (F1, untested branch): "```\n## Hidden heading one\n ```\n## Real heading one\n" gives ["Real heading one"] at the head. If the closer check is changed to not line[len(fence.group(1)):].strip(), that becomes [] and every test still passes. Indented fences are how fences look inside list items. Also unpinned: "status": "ok", the triage: self-derived tag on the model row, the < 5 warning threshold, and a tab after ##.
  • Pushed b6e3d7d (test-only): parametrized open/close indents 0-3 for backtick and tilde fences, the status == "ok" check, a model-row tag check under --queries-from-headings --model, a warning at 4 scored queries, and a ##\t heading. Each mutant above now turns a test red.
  • Left for the author: resolve the three outdated inline threads, which are fixed at the head.

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

Approved at b6e3d7d. Every earlier point re-run at this head passes and no must-fix or mid item is open; full suite, ruff and mypy clean on Linux; CI green.

@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 b6e3d7d. The commit since fc0539e adds test-only changes, and they close @xaleryb's gaps on indented closers, status: ok, the model-row tag and the warning threshold. One test gap from my earlier review is still open, so I am not approving yet.

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

  • make ci-local: 28 passed, 1 failed, 7 skipped. The failure is pip-audit on the lock files, which this PR does not touch. Tests: 7257 passed, 1 skipped; changed-lines coverage gate, schema-compat, docs build, wheel build and smoke, and gitleaks passed.
  • Two mutants run against the full tests/test_novelty_routing.py (98 tests): both pass.

Still open from my earlier review:

  • dokimi/tests/test_novelty_routing.py:593: the minimum fence length and the heading separator are still unpinned. With _FENCE at {2,} for both characters, headings_as_queries("~~strike~~ text\n## Real heading one\n") returns [] instead of ['Real heading one'], and all 98 tests pass. With the heading regex at ^#{2,3}[ \t]*(.+)$, headings_as_queries("##hashtag word\n") returns ['hashtag word'] instead of [], and all 98 pass. The new ##\tTab heading words test does not help: it passes under [ \t]* too. The new indent tests use three-character fences only. Suggestion: add headings_as_queries("~~strike~~ text\n## Real heading one\n") == ["Real heading one"] and headings_as_queries("##hashtag word\n") == [].

Checked, no issues

  • Zero-query path: an all-stopword file, a blank file and an all-fenced heading file each exit 1 with a reason and write status: no_queries.
  • Rate line and warning: triage: self-derived shows on the rate line only for headings-derived queries; the warning fires below five scored queries.
  • Docs and changelog: the docs tests, the growth ratchet and ruff pass on the changed files.

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.

LGTM. The two tests added in 6125691 pin both points from my earlier thread, and nothing else changed since b6e3d7d.

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

  • make ci-local: 28 passed, 1 failed, 7 skipped. The failure is pip-audit on the lock files, which this PR does not touch. Tests: 7261 passed, 1 skipped; changed-lines coverage gate, schema-compat, docs build, wheel build and smoke, and gitleaks passed.
  • Mutation runs against the full tests/test_novelty_routing.py (102 tests): _FENCE at {2,} for backtick, for tilde and for both, and the heading regex at [ \t]*, each turn a test red. Seven further mutants on the indent bounds, the closer length, the closer character, trailing text on a closer and the backtick info-string lookahead are each killed by one test.

Checked, no issues

  • Fence minimum: ~~strike~~ text, ``x`` text and ``x text keep the heading after them.
  • Heading separator: ##hashtag word yields no query.
  • Docs and changelog: exit code 1, status: no_queries with a reason, the n_queries N of M given / n_queries N given rate lines, the triage: self-derived tag and the under-five warning match the code.

@antonwolfy
antonwolfy merged commit 98ed46b into intel:main Oct 23, 2026
24 checks passed
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.

4 participants