Skip to content

test(skills): the vacuity guard gets its own red arm - #70

Merged
github-actions[bot] merged 1 commit into
mainfrom
feat/skill-doc-vacuity-69
Oct 28, 2026
Merged

github-actions[bot] merged 1 commit into
mainfrom
feat/skill-doc-vacuity-69

Conversation

@aitrawog

Copy link
Copy Markdown
Contributor

Closes #69

Summary

Head b2462e48a18f031bbcdde0f6af32e99f8779ec1d — the commit this PR pushes: 1 file changed, 39 insertions(+), 1 deletions(-).

The finding. #68's validator review raised one non-blocking observation: the skill-body control's VACUITY guard — the assertion that a body makes at least one usage claim for the command it documents — has no demonstration that it can fire. The guard is the assertion that stops a case from passing by comparing nothing, and it was the one assertion in that control with no red arm.

The RCA.

  • Mechanism — the rule was asserted inline in the control, as a len(claims) == 0 test that called t.Errorf on the spot. An inline assertion has no seam a test can address: nothing in the suite could hand the rule a body and observe what it decides. The suite's other red arm (TestSkillDocCoverageIsEffective) covers the COVERAGE rule, not this one.
  • Missed control — no test exercised the vacuity branch, so the control's FAILING path had never run. A guard that has never fired is a guard whose absence is silent.
  • Blast radius — the published corpus of this repo's verb skills. The control exists because every .agents/skills/<verb>/SKILL.md here is published VERBATIM into the opencharly/marketplace corpus, and every harness loads that corpus; a body that documents a flag the grammar does not define publishes a command that fails AT THE FLAG. The vacuity guard is the second half of that subject: a body that IS read, but whose prose never invokes its own command, is compared to nothing — the usage claims are what tie a flag in the prose to the grammar. With the guard inverted, every such body would pass the control silently, and the corpus would carry the defect the control exists to catch.
  • Root fix — the rule moves into a function, skillDocIsVacuous, and TestSkillDocVacuityIsEffective gives it two arms: a body that never invokes the command it documents (the guard must fire) and a body that does (the guard must stay silent). The control calls the function the test exercises, so the rule stays ONE implementation.

Why this is a change of its own, and not a filing. The org's rule is that a finding raised on a PR is fixed or rebutted on the thread with evidence, never filed away. This observation was raised on #68, and #68 is already merged, so the fix cannot ride on that PR: it is its own change, under its own issue, #69, filed and claimed before the branch was cut.

What lands. One file:

file what it carries
candy/plugin-box/skill_doc_flags_test.go the vacuity rule as a named function, and the two-arm test that gives it a red arm

No verb, no flag, no published prose, and no grammar changes: this is a coverage fix to the control that guards the corpus.

How tested

Everything below ran on the committed tree this PR pushes.

$ git rev-parse HEAD
b2462e48a18f031bbcdde0f6af32e99f8779ec1d
$ git diff --stat origin/main...HEAD
 candy/plugin-box/skill_doc_flags_test.go | 40 +++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

1. The repo's own Go gate — the gate this repo's AGENTS.md names.

$ cd candy/plugin-box && gofmt -l . ; echo "GOFMT_CLEAN=$?"
GOFMT_CLEAN=0
$ cd candy/plugin-box && go build ./... && echo BUILD_OK=1
BUILD_OK=1
$ cd candy/plugin-box && go vet ./... && echo VET_OK=1
VET_OK=1
$ cd candy/plugin-box && go test -count=1 ./... ; echo "GOTEST_EXIT=$?"
ok  	github.com/opencharly/plugin-box/candy/plugin-box	0.023s
?   	github.com/opencharly/plugin-box/candy/plugin-box/cmd/serve	[no test files]
GOTEST_EXIT=0

2. R7 (a) — the guard's RED ARM, in the unit test. A guard that cannot fire is not coverage, so the new test's failing branch has to be reachable. The guard is inverted by one line — the rule's own body replaced by return false, so it never fires — and the suite must then go RED on the arm that expects it to fire:

$ cd candy/plugin-box
$ cp skill_doc_flags_test.go /tmp/umb-stagepar/pb69-backup.go
$ sed -i 's|return len(usageClaims(body, command)) == 0|return false|' skill_doc_flags_test.go
$ grep -n 'return false' skill_doc_flags_test.go
304:	return false
$ go test -count=1 -run 'TestSkillDocVacuityIsEffective' .
--- FAIL: TestSkillDocVacuityIsEffective (0.00s)
    skill_doc_flags_test.go:450: the vacuity guard did not fire on a body that never invokes the command it documents
FAIL
FAIL	github.com/opencharly/plugin-box/candy/plugin-box	0.003s
FAIL
RED_ARM_VACUITY_EXIT=1
$ cp /tmp/umb-stagepar/pb69-backup.go skill_doc_flags_test.go
$ cd ../.. && git status --porcelain ; echo "RESTORED_CLEAN"
RESTORED_CLEAN

The file is restored and the tree is clean; the green run of the same test is below, and the whole-suite green is block 1.

$ cd candy/plugin-box && go test -count=1 -run 'TestSkillDocVacuityIsEffective' -v . ; echo "GREEN_VACUITY_EXIT=$?"
=== RUN   TestSkillDocVacuityIsEffective
--- PASS: TestSkillDocVacuityIsEffective (0.00s)
PASS
ok  	github.com/opencharly/plugin-box/candy/plugin-box	0.003s
GREEN_VACUITY_EXIT=0

3. R7 (b) — the guard's RED ARM, inside the control. The unit test proves the function fires; this proves the CONTROL calls it, so the guard is live where it does its work rather than only in a test of itself. One case's command is mutated to a spelling the body never invokes, so the body makes no usage claim for it:

$ cp candy/plugin-box/skill_doc_flags_test.go /tmp/umb-stagepar/pb69-backup2.go
$ sed -i 's|{skill: "build", command: "charly box build", grammar: \&buildGrammar{}},|{skill: "build", command: "charly box buildz", grammar: \&buildGrammar{}},|' candy/plugin-box/skill_doc_flags_test.go
$ grep -n 'charly box buildz' candy/plugin-box/skill_doc_flags_test.go
89:	{skill: "build", command: "charly box buildz", grammar: &buildGrammar{}},
$ (cd candy/plugin-box && go test -count=1 -run 'TestSkillBodiesDocumentOnlyRealFlags' . ) ; echo "RED_ARM_CONTROL_EXIT=$?"
--- FAIL: TestSkillBodiesDocumentOnlyRealFlags (0.00s)
    --- FAIL: TestSkillBodiesDocumentOnlyRealFlags/build (0.00s)
        skill_doc_flags_test.go:338: ../../.agents/skills/build/SKILL.md: the body makes no usage claim for charly box buildz, so the control compares nothing in it
FAIL
FAIL	github.com/opencharly/plugin-box/candy/plugin-box	0.004s
FAIL
RED_ARM_CONTROL_EXIT=1
$ cp /tmp/umb-stagepar/pb69-backup2.go candy/plugin-box/skill_doc_flags_test.go
$ git status --porcelain ; echo "RESTORED_CLEAN"
RESTORED_CLEAN

Both arms fail the suite when the rule is broken and pass when it is intact, and the tree is restored after each.

4. The pre-flight — the project's own manifest validates on the tree that carries the change.

$ charly -C plugin-box box validate
charly box validate: OK — checked 1 candy, 1 deploy, 7 distros, 7 builders; 0 warnings, 0 errors
BOX_VALIDATE_EXIT=0

5. R10 — the live bed. check-box-local is this repo's disposable witness (a kind:local deploy on host: local), and it ran green on the committed tree:

$ charly -C plugin-box check run check-box-local
charly check run check-box-local: [deploy-add] PASS after 1.153s (log: .check/check-box-local/2026.301.1946/deploy-add.log)
charly check run check-box-local: [bring-up-members] PASS after 0s
charly check run check-box-local: [check-live] PASS after 14.44s (log: .check/check-box-local/2026.301.1946/check-live.log)
charly check run check-box-local: [update] PASS after 1.164s (log: .check/check-box-local/2026.301.1946/update.log)
charly check run check-box-local: [cleanup] PASS after 1.17s (log: .check/check-box-local/2026.301.1946/cleanup.log)
charly check run check-box-local: [cleanup-members] PASS after 0s
charly check run check-box-local: PASS (steps=6)
BED_EXIT=0

The bed's own summary carries the verdicts, with zero diagnostics:

$ cat .check/check-box-local/2026.301.1946/summary.yml
bed: check-box-local
calver: 2026.301.1946
driver: /home/atrawog/Sync/Atrapub/a/claude/opencharly/.worktrees/umb-stagepar/charly/bin/charly
driver_version: 2026.301.1632
steps:
  - name: deploy-add
    status: PASS
  - name: bring-up-members
    status: PASS
  - name: check-live
    status: PASS
  - name: update
    status: PASS
  - name: cleanup
    status: PASS
  - name: cleanup-members
    status: PASS
diagnostics:
  errors: 0
  warnings: 0
  advisories: 0
ok: true
status: PASS

6. R5 — the sweep. The claim: the vacuity rule has exactly one implementation, and the control calls the function the test exercises — not a second copy of the rule beside it. The block below is the sweep for both spellings:

$ grep -rn "skillDocIsVacuous" --include="*.go" .
candy/plugin-box/skill_doc_flags_test.go:299:// skillDocIsVacuous reports whether a body makes NO usage claim for the command it documents —
candy/plugin-box/skill_doc_flags_test.go:303:func skillDocIsVacuous(body []string, command string) bool {
candy/plugin-box/skill_doc_flags_test.go:333:			if skillDocIsVacuous(body, tc.command) {
candy/plugin-box/skill_doc_flags_test.go:449:	if !skillDocIsVacuous(neverInvokes, "charly box build") {
candy/plugin-box/skill_doc_flags_test.go:460:	if skillDocIsVacuous(invokes, "charly box build") {
$ grep -rn "len(claims) == 0" --include="*.go" .
GREP_EXIT=1

Every hit of the rule is the one function and its two call sites — the control (line 333) and the test (lines 449 and 460) — and the old inline spelling len(claims) == 0 has no occurrence anywhere in the repo.

Rulebook compliance

  • R0 — skills first. /charly-image:image, /charly-build:build, /charly-build:validate, /charly-internals:plugin and /charly-internals:git-workflow are the skills this repo's AGENTS.md names for this area; they were read before the first edit, and the git-workflow mechanics this PR follows are the ones they state (branch off fresh origin/main, commit, gate the committed tree, write the whole body before the push, PR-only landing).
  • R1 — every anomaly gets an RCA. The finding this PR fixes is RCA'd above with mechanism, missed control, blast radius and root fix. It is a finding raised ON a PR (test(skills): the skill-body control reads the tree, so no body is left unchecked #68's validator review), and the org's rule is that such a finding is fixed or rebutted with evidence, never filed away: it is fixed here. Nothing else was filed by this change.
  • R2 — no duplication. The vacuity rule has one implementation, skillDocIsVacuous, and the control calls it (block 6). The inline len(claims) == 0 form that sat beside the call site is gone in the same cutover, which is what the second grep in block 6 shows.
  • R3 — no workaround. No sleep, no retry, no suppression, no magic number. The control fails with a message that names the body and the command, and the test fails with a message that names the arm that did not hold.
  • R4 — product before prose. The change is in the control. The two comments this PR adds describe the function and the test that exist in the same commit.
  • R5 — legacy deleted completely. The old inline spelling of the rule has no occurrence left in the repo (block 6): the rule was moved, not copied.
  • R6 — preserve user work and Git safety. git status was run first in this worktree; the branch is feat/skill-doc-vacuity-69, cut off a fresh origin/main (49e205c8ce5d2c72028ec27ca182a3c80d3ea50a); no force-push, no history rewrite, no hook bypass, no push to main. The two mutations in blocks 2 and 3 were reverted from a backup copy, and git status --porcelain printed nothing after each.
  • R7 — prove behavior, not compilation. Two red arms, both live and both pasted above: the unit test's failing branch goes RED when the rule is inverted (block 2), and the control itself goes RED with the guard's own message when a case names a command the body never invokes (block 3). Neither arm can pass vacuously, and the green runs are pasted beside them.
  • R8 — live or skip, never fake a live service. The bed ran live against a disposable kind:local deploy and removed it again (the cleanup and cleanup-members steps are in the summary above). Nothing is mocked.
  • R9 — binary equals source. The binary under test is this session's worktree-local CalVer-stamped build (2026.301.1632), named by the bed's own summary driver and driver_version lines. The only .go file in the diff is a TEST file, so no production code changed and the binary is unaffected by this commit; no new runtime OS dependency is introduced, so packaging/ is untouched.
  • R10 — fresh disposable proof. The change class is a test control in a plugin's Go package, so the gate is this repo's Go gate, the charly box validate pre-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 and zero diagnostics.
  • Cutover. One change, one PR: the rule moves from an inline assertion to a named function, and the test that gives it a red arm lands in the same commit. Nothing is deferred and no scope is hidden inside it.

Change classification

  • Class: a test control in a plugin's Go package — the Go class's gate (go build / go vet / go test) plus this repo's project-configuration pre-flight (charly box validate) and its disposable R10 bed (check-box-local). NOT documentation: what changes is the control's behavior and what proves it, and both red arms above are what prove it.
  • Attribution tier: 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 path was executed live, and both red arms demonstrate the coverage can fail.
  • Scope. This is the follow-up to test(skills): the skill-body control reads the tree, so no body is left unchecked #68 (the tree-derived skill-body coverage), not a second cutover of that surface: it changes no verb, no flag, and no published prose. It closes the one gap that leg's validator recorded.

Filed issues

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0

Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)

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)
@aitrawog

Copy link
Copy Markdown
Contributor Author

STATUS

STATUS

The follow-up PR is open: #70 — head b2462e48a18f031bbcdde0f6af32e99f8779ec1d.

What is done. The vacuity rule moved into skillDocIsVacuous, and TestSkillDocVacuityIsEffective gives it two arms: a body that never invokes the command it documents (the guard must fire) and a body that does (the guard must stay silent). The control calls the function the test exercises, so the rule stays one implementation. The gate passed on the committed tree: the repo's Go gate (gofmt clean, go build, go vet, go test all green), the charly box validate pre-flight (0 warnings, 0 errors), and the disposable check-box-local bed (PASS, 6 steps, 0 diagnostics). Two red arms are pasted in the PR body: the unit test's failing branch goes RED when the rule is inverted, and the control itself goes RED with the guard's own message when a case names a command the body never invokes.

What is next. Read the validator's full report on #70, fix every finding it raises in one commit, and land through the org's auto-merge. Then close this issue and record the resolution.

Next update. When the validator's verdict lands on #70.

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)

@github-actions

Copy link
Copy Markdown

Review — PASS

What the diff does

The change is exactly what the body describes: one test file, the vacuity rule extracted into a named function skillDocIsVacuous, the control's inline len(claims) == 0 replaced by a call to it, and a new two-arm test TestSkillDocVacuityIsEffective.

I re-derived the body's mechanical claims against the diff and they hold:

  • Counts. Hunk 1 adds 8 lines (comment + function), hunk 2 replaces 1 line, hunk 3 adds 30 lines. Total 39 insertions / 1 deletion — matches the stated stat.
  • Line numbers. The skillDocIsVacuous comment lands at new line 299, the function at 303, the return at 304, the control call at 330, and the two test assertions at 449 and 460 — all consistent with the body's grep output (block 6), the return false mutation at line 304 (block 2), and the t.Fatal at line 450. The block-3 control-level error at line 338 is consistent with the error sitting just past the hunk's trailing context.
  • Single implementation. The len(claims) == 0 spelling is genuinely gone from the control (replaced, not duplicated); the rule now lives only in skillDocIsVacuous with its two call sites. claims is still computed for the loop below, so no dead code is introduced.
  • Scope. Only a _test.go file changes — no verb, flag, grammar, or published prose. Consistent with the "test control" classification.

Tests

The test is a real red arm, not a tautology: it asserts the guard fires on a body whose only fenced command is charly box other --flag (no claim for charly box build) and stays silent on charly box build --flag. The body's block-3 evidence — mutating a case command to charly box buildz and getting the control's own "makes no usage claim" failure — additionally demonstrates the guard is live inside the control, and that usageClaims uses word-boundary (not naive prefix) matching, which is exactly why the test's two arms are meaningful.

Comments

The single comment (by @aitrawog, the PR author) is a status update on issue #69 — "follow-up PR open, head SHA, what is done / what is next." Every claim in it (function name, test name, gate green, two red arms) is reproduced by the current diff and body. It does not assert a verdict or a passed check, and no designated maintainer sign-off is present in this run, so I treat no comment as approval and judge the change on its own evidence — which stands.

Minor (non-blocking)

The control computes usageClaims(body, tc.command) into claims and then calls skillDocIsVacuous, which recomputes it. This is a small redundant call, not a rule duplication and not a correctness issue; it could be tidied later but does not affect the verdict.

No security-relevant surface (test-only, no secrets, no input handling, no dependency change). Body is honest and internally consistent; the change does what it claims.

Verdict: PASS


ollama-cloud/deepseek-v4.1-flash — action-review.

View action run

@github-actions
github-actions Bot enabled auto-merge (squash) October 28, 2026 19:50
@github-actions
github-actions Bot merged commit 9bcdfbc into main Oct 28, 2026
3 checks passed
charly-auto-merge Bot added a commit that referenced this pull request Oct 28, 2026
@aitrawog

Copy link
Copy Markdown
Contributor Author

RESOLVED

RESOLVED — this PR landed (squash-merged 2026-10-28T19:52:03Z, tag v2026.301.1952), and its one non-blocking observation is fixed in its successor.

What landed. The skill-body control's VACUITY guard — the assertion that a body makes at least one usage claim for the command it documents — now lives in a named function (skillDocIsVacuous), and TestSkillDocVacuityIsEffective gives it a RED ARM: a body that never invokes the command (the guard must fire) and a body that does (the guard must stay silent). Before this PR the guard was an inline assertion with no seam a test could address, so nothing in the suite had ever exercised its failing branch — a guard that cannot fire is not coverage.

The observation the validator raised, and where it went. The review recorded one non-blocking finding: "The control computes usageClaims(body, tc.command) into claims and then calls skillDocIsVacuous, which recomputes it. This is a small redundant call, not a rule duplication and not a correctness issue." It is FIXED, not filed away: #72 is the successor, and the guard now takes the claims it judges, so the control derives a body's claims once and hands the same slice to both the guard and the loop.

The merge was the org's native auto-merge (squash) after the validator's PASS; no agent merged it.

Agent: charly · session ses_8efb271d-f2c0-47d3-85e3-2a1e00b11ae0
Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)

github-actions Bot pushed a commit that referenced this pull request Oct 28, 2026
The control computed the body's usage claims into `claims` and then called
`skillDocIsVacuous(body, command)`, which computed them AGAIN — the same
claims, read twice, for one decision. The guard now takes the claims, so
the control computes them once and hands the same slice to both the guard
and the loop below. The rule stays one implementation and the red arm
still fires on a body that never invokes its command.

This is the non-blocking observation #70's validator
review raised, and it is fixed here rather than filed away.

Assisted-by: Claude Code minimax/minimax-m3.1-flash:cloud (fully tested and validated)
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.

the skill-body control's vacuity guard has no red arm — a guard that cannot fire is not coverage

1 participant