Essay
Spec-driven execution: tickets with files_predicted + acceptance_criteria as the FSM gate
The pattern that turned a vague ticket queue into a reliable dispatch system: two required fields that structurally gate quality instead of hoping the executor infers your intent.
Early in building the Master OS, I had a problem I didn’t know how to name: ticket executors were producing work that was technically correct but not what I wanted. The code compiled. The tests passed. The merge succeeded. And then I’d look at what actually shipped and realize the executor had made a reasonable interpretation of an ambiguous spec — just not the interpretation I had in mind.
The solution wasn’t better prompts. It was structure.
Two fields that changed everything
The quality gate for ticket dispatch is two required fields: files_predicted and acceptance_criteria. A ticket missing either field is invisible to the dispatcher — it sits in the queue and no executor picks it up.
files_predicted is a list of the exact file paths the ticket is expected to touch. Not directories. Not “the auth module.” Specific paths: src/components/Header.astro, scripts/tickets.py, wiki/operations/tickets.json. The executor reads these files at the start of its run, and the verifier checks that the commit actually touched them.
acceptance_criteria is a list of verifiable conditions the work must satisfy before the verifier returns pass. Not “the component looks better” — that’s an opinion. “The header renders at 375px without text overflow” is verifiable. “The system_doctor --grade returns A 19/19” is verifiable. Conditions that can be checked by a subagent without operator judgment.
Together, these two fields define what the executor should touch and what done looks like. The executor can’t misinterpret either one — there’s no ambiguity to fill with the wrong assumption.
Why this is a FSM gate, not just good practice
The finite state machine that governs ticket lifecycle has hard invariants. The verifying → merged transition requires that the verifier subagent returns verdict: pass. The verifier checks the acceptance criteria — and if the criteria are ambiguous, the verifier makes a judgment call that may not match yours.
When acceptance criteria are precise, the verifier’s judgment call and your intent are the same thing. When they’re vague, they diverge. The FSM enforces the structure; the spec quality determines whether the structure produces the right outcome.
The dispatcher also filters on files_predicted. A ticket without predicted files can’t be context-loaded correctly — the executor doesn’t know what to read before starting. Missing this field isn’t just a style issue; it structurally degrades the executor’s ability to do the work.
Writing specs that work
A good ticket spec has four things:
-
One-liner summary. What is this ticket doing? One sentence, past tense, as if describing a commit. “Updated the Header component to prevent text overflow at 375px.”
-
files_predicted. Every file the executor will touch. If you’re not sure, list the likely files and let the executor surface the rest in the blockers. Better to over-specify than under-specify.
-
acceptance_criteria. Verifiable conditions. Use the form “X happens / X returns / X renders / X passes” — not “X should” or “X looks good.”
-
researched_context_refs. Files the executor should read for context but not necessarily modify. The CLAUDE.md, the brand wiki, the relevant schema files.
That’s it. Four fields. The spec doesn’t need to be long — it needs to be precise. A 3-line spec with precise files_predicted and acceptance_criteria outperforms a 20-line spec with vague acceptance criteria every time.
The meta-lesson
Every system that relies on human operators to “just know” what quality looks like will degrade over time. The operators change, the context accumulates, the implicit expectations drift. Structural gates — required fields, FSM invariants, pre-merge checks — are what keep the quality bar consistent without requiring the operator to re-establish it from scratch every session.
Spec-driven execution is not a workflow. It’s a constraint that makes the workflow reliable.
The ticket FSM and dispatch protocol are documented in wiki/_global/repo-protocol.md in the Master OS.