About Issue checks
Five of Vinaya's 37 core checks validate a task Issue's own content. They never apply to a pull request.
All five are Vinaya-specific: they encode Vinaya's task grammar, which is the title, ## Objectives, ## Parts, ## Surface, tranche labels and Milestones.
| Check | Implements |
|---|---|
issue- | Vinaya-specific |
issue- | Vinaya-specific |
issue- | Vinaya-specific |
issue- | Vinaya-specific |
issue- | Vinaya-specific |
Each reports the same way as every check: exit 0 is a pass, and exit 1 with error lines is a failure.
How they run
All five belong to Ring 1, check Issues (validates: 'issue'), have scope full, and run in their own path (ownWorkflow: true). No workflow runs them, and vinaya check - never selects them. They run in one place: when Vinaya writes a task Issue.
| Command | What runs the checks |
|---|---|
vinaya issue create (and --validate-only) | Issue validation, before the create |
vinaya issue edit <n> (and --validate-only) | The validated edit (or, with --validate-only, Issue validation directly) |
vinaya issue objectives edit | The validated edit, with a temporary body file |
The path applies only to a task Issue: one carrying a vinaya/tranche:* label, or one whose body is task-shaped, which covers backlog Issues. It runs every resolved check with validates: 'issue', core or added by your team, through the same runner vinaya check uses.
The caller passes every fact as an environment variable, so no check re-fetches forge state:
| Variable | Value |
|---|---|
ISSUE_BODY | The body about to be written |
ISSUE_LABELS | Labels, comma-joined (on edit: the forge's labels plus any on the command line) |
ISSUE_TITLE | The --title value, or empty |
ISSUE_NUMBER | The Issue number, or empty on create |
CURRENT_ | Always empty on the write path |
RESOLVED_ | Always empty on the write path |
The findings join one list with the other Issue gate groups: brief-schema sections, Issue content and rendered-brief shape. The write is refused once if any finding is not a warning. Otherwise the Issue is written with gh. See Gate mechanisms for the full write path.
Checks
issue- title- grammar
Issue titles follow one grammar, so every task reads the same way on the forge.
| Refuses | A title outside the forge-title grammar: Type: description, Type(scope): description, or [tranche] id — description. |
| Runs | At Issue write time (create, edit). |
| Reads | ISSUE_TITLE |
| Outcomes | Pass. Skip (exit 0) when no title is given, as on an edit that does not change it. Fail with one error per grammar finding. |
| Implements | Vinaya-specific |
| Settings | checks |
issue- objectives- numbering
Each objective must be a numbered, observable outcome, so Parts can cite it by id.
| Refuses | A malformed ## Objectives section. Lines must be numbered O<n>. <sentence>, one observable outcome each, with no gaps. |
| Runs | At Issue write time. |
| Reads | ISSUE_BODY, ISSUE_NUMBER; gateCutovers. from the working-tree config. On create the number is empty, which the check treats as not exempt. |
| Outcomes | Pass. Skip (exit 0) with an empty body. Fail with one error per finding. An Issue numbered below the cutover passes. |
| Implements | Vinaya-specific |
| Settings | checks; gateCutovers. (absent means no cutover: every Issue is graded) |
issue- parts- coverage
A Part must point at objectives that exist, so every piece of work traces back to a stated outcome.
| Refuses | A ## Parts line that cites an objective id the ## Objectives section does not define. Part lines read Part <n> (O<k>[, O<j>]) — <outcome>. |
| Runs | At Issue write time. |
| Reads | ISSUE_BODY |
| Outcomes | Pass. Skip (exit 0) with an empty body. Fail with one error per finding. |
| Implements | Vinaya-specific |
| Settings | checks |
issue- surface- globs
A Surface glob that matches nothing cannot scope any work, so it is caught before the Issue is written.
| Refuses | A ## Surface in: glob that matches no tracked file. Globs are expanded with git ls-files; the brief renderer uses the same expansion. |
| Runs | At Issue write time. |
| Reads | ISSUE_BODY; the repository's tracked files. |
| Outcomes | Pass. Skip (exit 0) with an empty body. Fail with one error per unresolved glob. |
| Implements | Vinaya-specific |
| Settings | checks |
issue- milestone- attach
A task Issue belongs to its tranche's Milestone, and this check names the Milestone when the two drift apart.
| Refuses | On edit, a task Issue whose Milestone is not the one its tranche label resolves to (not checked on create). |
| Runs | At Issue write time, on edit only. On create the attach happens in the same write, so there is nothing to compare yet. |
| Reads | ISSUE_LABELS, CURRENT_, RESOLVED_ |
| Outcomes | Pass when the labels are not a task label set, when the resolved title is empty, or when the two titles match. Fail otherwise, naming the Milestone to attach. |
| Implements | Vinaya-specific |
| Settings | checks |
Configuration
| Key | Effect |
|---|---|
checks | A key equal to a check's name replaces it (for example with a no-op). A namespaced check you add that declares validates: 'issue' runs on the same write path with no further wiring. |
gateCutovers. | Issues numbered below it pass issue-. Read from the working-tree config. |
rings. | Does not affect these five. false empties the brief-schema section group on the same write path, but the Issue checks have no opt-out. |
What gets logged
Each Issue validation goes through the check runner, so it records one gate · summary event, and one gate · checked event per check that did not pass, to the logs destination. The event carries the check name, outcome, a short reason code and an input fingerprint, never the Issue text. Nothing is written to GitHub as a log. See Events for every field.