Skip to content

Validate the `.case/` folder

The structural validator is the ruleset every .case/ tree must pass before it can be published. It reads a local checkout and nothing else.

You rarely run it yourself. /fito-case-generate drives it as its edit-and-check loop, and /fito-publish-case re-runs it before anything is pushed. This page is for reading its output, and for re-checking a tree by hand.

node <fito-case-author skill dir>/validate.js <case-working-dir>

Replace <fito-case-author skill dir> with the path to Fito’s fito-case-author skill, and <case-working-dir> with the directory holding .case/. Inside a pi session you can ask for the skill by name and it resolves the path for you.

It prints JSON on standard output and sets an exit code: 0 for a pass, 1 for a failure, 2 for a usage problem such as a missing or non-existent directory.

{
"ok": false,
"errors": [
{
"file": "rubric.yaml",
"message": "rubric criterion weights must sum to exactly 100 (got 90)",
"path": ["criteria"]
}
]
}

Every violation is reported at once — it never stops at the first. Each error is scoped to the .case/ file that produced it, and usually to a field path inside that file.

Fix the named files and run it again. Do not regenerate the tree over an error you can fix.

{
"ok": true,
"attestation": { "pass": true, "validatorVersion": "0.1.8", "rulesetVersion": "1.8.0" },
"references": [{ "componentId": "concept:javalin.handler", "bloomLevel": "APPLICATION" }],
"optionalFieldsNotUsed": { "manifest.yaml": ["created_at", "updated_at"] }
}
  • attestation — the stamp a publish carries to the Fito server. It names the validator build and the ruleset version the tree was checked against.
  • references — the case’s reference set: every component and Bloom level, deduplicated, gathered from the learning objectives, the prerequisites, the rubric and the quiz. This is the set the server resolves at publish, and the set that freezes afterwards.
  • optionalFieldsNotUsed — the optional fields this case leaves empty, grouped by file. Nothing here is an error.
Rule What it means
Required files All fourteen are present, plus task/steps.md for a tutorial
File shapes Every field carries the type and the allowed values its file declares
Reference form Every reference reads <type>:<technology-slug>.<component-slug>
Bloom levels Only KNOWLEDGE, COMPREHENSION and APPLICATION
Rubric weights Positive whole numbers summing to exactly 100
Rubric levels Every criterion covers scores 0, 1, 2 and 3
One primary objective At least one learning objective carries weight: primary
Objective coverage Every learning objective is scored by at least one rubric criterion. A quiz question does not count
Objective level At least one of those criteria declares the objective’s Bloom level or a higher one, because a criterion records no more than the level it declares
Situation documents Every file listed in situation/situation.yaml exists on disk
Deprecation reason A deprecated case gives a deprecated_reason
Case type The artifact the type binds is present — see The three types
Quiz shape A multiple_choice question has choices and an answer matching one of them; the other two types carry an evaluation

Two things a passing run tells you nothing about. Both are resolved by the Fito server when you publish:

  • Whether the components you referenced exist. The form is checked here; the existence is not.
  • Whether your git refs are reachable. The server pings the version tag and the solution branch itself.

It cannot check the topic-not-move rule either. A case that gives away its own answer validates clean. That one is carried by the authoring commands and by your review.

The attestation carries two numbers, and they move independently:

  • validatorVersion is the build of the checker.
  • rulesetVersion is the version of the rules themselves.

A published case is stamped with the pair it was checked against.