PROMPTING.md — how to phrase a correction so it lands first time
The queue runner is only as good as the row it is given. A correction that names a screen, a visible outcome, and a way to check it gets implemented and verified without a round-trip. A vague one gets guessed at — and guessing is the number-one source of the bugs and missed changes you are seeing.
This is the contract the lane triage step, the acceptance checks and the
verifier all rely on. Write rows to it and the loop runs itself.
The 5 slots (fill all five)
| Slot | Question | Bad | Good |
|---|---|---|---|
| WHERE | which screen/route/form? | "the list page" | Quote list / src/routes/quote |
| DO | what exactly changes? | "fix the buttons" | remove Expire + Follow-up; keep Duplicate + Create SO |
| SHOW ME | what will I see when it is done? | "it works" | clicking Add Quote opens a modal; table stays visible |
| MUST NOT | what must stay untouched? | (omitted) | table + search stay; no cost lines in the customer share |
| EXAMPLE | a concrete case / data | (omitted) | party "Shree", 32s CW, qty 1250 mtrs |
If you cannot fill SHOW ME, the item is not a correction yet — it is a
discussion. Say "discuss" and the runner holds it (blocked-owner) instead of
guessing.
One correction = one screen
Your CORRECTIONS.md already breaks a message into one row per form. Keep
that: a row that spans leads + quote + orders cannot be batched and cannot be
verified in one shot. Split it. Wide rows are the exception.
Say when the AI must NOT act
Ambiguity is expensive. Mark it explicitly so the runner holds the row:
VERIFY-FIRST: confirm X feeds no calculation before removing; if it does, report back — do not delete.(this is exactly C35/C36 — good rows.)NEEDS CLARIFICATION — owner to restate.(C56 — a good hold, a bad correction.)awaiting owner decision/do not guess(C55 — correctly held.)
The runner auto-detects these phrases (blocked-owner). Use them and it will
never invent an answer — instead it asks you: the question lands in
docs/QUESTIONS.md and shows on the /queue board (banner + the row's
"Needs your action" cell). Answer by telling any session — it records the
answer and releases the row.
The "done looks like" line
End every correction with the acceptance check in plain words. The triage lane turns it into 2–6 checks; giving it yourself makes them correct on the first pass:
Done looks like: on
/quotethe row has Duplicate + Create SO + Re-quote only; clicking Duplicate opens/quote/new?reuse=<id>with rates prefilled;bun test tests/c32-requote.test.tspasses.
Rewrites from your own shelf
| Row | As told | Why it stalls | Rewrite |
|---|---|---|---|
| C56 | "breakdown the gate prices into multiples of gate passes… check all the gate passes separately" | no screen, no outcome, open to interpretation | Gatepass list: group rows by gatepass kind, subtotal qty per kind, add per-kind filter; done = filter shows only that kind + subtotal matches sum of rows. |
| C32 | "Re-quote button is NOT working — fix it; it must be present and allow ONLY a rate change" | good, but no repro | add done = clicking Re-quote on a quote row opens that quote with only rate + validity editable; other fields disabled; test tests/c32-requote.test.ts passes. |
| C45 | "Wherever the system suggests data entry from past entries, use Chip Suggestions UI." | "wherever" is open scope | list the exact screens: rate + qty suggestions on quote, bookings, orders use the chip component (docs/UIPATTERN §chip); done = each shows chips from the last 5 entries. |
| C24 | "Same separation for EVERY form in the app." | unbounded | Apply the list/entry separation to leads, quote, orders, bookings, gatepass, tippans, masters — done = each Add opens a popup; list shows table only. |
Copy-paste template
WHERE: <screen / route>
DO: <the exact change>
SHOW ME:<what is visibly different when done>
MUST NOT: <what stays untouched>
EXAMPLE: <a concrete case>
DONE LOOKS LIKE: <observable acceptance; test file name if known>
HOLD IF: <phrases that mean stop and ask>
What the system does with it
lanetriage turns WHERE/DO intotarget:globs + observable checks indocs/QUEUE.md.laneimplements it test-first on those files only.verifierreproduces the checks on the running app — never trusting the implementer. Fail → the row auto-reopens at P0.runnerdeploys one verified batch at a time and appends the ledger.
Your only jobs: queue rows in this shape, and answer the blocked-owner
questions. Everything else is the loop.