Repository navigation
test(skills): the skill-body control reads the tree, so no body is left unchecked - #68
Conversation
…ft unchecked The control that keeps this repo's skill bodies true compared the bodies it reads against a hand-kept list of ten names. A body added under .agents/skills/ was read by NOTHING and the control stayed green — the drift is invisible, because the hand-kept list is only ever wrong in the one direction no assertion can see (#67). The TREE now names the bodies: the control derives the set from .agents/skills/ and asserts BOTH directions — every body in the tree has a case, every case names a body that exists — and that every body it reads makes at least one usage claim, so a case cannot pass by comparing nothing. The bed's skill-owner arm now pins the lookup's base, MEASURED: the body lookup reads the owning candy's REPO ROOT, and the same body BESIDE the candy is refused. Both that arm's log and the step's own log are TRUNCATED, so their assertions read this run and never a previous run's residue — a control that can pass over a broken arm is not coverage. Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
Review — PASSCorrectness — the diff does what the body claims
Honesty of the body — verified against the diff
TestsCoverage ships a self-contained unit test for the new comparison function plus the live bed red arm. The only observation (non-blocking): the Security / scope / cleanlinessNo secrets, no injection surface (all shell expansions are double-quoted; CommentsThere are no comments on this PR, so nothing to disposition. No maintainer sign-off is present, but the change stands on its own reproduced evidence (line-accurate, count-accurate red/green arms). VerdictThe change closes the reported gap (hand-kept body list → tree-derived set with both-directions and non-vacuous assertions), fixes the appended-log defect in the same step, and every numeric and line-level claim in the body reconciles with the supplied diff. Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
The control's second half — a body that IS read but whose prose never invokes the command it documents, so the control compares nothing in it — was asserted inline, with nothing in the suite exercising its FAILING branch. The suite's other red arm covers the COVERAGE rule; it does not touch this one. The rule moves into skillDocIsVacuous, so the control calls the function the test exercises (one implementation), and TestSkillDocVacuityIsEffective gives it two arms: a body that never invokes the command (the guard must fire) and a body that does (the guard must stay silent). This is the one non-blocking observation #68's validator review raised, and it is fixed here rather than filed away (#69). Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
Closes #67
Summary
Head
350f885c923742f89e9f40afdd703879ca92b160— the commit this PR pushes: 2 files changed, 167 insertions(+), 3 deletions(-).The defect. The control that keeps this repo's skill bodies true —
candy/plugin-box/skill_doc_flags_test.go— compared the bodies it reads against a hand-kept list of ten names (skillDocCases). That list was the control's only source of the SET of bodies: it read exactly the ten bodies it named, and asserted only what those bodies claim. A body added under.agents/skills/was therefore read by NOTHING, and the control stayed green over it.That is not a hypothetical gap. Every
.agents/skills/<verb>/SKILL.mdin this repo is published VERBATIM into the opencharly/marketplace corpus, and every harness loads that corpus. The class of defect this control exists to catch is a body that documents a flag the grammar does not define — the class that produced--platform(#40) and the inner-concurrency flag (#65), each of which published a command that fails AT THE FLAG. A body the control never reads is a body that can carry that class into the corpus with nothing to see it.The RCA.
skillDocCaseswas a hand-kept list of the ten body names, and the control iterated it. The corpus generator, in contrast, reads the TREE. Two sets: the published one (the tree) and the checked one (the list). The control never compared them, so the difference was invisible from the inside: the list is only ever wrong in the one direction no assertion could see..agents/skills/(skillBodyNames) and asserts BOTH directions: every body in the tree has a case, and every case names a body that exists. It also asserts that every body it reads makes at least one usage claim, so a case cannot pass by comparing nothing.A second defect, found while proving the new arm. The bed's step wrote its evidence with
>>and never truncated the log, so an assertion could be satisfied by a PREVIOUS run's output. MEASURED: the new arm, mutated so the body sits at the repo root — which makes the arm's expectation false — still PASSED, against the log the green run had left behind. Both logs are now truncated at the start of the step, so every assertion in the step reads THIS run.What lands. Two files:
candy/plugin-box/skill_doc_flags_test.gocharly.ymlThe lookup's base, pinned. The bed's skill-owner step proves that a skill's prose is readable when the owner is a package candy; its control puts the body at that candy's REPO ROOT. MEASURED, and now held by an arm: the body lookup reads the owning candy's repo root, and the SAME body BESIDE the candy is REFUSED — "no .agents/skills/psk1/SKILL.md exists at the repo root of the owning candy". The arm holds that base, so the fixture's placement cannot drift back to a claim the lookup does not make.
How tested
Everything below ran on the committed tree this PR pushes.
1. The repo's own Go gate — the gate this repo's AGENTS.md names.
2. R7 (a) — the coverage control's RED ARM. A body no case covers must turn the suite RED, naming the body. The arm adds one body under
.agents/skills/and runs the whole suite:The tree is restored (
git status --shortprints nothing), and the suite is green again — the green run is the one in block 1.3. R7 (b) — the bed arm's RED ARM. The arm pins the skill-body lookup's base, so it must FAIL when the base is wrong. The arm's shell is the step's own text, extracted from the committed
charly.ymland mutated in one line: the body moves from the candy's own tree to the project's root, so the lookup finds it and the arm's expectation (a refusal) is false:4. The GREEN step. The step as committed refuses the "beside" placement and accepts the repo-root placement:
5. The pre-flight — the project's own manifest validates on the tree that carries the change.
6. R10 — the live bed.
check-box-localis this repo's disposable witness (akind:localdeploy onhost: local), and it ran green on the committed tree:The bed's own summary carries the verdicts, with zero diagnostics:
and the new arm's own evidence, from the bed run itself:
7. R5 — the sweep. The claim: the set of bodies the control reads is READ from the tree, so no hand-kept list of body names survives as its source of truth. The list itself survives as the per-body CASE table (which command, which grammar) — and it is now bound to the tree in both directions, which is what block 2 proves.
Every hit is in the one control file, and the file's two new directions are the ones that keep the table honest:
skillDocCoveragereturns the bodies NO case covers and the cases that name NO body, and the control fails on either.Rulebook compliance
/charly-image:image,/charly-build:build,/charly-build:validate,/charly-internals:pluginand/charly-internals:git-workfloware the skills this repo's AGENTS.md names for this area; they were read before the first edit, and the git-workflow mechanics (branch off freshorigin/main, commit, gate, write the whole body, push, PR-only landing) are the ones this PR follows.skillBodyNamesreads it from the tree,skillDocCoveragecompares it with the cases, and the control calls those two. There is no second list of body names anywhere in the repo (block 7).git statuswas run first in this worktree; the branch isfeat/skill-body-coverage-67off a freshorigin/main; no force-push, no history rewrite, no bypass, no push tomain. Nothing outside this repo's two files was touched.kind:localdeploy and was removed again (itscleanupandcleanup-memberssteps are in the summary above). Nothing is mocked.2026.301.1632), named by the bed's own first step and by the summary'sdriverline. No Go production code changed — the only.gofile in the diff is a TEST file — so the binary is unaffected by this commit, and no new runtime OS dependency is introduced, sopackaging/is untouched.charly box validatepre-flight, and the disposable bed that composes the changed entity (check-box-local) — all pasted above, all on the committed tree, all with zero warnings.Change classification
go build/go vet/go test) and the project-configuration class's gate (thecharly box validatepre-flight plus the disposable bed that composes the changed entity). NOT documentation: the control's behaviour and the bed's assertions are what change, and both red arms above are what prove it.fully tested and validated— the change-class gate passed on the final tree (the repo's Go gate, the pre-flight, and the disposable R10 bed), the changed paths were executed live, and both red arms demonstrate the coverage can fail.stage_parallelismcutover's producer leg), not a second cutover of that surface: it changes no verb, no flag, and no published prose. It closes the gap that leg's validator recorded.Filed issues
.agents/skills/is read by nothing". This is the finding this PR fixes, filed from refactor(cli)!: the build concurrency flag is --stage-parallelism, and a control holds every skill body to the grammar #66's validator report and claimed before the branch was cut. The evidence and the RCA are above; this PR closes it.Agent: charly · session
ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)