Write lint_spec(spec) — the gate every ticket passes before any
builder sees it. Return (verdict, reasons).
Build reasons in this rule order:
- no
owner(missing or falsy) → append"no owner" - no
acceptance(missing or empty) → append"no acceptance checks" - for each acceptance check, in list order: if any word from
VAGUEappears in the lowercased check text, append"<id> vague: <first hit>"— first hit in VAGUE-list order - no
out_of_scope(missing or empty) → append"no scope fence"
verdict is "READY" if reasons is empty, else "BLOCKED".
Three tickets run. Expected output:
DS-401: READY
DS-402: BLOCKED — A2 vague: intuitive
DS-403: BLOCKED — no owner; no scope fence