Files
Panama/user/agents/skills/ticket/SKILL.md
T
Gabriel Brown 86f6e391b7 Run the ticket skills through T3 Code, with a review council before pre-mr-review
Agents now start pre-mr-review on the work account themselves, through a Klaude
delegate, and continue from its verdict. A council of models on my own accounts
replaces the single reviewer before it, and adding a seat is one table row.

Proof comes from T3's browser, with mp4 recordings, and capture-proof stays as
the fallback. Ticket pages carry their own data, so index.html renders alone in
T3's file viewer, and worktree threads share the main checkout's docs.

A PreToolUse hook sends subagents in T3 threads to delegate_task. Blocker, proof,
review and MR summary rules come from ideas in t3dotgg/tstack.
2026-11-04 18:04:18 -05:00

956 lines
63 KiB
Markdown

---
name: ticket
description: End-to-end Jira ticket workflow — fetch a ticket into a live ticket page under .claude/docs/epics/, plan it, implement it with clean commits, review it with a council of models, drive the pre-mr-review audit to convergence on the work Claude account, and write the MR doc. Use when the user gives you a Jira ticket key (e.g. KACP-11111) to work, or asks to plan/implement/wrap up a ticket.
---
# Ticket Workflow
Turns a Jira ticket key into: a live ticket page carrying the ticket, a reviewed plan,
progress, and proof, implemented and committed code, a converged `pre-mr-review` audit, and
an MR doc ready to paste into GitLab/GitHub. This skill is user-level (`~/.agents/skills/ticket/`) and works the same
way in any repo that has a `.claude/docs/` directory and a `pre-mr-review` skill.
Invoked as `/ticket KACP-11111`. The ticket key is passed as the skill's arguments. Called
again later with the same key, it resumes wherever it left off — see **Phase 0**.
Not to be confused with `/review-ticket`. That skill writes the *developer review* on a
Jira story, the estimate, risk level, and testing tables, as part of authoring a ticket
before anyone builds it. It has nothing to do with reviewing code. The code review in
this skill is Phase 2 step 5 and is performed by the review council in [COUNCIL.md](COUNCIL.md).
## The ticket page
Every ticket gets a **ticket page**, a web page Gib keeps open while you work: the ticket as
Jira has it, the plan with its mocks, live progress, proof beside the mocks, and the review.
Every epic gets an **epic index** listing its stories in build order. Both render from data
files that only `ticket-page` writes, and both update themselves as it writes.
Gib works in T3 Code. The page opens in T3's file viewer beside the thread when you link its
absolute path, so never start a server for it. At two moments, plan approval and hand-off,
the skill also shows a snapshot inline in the thread with `ticket-page view`, so he can read
it without leaving the conversation. SITE.md has the commands, under **In T3 Code**.
**Read [SITE.md](SITE.md) before the first write of every run.** It holds the command for each
moment the phases below name, the plan's JSON shape, how to draw mocks, and how the epic order
is seeded. Record each moment when it happens, not in a batch at the end, because Gib is
watching the page change.
## Working in T3 Code
Gib runs this skill in a T3 Code thread (`T3CODE_THREAD_ID` is set) and stays there, so the work
comes to him through T3's own tools.
- **Agents are T3 delegates.** Every agent this skill starts is a `delegate_task`, and a local one
always runs in this thread's project. A delegate gets only its `task` text, so write the brief
as though it knows nothing. `/skill` lines do not expand there: tell it to call the Skill tool.
Start one with `mode: "async"` and end your turn, because T3 wakes you when it finishes.
- **Proof comes from T3's browser,** the `preview_*` tools. `/ticket` is the request for browser
work that T3's rules ask for, so use them at the proof step. Phase 2 step 9 has the recipe.
Claude in Chrome stays for reading Gib's signed-in sites, such as a Jira page.
- **Questions go through AskUserQuestion,** with the context, what blocks you, and your
recommendation first, because a question in a normal message leaves the thread looking done.
Without `T3CODE_THREAD_ID`, the fallbacks are named where each one applies.
## Directory layout this skill maintains
```
.claude/docs/epics/
<EPIC-KEY>/
index.html, epic.data.js # the epic index (each index.html carries its own renderer)
<TICKET-KEY>/
index.html, ticket.data.js # the ticket page
resources/
issue.raw.json # the fetched issue, kept for re-imports
<attachments...> # images, videos, other files as downloaded
<video>.transcript.txt # only for videos that got transcribed
<video>.transcript.srt
<video>.frames/
deliverables/ # only for tickets whose output is documents, not code
<deliverable-slug>/
<deliverable-slug>.md
<deliverable-slug>.typ
<deliverable-slug>.pdf
proof/ # captured working feature proof, uploaded to Jira by the user
mr.md # the MR description only, written once pre-mr-review says Ready to Open MR
tickets/
<TICKET-KEY>/ # same shape, for tickets with no epic, and no index
```
## Scripts this skill uses
- `~/.agents/skills/ticket/scripts/ticket-page <command> <KEY> ...` — the only writer of the
ticket page and epic index. See [SITE.md](SITE.md), or `ticket-page help`. Runs under bun.
- `~/.agents/skills/ticket/scripts/capture-proof` — the fallback for proof screenshots: 2x
Playwright captures, full page or cropped, for what T3's browser cannot do (Phase 2 step 9).
`capture-proof help` lists its options. The first run installs a pinned Playwright into
`~/.cache/ticket-page/`.
- `~/.agents/skills/ticket/scripts/jira-fetch-issue.sh <KEY> <OUT.json>` — fetches one
issue (`fields=*all`, rendered HTML description, field-name map) via `JIRA_BASE_URL` /
`JIRA_CREDENTIALS`.
- `~/.agents/skills/ticket/scripts/jira-download-attachments.sh <issue.json> <resources-dir>`
— downloads every attachment on that issue into the given directory, printing
`filename<TAB>mimeType<TAB>bytes` per file.
- `~/.agents/skills/ticket/scripts/transcribe.sh <media-file> <output-dir> [model]` —
transcribes via whisper.cpp in podman, auto-detecting NVIDIA/AMD/Vulkan acceleration
and falling back to CPU on failure. Requires `podman`; uses host `ffmpeg` if present.
Both Jira scripts require `JIRA_CREDENTIALS` (`[email protected]:api-token`, Basic auth)
to already be exported in the environment. `JIRA_BASE_URL` defaults to
`https://ksense-tech.atlassian.net` if unset.
Each Bash tool call runs in a fresh shell that does not inherit state from previous
calls, so a plain `export` the user ran earlier in their own terminal will not show up
here. Before calling either Jira script, always run `source ~/.bashrc 2>/dev/null` in
the same Bash call (chained with `&&` or on the line before), then check the var is
actually set. Only if it's still missing after that should you stop and tell the user
to export it (or point you at wherever it's actually set, e.g. a dotfiles repo) rather
than guessing or prompting for a token inline.
### AMD Vulkan acceleration
`transcribe.sh` uses the whisper.cpp Vulkan image when `/dev/dri` and `vainfo` are
available. On a host with more than one AMD or Intel GPU, select the intended render
node explicitly instead of exposing every DRI device and trusting enumeration order:
1. Identify the GPU PCI address with `lspci | rg -i 'vga|display|3d'`.
2. Map it to a render node with `ls -l /dev/dri/by-path` and resolve the matching
`pci-<address>-render` symlink with `readlink -f`.
3. Run the helper with the resolved node, for example:
`WHISPER_VULKAN_DEVICE=/dev/dri/renderD128 ~/.agents/skills/ticket/scripts/transcribe.sh <media-file> <output-dir> [model]`.
4. Verify the runtime log. `Selected acceleration: vulkan` only confirms the intended
path. Require `ggml_vulkan: Found ...`, the exact requested GPU name, and
`use gpu = 1` before claiming hardware acceleration worked.
The current whisper.cpp images declare `bash -c` as their container entrypoint. The
helper overrides it with `/app/build/bin/whisper-cli`. An older helper without this
override can fail before Whisper starts with `-f: line 1: /models/...: Permission
denied` and then fall back to CPU.
The accelerated paths remain best-effort on other hosts. The helper falls back to the
CPU image after an accelerated runtime failure. If the user explicitly requested GPU
acceleration, CPU fallback does not satisfy the request. Diagnose the accelerated path,
rerun it, and verify the device log instead of accepting the fallback transcript.
## House style (applies to everything this skill writes or commits)
- No code comments unless the user explicitly asks for one in that spot.
- No em dashes, en dashes, semicolons, or arrow glyphs in commit messages, the ticket page,
or `mr.md`. Plain punctuation only.
- Commits are `git commit -m "<short imperative message>"` only — no body, no
co-author line, no `Claude` / `Codex` / `AI` trailer of any kind.
- Never `git push`. Never open an MR/PR. This skill prepares everything needed to open
one by hand; opening it is the user's call.
- Don't check a checklist box (in `mr.md` or anywhere else) unless you actually verified
it. Leave it unchecked and say why in the notes rather than guessing.
## The prose bar (anything another person reads)
Everything this skill produces for someone else gets a pattern pass before it ships:
`mr.md`'s Summary and Additional Notes, every Jira field including the proof and
mitigation cells, and every deliverable document. Call the Skill tool with "unslop" and
apply its pattern detection.
- **Skip unslop's "Adding soul" section.** It asks for opinions, varied rhythm, and some
mess. That is right for an essay and wrong for a mitigation cell Henry is auditing.
These want plain, factual, and specific.
- **Never edit generated output.** The pre-MR handoff pasted into `mr.md` is the audit's
own words. If it reads badly, regenerate it, don't rewrite it.
- **Proof cells are prose too.** A cell that wraps three sentences around a filename is
writing, not a citation, and it picks up passive voice and jargon like any other
paragraph. Real examples caught this way: "affordance" for button, "vacuously" for
"for the wrong reason", "the test was confirmed able to fail" for "I emptied the
legacy render and confirmed the test fails".
- **Passive voice is the usual offender here,** not puffery. Technical writing drifts
into "X was verified" when "I verified X" is shorter and says who did it.
### Write as Gabriel, and never flag his own decisions
Everything that ships under his name is written **as him**, in first person. Never write
his name or any stand-in for it. Not "Gib decided", not "the author", not "per the
developer". When a sentence needs an actor, it is "I".
**Never frame one of his decisions as a deviation.** Do not write that something "was not
in this story's scope", that an AC or dev review said otherwise, that an earlier story
"should have caught it", or that a direction was "reversed". State what the change is and
why it belongs where it is, then stop.
He writes the tickets himself, so he is entitled to change them, and a dev review is a
proposal rather than a contract. Calling the change out reads as his own AI tattling on
him. It waves a red flag at a nothing burger, costs the PM time investigating a
non-issue, and leaves them assuming he did something wrong. The real story is normally
mundane and good: the better component already existed and cost almost nothing to use.
Compare, on KACP-23058:
> Bad: "This was not in this story's scope. KACP-23059 shipped that page still on the
> legacy tables, and Gib reversed the reuse-legacy direction on 2026-09-02."
>
> Good: "Both detail pages now share one set of grid components instead of two divergent
> implementations, so the move ships with the components it shares."
Same information, no flag attached. **If a decision feels big enough that you want to
narrate it, that is the signal to ask him about it before writing, not to annotate it in
the document.** Being aligned first is the point, and the writing should read as though
you always were.
This governs `mr.md`, `customfield_10260` and `10261`, every other Jira field, and PM
deliverables. It does not govern files only he reads. The ticket page, `bugs.md`, audits and
working notes can name him and record who decided what, because that history is useful.
The House style punctuation rule above is the stricter one where the two overlap. Keep
it. The ticket page is a personal working file and exempt, nobody else reads it.
## Verification tools available
The goal isn't "a plausible-sounding plan" or "code that compiles" — it's a plan and
an implementation that are actually correct, checked against the real system rather
than assumed from the ticket text. Use whichever of these actually verify the thing
in question, before writing the plan (Phase 1) and again whenever Phase 2's
implementation makes a claim that's checkable:
- **The codebase itself.** Don't take the ticket's description of "how things work
today" at face value. Read the actual models, routes, and components involved and
reconcile any mismatch. If the ticket says a field works one way and the code says
otherwise, say so in the plan rather than silently trusting either source.
- **Jira, beyond the single ticket.** Many tickets assume Jira's own data model (custom
fields, issue types, workflow states) or context that lives on linked issues,
comments, or the epic rather than on the ticket itself. Search related issues
(`searchJiraIssuesUsingJql`, issue links, other children of the same epic) and check
the real field list (the `names` map `jira-fetch-issue.sh` already pulls, or
`/rest/api/3/field` for the full set) instead of guessing at a custom field's shape.
- **Staging**, via Infisical (see the `infisical-api` / `infisical-user-setup-guide`
skills for pulling secrets). Staging is fair game to probe directly whenever it
would settle something real, no need to ask first, that's what it's for.
- **Prod and CI env vars**, at `.claude/docs/env/prod/.env` and
`.claude/docs/env/ci/.env`. Ask the user for permission before every use, even if
they granted it last time, say what you want to verify and why. Once granted: use
the values (e.g. source them for a one-off read-only command) without printing the
raw file contents or individual secret values into your output. Read-only, always —
never run anything that writes, mutates, or deletes against prod or CI. If what you
actually need is a prod database query, that's exactly the kind of thing to ask
about explicitly rather than assume the file's DB credential is fair game by default.
If something would need access you don't have (a different repo, a system you can't
reach), say so explicitly in the plan's open questions instead of silently skipping
the check.
**How to write what you found, in a deliverable.** State it as a plain confirmed
fact: "Confirmed in prod: 67 of 70 companies have `hourlyRate` set." Never describe
the verification method itself, no "a read-only pull," "a read-only pass," "read-only
query," or similar plumbing language. The reader doesn't know or care that you ran a
SQL query, they care what's true. This applies to prod, staging, Jira, and the
codebase equally.
## Deliverable documents (spikes, proposals, anything whose output is a document)
Some tickets (spikes, research, migration proposals, the KACP-22764 kind of ticket)
don't produce code, they produce documents for a PM or another engineer to read. When
a plan step produces a document rather than a code change, it becomes its own
subfolder under `<target-dir>/deliverables/<deliverable-slug>/` with three files:
- `<slug>.md` — the source of truth for content. Write this first, get the content
right before worrying about layout.
- `<slug>.typ` — a Typst version of the same content, laid out for an actual printed
or PDF-read document, not a mechanical markdown-to-typst conversion. Real headings,
`table()` for tabular data, and a diagram (via the `cetz` package,
`#import "@preview/cetz:VERSION"`) wherever a diagram would genuinely communicate
faster than prose — entity relationships, hierarchies, flows. Don't force a diagram
in where a bullet list would do. Style is engineering-oriented and readable: nothing
colorful or flashy, this goes to a technical PM and other engineers.
- `<slug>.pdf` — compiled from the `.typ` file.
**Write for the actual audience, not for yourself.** The reader is a PM or another
engineer who has never seen `.claude/docs/` or the ticket page, and doesn't have this
repo (or any other local repo) checked out. Never reference `.claude/docs/` or any local
file path in a deliverable's content. Never point the reader at the ticket page or the
plan, those are personal working files, not things a reader can open. Refer to "this ticket" or a plain Jira link, not a local
path. If a fact came from another repo on this machine, state the fact, don't cite
the local checkout path it came from.
**Structure mirrors the ticket, not a narrative.** The PM reads a deliverable to
verify that everything they asked for is in it, and to come back later and re-find
one specific answer. Build the document from the ticket's own structure:
- If the ticket asks direct questions (a spike's "Questions to Answer" table), the
first section is `Questions and answers`: every ticket question in ticket order,
each with its priority, a direct two or three sentence answer, and a pointer to
the section holding the detail. This page is how the reader checks all
acceptance criteria without reading the rest.
- One section per named deliverable or requested topic, titled with the ticket's
own words. If the ticket says "status-weighting approach" there is a section
called "Status weighting"; if it asks how the datamodel changes, the section is
"Datamodel". Plain flat headings, one level below the title, in roughly the
ticket's order of importance (schema and calculations early).
- Each section is the artifact, not prose about it: schema changes as real schema
code in the repo's conventions (e.g. Prisma model blocks), math as formula code
blocks, mappings as tables, UI as the real mockup screenshots. Current-state
context earns a sentence or two inside the section that needs it; the section
states the decision, not the investigation that produced it.
- Sections are short. Cover every question and requirement, spend few words each.
Depth lives in the code blocks and tables, not in longer paragraphs.
- The voice is a dry engineering spec. Plain declarative sentences, no scene
setting, no flourishes ("the heart of the model", "the honest story"). A
correct document that reads glossy costs the reader's trust in it.
**State final decisions, don't narrate the journey.** A deliverable answers "what
goes where and why," not "here's what we used to think, here's what turned out to be
wrong, here's what's resolved now versus still open." No "Corrections made" section
listing earlier mistakes, no "Resolved" / "Still open" split, no "first draft said
X, that was wrong" asides. Figure out the right answer (including asking the user
directly, mid-task, for anything you can't determine yourself) before or while
writing the deliverable, then write the resolved shape as plain fact, the same way
the very first version of a proposal document should read: a clean "stays here,
moves there, and why" description, nothing else. If something genuinely can't be
resolved without more input and truly must ship as an open question, keep it to the
smallest possible list, phrase it as a direct question, and ask the user about it
directly (don't just leave it sitting in the document) rather than defaulting to
"flag everything as open" as a way to look thorough.
**Describe the mock, not how far the implementation went.** A mockup deliverable
should say that a quick UI mockup was made by updating the relevant screens, then
explain what the mock demonstrates. A schema deliverable should present the proposed
schema and migration direction. Never tell the deliverable's audience that the mock
was fully coded, built as a real feature, production-ready, implemented end to end,
or created on a working branch. The code-based mock workflow below is an internal
method for producing accurate screenshots, not part of the deliverable's story.
Process, per deliverable:
1. Write `<slug>.md`.
2. Run the prose bar over `<slug>.md` before building anything from it. A spike
deliverable is the most prose-heavy thing this skill produces and it goes straight to
Conrad, who is skeptical of AI. Fixing it here means fixing it once, rather than in
the markdown and again in the Typst.
3. Write `<slug>.typ` from it, per the styling notes above.
4. Compile: `typst compile <slug>.typ <slug>.pdf`. `typst` should already be on PATH;
if it isn't, tell the user rather than silently skipping the PDF.
5. Actually look at the compiled PDF using the Read tool (it reads PDFs directly, page
by page for longer documents). Check every page for real layout problems: text or
a table overflowing a page, an awkward page break splitting a table or diagram,
cramped or excessive spacing, a diagram that rendered wrong. A successful compile
only means valid Typst, not that it looks right — actually look.
6. If anything looks wrong, fix `<slug>.typ` and go back to step 4. Repeat until the
PDF genuinely looks right, not just until it compiles without erroring.
If `.claude/docs/` is tracked by git in this repo (check with
`git check-ignore .claude/docs` — no output means it's tracked), commit a
deliverable's three files together as one commit, same as any other step. If it's
gitignored (as in command-center), these files never show up in git at all, which is
expected and fine — they're meant to be shared manually (Slack, attached to the Jira
ticket, however this team actually hands off docs), not through the MR. Don't try to
force-add gitignored files to work around this without asking first, that's an
existing deliberate house rule, not an oversight.
If a deliverable is a UI mock, capture the UI mock described in **Mocks and datamodel
changes** below rather than drawing a separate wireframe. In the deliverable itself,
describe it only as a quick UI mockup.
## Mocks and datamodel changes: build them for real
When a ticket calls for mocks or datamodel changes (a spike proposing new screens or a
new schema, for instance), don't stop at wireframes or a schema proposal document.
Build it for real, on the ticket's branch. Give these steps `"kind": "mock"` in the plan.
A mock deliverable is **two artifacts**, not one, and they answer different questions.
The code proves the thing is buildable and surfaces the problems a picture hides. The
visual mocks show what it should look like once it's built properly, unconstrained by
what was quick to wire up. Ship both, and don't let either stand in for the other.
- **Datamodel changes**: make the actual schema change (e.g. edit
`packages/db/prisma/schema.prisma` and generate a migration the normal way for this
repo) rather than only describing it in a document. The proposal document from
Deliverable documents above can and should still exist, but it now describes
something that's actually in the branch, not just a plan for something that might
be built later.
- **UI mocks**: build the actual screens/components in the app, wired up enough to
navigate to and look real, not a static image or a markdown wireframe. Where it
isn't much more work, prefer making it an actually working proof of concept (real
data flowing through, not a placeholder-filled shell) over a purely cosmetic mock —
that's almost always more informative for close to the same effort.
MVP quality is the bar for this half, not polish: real data flowing and a screen you
can navigate to is what matters, and rough or ugly is fine, because the visual mocks
below are what carry the intended look.
- **Visual mocks alongside the code, one or two of them.** The built version is
deliberately rough, so on its own it under-sells the idea to anyone reviewing it.
Produce one or two polished mocks that aren't constrained by what was cheap to build:
the layout, spacing, and density as they should actually be. A self-contained HTML
page does this job, shown through `html_preview` and `html_render`. These are design
intent, not implementation promises, so call out anything a mock shows that the code
doesn't do yet.
- **Scope discipline still applies.** This is a proof of concept, not a production
feature. Don't chase every edge case and don't fix unrelated pre-existing bugs you
happen to notice along the way, just implement enough of the real thing to be
screenshotted and evaluated. If doing it for real would take significantly longer
than a static mock would, say so in the plan's approach rather than silently scoping it down
without mentioning the tradeoff.
- **Screenshot the real thing.** Once it's built and running, use the `run` skill to
get the app up and capture the actual screens as the proof step in Phase 2 describes,
instead of drawing a wireframe. Save screenshots under
`deliverables/<slug>/screenshots/` and the visual mocks under
`deliverables/<slug>/mocks/`, and embed both in `<slug>.typ` via `image()` when
building the mockups deliverable. Label which is which. A reader who can't tell a
built screen from a design mock will read the mock as a promise of what already
works.
- **Same rigor as any other code.** This is real work on the ticket branch like any
other implementation step: same commit discipline, included in Phase 2's
verification pass, and not exempt from `pre-mr-review` just because the ticket is a
spike.
The `prototype` skill is a different job, not this one. It makes throwaway code for
settling which direction to take, parked on a branch out of main and thrown away after.
Reach for it when the spike's real open question is which of several directions to
build. Once a direction is settled, the deliverable is the two artifacts above, and both
ship with the ticket.
---
## Branch setup — run this before any repo work in Phase 1 or Phase 2
Every ticket gets its own branch, prefixed with the ticket key
(`<KEY>-Title-Case-Hyphenated-summary`, matching this org's existing convention, e.g.
`KACP-22823-Fix-Invalid-Date-In-Retainer-Datagrid`). Do this unconditionally as the
first thing in Phase 1, before fetching or writing anything, not just in Phase 2 —
spikes and plans can turn into real code (prototypes, mockup components) partway
through, and the branch needs to already exist when that happens.
1. Determine the repo's default branch (`main` here; if genuinely unsure, check
`git symbolic-ref refs/remotes/origin/HEAD`).
2. Find candidate branches for this ticket, local and remote:
`git branch --list "<KEY>-*"` and `git branch -r --list "origin/<KEY>-*"`.
3. **No matches** — fresh ticket branch:
- Run `git status`. If there are uncommitted changes, stop and ask before doing
anything — don't risk carrying unrelated work onto a new branch.
- If not already on the default branch, check it out.
- Update it: `git pull --ff-only`. If that fails (local default branch has
diverged from `origin`), stop and ask rather than forcing anything.
- Create the new branch off the now up-to-date default branch, named from the
ticket title (2-6 words, Title-Case-Hyphenated, prefixed with `<KEY>-`).
`git checkout -b <name>`.
4. **Exactly one match** — this ticket already has a branch:
- If not already on it: check `git status` first. If there are uncommitted changes
that don't look like they belong to this ticket, stop and ask before switching.
Otherwise check it out (`git checkout <branch>`, or
`git checkout -t origin/<branch>` if it only exists remotely).
- Compare it to the default branch: `git merge-base <branch> <default>` vs
`git rev-parse <default>`. If they match, the branch is current off the default
branch — proceed normally.
- If the default branch has moved on since the branch's merge-base, don't silently
merge or rebase anything. Tell the user how many commits the branch is behind
(and how many commits of ticket work are already on it), then ask
(AskUserQuestion) what they want: merge the default branch in, rebase onto it,
proceed as-is, or abandon it and cut a fresh branch instead. Do whichever they
pick.
5. **More than one match** — don't guess which one is "the" branch. List them (last
commit date and subject each) and ask the user which to use.
In a T3 worktree thread (`git rev-parse --git-dir` differs from `--git-common-dir`) the
default branch is usually checked out elsewhere, so cut from the remote instead:
`git fetch origin` and `git checkout -b <name> origin/<default>`. `ticket-page` finds the
main checkout's `.claude/docs/` from a worktree on its own.
Once this resolves you're on the correct branch, and Phase 1/Phase 2 work happens
there. `.claude/docs/` itself is gitignored in this repo, so which branch you're on
doesn't affect the ticket page or `mr.md` directly — this is about making sure any
actual code (mockup prototypes, spike code, real implementation) lands in the right
place from the start.
## Phase 0 — figure out where this ticket stands
1. Validate the ticket key looks like `[A-Z]+-[0-9]+`. If not, ask the user for a
correct key.
2. Look for an existing directory for this ticket without hitting the network:
`find .claude/docs/epics -mindepth 2 -maxdepth 2 -type d -name "<KEY>"`
(this matches both `epics/<EPIC>/<KEY>` and `epics/tickets/<KEY>`). If it holds a
`plan.md` but no `ticket.data.js`, it predates the ticket page: convert it first, as
[SITE.md](SITE.md) describes under **Tickets from before the page**, then continue.
`ticket-page show <KEY>` says where the ticket stands.
3. Branch on what you find:
- **Nothing found** — this is a fresh ticket. Go to **Phase 1**.
- **A page with no plan** — a previous run was interrupted before writing a plan. Go
to **Phase 1** and regenerate from scratch (re-fetch, re-import, re-check
attachments); it's idempotent and cheap.
- **A plan, no `mr.md`** — ask the user (AskUserQuestion) what they want:
- Re-fetch the ticket and rewrite the plan from scratch (they want to start over)
- Proceed to implementing the existing plan as-is (they reviewed and approved it)
- Resume implementation (some steps are already done on the page / some commits
already exist on the ticket branch — pick up from the first open step)
- Move to the pre-mr-review stage (implementation looks done, just need the audit + MR doc, see Phase 2 step 7)
Route to **Phase 1** or **Phase 2** accordingly.
- **A plan and `mr.md`** — this ticket looks finished. Tell the user
`mr.md` already exists at its path and ask whether they want you to refresh it
(e.g. they made more changes since) or leave it alone. Only re-enter Phase 2's
verification/pre-mr-review loop if they say the code changed since `mr.md` was
written. Also fetch the ticket and check whether its type's Jira fields (Phase 2
step 9) are actually filled; an `mr.md` from before this skill filled Jira
directly may mean the fields were never written, offer to fill them.
## Phase 1 — fetch, scaffold, and plan
1. Do **Branch setup** above first, unconditionally.
2. Run `jira-fetch-issue.sh <KEY> <tmp-path>` (a scratch path is fine here — the next
step knows the final directory). Read the resulting JSON.
3. Import it: `ticket-page init <KEY> --issue <tmp-path>`. This files the ticket under its
epic (or `tickets/` without one), imports every rich-text field verbatim as sanitized
HTML, writes the page, and prints the ticket folder. Copy the fetched JSON to
`<target-dir>/resources/issue.raw.json`, which later re-imports and the attachment
script read. Record the branch from **Branch setup** with `ticket-page meta`, then run
`ticket-page open <KEY>` and link the path it prints, so Gib can follow from here on.
4. `init` ends by listing populated Jira fields the page does not show. Read each one and
add any that bear on implementing or verifying the ticket as a note. This sweep exists
because real content sometimes hides in per-project custom fields with unpredictable
names, and a name-pattern miss must not silently drop it.
5. Read what the Ticket tab now holds, and treat its tables as the ticket's contract.
- **Test cases** (KACP's "Test Cases & Working Feature Proof") and **risk mitigation**
are imported with every row verbatim. Often a field is just the bare instruction
panel and an empty table, which needs no further thought. When it has real rows,
those are the scenarios the developer must prove and the mitigations the developer
must implement: the plan names each one (`"fromTicket": true`), Phase 2 proves each
one, and Phase 2 step 9 fills its proof column back into the Jira field. The PM and
Lead write the risks. Implementing and proving each is the developer's job.
- Never substitute your own invented test cases or risks for the ticket's, in the plan
or in the Jira fields. Your own additional cases are welcome alongside the ticket's
rows, never in place of them.
6. If the ticket has an epic, seed or refresh its epic index as [SITE.md](SITE.md)
describes under **The epic index**. This is best-effort context: if the epic search
fails, say so and continue.
7. Run `jira-download-attachments.sh <issue.raw.json> <target-dir>/resources/`. For each
attachment with a `video/*` mime type, check whether another attachment already looks
like its transcript (same base filename with `.txt`/`.srt`/`.vtt`, or a filename
containing "transcript"). Collect any videos with no matching transcript.
8. If there are untranscribed videos, ask the user (AskUserQuestion, one question,
multiSelect if more than one video) whether to transcribe them now. For each they
approve, run `transcribe.sh <video-path> <target-dir>/resources/`.
For every video that gets transcribed, also extract frames — ticket videos are
almost always screen recordings, and the transcript alone misses what was on
screen (the UI being pointed at, the annotation, the row that's wrong). Extract to
`<target-dir>/resources/<video-basename>.frames/` with scene detection plus a time
floor, for example:
`mkdir -p <frames-dir> && ffmpeg -i <video> -vf "select='gt(scene,0.1)+isnan(prev_selected_t)+gte(t-prev_selected_t\,15)'" -fps_mode vfr <frames-dir>/frame-%03d.png`
Tune the scene threshold or floor so a typical video yields tens of frames, not
hundreds (raise the floor for long recordings). Then actually look at the frames
with the Read tool during research, cross-referencing the transcript's timestamps,
and treat what's visible on screen as part of the ticket's content the same way
the transcript is. Skip frame extraction only when the video is confirmed
audio-only or the user says the visuals don't matter.
9. Run `ticket-page scan <KEY>` so the page carries the attachments, each video with its
transcript and frames. When a video, spreadsheet, or linked document holds the
ticket's real requirements, write what it says as a note (`ticket-page note`), the
way "What the video says" summarizes a recording point by point.
10. Now actually understand the ticket in the context of this codebase: read whatever
source files, tests, or docs are relevant to what's being asked. Read them yourself:
this is normal engineering research, not scripted. Only a sweep too broad for one
pass earns a `delegate_task` with `role: "research"`. Use the
**Verification tools available** above to check the ticket's own claims against
reality (codebase, Jira, staging, and prod/CI env with permission) rather than
taking the ticket's description at face value — this is what makes the plan
trustworthy instead of just plausible-sounding.
Then classify the ticket before drafting anything, and say the classification out
loud so Gib can override it. Borrowing the `grilling` skill's paths: **bounded** is
a well-scoped change to a flow that already exists in this repo, and
**architectural** is a new subsystem, a schema change other stories depend on, or
anything that alters an interface neighbouring work relies on. Bounded is the common
case and goes straight to step 11. For architectural, call the Skill tool with
"grilling" and resolve its frontier with Gib BEFORE writing the plan — those
questions get answered in conversation, not deferred into the plan's Open questions
section, because an architectural plan built on a wrong assumption is the expensive
one to discover in Phase 2. Bounded measures the repo, not your familiarity: if the
flow being changed isn't already there to read, it isn't bounded. In doubt, take the
heavier path. Either way, record the classification with `ticket-page meta`.
11. Write the plan as `plan.json` in a scratch path, in the shape [SITE.md](SITE.md) gives,
and load it with `ticket-page plan <KEY> --file plan.json`. Its parts: acceptance
criteria restated precisely from the ticket, each naming the steps that satisfy it;
open questions that genuinely need Gib's answer, empty if there really aren't any
(don't manufacture questions to look thorough); the approach, meaning what you're
going to do and why, which files, modules and functions are involved, and how it fits
the existing patterns; decisions already settled with Gib; steps, each roughly one
commit's worth of work, with `"kind": "deliverable"` for a step that produces a
document via **Deliverable documents** and `"kind": "mock"` for a real schema or UI
change built to demonstrate a mock (see **Mocks and datamodel changes**); risks and
edge cases, each with how the plan handles it; and the test plan, meaning how each
criterion gets verified, the existing suites to run, and any new tests.
Be thorough: address every acceptance criterion, resolve as many open questions as
you reasonably can by reading the code first, and don't leave logic gaps. Steps
should be concrete enough that Phase 2 can execute them without re-deriving the
approach. The test plan must name every test case on the Ticket tab and say how
that exact case gets proven, and the risks must name every risk on the Ticket tab
and say which code enforces its mitigation. Read the notes column of a ticket test
case as part of the case, not as commentary: a note like "confirm the certificate
matches the emailed version" is its own thing to prove.
**Where the shape is in question, borrow the vocabulary.** When the plan has to
decide how deep a module should be, where a seam belongs, or what an interface
exposes — not merely which file to edit — call the Skill tool with "codebase-design"
and use its terms in the Approach section. `review-ticket` already does this when it
writes the dev review; this is the same judgment made again, with code about to be
written for real.
**The Test plan is a design decision, not a formality.** Beyond the cases
the ticket already carries, call the Skill tool with "tdd" to decide which
additional tests are worth writing, where the seam under test goes, and whether a
mock is warranted. That judgment is what keeps this section focused instead of
padded: a test plan listing one case per changed file is slop, and three tests that
can actually fail beat twelve that can't. If the ticket carries automated-test
subtasks from its dev review, name them here as the tests Phase 2 writes first.
**Wide refactors are the exception to one-commit steps.** A wide refactor is a single
mechanical change whose blast radius fans across the codebase (renaming a column,
retyping a shared symbol), so one edit breaks thousands of call sites at once and no
single step can land green. Don't force it into one. Sequence it as expand, then
migrate, then contract: first add the new form beside the old so nothing breaks, then
migrate the call sites in batches sized by blast radius (per package, per directory)
with each batch its own step, then delete the old form once no caller remains. Every
step stays green because the old form still exists until the last one. Say in the
Approach that this is what you're doing and why, since the step count looks inflated
otherwise.
12. When a step changes what a user sees, draw its mock artboards with `ticket-page mock`,
as [SITE.md](SITE.md) describes under **Mocks**.
13. Stop here. Show the plan in the thread: `ticket-page view <KEY> plan`, then each mock
artboard with `ticket-page view <KEY> mocks --mock <id>`, each through `html_preview`
and then `html_render` (SITE.md, **In T3 Code**). Then link the page path from
`ticket-page path <KEY>`, summarize the approach in a couple of sentences, and mention
any open questions that need their input before you'd implement it. Do not start
implementing in this same run — wait for them to review the plan and invoke
`/ticket <KEY>` again. They change the plan by asking, and you rewrite it with
`ticket-page plan`.
## Phase 2 — implement, verify, and hand off
Entered only when the user has confirmed (per Phase 0) that the plan is approved. From
there this phase runs through to the step 10 hand-off without waiting on Gib: the council
and the audit both run as delegates. Stop only for a real blocker, asked with AskUserQuestion.
1. Do **Branch setup** above first, unconditionally — even if Phase 1 already did this
for the same ticket earlier, confirm you're still actually on that branch now (the
user may have switched branches between runs).
2. Read the plan fresh with `ticket-page md <KEY>`, then mark it approved with
`ticket-page approve <KEY>`.
3. Work through the plan's steps in order. For each step: implement it (a
`deliverable` step follows the **Deliverable documents** process above instead of
writing code; a `mock` step follows **Mocks and datamodel changes** — real schema/UI work, not a static wireframe), and make one commit for it (or
a few, if the step naturally splits into independent units). Commit messages are short
and imperative, describing what changed, following House style above. Mark the step
running on the page when you start it and done with its commits when they exist, and
mark each acceptance criterion met the moment it is (SITE.md has the commands). A step
is done when `ticket-page show <KEY>` lists its commit.
**Write the test first for steps that carry real logic**, meaning a router
procedure, a derivation, a permission or authorization check, a migration, or a
state machine. For those, call the Skill tool with "tdd" and get a failing test
before the implementation. A step covered by an automated-test subtask from the
ticket's dev review is always one of these, and that subtask names the behavior the
test has to demonstrate. Do NOT do this for UI wiring, a grid column, a copy change,
or a styling fix — a test-first cycle there produces exactly the smoke-test padding
House style rejects. When unsure whether a step qualifies, ask whether the test could
ever fail for a reason worth knowing about. If it couldn't, skip it.
If a step fails in a way the plan didn't predict, and the cause isn't obvious within
a couple of minutes, call the Skill tool with "diagnosing-bugs" rather than trying
fixes to see what sticks. Note anything it turns up that changes the plan as an event on
the page. When it changes the steps, amend the plan as [SITE.md](SITE.md) describes, which
keeps the progress already made.
4. Do not run the full verification suite after every commit (checks-at-the-end mode).
Once every step is implemented and marked done, find and run this project's standard
verification (check `package.json` scripts for something like `ci:check`,
`typecheck`, `lint`, `test`, or fall back to whatever the repo's README documents).
Fix anything broken, committing fixes as their own commits, until it's clean. If you
can't find any verification command at all, say so explicitly later in `mr.md`
rather than claiming a build/lint/test pass that never happened. Beyond the standard
suite, use the **Verification tools available** above for anything the suite
wouldn't actually catch, e.g. confirming behavior against real staging data via
Infisical, or a specific prod/CI config question, when that's genuinely what it
takes to be confident the change works as intended rather than just "looks right."
5. Convene the review council before `pre-mr-review`. Read [COUNCIL.md](COUNCIL.md) and follow
it: it holds the seats, when the step applies, the brief, how to judge what comes back,
and when to stop. This step is done when every seat has returned or been recorded as
unavailable, and every finding on the page is fixed or rejected with its reason.
6. Confirm this project actually has a `pre-mr-review` skill (`.claude/skills/pre-mr-review/`
in the current repo). If it doesn't, stop here, tell the user implementation and
local verification are done but this repo has no `pre-mr-review` skill to run, and
let them decide how to proceed.
7. **Run `pre-mr-review` on the work account, from a Klaude delegate.** The org asks
that this review run from the developer's work Claude account, so the audit on record must
come from there, never from this session and never from another provider. Klaude is that
account (`~/.klaude`). The audit is one agent, not a council.
1. Show where the build stands with `ticket-page view <KEY> progress`, through
`html_preview` and then `html_render`. Write `ticket-page md <KEY>` to a scratch file.
2. Start it, then end your turn. T3 wakes you when it finishes:
```
delegate_task
title: pre-mr-review <KEY>
role: review
mode: async
target: { providerInstanceId: "claudeAgent_klaude" }
task: Call the Skill tool with "pre-mr-review" and run the audit on this branch.
Follow that skill's own rules, and start no subagents. The ticket and its
plan are in <scratch file>. <decisions from earlier runs, if any>
Reply with the verdict, the recommendation, the audited HEAD, and the audit
and handoff paths.
```
Leave `model` out so it runs Klaude's default, and leave `isolation` unset so the audit
lands in this checkout. A rerun is always a new `delegate_task`, one at a time.
Without `T3CODE_THREAD_ID`, or if Klaude is refused, ask Gib to run `/pre-mr-review`
from his work account and wait for him. Never fall back to another provider.
3. Read the audit and handoff files it wrote under `.claude/audits/pre-mr/` (the context
script from the repo's `pre-mr-review` skill prints the exact paths), not just the
delegate's summary. Check the `last_reviewed_head` in the audit header matches the
current HEAD. If the branch moved after the run, start a new run before acting on a
stale audit.
4. Read the verdict, and record it on the page with `ticket-page verdict`.
- **Ready to Open MR**: continue to step 8.
- **Almost Ready / Not Ready Yet**: fix what it flagged (each meaningful fix as its own
commit), then start a new run. Repeat until the verdict is Ready to Open MR. Don't
write `mr.md` before that verdict is reached. After three runs with no Ready verdict,
stop and ask Gib how to proceed.
Findings that need no code change (mentions, disclosures) get addressed in
`mr.md`'s Additional Notes or the Jira fields as usual.
**The verdict is the gate and it is not negotiable.** Ready to Open MR is what
goes on record with the Lead, so never reason your way past it because the
remaining items look harmless. That judgment is not yours to make.
**Don't confuse the verdict with the handoff's recommendation.** They are
different fields in different files for different readers. The audit's
`Verdict` says whether the branch is ready to become an MR, and that is the
gate. The handoff's `Recommendation` (`Merge`, `Merge after conditions`) is
advice to the maintainer about merging it, and `Merge after conditions` is
normal and expected at a Ready verdict. Never treat the recommendation as a
blocker or report it as one.
**Reruns converge by giving the audit more, not by repeating the command.** Each run
spends the work account's quota, so make each one count:
- **Feed it context on the first run.** It reviews the diff, and left alone it re-derives
intent from the branch name and re-raises decisions that are already settled. The
scratch file in the task is the cheapest thing that reduces repeat findings.
- **Answer its decisions explicitly in the rerun.** When it parks a finding under "Decide
before opening", write the decision and its reasoning into the next task, so it can
reclassify rather than re-ask. A silent rerun on an unchanged diff re-asks the same
question. A decision that is genuinely Gib's goes to him first.
- **Say so when it finds new things in unchanged code.** That means the earlier run was an
incomplete pass, not that the branch got worse, and it changes how much weight the next
run deserves. Tell Gib at hand-off.
8. Read `~/.agents/skills/ticket/templates/mr.md` — this is the org's MR template,
copied into this skill so it still works even though the original
`.claude/docs/mr/template.md` no longer exists in the command-center repo. `mr.md`
is ONLY the MR description: the filled template plus the pasted pre-MR handoff.
Jira ticket fields are not written here, they go straight into Jira in step 9.
Fill it in for real:
- H1: from the ticket and the actual work done, not the ticket title verbatim if the
real change ended up narrower/broader.
- Summary: one short paragraph max. Open with the problem in plain words, then say
what changed, not how. Lead with why this MR exists rather than an inventory of what
it touches.
- Issue Link: `<JIRA_BASE_URL>/browse/<KEY>`.
- New ENVs: list any env vars actually introduced; "None" if none.
- Additional Notes: a bulleted checklist of the changes you actually made, not a
dumping ground. Between Summary and this section, every acceptance criterion from
the plan (or, for a bug ticket, the bug itself) needs to be directly addressed,
not just gestured at. If there's genuinely unrelated work worth mentioning (e.g.
an incidental fix along the way), it goes after everything ticket-relevant, still
as short bullets. Five bullet points max total, ticket-relevant and incidental
combined. If it doesn't fit in five, it's too much detail for this section, trim
it rather than running long.
- Checklist: check only boxes you actually verified (e.g. only check "Build
verified" if you actually ran a build and it passed).
- Replace `<!-- Paste the Pre-MR handoff here -->` with the exact content of the
latest `pre-mr-review` handoff file (the one with verdict Ready to Open MR) —
paste it verbatim, don't summarize it. Its `Recommendation` line is the
audit's advice to the maintainer and is left exactly as written, including
`Merge after conditions`.
The handoff section of `mr.md` is GENERATED OUTPUT, not something you author.
It is the block that states whether the branch is ready to merge, so it must be
the audit's own words, not a retelling of them. Concretely:
- Never hand-write a handoff section, and never edit one in place. If it is
wrong, thin, or stale, start a new Klaude run (step 7) to regenerate the handoff
file, then re-paste.
- On EVERY rerun, replace the whole existing handoff block with the whole
regenerated one. Do not patch the copy sitting in `mr.md` to match the new
head — that is how the two silently diverge, and the version the reviewer
reads stops being the version the audit actually produced.
- After pasting, verify the tail of `mr.md` is byte-identical to the handoff
file. If it isn't, you edited it.
- The handoff file itself must follow `templates/handoff.md` in the repo's
`pre-mr-review` skill. If real content doesn't fit that structure, the fix is
to write it into the handoff file under the right heading, not to bolt an
extra section onto `mr.md`.
- Developer responsibilities: if the ticket's dev review instructions impose their
own deliverables on the developer (e.g. KACP's standing "document three to five
additional edge cases discovered during implementation, each with its handling
and test, or its deferral and follow-up story"), satisfy them EXPLICITLY, under a
heading that uses the requirement's own words, in the JIRA FIELD that owns them —
not in `mr.md`. In command-center that is the engineer-facing patch notes field
(`customfield_10260`, "For The Engineer: Patch Notes"). Step 9 writes it.
Scattered coverage across notes does not count as having answered a named
requirement, and neither does burying it in the MR description.
Save this as `<target-dir>/mr.md` (next to `index.html`, not under `resources/`), and
record it with `ticket-page mr <KEY>`.
**`mr.md` is the template plus the pasted handoff, and NOTHING ELSE.** This is a
hard shape, not a starting point. Its only headings are the template's own numbered
sections and the handoff's. Do not add narrative sections, however well justified
they feel: no "how I built it", no per-ticket deep dives, no edge-case writeups, no
"Jira Ticket Fields" section, no test tables, no root cause analysis. Those live in
Jira and step 9 puts them there.
Anything you are tempted to add as a section belongs in **Additional Notes**, as one
tight bullet. If it will not compress to a bullet, it is Jira content, not MR
content. A reviewer should be able to read the whole file in about a minute; if it
has grown past roughly 120 lines including the handoff, it has drifted.
Before saving, run the prose bar (see **The prose bar** above) over the Summary and
Additional Notes ONLY. The pasted handoff is generated output and is never edited.
Henry reads every one of these, and prose that reads as machine-generated costs the
MR its credibility before anyone looks at the diff.
9. Fill the Jira ticket fields directly, by issue type. Rich text fields are ADF:
render markdown with `python3 ~/.agents/skills/review-ticket/scripts/review2adf.py
render <file.md>` and PUT via `{"fields": {...}}` to `/rest/api/3/issue/<KEY>`.
After every PUT, re-fetch and verify the field landed, then record it with
`ticket-page jira <KEY> "<field name>"` (compare extracted text,
treating empty `attrs` objects and `localId`/`colwidth`/`width` as noise). The
field-to-type map below is verified against the project's edit screens, don't PUT
a field to a type that doesn't carry it.
**Run the prose bar** (see **The prose bar** above) over every field before rendering
it to ADF, proof and mitigation cells included. Everything here is read by the Lead
and the PM.
**Proof first.** Proof is evidence you observed yourself in this session. Before filling
any proof column, capture it wherever possible, using the most direct form the change allows:
- For a bug, reproduce the failure, apply the fix, and watch the same reproduction pass.
- For UI and runtime behavior, run the app (`run` skill) and look at the real feature.
Green mocked tests do not prove the user experience works.
- For behavior with no UI, capture the test or command output.
**Screenshots and recordings come from T3's browser.** It runs in the thread, so Gib can
watch and sign in without leaving T3. Use one tab and keep its `tabId`:
1. `preview_open` with the app's URL, or `preview_navigate` with
`target: {kind: "environment-port", port}` for a dev server.
2. `preview_resize` to `{mode: "freeform", width: 1280, height: 800}`. Saved screenshots
top out at 1280x800, so a larger viewport comes out downscaled and soft.
3. `preview_wait_for` the thing the proof is about, so the capture never catches a spinner.
Drive any state with `preview_snapshot` refs and `preview_act`: open the dialog, fill the
form, trigger the warning. Use `preview_set_appearance` for dark mode.
4. `preview_snapshot` with `save: true`, then copy `screenshotPath` into `proof/`.
5. For a flow a still cannot show, `preview_recording_start`, drive it, then
`preview_recording_stop` and copy the mp4 from its `path` into `proof/`. Keep it short:
a recording caps at 50 MiB.
6. `t3_preview_close` when the proof is done.
- **Sign-in.** If the tab lands on a sign-in page, ask Gib with AskUserQuestion to sign in in
that tab, then continue. Do not drive a login yourself.
- **Look before you record it.** Read every capture with the Read tool. A crisp picture of
the wrong screen is still wrong.
- **The fallback.** Use `capture-proof` when the screen is too dense to read at 1280x800, when
the proof needs a full page or an element crop, or outside T3 Code. It renders at 2x with
animations frozen and dev overlays hidden:
```
capture-proof shot http://localhost:3000/companies --wait-for "text=Canonical ID" --out <target-dir>/proof/companies-grid-canonical-ids.png
```
Pass `--selector` to crop, `--full` for the whole page, and `--script` for clicks and
typing. It keeps its own session, so the first `shot` against an app that needs one stops
with a sign-in hint: ask Gib to run `capture-proof login <origin>`. That hint only catches a
redirect to a sign-in path.
Save artifacts under `<target-dir>/proof/` with names that match the test-case
rows they prove, and put each on the page with `ticket-page proof`, naming the
criteria it proves and the mock it answers. A proof cell references its artifact by filename plus "attached"
(Gib uploads every attachment, this skill NEVER uploads files to Jira) or names
the passing test. When proof genuinely can't be captured here (needs prod, a real
inbox, a flag flip), the cell says exactly what's needed and step 10 lists it for
Gib. A row with no proof and no named gap is missing work, not a documentation
gap: go run the check first.
**Cap the proof at five files, and aim for two or three.** Gib uploads every
attachment by hand, so each file has a real cost and a wall of near-duplicate
screenshots buries the two that matter. Before filling the proof column, pick the
smallest set that actually carries the evidence, delete the rest from `proof/`, and
drop them from the page with `ticket-page unproof`.
- One screenshot can prove several rows at once. A company page that shows the
navigation, the tabs, and the absent section proves three criteria in one image,
so prefer it over three separate captures.
- Prefer text over images wherever the evidence is textual. Command output, a
config diff, a grep result, or a list of rendered labels all belong in a single
`.txt` file, which is cheaper to attach and easier to read than a screenshot of
the same thing. Fold what a dropped screenshot proved into that file rather than
losing the evidence.
- Capture as many as you like while working. The cap applies to what survives in
`proof/` when you fill the Jira fields, not to what you take along the way.
- Never reference a file in a proof cell that is not in `proof/`, and never leave a
file in `proof/` that no proof cell references. The two lists match exactly.
**Bug** (fields on the Bug edit screen):
- `customfield_10259` For the Engineer: Root Cause Analysis: the actual diagnosed
cause as a short narrative naming the real files and mechanism, not the ticket's
theory.
- `customfield_10263` Precipitating Event: what introduced or exposed the bug and
when (the commit, upgrade, or change that made it start happening).
- `customfield_10260` For The Engineer: Patch Notes: changelog-style statement of
the fix.
- `customfield_10142` Working Feature Proof: the test-case table (Summary, Steps,
Expected Results, Working Feature Proof, Notes) with the real scenarios verified
and the proof column filled.
**Story** (fields on the Story edit screen):
- `customfield_10253` Test Cases & Working Feature Proof: ALWAYS fetch and read
this field, whoever wrote the dev review, and no matter what state it's in.
Whatever rows it carries are the scenarios to prove: fill the empty Working
Feature Proof cells of the existing rows in place, never duplicate rows. If the
field is still a bare template with no rows, add the real scenarios verified as
new rows. New rows go through `review2adf.py tables <field.json> <rows.md>`,
which preserves the instruction panels and headers.
- `customfield_10129` Risk Mitigation: same in-place treatment for the Mitigation
Proof column.
- `customfield_10260` Engineer Patch Notes: changelog-style, what changed. This is
also where the dev review instructions' own developer deliverables go, under a
heading in the requirement's own words. For KACP that is the standing "three to
five additional edge cases discovered during implementation", each with how it was
handled and what covers it. Deliver the number asked for, not more, and pick the
ones a reviewer most benefits from. This field, not `mr.md`.
- `customfield_10261` User Story Patch Notes: the same change in user-facing words.
- `customfield_10142` Working Feature Proof: leave it alone. Write nothing here.
This field is where Gib drops the proof attachments, and dragging files into it
replaces whatever text is sitting there, so a written list is destroyed by the
upload it was describing. Naming each artifact is already the job of the Test
Cases proof cells, which reference it by filename. Step 10 tells Gib which files
to upload. Do not PUT this field on a Story.
**Spike** (deliverables, not code): no test or proof fields to fill. The output is
the deliverables directory, and step 10 tells Gib which files to upload where (the
ticket, Drive, or both, per the ticket's instructions). Fill `customfield_10260`
only if the spike actually shipped code.
Before moving on, re-read the Ticket tab's test case and risk tables row by row: every
test case and every risk the ticket carries now has its developer column filled in
Jira. Leave none
unanswered.
10. Tell the user: implementation is committed on `<branch>`, `pre-mr-review` verdict is
Ready to Open MR, the Jira fields are filled (name which), `mr.md` is ready at its
path, and the ticket page shows the finished work beside its mocks. Show
`ticket-page view <KEY> progress` in the thread, embed each proof screenshot by absolute
path as `![caption](path)`, and link `mr.md` and the page path. Name any council seat that
could not run, and list the nits you declined as follow-ups. Then the manual list, which should only ever be:
- push the branch, open the MR, and paste `mr.md` in as the description
- upload the named proof or deliverable files (from `proof/` or `deliverables/`)
to the ticket, plus anything flagged as proof only Gib can capture
Remind them nothing was pushed, no MR was opened, and no attachments were uploaded.
## Resuming mid-implementation
If Phase 0 routes here because some steps are already done on the page: check
`git log` on the current branch against the page's step commits to sanity-check they actually
match reality (a checked-off step should have a corresponding commit), then show
`ticket-page view <KEY> progress` in the thread and continue from the first open step.
If the plan and the git history disagree, stop and ask the user rather than guessing
which one is right.