ia-verification-before-completion
Enforces fresh verification evidence before any completion claim. Use when about to claim "tests pass", "bug fixed", "done", "ready to merge", handing off work, or before editing when a request has ambiguous scope.
Install
npx skills add https://github.com/iliaal/whetstone/tree/master/plugins/whetstone/skills/ia-verification-before-completion
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install iliaal-whetstone@llmmart
git clone https://github.com/iliaal/whetstone.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole iliaal/whetstone collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Verification before completion
Make completion claims only from fresh evidence for the actual claim. Follow the user's authorized scope; repository instructions supply applicable checks, not permission to mutate, publish, or weaken a requirement.
Procedure
- Resolve ambiguous scope before editing. Inspect the repository and state a safe assumption when one interpretation is clear. Ask only when materially different interpretations remain; do not edit the disputed scope while waiting.
- Inspect
git status --porcelainand preserve unrelated work. For dependency/framework upgrades, codegen, or migrations, capture the existing validation command set before writing and rerun it unchanged afterward. If that baseline is red, report before proceeding. Shared-module verification on a dirty tree needs an isolated base comparison. - Identify the command that proves the claim. For ship-level claims, check the full applicable chain: build, types, lint, tests, security scan, and diff review; stop on the first failure. Read project-declared gates and run the ones that apply to this action in their required order; do not invent gates.
- Run the proof now. Earlier output, a subagent's report, confidence, and a renamed success phrase do not replace fresh execution.
- Read complete output and exit status, including warnings, executed/passed counts, and missing artifacts. A suite that executes nothing is not proof. Confirm the intended binary, interpreter, source revision, and entry point actually ran.
- Verify that evidence covers the requirements and relevant failure paths. An implemented safe positive capability must work through its intended entry point; a refusal-only path, stub, mock, or unreachable implementation is partial.
- Claim only what the evidence establishes. Report the outcome, exercise command/URL/click path, failed or skipped checks, and material residual risks. State narrower proof scope and distinguish deterministic fixtures from live behavior.
Never make an oracle easier to satisfy to obtain green. Review and justify semantic changes before regenerating expected output. Never hard-code the exercised subject or success path. A clean review is valid when it covers the relevant criteria; broaden checks only for a named remaining risk.
Route by verification risk
- For dirty worktrees, broad changes, strict input validation, or fixture-versus-live provenance, read proof-integrity.md. For shared modules with unrelated edits, also read isolated-verification.md.
- For repository-wide sweeps or “every item” claims, read scope-and-sweeps.md. Enumerate every item in untracked/ignored scratch state, preserve explicit dispositions, re-enumerate after moves, and account for removals. Completion requires zero pending and zero blocked items.
- For command wrappers, empty results, aggregate totals, installed binaries, or materialized revisions, read verification-oracles.md. Require positive controls through the same invocation shape before interpreting an absence.
- For frontend, backend, CLI, infrastructure, migration, package, schema, documentation, or scripted-sweep changes, read the matching row of change-strategies.md. It also covers adversarial probes, history rewrites, and stale reviews.
- For integration boundaries, callbacks, or orphaned state, read system-wide-test-check.md.
- When classifying deliverables, handling failed checks, discussing branch scope, or encountering a pre-commit failure, read claims-and-failures.md.
Failure and handoff rules
Do not retry unchanged verification until it happens to pass. Fix authorized implementation failures and rerun; otherwise name the concrete blocker. “Pre-existing,” “environmental,” and “flaky” require evidence against the deliberately chosen base or independently established cause.
Do not bypass a pre-commit failure caused by this work. The documented exception requires a reproduced base-branch failure and prior visibility to the user; this skill supplies no new bypass authority.
Verify delegated work directly through the diff and relevant command. Check specification compliance separately from quality. Re-read requirements line by line: passing tests and meeting requirements are different claims. Refresh facts and coordinates when new commits or external state could invalidate a prior review. Keep reports decision-relevant, without empty status sections or fabricated certainty.
Files (whetstone)
-
references
-
change-strategies.md 7.5 KB
# change strategies ## Verification Strategies by Change Type For runnable code with those checks available, type-check and unit tests form a baseline, not sufficient proof on their own. Apply the repository's actual checks to other artifacts. Match the strategy to the change: | Change type | Required verification | |-------------|----------------------| | Frontend (component, page, form) | Start the dev server, exercise the feature in a browser, check the console; test the happy path AND one failure path | | Backend handler / endpoint | `curl` the endpoint, check response shape and status code, hit at least one error path (invalid input, missing auth) | | CLI tool | Run the binary with real inputs; check stdout, stderr, exit code. Run from `/tmp` to catch "only works from source" bugs | | Infra / IaC (Terraform, Dockerfile, k8s) | `terraform plan` / `docker build` / `kubectl apply --dry-run=server`; review the diff before applying | | Database migration | Run migration up, down, then up again against production-shape data | | Refactoring (no behavior change) | Full test suite passes unchanged; public API surface diff shows no breakage (`grep` exported identifiers) | | Mechanical or scripted sweep (width-based rewrap, regex pass, in-place edit) | Verify with a parser or compiler (`compileall`, `cargo check`, `tsc --noEmit`, a build), never with the linter's error tally | | Library / package update | Run the consumer's test suite against the new version; check for deprecation warnings | | Published package or release artifact | Install the published version into a throwaway directory and exercise the API the release added; the working tree shares the source, autoloader, and every uncommitted edit, so it proves nothing about what a consumer receives | | Schema change | Old consumers parse the new shape (forward compat); new consumers handle old data still present (backward compat) | | Documentation / prose | Read the rendered output; confirm links, formatting, and content match intent | | Config with no validator | Validate syntax where possible (`jq .`, `yamllint`); otherwise read the file and confirm it matches the intended change | | Non-runnable changes | `git diff`, confirm the diff matches intent, and state explicitly: "No automated verification available — verified by reading the diff." | Reading code is not a strategy. If the table has no row for the change, fall back to the Non-runnable row. The principle holds even when no test suite applies: state what was checked and how. A falling lint count is fully compatible with a corrupted file: most linters report only the *first* parse failure per file, so six broken literals surface as one error, six runs in a row, each looking like the last. A width-based rewriter has no parser -- it splits string literals into syntax errors and breaks comments mid-clause -- and a formatter run afterwards happily reformats prose that no longer says what the author wrote. In-place writes also replace a symlink with a regular file; check `git status --short` for a `T` (typechange) entry after any scripted edit. **"Successfully rebased" is not proof the commit survived intact.** A three-way merge can resolve a pure insertion toward the new base when the surrounding lines were rewritten upstream -- no conflict, no warning, the hunk simply gone from the commit. After any rebase, cherry-pick, or history rewrite, diff the commit's touched-file list across the operation (`git show --stat --name-only HEAD@{1}` against `HEAD`) and confirm the expected content is still present. Do this whenever the base moved since the branch was cut, not only when conflicts appeared: a clean run is not the evidence. A second mechanism drops a hunk just as quietly: `.gitattributes` can bind a path to a merge driver that keeps one side (`driver = true`, `driver = touch %A`) and records a successful merge of a file it never merged, and during a rebase "ours" is the new base, so the incoming edit is the one discarded. Ask before the operation (`git check-attr merge -- <path>`, `git config --get merge.<name>.driver`); `git merge-file` does not consult `.gitattributes`. **Self-review against the base, not HEAD.** `git diff` and `git diff HEAD` hide anything already committed on the branch. When HEAD holds an earlier attempt at the same fix, the superseded code is part of the base and never appears as an add or a remove -- the patch is unreviewable that way, and layering a second approach on top of a half-reverted first one is how a double-free or double-write ships. Diff against the upstream branch (`git diff origin/<branch> -- <files>`) and re-read the whole changed region, including lines believed reverted. ## Adversarial Probes For any change that touches production logic, include at least one adversarial probe in the verification. Pick the most relevant from: - **Boundary value**: 0, -1, empty string, empty array, `null`, `undefined`, `MAX_INT`, 1-char unicode combining mark - **Concurrency**: two parallel requests with the same identifier (for state changes, races, double-spend classes) - **Idempotency**: run the same mutation twice; the second should either no-op or error cleanly, not corrupt state - **Orphan op**: delete/update/get a nonexistent ID — does it 404/return-null as expected, or throw an internal error? - **Implementation shape**: vary what callers supply to an I/O path or an extension point -- a plugin with and without each optional method, a destination that exists and one that does not, a symlink, a read-only parent. A green suite, a clean sanitizer, and a differential API sweep share one blind spot: the signature is unchanged while the capability is gone, because an identical `false` for a different reason reads as no change. State the capability verified, not the aggregate. Exempt: docs changes, trivial typo fixes, pure rename refactors. Everything else: one probe minimum -- a report with zero adversarial probes is a happy-path confirmation, not verification. **A corpus assembled to expose a defect cannot test the fix.** Every row is an instance of the defect, so green proves only that the known cases are closed; the cases a fix can break are the ones the corpus omits, and it has a hole in exactly the region the defect reached through. Build a second set from cases the base already handles correctly, assert that none of them regresses, and state both numbers. If every row is a case the claim names, the measurement is of the claim, not of the code. When an author reports a wider run, check whether they varied a new dimension or only scaled yours. ## Review Staleness Before shipping, check whether prior reviews (agent or human) are still valid. If commits landed after the last review (`git log --oneline <review-commit>..HEAD`), verify the new changes don't invalidate its conclusions: previously flagged issues are still fixed, and no new code contradicts the review's approval. **Refresh the source of truth before concluding from what it does not contain.** A snapshot fetched minutes ago supports "I did not see X", never "X does not exist" -- and a stale snapshot can *manufacture* a finding rather than merely miss one. Re-fetch immediately before the decision, not only before acting on it, whenever the conclusion depends on nothing having happened: unpushed local commits, a queued job, an unsynced remote all read as absence. Line numbers, anchors, and citations computed against the old state need re-deriving too; a moved base invalidates every coordinate even when the substance survives. Conclusions about a *person's* actions do not fail safe -- hold those to a fresh fetch and a second corroborating signal before they go anywhere external. -
claims-and-failures.md 7.3 KB
# claims and failures ## When This Applies - About to claim "tests pass", "build succeeds", or "bug fixed" - About to commit, push, create a PR, or mark a task complete - Before closing a phase or work item - Reporting results to the user - A subagent reports success on delegated work ## Red Flags **Clean results do not require manufactured findings.** A first pass with zero issues is valid when the evidence covers the stated acceptance criteria and relevant failure paths. Broaden verification only when the current proof leaves a named risk untested. **Do not inflate the claim.** Name the proof scope when it is narrower than the natural reading of the completion claim. A targeted test supports the named behavior; only the full suite supports a full-suite claim. ## Requirements vs Tests "Tests pass" and "requirements met" are different claims: re-read the plan or requirements, create a line-by-line checklist, verify each item against the implementation, then report gaps or confirm completion. Passing tests prove the code works, not that the right code was written. ## Common Claims and Their Proof | Claim | Required Proof | |-------|---------------| | "Tests pass" | Test runner output showing 0 failures, exit code 0 | | "Build succeeds" | Build command output with exit code 0 | | "Bug is fixed" | Original reproduction case now passes | | "Feature complete" | All acceptance criteria verified individually | | "No regressions" | Full test suite passes, not just new tests | | "Regression test works" | Red-green cycle: test passes, revert fix, test fails, restore fix, test passes | | "Linting clean" | Linter output showing 0 errors/warnings | ## Classify Before Claiming Done Before marking a deliverable done, classify how it can be verified, then verify by that route: | Class | Example | Verification route | |-------|---------|-------------------| | Diff-verifiable | new service, validation logic, migration file | the change appears in `git diff <base>...HEAD` and its check runs | | Cross-repo | a file or contract in a sibling repository | the sibling is reachable on disk: check the path exists and holds the expected content; unreachable means unverifiable, cite what to check | | External state | DNS record, cloud console setting, OAuth allowlist, secret-manager entry | unverifiable from the tree; name the system and the exact check the user must run | | Content shape | a file must follow a convention | in this repo: run the project's validator; elsewhere: cross-repo rules apply | The ledger tracks per-item sweep state; these outcomes classify each deliverable in the final report; a ledger row is `done` only when its deliverable classifies as done or changed. Outcomes are **done**, **partial**, **not done**, **changed** (same goal, different means -- say how), or **unverifiable**. A concrete filesystem path is never unverifiable: run the existence check and report done or not done. Code that *handles* a deliverable is not the deliverable -- shipping the extractor is not shipping the extracted file. When torn between done and unverifiable, report unverifiable; a confirmation prompt costs seconds, a silently missed deliverable does not. **Every per-branch scope claim is falsifiable and needs its own evidence.** "Master-only" and "the stable branch still has the guard" are assertions a reviewer will check, and reading the broken code on the branch being patched proves nothing about the others. For each branch named, run both a containment query for the introducing commit and a direct read of the function body at that branch's tip -- a branch can contain the commit and have been re-fixed since, or not contain it and be broken for another reason. ## When Verification Fails If the output does not confirm the claim: 1. **Do not claim completion.** Report the actual failure output to the user. 2. **Do not retry the same verification** hoping for a different result. 3. **Return to implementation.** Fix the issue, then re-run from Step 1 of the Gate Function. 4. **Failure unrelated to the current changes** (pre-existing flaky test, environment issue)? State it explicitly with evidence: show the failure also occurs on the base branch or is a known issue. Pick that ref deliberately -- the prior head is an intermediate state, so a regression claim is measured against the base the branch was cut from -- and strip machinery the question does not need. Distrust a control that was expected to fail narrowly and came back with a wide sweep: a whole class may not have existed at that ref. "Environmental" and "pre-existing" are compatible, so naming one does not retire the other. Before either label, rule out the task's own formatters, hooks, and generators as the cause, including downstream failures they produced outside the approved files; an aggregate check that broke because this change triggered a regeneration is a regression of this change. **Where the harness has a known noise floor, the signal is the failing-set diff, not the pass count.** Against a stubbed dependency or an unsupported lane, a suite reports the same fixed block of failures every run. Capture the failing test names on the unmodified base, re-run with the change, and diff the sets; an empty diff is the pass criterion. ## Pre-Commit Hook Failures A failing pre-commit hook is a verification checkpoint, not an obstacle to route around. **`git commit --no-verify` is forbidden when the current session's changes caused the failure -- fix the root cause.** Permitted only when: (1) the failure reproduces on the base branch (show it), and (2) the user saw the failure first. A `--no-verify` the user never saw is a defeated check -- the same failure mode as claiming completion without evidence. ## Rationalization Prevention Reasoning about the outcome instead of running the command means the Gate is not satisfied. "Should work", "trivial change", "just a refactor", "new tests pass" (not "all tests pass"), "CI will catch it" -- all the same failure mode: substituting confidence for evidence. Any satisfaction expression ("looks good", "seems correct", "that should do it") or any positive statement about completion -- including paraphrases and synonyms -- triggers the Gate: spirit over letter, rephrasing a claim to avoid the trigger words does not exempt it from verification. ## Completion Reporting Report only facts that affect the handoff: the outcome, the command, URL, or click path that exercises it, failing or skipped checks, and any material residual risk. Include verification commands and observed results when the user cannot see them directly. Do not emit empty status sections, concern slots, or scope ledgers to prove diligence. Name partial implementations, stubs, mocks, unreachable paths, and refusal-only behavior explicitly. When blocked, name the concrete blocker and the authority or information needed to continue. ## References - [System-Wide Test Check](./system-wide-test-check.md) -- blast-radius verification for task completion (callbacks, integration, orphaned state) ## Integration Referenced by `/ia-work` (before task completion, shipping, and merge/PR creation), `ia-receiving-code-review` (verify each fix before marking resolved), `ia-debugging` (before claiming a bug fixed), `ia-writing-tests` (tests as primary evidence), the `ia-design-iterator` and `ia-figma-design-sync` agents (verify rendering / Figma fidelity), and `/ia-verify` (full pre-PR verification pipeline). -
isolated-verification.md 1.3 KB
# Isolated Verification A green build or test run in the working tree is not proof the change is sound. Unrelated work-in-progress already present -- uncommitted edits, untracked files, a sibling branch's leftovers -- can supply a missing symbol, satisfy an import, or mask a break that the change alone would expose. The contaminated local pass is not the evidence; a clean pass in isolation is. When the change is high-stakes (touches shared modules consumed elsewhere) or the tree cannot be made clean first, reproduce the pass against a known-good commit with only the owned diff applied: ```bash # 1. Stage a detached worktree at a known-good base (last green commit) git worktree add --detach .worktrees/verify <known-good-commit> # 2. Apply ONLY the diff of the files owned by this change git diff -- path/to/owned-file path/to/other-owned-file | git apply --directory=.worktrees/verify - # 3. Build and test there, in isolation ( cd .worktrees/verify && <build-command> && <test-command> ) # 4. Tear down git worktree remove .worktrees/verify ``` A clean pass in the isolated tree is the proof. A failure there -- while the local tree stays green -- means surrounding WIP was masking the break: return to implementation, do not claim done. State which base commit and which files were isolated in the verification evidence. -
proof-integrity.md 3.6 KB
# proof integrity ## The Rule No completion claims without fresh verification evidence. If the verification command has not been run **immediately before the claim**, the claim cannot be made. "Should pass", "probably works", and "looks correct" are not verification. Only command output confirming the claim counts (typically exit code 0). For independently established base failures, see [When verification fails](./claims-and-failures.md#when-verification-fails). Evidence is invalid when the change makes the oracle easier to satisfy instead of making the behavior correct. Never weaken a specification, assertion, test, validator, or acceptance criterion to obtain a pass. Regenerate expected output only after reviewing and justifying the semantic change. Do not hard-code the exercised subject or success path. Classify proof honestly. Fixtures, mocks, seeded rows, retained captures, and recorded responses can support deterministic tests, but they are not live evidence. Claim live behavior only after a fresh process exercises the intended entry point against runtime-selected or independently varied subjects where that distinction matters. **Tightening validation on input you cannot read is not covered by green tests.** When a change moves a parser from lenient to strict (`validate=True`, `strict=True`, `errors="strict"`, a tight regex replacing a permissive built-in) and the value comes from a secret store, an environment variable, or a human, the tests construct their input with the canonical encoder and are green by construction -- they cannot emit the stray byte the old leniency was absorbing. "It has worked in production for a year" is likewise zero evidence: the leniency is precisely what hid the byte. Pair the strictness with an explicit normalization step and state the coverage gap rather than reporting the change as verified. When the positive capability is safe, authorized, and in scope, a refusal-only path is incomplete. Verify and report the refusal behavior, but do not close the feature until the positive path works through its intended entry point. ## Pre-Verification Check Before running verification, check the working tree state: `git status --porcelain`. If there are uncommitted changes unrelated to the current task, handle them first (commit, stash, or acknowledge) -- verification commits on top of a dirty tree create tangled history. **Dirty tree + shared-module change → local green is not evidence.** Reproduce on a clean base ([isolated-verification.md](./isolated-verification.md)). **Broad-blast-radius changes need the baseline captured before the first write.** For a dependency bump, framework upgrade, codegen change, or migration, run the repo's validation suite against the existing state first and record the exact command set. Rerun that same set verbatim afterward -- a post-change run of a *different* command set proves nothing. If the baseline is already red, stop and report before writing anything: starting a migration on a red base makes every later failure unattributable, and a recorded red baseline is one step from "it was already broken, not my problem". This is the one case where the retroactive base-branch proof under When Verification Fails is impractical -- a regenerated lockfile does not `git stash` cleanly. Ordinary source edits stay on that retroactive path. For delegated work: never trust the implementer subagent's own report -- spec compliance and quality are separate concerns, verify both. Confirm via the VCS diff that changes were actually made, then run the verification command directly; never relay the subagent's claim. -
scope-and-sweeps.md 2.3 KB
# scope and sweeps ## Scope Confirmation (Pre-Edit Gate) This gate fires at task start, before the first edit. When a request uses ambiguous spatial scope -- "migrate my project", "refactor the codebase", "update everywhere", "fix this across the app", "my code/repo/project" -- inspect the repository to resolve the concrete scope before any Write or Edit. Imperative phrasing is not defined scope. Run a breakdown command to surface the real blast radius: ```bash rg -l 'pattern' | cut -d/ -f1 | sort | uniq -c | sort -rn # files per top-level dir rg -l 'pattern' | xargs dirname | sort -u # affected directories ``` When the request and repository structure identify one safe interpretation, state the assumption and proceed. If multiple interpretations materially change the result, present the breakdown and ask via AskUserQuestion (Claude Code; load with ToolSearch `select:AskUserQuestion` if not loaded) or request_user_input (Codex); fall back to numbered options in chat. Do not start editing until that material choice is resolved. **When this applies**: any request whose scope could plausibly span more than one subsystem and cannot be resolved safely from the request and repository structure. For a request with explicit file paths or one clear repository-wide interpretation, skip the question. ## Sweep Completion For tasks whose scope is *every* item in a set -- a repo-wide rename, "migrate everywhere", audit every file, resolve all findings -- the Gate Function proves a command passed, not that it ran over the whole set. Track coverage explicitly. Enumerate the set into a ledger held outside version control -- a session-scratch path where the harness provides one, otherwise any git-ignored local directory, never a tracked file -- one row per item with an explicit disposition: `pending`, `done`, `excluded (reason)`, or `blocked (evidence)`. Completion requires zero `pending` and zero `blocked` -- "I covered a lot of them" is not a disposition. Two rules close the holes that make a ledger lie: - Re-enumerate after any path move or rename, so items created or relocated mid-sweep enter coverage instead of falling outside the original list. - Keep removed items in the ledger until explicitly accounted for -- an item that silently disappears reads identically to one that was finished. Never claim coverage the ledger does not show. -
system-wide-test-check.md 1.9 KB
# System-Wide Test Check Before marking a task done, pause and trace the blast radius of the change. This catches integration failures that pass-in-isolation testing misses. | Question | What to do | |----------|------------| | **What fires when this runs?** Callbacks, middleware, observers, event handlers -- trace two levels out from the change. | Read the actual code (not docs) for callbacks on models touched, middleware in the request chain, `after_*` hooks. | | **Do tests exercise the real chain?** If every dependency is mocked, the test proves logic works in isolation -- it says nothing about the interaction. | Write at least one integration test that uses real objects through the full callback/middleware chain. No mocks for layers that interact. | | **Can failure leave orphaned state?** If code persists state (DB row, cache, file) before calling an external service, what happens when the service fails? Does retry create duplicates? | Trace the failure path with real objects. If state is created before the risky call, test that failure cleans up or that retry is idempotent. | | **What other interfaces expose this?** Mixins, DSLs, alternative entry points. | Grep for the method/behavior in related classes. If parity is needed, add it now. | | **Do error strategies align across layers?** Retry middleware + application fallback + framework error handling -- do they conflict or create double execution? | List the specific error classes at each layer. Verify the rescue list matches what the lower layer actually raises. | **When to skip:** Leaf-node changes with no callbacks, no state persistence, no parallel interfaces. Purely additive changes (new helper, new view partial) take 10 seconds to verify "nothing fires." **When this matters most:** Changes touching models with callbacks, error handling with fallback/retry, or functionality exposed through multiple interfaces. -
verification-oracles.md 4.7 KB
# verification oracles ## Gate Function Before any success claim, run through these five steps: | Step | Action | Example | |------|--------|---------| | **1. Identify** | What command proves this claim? The full chain -- build -> typecheck -> lint -> test -> security scan -> diff review, **stop on first failure** -- applies to ship-level claims (commit/push/PR-ready); for a single claim, run the proof command from the Common Claims table below. | `pytest tests/`, `npm test`, `curl -s localhost:3000/health` | | **2. Run** | **Run it now, in this same message.** Output from an earlier turn is stale and does not count. | "I ran it earlier" fails this step | | **3. Read** | Read the complete output, check exit code | Don't scan for "passed" -- read failure counts, warnings, errors | | **4. Verify** | Does the output actually confirm the claim? | "42 passed, 0 failed" confirms "tests pass". "41 passed, 1 failed" does not. | | **5. Claim** | Only now make the statement | "All 42 tests pass" with the evidence visible | **A suite that executed nothing exits 0.** Zero failures is not a pass when the executed count is also zero -- an unloadable module, an unmet skip condition, a collection error, or a filter matching no tests all produce a green exit and an empty summary. Read the executed and passed counts, not just the failure count, and require the passed count to be positive before accepting a run as evidence. Where a suite can legitimately skip everything (optional dependency, service-backed cases), keep at least one unconditional case so a positive count still means something. **A command that cannot return a positive has not returned a negative.** A pathspec the tool globs differently than you read it, a filter that discards `command not found`, a wrapper exiting 0 on an empty stream -- each yields a clean zero that supports whatever is being tested. Run a positive control through the *same* invocation shape (same tool, ref, filter, shell) and read its output before you read the zero. Never filter stderr on the run that establishes the harness works. **An absent output artifact is a launch failure, never an empty result.** When a wrapper writes its findings to a file, a run that never started and a run that found nothing both give exit 0 and no file. Require the artifact to exist before interpreting it. **A reconciling total is not per-item agreement.** Counts, sums, and digests all pass when two items' verdicts are swapped, and two independent errors pointing opposite ways cancel into a *correct* aggregate. Make one typed per-item record the authority, cross-check every id against the producer that knows them, and derive summaries from that record; test with a two-row permutation whose totals do not move. For an evidence block you assemble yourself, write down the relation the counts satisfy by construction (baseline + added = total) and evaluate that instead of re-running -- a re-run reproduces the same reading. **Prove which binary produced the evidence.** A green run says nothing about *what ran*. PATH lookup, a stale installed copy, a compiled sibling, or a system interpreter can shadow the tree under test: run `command -v`, resolve symlinks, and compare the reported version or build SHA against the source being verified. For deployed code, run the check through the exact interpreter or entry point the service uses -- the one named in the scheduler entry, the unit's `ExecStart`, or the image's `CMD` -- never the bare binary on PATH. An error about a symbol or argument the deployed code plainly uses is a tell that the check is on the wrong interpreter, not that the deploy is broken. A live failure from an installed helper does not refute a source fix until that identity is checked. **When the subject is a tree materialized at a revision, prove the bytes before trusting the result.** Extracting a subtree at a commit can half-fail and leave what was there before. Diff one file under test against its content at that revision, or compare hashes, as a provenance control -- the same check catches a run against the working tree that was believed pinned. **Project-declared gates.** Before a push or PR open, read `CLAUDE.md`, `AGENTS.md`, and `CONTRIBUTING.md` if not already loaded. For each declared check, identify its triggering action, scope conditions, order, and blocking or warning status. Run every check applicable to the current action in the required order; stop on the first unmet blocking gate and name it verbatim from the instruction file. Report warning-only failures without promoting them to blockers. A release-only metadata, changelog, or validation requirement applies during release, not an ordinary push or PR. Do not invent gates, widen their triggers, or skip an applicable requirement.
-
-
SKILL.md 4.9 KB
--- name: ia-verification-before-completion class: discipline description: >- Enforces fresh verification evidence before any completion claim. Use when about to claim "tests pass", "bug fixed", "done", "ready to merge", handing off work, or before editing when a request has ambiguous scope. --- # Verification before completion Make completion claims only from fresh evidence for the actual claim. Follow the user's authorized scope; repository instructions supply applicable checks, not permission to mutate, publish, or weaken a requirement. ## Procedure 1. Resolve ambiguous scope before editing. Inspect the repository and state a safe assumption when one interpretation is clear. Ask only when materially different interpretations remain; do not edit the disputed scope while waiting. 2. Inspect `git status --porcelain` and preserve unrelated work. For dependency/framework upgrades, codegen, or migrations, capture the existing validation command set before writing and rerun it unchanged afterward. If that baseline is red, report before proceeding. Shared-module verification on a dirty tree needs an isolated base comparison. 3. **Identify** the command that proves the claim. For ship-level claims, check the full applicable chain: build, types, lint, tests, security scan, and diff review; stop on the first failure. Read project-declared gates and run the ones that apply to this action in their required order; do not invent gates. 4. **Run** the proof now. Earlier output, a subagent's report, confidence, and a renamed success phrase do not replace fresh execution. 5. **Read** complete output and exit status, including warnings, executed/passed counts, and missing artifacts. A suite that executes nothing is not proof. Confirm the intended binary, interpreter, source revision, and entry point actually ran. 6. **Verify** that evidence covers the requirements and relevant failure paths. An implemented safe positive capability must work through its intended entry point; a refusal-only path, stub, mock, or unreachable implementation is partial. 7. **Claim** only what the evidence establishes. Report the outcome, exercise command/URL/click path, failed or skipped checks, and material residual risks. State narrower proof scope and distinguish deterministic fixtures from live behavior. Never make an oracle easier to satisfy to obtain green. Review and justify semantic changes before regenerating expected output. Never hard-code the exercised subject or success path. A clean review is valid when it covers the relevant criteria; broaden checks only for a named remaining risk. ## Route by verification risk - For dirty worktrees, broad changes, strict input validation, or fixture-versus-live provenance, read [proof-integrity.md](./references/proof-integrity.md). For shared modules with unrelated edits, also read [isolated-verification.md](./references/isolated-verification.md). - For repository-wide sweeps or “every item” claims, read [scope-and-sweeps.md](./references/scope-and-sweeps.md). Enumerate every item in untracked/ignored scratch state, preserve explicit dispositions, re-enumerate after moves, and account for removals. Completion requires zero pending and zero blocked items. - For command wrappers, empty results, aggregate totals, installed binaries, or materialized revisions, read [verification-oracles.md](./references/verification-oracles.md). Require positive controls through the same invocation shape before interpreting an absence. - For frontend, backend, CLI, infrastructure, migration, package, schema, documentation, or scripted-sweep changes, read the matching row of [change-strategies.md](./references/change-strategies.md). It also covers adversarial probes, history rewrites, and stale reviews. - For integration boundaries, callbacks, or orphaned state, read [system-wide-test-check.md](./references/system-wide-test-check.md). - When classifying deliverables, handling failed checks, discussing branch scope, or encountering a pre-commit failure, read [claims-and-failures.md](./references/claims-and-failures.md). ## Failure and handoff rules Do not retry unchanged verification until it happens to pass. Fix authorized implementation failures and rerun; otherwise name the concrete blocker. “Pre-existing,” “environmental,” and “flaky” require evidence against the deliberately chosen base or independently established cause. Do not bypass a pre-commit failure caused by this work. The documented exception requires a reproduced base-branch failure and prior visibility to the user; this skill supplies no new bypass authority. Verify delegated work directly through the diff and relevant command. Check specification compliance separately from quality. Re-read requirements line by line: passing tests and meeting requirements are different claims. Refresh facts and coordinates when new commits or external state could invalidate a prior review. Keep reports decision-relevant, without empty status sections or fabricated certainty. -
SPEC.md 4.8 KB
# ia-verification-before-completion Specification ## Intent `ia-verification-before-completion` is a `discipline`-class skill (an engineering practice not tied to one stack). It requires fresh, claim-matched evidence, rejects weakened proof and proof-class inflation, and keeps partial or refusal-only behavior visibly incomplete without imposing a fixed report template. ## Scope In scope: - Behaviors described in `SKILL.md` and routed via the should_trigger phrasings in `distillery/tests/fixtures/triggers/ia-verification-before-completion.jsonl`. - Updates to runtime behavior, structure, trigger precision, references, and validation. Out of scope: - Acting as the runtime instructions themselves (those live in `SKILL.md`). - Trigger phrasings already covered by adjacent `ia-*` skills (`validate-plugin` flags >70% description overlap as DUPLICATE_TRIGGER). - <!-- to fill in: domain-specific exclusions when the skill drifts --> ## Trigger Context - Class: `discipline` - Hook regex: `plugins/whetstone/hooks/skill-patterns.sh` -> `SKILL_PATTERNS[ia-verification-before-completion]` - Common requests (from fixture should_trigger): - "verify before pushing the release branch" - "verify that tests pass before committing" - "about to mark this done -- verify first" - Should not trigger for (from fixture should_not_trigger): - "write a new middleware for rate limiting" - "refactor the payment gateway integration" - "I'm confident the refactor didn't break anything" ## Source And Evidence Model Authoritative sources: - `SKILL.md` -- runtime instructions and reference routing. - `references/*.md` -- bundled supplementary content (1 file(s)). - `distillery/tests/fixtures/triggers/ia-verification-before-completion.jsonl` -- positive and negative trigger phrasings under regression test. - `plugins/whetstone/hooks/skill-patterns.sh` -- regex pattern that fires this skill. - `distillery/.eval-data/ia-verification-before-completion/` -- harvested session examples (when present). Data that must not be stored in this skill or its references: - Secrets, credentials, tokens. - Machine-specific filesystem paths (`/home/...`, `/Users/...`, `~/ai/...`). The validator (`MACHINE_PATH_LEAK`) flags these as HIGH. - Private URLs, customer data, or unredacted personal information. ### Coverage matrix | Dimension | Status | Evidence | |---|---|---| | Trigger fixtures | complete | distillery/tests/fixtures/triggers/ia-verification-before-completion.jsonl (>=5 should_trigger, >=5 should_not_trigger) | | Hook regex pattern | complete | plugins/whetstone/hooks/skill-patterns.sh (`SKILL_PATTERNS[ia-verification-before-completion]`) | | Reference architecture | complete | 1 file(s) under references/ | | Proof integrity and honest completion | complete | `SKILL.md` The Rule, Red Flags, and Completion Reporting | | Real-usage signal | <!-- populated by harvest-sessions when sessions exist --> | distillery/.eval-data/ia-verification-before-completion/ (created by harvest-sessions) | ## Evaluation Lightweight (run on every change): ```bash python3 distillery/scripts/distiller.py validate-plugin --component ia-verification-before-completion python3 distillery/scripts/distiller.py test-triggers --skill ia-verification-before-completion ``` Deeper (when behavior risk warrants): ```bash python3 distillery/scripts/distiller.py dspy-eval ia-verification-before-completion python3 distillery/scripts/distiller.py diagnose-negatives ia-verification-before-completion ``` Acceptance gates: - `validate-plugin --component ia-verification-before-completion` returns 0 HIGH findings. - `test-triggers --skill ia-verification-before-completion` returns F1 = 1.0 with floors of 5 should_trigger and 5 should_not_trigger. - For dspy-eval, the composite score does not regress against the most recent saved baseline (see `distillery/.eval-data/ia-verification-before-completion/history.json`). ## Known Limitations - Whether evidence is genuinely live can depend on repository-specific runtime boundaries that this portable skill cannot infer. - Scope confirmation remains judgment-based; inspection should resolve safe defaults, while material ambiguity still requires user input. ## Maintenance Notes - Update `SKILL.md` when the runtime workflow, branch conditions, or output contract changes. - Update this `SPEC.md` when intent, scope, evidence model, evaluation gates, or maintenance expectations change. - Update the trigger fixture when adding new positive phrasings, removing stale ones, or expanding scope (the 5/5 floor is a hard validator gate). - Update the hook regex in `skill-patterns.sh` whenever fixture positives expose a missed phrasing; verify F1 = 1.0 with `eval-triggers` before committing. - Run the full release pipeline via `/release` -- never bump versions or update CHANGELOG.md from a per-skill edit.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.