ci: block a Harbor task that gives away its own answer - #22
Open
xaleryb wants to merge 1 commit into
Open
Conversation
tools/lint_task_leakage.py has been in the tree since the catalog landed and is wired into no workflow, so a task whose instruction hands over the symbols its own skill teaches can merge. Such a task is passed with or without the skill and measures nothing, at the price of one that measures something. validate.yml now runs it at --fail-on-leak 5, the score of the worst task in the tree (dpnp-migration-replace-numpy). The budget is a ratchet rather than a target: it grandfathers the twelve tasks that leak today and stops a new one arriving worse than any of them. A gate is worth what the detector behind it is worth, and every way this one can break is silent - a regex that stops matching reports a clean zero for every task, which reads exactly like a repository whose tasks are all sound. So --self-test asserts the detector against the skills and tasks in this tree, the same way the install job asserts that `verify` refuses a skill that was altered: that a dotted call, a `::` call and a keyword argument are all still seen, that an alias bound twice keeps both meanings, that one more given-away symbol costs exactly one point and a pasted line costs three, and that the budget in the workflow is still the worst task's score - so improving the worst instruction turns CI red until the number comes down with it. It writes nothing; both injections are made to a copy of the instruction in memory. Six ways of breaking the detector were tried and each one fails it. Two recorded numbers were wrong and are corrected while wiring it up: evaluation/harbor/README.md put dpnp-device-fallback at 3 where the committed tool prints 4, and the tool's own --fail-on-leak help said all fifteen tasks leak where three score zero. Docs move with the behaviour: CONTRIBUTING adds the command to the local gate, the rule to "What CI checks" and the ratchet to the task section, MAINTAINERS gains the workflow row and the caveat that a task under the budget can still sit at a ceiling - leakage is necessary, not sufficient, and only the no-skill arm settles it.
napetrov
reviewed
Sep 12, 2026
|
|
||
| The first and third need no network. If they pass, the blocking checks left are about the | ||
| repository rather than your text: the workflow linters and the installer round trip. | ||
| Everything but the second and the last needs no network. If they pass, the blocking checks |
Contributor
There was a problem hiding this comment.
bad way to number things in constantly changing documentation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
tools/lint_task_leakage.pyhas been in the tree since the catalog landed and is wired into no workflow. So a Harbor task whoseinstruction.mdhands over the API symbols its own skill teaches can merge: both arms of the differential read the answer out of the prompt, both score 1.0, and the task measures nothing at the price of one that measures something. That is how the first scored run ofdpnp-quickstartput all five of its tasks at a ceiling — visible statically, without a container or a credential, but only if something runs the check.What this does
validate.ymlgains two steps in thevalidatejob, both stdlib-only and fork-safe:Why the budget is 5
Measured over all fifteen tasks as committed:
dpnp-migration-replace-numpydpnp.arange,dpnp.asnumpy,np.arange,numpy.arange,numpy.dotdpnp-device-fallbackdevice=,dpnp.arange,dpnp.sum,y=dpnp-reduction-statsdpnp.mean,dpnp.std,dpnp.summkl-fft-patch-numpymkl_fft.is_patched,np.fft.fft.__module__,numpy.fftdpnp-fft-pipeline,mkl-random-parallel-streamsonetbb-flow-graph,onetbb-parallel-scan,onetbb-parallel-sort5 is the tightest budget that is green on this tree, and no task shares a verbatim line of code with its skill. The budget is a ratchet rather than a target: it grandfathers the twelve tasks that leak today and blocks a new one from arriving worse than any of them. Bringing it below 5 means rewriting instructions, which is a separate change.
Because the score is an intersection, a pull request that only adds to a skill can push a task over the budget with no edit to the task at all. That is the check working — the task really has stopped discriminating, and the fix is the instruction, not the number.
Why there is a self-test
A gate is worth what the detector behind it is worth, and every way this detector can break is silent: a regex that stops matching reports a clean zero for every task, which reads exactly like a repository whose tasks are all sound. So
--self-testasserts the detector against the skills and tasks in this tree — the same reason theinstalljob asserts thatverifyrefuses a skill that was altered. It writes nothing; both injections are made to a copy of the instruction text in memory.The budget assertion reads
--fail-on-leakout ofvalidate.ymlrather than carrying a second copy of the number, and requires it to equal the worst task's score exactly. So the gate cannot keep slack nobody voted for, and improving the worst instruction turns CI red until the budget comes down with it — the ratchet is enforced rather than promised.Six ways of breaking the detector were tried, and each one fails the self-test:
dotted symbol,:: symbol,budget matches tree,+1 pointa keyword argument is taughtPREMISEswallows a real call (dpnp.std)dotted symbolalias bound twice,budget matches treecode_lines()returns nothingthe CI budget is the worst task in the treeTwo recorded numbers were wrong
Corrected here, since wiring the check up is what stops a recorded number drifting from the tool again:
evaluation/harbor/README.mdputdpnp-device-fallbackat 3 where the committed tool prints 4. Nothing changed under it — the task, the skill and the tool all arrived in the same commit — so this was a transcription error from the start.--fail-on-leakhelp said the fifteen tasks "all leak today", where three score zero. Its example also showed--fail-on-leak 2, which fails on this tree.What is not claimed
A task under the budget can still sit at a ceiling. Leakage is necessary, not sufficient — a model that knows the answer from pre-training produces the same tie with a spotless instruction, and only the
no_skillarm tells the two apart. This check says "this task cannot discriminate", never "this task will".Docs in the same change
CONTRIBUTING.md— the command in the local gate list, the rule in "What CI checks", and in the task section: aim at zero, not at 5, and lower the budget in the same PR if you improve the worst instructionMAINTAINERS.md— the CI table row, the tools row, and the caveat above next to the tie-is-a-verdict-on-the-suite ruleevaluation/harbor/README.md— the corrected ranking,--self-testin the command block, and what the budget does and does not meanChecks run locally
validate_skills.py,run_evals.py --validate,--self-test,--fail-on-leak 5,--json,--helpall exit 0.validate_skills.py --check-linksexits 0 with 77 pre-existing warnings (404s in imported bodies, timeouts through a proxy). The workflow YAML parses and the step order isSkill structure and catalog → Eval schema → Task leakage detector still detects → Task leakage → Link check → Imported skills match their pinned upstream.actionlintandzizmorare not installed locally; both new steps are plainrun:lines with no expressions, andsecurity.ymlwill confirm.Opened from a fork, replacing #21, which had the same commit (
711630b) on a branch pushed into this repository by mistake. No review had happened there.