mino-verify
Verification Gatekeeper
Validate executed work against explicit acceptance criteria and repository-native checks, then produce a deterministic pass/fail verdict bound to a specific commit (Verify Anchor SHA).
This skill consumes run's output and feeds checkup. All structured artifacts (events, brief sections) are rendered from templates in templates/ so downstream skills can rely on schema stability.
Workflow
Step 1: Confirm Scope
- Identify the task being verified (issue number or task key from the user)
- Load
.mino/briefs/issue-{N}.mdand the latest valid event sequence from the issue - Verify
Approved Revision == Spec Revision; if not, halt and direct user to/mino-taskfor re-approval
Optional note: the invocation may include free-form text after the issue/spec ref (e.g., /mino-verify #1842 在小红书场景下需要 ...). If present:
- Capture it as local variable
manual_verifier_note(single string). - Otherwise
manual_verifier_note = null.
Step 2: Anchor The Verification
Record Verify Anchor SHA = git rev-parse HEAD before running any check.
This SHA is bound into every event and the verification summary. It guarantees the verdict refers to a specific committed state, not the current working tree.
If git status --porcelain shows uncommitted changes at this point, halt and direct user back to /mino-run — verify evaluates committed code only. (run is responsible for committing before handoff.)
Step 3: Select Verification Commands
Resolve commands in this order; the first hit wins:
.mino/config.ymloverride — readverify.commands(a list); if present, use exactly this list and skip auto-detection. The list may include any shell-runnable command.Brief override — if the brief's
Verificationsection contains an explicit shell command list (lines starting with$), use that.Auto-detect repo-native tooling by file signature:
Signature Default commands package.json(withpnpm-lock.yaml)pnpm install --frozen-lockfile,pnpm build,pnpm test,pnpm lintpackage.json(withyarn.lock)yarn install --frozen-lockfile,yarn build,yarn test,yarn lintpackage.json(otherwise)npm ci,npm run build,npm test,npm run lintpyproject.toml/setup.pypytestCargo.tomlcargo build,cargo test,cargo clippy -- -D warningsPackage.swiftswift build,swift testMino.xcodeproj/*.xcodeprojxcodebuild -scheme <name> testMakefilemake testSkip commands whose script is not present (e.g.,
pnpm lintifpackage.jsonhas nolintscript). Do not invent a missing build/test target.Nothing detected → route to
pending_acceptance(Step 6.D).
Step 4: Run Checks
Execute the selected commands sequentially. Capture stdout + stderr per command. Stop on the first failure.
When tooling integration with PRs is available and a PR is known, also surface gh pr checks output in the failure context if it is more authoritative than the local result.
Step 5: Compare To Acceptance Criteria
Walk each item in the brief's Acceptance Criteria section:
- If the criterion is satisfied by an automated check, mark it as covered
- If a criterion has no automated coverage, route the verdict to
pending_acceptance(Step 6.D), even if all automated checks pass
Step 5.5: Author Verification Report
For outcomes 6.A (passed), 6.C (terminal failure), and 6.D (pending acceptance) — when there is substantive evidence to record — render templates/report.md.tmpl to .mino/reports/issue-{N}/report.md.
Skip for 6.B (retryable failure) and 6.E (publication failure): their context already lives in the brief's Failure Context section.
The report's content is your synthesis of:
- The selected verification commands (Step 3) and their outputs (Step 4)
- The acceptance-criteria walk (Step 5)
- Environment versions discovered (language toolchain, framework, key deps)
- Configuration steps that were necessary to make verification pass
- Recurring gotchas worth documenting
Write .mino/reports/issue-{N}/report.md (overwrite if it already exists — the verify_anchor_sha in the header preserves which run authored it). Set local variable report_path = .mino/reports/issue-{N}/report.md for use in Step 6's event yml.
If there is genuinely no substantive content (e.g., a trivial change with only a one-line test pass), set report_path = null and skip writing.
If manual_verifier_note is non-null, append the following block to the report verbatim (no agent rephrasing — this is the human's input, preserved for audit):
## Manual Verifier Note
{{ manual_verifier_note }}The agent will synthesise from this note in Step 7 (Reply Dispatch); the verbatim copy here is the source of truth.
Step 6: Render Verdict
Choose exactly one of A–E. Each writes the brief and writes a local event file under .mino/events/issue-{N}/{next_seq:04d}-{event-kebab}.yml. Whether a GitHub comment is posted depends on the event's category:
- 6.A
verify_passed→ silent, no comment. - 6.B
verify_failed_retryable→ audible, post comment. - 6.C
verify_failed_terminal→ audible, post comment. - 6.D
verify_pending_acceptance→ audible, post comment. - 6.E
verify_publication_failed→ audible, post comment.
Audible comment bodies are pure human notifications: short heading line, Reason:, and Action:. Do NOT include a Local events: pointer or any rendered YAML block — those exist in the local event file only. The local YAML at .mino/events/issue-{N}/{seq:04d}-{event-kebab}.yml is the authoritative log; the comment is a notification channel.
No path stages or commits .mino/briefs/.
Brief updates use surgical section replacement; preserve Open Questions / Warnings and any other human-authored content.
6.A All automated checks passed AND all acceptance criteria covered
- Publish code if relevant:
- If code files changed during
run:- The commit was already created by
run. - Run all
git commitoperations for this outcome (run's commit is already in place; docs commit comes from 6.A.1.5). Rungit pushexactly once after 6.A.1.5 has had its chance to add a docs commit. If push fails, go to 6.E (publication failed) instead. - Capture
Code Ref = git rev-parse HEADafter push. - Set
Code Publication State: published.
- The commit was already created by
- If no code files changed:
- Set
Code Ref: not_applicable,Code Publication State: not_applicable.
- Set
- If code files changed during
1.5. Promote to Project Docs (optional):
Read .mino/config.yml field report.promotion (default auto). Read .mino/config.yml field report.docs_path (default docs/integrations/).
- If
promotion: never→ skip; setpromoted_doc = null. - If
promotion: always→ promote. - If
promotion: auto→ apply the heuristic from protocol § Verification Report ("Promotion Heuristic"). When in doubt, do NOT promote.
On promote:
- Compute
slug = kebab-case(issue_title, max 60 chars)(see protocol). promoted_path = {docs_path}/{slug}.md.- If
promoted_pathexists: append a new section## Update {YYYY-MM-DD} (verify_anchor: {sha7})with the new content. - If not: write the report content as a fresh file.
git add {promoted_path}git commit -m "docs(issue-{N}): {short title} integration notes"with the standardCo-authored-bytrailer.- NEVER
git commit --amendand NEVERgit push --force. - Set local variable
promoted_doc = {promoted_path}.
After step 1.5 (whether promotion occurred or not):
- Run
git pushexactly once. If push fails, go to 6.E.
On promotion failure (commit error, file write error): log promotion_failed: <reason> to the report header and set promoted_doc = null. Do NOT abort verify_passed.
Update brief sections (surgical replace):
Verification Report← rendertemplates/brief-section-verification-report.md.tmplVerification Summary← rendertemplates/brief-section-verification-summary.md.tmplWorkflow State:Current Stage: checkupNext Stage: doneWorkflow Entry State: ready_to_startCode Publication State: published | not_applicable
Pass/Fail Outcome←passCompletion Handoff:Completion Basis: verifiedCode Ref: {sha or not_applicable}
Do NOT post a GitHub comment —
verify_passedis silent in v1.10 and remains silent in v0.6.2. The local event yml at.mino/events/issue-{N}/{seq}-verify-passed.ymlis the sole record at this stage. The eventualcheckup_donecomment will surface the commit + docs links.
After recording verify_passed, sync the GitHub stage label:
gh issue edit {N} --remove-label "stage:verify" --add-label "stage:done"Label sync failure is a warning, not an error: log stage_label_sync_failed: <reason> in the verify report and proceed. The local yml remains authoritative.
- Detect orchestrator mode: if
.mino/loops/active.lockexists AND itsholder_agent: mino-taskAND itsheartbeat_atis within the last 6 hours: return silently. Otherwise proceed (the local event and brief updates are the hand-off signal).
6.B Checks failed AND attempt budget remains
A failure on attempt N is retryable when N <= Max Retry Count. With default Max Retry Count: 3, attempts 1/2/3 may yield fail_retryable; attempt 4 must be terminal.
Update brief sections:
Failure Context← rendertemplates/brief-section-failure-context.md.tmplwithpass_fail_outcome: fail_retryableWorkflow State:Current Stage: runNext Stage: verifyWorkflow Entry State: ready_to_start
Pass/Fail Outcome←fail_retryable
Do NOT change
Attempt Count. Onlyrunincrements it.Post comment — render
templates/comment-verify-failed-retryable.md.tmpl. The full error output lives in the briefFailure Contextsection, NOT in the GitHub comment.Detect orchestrator mode: if
.mino/loops/active.lockexists AND itsholder_agent: mino-taskAND itsheartbeat_atis within the last 6 hours: return silently. Otherwise proceed.
6.C Checks failed AND attempt budget exhausted (or unrecoverable)
Update brief sections:
Failure Context← rendertemplates/brief-section-failure-context.md.tmplwithpass_fail_outcome: fail_terminalWorkflow State:Current Stage: verifyNext Stage: noneWorkflow Entry State: blocked
Pass/Fail Outcome←fail_terminal
Post comment — render
templates/comment-verify-failed-terminal.md.tmpl. Truncated output stays in the briefFailure Context; the comment links toReport:if a report was authored in Step 5.5.Detect orchestrator mode: if
.mino/loops/active.lockexists AND itsholder_agent: mino-taskAND itsheartbeat_atis within the last 6 hours: return silently. Otherwise proceed.
6.D Manual acceptance required
Triggers:
- All automated checks passed but at least one acceptance criterion has no automated coverage
- No verification tooling could be detected
- An acceptance criterion explicitly requires human review (UI screenshot, perceptual quality, etc.)
Update brief sections:
Verification Report← rendertemplates/brief-section-verification-report.md.tmplManual Acceptance← rendertemplates/brief-section-manual-acceptance.md.tmpl(write the actionable checklist here)Workflow State:Current Stage: verifyNext Stage: checkupWorkflow Entry State: pending_acceptance
- Leave
Pass/Fail Outcomeunset; do not writeCompletion Handoffyet.
Tag the issue with the
pending-acceptancelabel. Skip gracefully if the label is missing on this repo.Post comment — render
templates/comment-verify-pending-acceptance.md.tmpl. The acceptance checklist itself stays in the briefManual Acceptancesection, NOT in the GitHub comment.Detect orchestrator mode: if
.mino/loops/active.lockexists AND itsholder_agent: mino-taskAND itsheartbeat_atis within the last 6 hours: return silently. Otherwise proceed.
6.E Publication failed (push or commit refused after checks passed)
This is reachable only from 6.A when git push (or any equivalent publication step) fails after automated checks have already passed.
Do NOT record success. Leave
Pass/Fail OutcomeandCompletion Handoffunset.Update brief sections:
Failure Context← rendertemplates/brief-section-failure-context.md.tmplwith the publication error andpass_fail_outcome: nullWorkflow State:Current Stage: verifyNext Stage: verifyWorkflow Entry State: ready_to_startCode Publication State: local_only
Do NOT change
Attempt Count. Publication failure must not consume retry budget.Post comment — render
templates/comment-verify-publication-failed.md.tmpl.Detect orchestrator mode: if
.mino/loops/active.lockexists AND itsholder_agent: mino-taskAND itsheartbeat_atis within the last 6 hours: return silently. Otherwise proceed.
Step 7: Reply Dispatch
Runs after the verify outcome is recorded, only for outcomes 6.A (verify_passed) and 6.D (verify_pending_acceptance). Skip for 6.B / 6.C / 6.E.
Read
.mino/config.yml > comment.reply(defaultauto).- If
never: setreply_posted = null, skip to step 5. - If
always: jump to step 3. - If
auto: continue to step 2.
- If
Apply the auto decision rule (see protocol § Reply Dispatch):
- If
manual_verifier_noteis non-null AND contains content the issue author would act on (steps, configuration, environment specifics), proceed to step 3. - Else if a doc was promoted in this flow (Step 6.A.1.5 set
promoted_doc != null), proceed to step 3. - Else: set
reply_posted = null, skip to step 5.
- If
Detect orchestrator context: if
.mino/loops/active.lockshowsholder_agent: mino-taskAND its heartbeat is fresh (≤ 6 hours), and the loop has already replied for this issue earlier in this iteration (check.mino/events/issue-{N}/for a priorreply_postednon-null in the current loop window): setreply_posted = null, skip to step 5. This avoids duplicate convergence comments per loop pass.Render
templates/comment-reply.md.tmpl:- Synthesise variables from the report (Step 5.5 output) and
manual_verifier_note. - Apply the variable rules in the template's HTML comment header.
- Post via
gh issue comment {N} --body-file <rendered>. - Capture the returned URL as
reply_posted. - On post failure: log
reply_post_failed: <reason>in the report, setreply_posted = null, do NOT retry. The local report remains authoritative.
- Synthesise variables from the report (Step 5.5 output) and
Patch the previously written event file (the one for the chosen verify outcome) to set the
reply_postedfield to the captured URL ornull. The event file is local and append-only at the file level but field-level edits before the next event are permitted (this matches howreport_pathandpromoted_docare written today).
Templates
All artifact shapes are externalized; verify MUST NOT generate freehand variations.
templates/event-verify-passed.yml.tmpltemplates/event-verify-failed-retryable.yml.tmpltemplates/event-verify-failed-terminal.yml.tmpltemplates/event-verify-publication-failed.yml.tmpltemplates/event-verify-pending-acceptance.yml.tmpltemplates/comment-verify-failed-retryable.md.tmpltemplates/comment-verify-failed-terminal.md.tmpltemplates/comment-verify-pending-acceptance.md.tmpltemplates/comment-verify-publication-failed.md.tmpltemplates/comment-reply.md.tmpltemplates/report.md.tmpltemplates/brief-section-verification-report.md.tmpltemplates/brief-section-verification-summary.md.tmpltemplates/brief-section-failure-context.md.tmpltemplates/brief-section-manual-acceptance.md.tmpl
Variable syntax is . Replace literally; do not introduce conditional logic in templates.
Constraints
- Do NOT skip recording
Verify Anchor SHA— it is required by the protocol (v1.4 § Verify Anchor) and required in every event. - Do NOT modify
Attempt Count. Onlyrunincrements it. - Do NOT auto-pass a task when no verification tooling is found — route to 6.D instead.
- Do NOT record
verify_passedbefore code publication has succeeded; on push failure go to 6.E. - Do NOT fix the failure here — hand
Failure Contextback torunfor self-correction. - Do NOT stage or commit
.mino/briefs/or.mino/locks/— these are local workflow cache. - Do NOT invent fields in the YAML events; the schema is fixed by
workflow-state-contract.md. - Do NOT overwrite
Open Questions / Warningsin the brief; replace target sections only. - Keep narrative summaries compact; the structured event is the machine source of truth.
- Do NOT
push --force,reset --hardpast the remote tip, rebase or amend any pushed commit; usegit revertto undo published work (see protocol § Multi-Agent Git Hygiene). - Do NOT treat
gh issue editlabel-sync failures as fatal; the local event yml is authoritative. - Do produce a verification report at
.mino/reports/issue-{N}/report.mdwhenever evidence is substantive (outcomes 6.A, 6.C, 6.D). - Do NOT include local report paths (
.mino/reports/...) in GitHub comments. Promoted docs/ paths are fine because they resolve as repo URLs. - Do NOT amend the run commit when promoting; create a separate docs commit before the verify push.
- Do honor
.mino/config.yml > report.promotion: neverto disable promotion. - When in doubt about promotion: do NOT promote.
- Audible comments are rendered exclusively from
comment-*.md.tmplfiles. NEVER inline event yml into a comment. - Commit auto-link: include the commit URL in audible comments when
verify_anchor_sha(orcode_ref) is known. - Do NOT post a GitHub comment for
verify_passed— silent in v1.10. - Do post audible comments for all other verify outcomes.
- Do NOT post
verify_passedas a status comment. The reply channel (Step 7) is the only audible surface for convergence outcomes. - Do NOT echo
manual_verifier_noteverbatim to GitHub. Synthesise into the reply template. - Do NOT retry a failed reply post. Local report is the durable artifact.
