--- name: hard-cheese description: Checks whether an author can explain a code change before review. Use when the user requests `/hard-cheese`, `/cheese --hard`, or an understanding check. Use it before a pull request or through the `--hard` pipeline flag. Do not use it for reviews, test hardening, or fixes. license: MIT metadata: {dispatches-agents: true} --- # /hard-cheese The gate reduces **epistemic debt**. This debt exists when code passes checks, but the author cannot explain it. ## Inputs ```text /hard-cheese [] [--socratic-cap N=3] [--passing-score N=3] [--no-judge] ``` Arguments: - `` identifies the artifact at `.cheese/hard-cheese/.md`. This argument is optional. Without it, use the short SHA of `HEAD`. An explicit slug overrides the SHA. - `--socratic-cap N` sets the maximum number of retries. The gate then marks the artifact `FAILED` and returns a non-zero status. The default is `3`. Vibecheck has no limit, but easy-cheese prevents infinite loops. - `--passing-score N` sets the minimum SOLO score for PASS. Use a value from `1` through `5`. The default is `3`. The gate treats a previous PASS below this value as stale. - `--no-judge` enables log-only mode. Record the user's explanation with `status: LOGGED`. Do not start the judge sub-agent. This mode is the easy-cheese equivalent of the optional JSONL telemetry mode in vibecheck. It retains more content. See `## Divergence from the paper`. ## Invocation modes | Mode | How the gate runs | Where the gate sits | | --- | --- | --- | | **standalone** | The user runs `/hard-cheese ` before a pull request. | Outside the pipeline. No upstream skill is required. | | **propagated** | `/plate --hard` runs `/hard-cheese ` after the final writes and before publication. | At the verified-artifacts to share-for-review boundary. | `--hard` passes through `/cheese → /mold → /cook → /press → /age → /cure → /plate`. Only `/plate` runs `/hard-cheese`. See [`../cheese/references/harness-portability.md`](../cheese/references/harness-portability.md) for portability requirements. It covers helper resolution, sub-agent dispatch, GitHub operations, and handoff transitions. Use the bundle or repository helper first. Use `${CLAUDE_SKILL_DIR}` only as an optional host fallback. The handoff blocks define the portable contract because slash commands are host renderings, not the control model. ## Flow 1. **Resolve scope.** - Set `diff_base = origin/main` and `diff_head = `. - Load `.cheese/specs/.md` as the optional intent reference when it exists. The diff remains the source of truth. - Use the short SHA of `HEAD` when no slug exists. - If the diff against `origin/main` is empty, return `0` with `"nothing to gate on"`. Do not write an artifact. 2. **Freshness check.** Run the freshness check before you run the gate: ``` python3 skills/hard-cheese/scripts/hard-cheese.pyz freshness-check \ --slug --passing-score ``` Exit `0` for `previously_passed`. Print `"previously passed"` and stop. Continue to step 3 for `stale` or `new`. A stale result has exit status `2`. A new result has exit status `3`. A result is stale when `HEAD` changes or the last PASS score is too low. 3. **Rank the hunks, then compose the vibecheck prompt.** Keep it faithful to Sankaranarayanan 2026. Use "share for review" to keep the gate implementation independent. Run `rank-hunks` before you compose the prompt: ``` python3 skills/hard-cheese/scripts/hard-cheese.pyz rank-hunks \ --base origin/main --head HEAD ``` Show the ranked regions next to the diff summary, one line per hunk, as `path:start-end — reasons`. Put the changed lines from every ranked region in the 80-line diff summary before other context. Make no judge call before the first attempt. > Before this is shared for review, explain in your own words what this change is for. How does ** work? Why does it produce the desired behavior? What state, control flow, or invariants does it rely on? Start with the highlighted regions. Show a diff summary with the prompt. For `/plate`, also show the complete final evidence: - the final artifact inventory, - each `{target, backend, verified}` completion row, - the tracked artifact diff, - the quality gate result. Stop with a non-zero status when `/plate` omits one of these four values. Stop with a non-zero status when a completion row has `verified: false`. 4. **Record the user's explanation** as free text. Do not provide coaching or example answers. The explanation is the artifact under test. 5. **Start the judge sub-agent** in a fresh context. Use the same pattern as the `/cook` fan pathway. - Use `references/judge-prompt.md` as the system prompt. - Provide the passing score, diff summary, optional spec excerpt, the `targets` JSON from `rank-hunks`, and user's explanation. - Require this JSON object: `{score, level, pass, feedback, socratic_qs, targets_addressed}`. See `references/judge-prompt.md` for the full system prompt and output shape. Skip this step when the user sets `--no-judge`. Mark the attempt `status: LOGGED`, write the artifact, and return `0`. 6. **Process the judge result.** - Mark the attempt PASS when `score >= `. - Mark the attempt FAIL when `score < `. Show the Socratic questions; at least one question anchors to a ranked hunk from `targets_addressed`. When `targets` is empty or absent, skip the anchoring requirement and expect an empty `targets_addressed`. Return to step 4 while retries remain. - Mark the attempt ERROR when the judge fails. Print a warning and return `0`. See `## Divergence from the paper`. Append the attempt row: ``` python3 skills/hard-cheese/scripts/hard-cheese.pyz append-attempt \ --slug --status --score \ --feedback "" --explanation "" ``` 7. **Process an exhausted limit.** Set the artifact `status: FAILED`. Print the artifact path and return a non-zero status. Stop downstream chains. ## Artifact `.cheese/hard-cheese/.md` contains the audit trail. The `.gitignore` file excludes `.cheese/`, so the audit trail remains local. Each file starts with this YAML frontmatter block: ```yaml --- slug: attribution: Sankaranarayanan 2026 / vibecheck rubric: SOLO Taxonomy (1-5), pass threshold = passing_score: divergence: fail-open on judge error (vibecheck fails closed) diff_base: diff_head: status: PASS | FAIL | FAILED | LOGGED | ERROR attempts: --- ``` `append-attempt` writes the attempt log as this six-column markdown table: ```markdown | timestamp | head_sha | status | score | feedback | explanation | | --- | --- | --- | --- | --- | --- | | 2026-06-25T10:00:00+00:00 | a1b2c3d | FAIL | 2 | "Unistructural: lists steps but no causal link" | | | 2026-06-25T10:05:00+00:00 | a1b2c3d | PASS | 4 | "Relational: explains why invariant holds" | | ``` Each invocation appends attempts and does not overwrite rows. If `HEAD` changes, append new rows below the earlier rows. ## Sub-agent contract — fresh judge - **Use fresh context for every invocation.** The code-writing context can bias the judge. - Resolve a no-tool or read-only `reviewer` at `powerful` power and `high` effort. Use the shared agent resolver. - The shared resolver pins each reviewer to `powerful`. Do not lower this value for the judge. - Use a general worker only with no-write enforcement. Set `degraded: true`. - Use `references/judge-prompt.md` as the system prompt. - Give the judge the diff summary, the optional spec excerpt, the `targets` JSON, and the explanation. Require a JSON reply. Prohibit repository writes. - **Parse the JSON output.** On a parse error, log an `ERROR` attempt and fail open. The gate requires a host sub-agent feature. Without this feature, recommend `/hard-cheese --no-judge` to record the explanation without a grade. ## Attribution > Sankaranarayanan, S. (2026). *Mitigating 'Epistemic Debt' in Generative AI-Scaffolded Novice Programming using Metacognitive Scripts.* Proceedings of the 13th ACM Conference on Learning at Scale. The implementation uses the open-source VS Code extension from the paper's author: This `SKILL.md`, `references/judge-prompt.md`, and each artifact include the attribution. Thus, the citation stays with the audit trail. ## Divergence from the paper Hard-cheese has three differences from vibecheck: **1. Judge errors.** Vibecheck fails closed. The modal blocks code application until the judge recovers or the user retries. Hard-cheese fails open. The gate records an `ERROR`, prints a warning, and returns `0`. This policy prevents API failures from blocking pull request work. **2. Telemetry content.** Vibecheck records the length of an explanation. It never records the text of an explanation. Hard-cheese records the complete text of every explanation in the local artifact. The `.gitignore` file excludes `.cheese/`, so this text remains on the author's machine. Tell the user about this retention before `--no-judge` records the first explanation. **3. Prompt wording.** Vibecheck's prompt states its three questions without a lead sentence. Hard-cheese adds a purpose-first lead sentence and a pointer to the ranked regions. The paper's three questions stay verbatim. Add each new difference to this section. ## Composition with `--auto` `--hard` and `--auto` can operate together. Terminal `/plate --hard` pauses automation once before publication, after `/plate` verifies the final artifacts. The user responds to the prompt. PASS permits publication. FAILED stops publication. ERROR uses the documented fail-open behavior. Commit-only `/plate --hard` does not run the gate. That path shares nothing. See `references/composition.md` for new pull requests and non-TTY behavior. ## Output When the gate ends, print: ``` Hard-cheese artifact: .cheese/hard-cheese/.md Status: PASS | FAILED | LOGGED | ERROR Score: /5 (, pass ≥ ) Attempts: ``` The `Score` line reports the latest judged attempt. Omit this line for LOGGED mode or an ERROR without a scored attempt. Then print one applicable message: - On PASS: `Ready to share for review.` - On FAILED: `Cap exhausted. Improve understanding of the change before sharing.` - On LOGGED: `Telemetry only — judge skipped via --no-judge.` - On ERROR: Print one warning that identifies the failure. Include `Fail-open divergence active — gate exited 0; you may share for review at your discretion.` ## Preferred tools and fallbacks | Need | Prefer | Fallback | | --- | --- | --- | | Diff inspection for the user-facing summary | `delta` | `git diff --unified=3` | | Ranking the hunks for the prompt | `rank-hunks` bundle command | none — skip the ranked regions and note the gap | | Reading the spec (when present) | bounded file read per [`code-intelligence-routing.md`](../cheese/references/code-intelligence-routing.md) | host file read | | Spawning the judge | host sub-agent primitive (`Agent()` or harness equivalent) | none — without sub-agent spawn, run `--no-judge` mode and tell the user the judge is unavailable | | GitHub / PR context (out of scope here) | n/a | n/a | ## Rules - Run the judge sub-agent in fresh context. Do not use the code-writing context to grade the author's understanding. - Do not coach the user before the answer. The explanation is the artifact under test. - Show only the judge's Socratic questions after a FAIL. Do not add hints. - Show the ranked regions; add no question or hint before the first attempt. - Pass the user's explanation to the judge unchanged. - Always run the freshness check. A changed `HEAD` requires a new attempt sequence. - Record every ERROR attempt. Show a warning for each judge failure. - Do not call `/gh` or a specific pull request tool. The gate operates before code enters review. - Apply the shared voice rules from `../age/references/voice.md`. Report the result. Classify the residual risk as `certain | speculating | don't know`. - Do not describe FAILED as `"almost passing"`. ## References - `references/judge-prompt.md` defines the SOLO Taxonomy rubric, judge prompt, and JSON output. - `references/composition.md` defines the complete `--hard` and `--auto` matrix. - [`references/commands.md`](references/commands.md) lists the generated bundle commands. ## Agent resolution Resolve the fresh judge through [`../cheese/references/agent-resolution.md`](../cheese/references/agent-resolution.md). | Work | Preferred types | Permissions/isolation | Minimum power | Effort | Fallback | | --- | --- | --- | --- | --- | --- | | Grade the explanation | reviewer | no-tool or read-only, fresh-context | powerful | high | compatible reviewer, then general | The canonical hard-cheese audit includes the shared `agent_resolution` block.