Files
Panama/user/agents/skills/ticket/SITE.md
T

146 lines
8.4 KiB
Markdown

# The ticket page
Every ticket this skill works has a **ticket page**, and every epic has an **epic index**. The
page is where Gib follows the work: the ticket as Jira has it, the plan, live progress, proof
beside the mocks, and the review. It updates while you work, so a write you skip is a gap he
sees. It is a personal working file, exempt from the prose bar like the rest of `.claude/docs/`.
```
.claude/docs/epics/
_site/site.css, site.js # shared renderer, refreshed from templates/site/ on every write
<EPIC-KEY>/
index.html, epic.data.js # the epic index, in build order
<TICKET-KEY>/
index.html, ticket.data.js # the ticket page
resources/ proof/ deliverables/ mr.md
tickets/<TICKET-KEY>/ # same shape, for a ticket with no epic, and no index
```
## Write through `ticket-page`, always
`~/.agents/skills/ticket/scripts/ticket-page` is the only writer of the data files. It validates
before every write and refuses a broken one, writes atomically so the open page never reads half
a file, appends each change to the page's live log, and keeps the ticket's row on the epic index
current. Editing a `.data.js` file by hand skips all four. `ticket-page help` lists every
command and its flags.
It finds the ticket by key under the current repo's `.claude/docs/epics/`, so run it from inside
the repo.
## What to record, and when
| Moment | Command |
|---|---|
| Issue fetched to a scratch path | `init <KEY> --issue <issue.raw.json>`. Prints the ticket folder, then any populated Jira fields the page does not show. |
| Attachments downloaded, a video transcribed, frames extracted | `scan <KEY>` |
| Ticket branch resolved, ticket classified | `meta <KEY> --branch <name> --classified bounded` |
| Research notes worth keeping: what a video says, what a spreadsheet holds, a check against prod | `note <KEY> "<Title>" --file notes.html` |
| Plan written | `plan <KEY> --file plan.json`, then one `mock` per artboard |
| Plan approved, Phase 2 begins | `approve <KEY>` |
| Starting a step | `step <KEY> <n> running` |
| A step's commit exists | `step <KEY> <n> done --commit <sha>`, one `--commit` per commit |
| A criterion is met | `criterion <KEY> <ID> done --evidence "<what shows it>"` |
| Proof captured, or dropped from `proof/` | `proof <KEY> --file proof/<name> --proves AC1,AC3 --caption "<test case>" [--mock <id>]`, `proof <KEY> --test "<name>" ...`, `unproof <KEY> <file>` |
| Reviewer finding, and its resolution | `finding <KEY> add "<text>" --severity CONFIRMED --where <file:line>`, then `finding <KEY> F1 fixed --commit <sha>` or `rejected --reason "<why>"` |
| pre-mr-review audit read | `verdict <KEY> <verdict text> --recommendation <R> --head <sha>` |
| A Jira field PUT and verified | `jira <KEY> "<field name>"` |
| `mr.md` written | `mr <KEY>` |
| Anything else Gib would want to see happen: suite green, a surprise, a blocker | `event <KEY> "<text>"` |
A step is done when its commit exists and `ticket-page show <KEY>` lists that commit beside it.
`step done` refuses without `--commit`. A step with nothing to commit, such as a verification
pass, takes `--no-commit`.
## `plan.json`
The plan is one JSON file, written with the Write tool and loaded with `ticket-page plan`. Prose
fields are HTML fragments: `<p>`, `<b>`, `<code>`, `<ul><li>`. `plan` replaces any earlier plan
and clears its progress and proof, because a rewritten plan is a restart. To change a plan
mid-build (a new step, a reworded criterion), print it with `plan-json <KEY> > plan.json`, edit
that, and load it with `plan --amend`: steps whose number and text are unchanged, and
criteria whose id remains, keep their progress, and proof keeps the criteria that still exist.
```json
{
"criteria": [
{ "id": "AC1", "text": "Every company can carry a five character canonical ID.", "steps": [1, 2] },
{ "id": "AC2", "text": "A duplicate canonical ID is rejected with a readable message.", "steps": [3] }
],
"questions": [],
"approach": "<p><b>Company.canonicalId</b> is the only new state. The engagement ID is derived by <code>formatEngagementCanonicalId</code>, so the two cannot drift.</p>",
"decisions": [["Engagement canonical ID", "Derived at read time", "Matches the spreadsheet formula, with no second column to backfill."]],
"steps": [
{ "n": 1, "text": "Add the canonicalId module, tests first.", "tdd": true },
{ "n": 2, "text": "Schema, migration and backfill." },
{ "n": 3, "text": "Map the unique violation to CONFLICT.", "tdd": true },
{ "n": 4, "text": "Canonical ID field on the company form.", "kind": "mock" }
],
"risks": [
{ "risk": "Two companies given the same code", "handling": "The unique index blocks it and step 3 returns a readable CONFLICT.", "criteria": ["AC2"], "fromTicket": true }
],
"tests": [
{ "kind": "integration", "text": "companies.update with a taken code throws CONFLICT.", "criteria": ["AC2"] }
]
}
```
- Steps are numbered 1 to N in order. `kind` is `code` (the default), `mock`, or `deliverable`.
- Every criterion names the steps that satisfy it. Risks and tests name the criteria they cover.
- A risk or test that comes from the ticket's own table carries `"fromTicket": true`. Your own
additions leave it off, so the page shows which rows the ticket asked for.
- `questions` holds only what genuinely needs Gib's answer, each as a direct question. Empty
means none.
## Mocks
When a step changes what a user sees (a new screen, a changed layout, a new control, copy a
user reads), the plan carries mock artboards:
```
ticket-page mock <KEY> <id> --title "<screen>" --criteria AC3,AC8 --note "<what the build will not do>" --file artboard.html
```
- An artboard is a complete small HTML document with its own `<style>`, rendered in a sandboxed
frame beside the proof. Draw the screen state the plan introduces, with the app's real
navigation and density around it rather than a wireframe of boxes.
- One artboard per new screen state. When the direction is Gib's call, draw each candidate as
its own artboard (`option-a`, `option-b`) and ask the choice in `questions`, naming the
artboards. This is how the house rule of several static mocks before touching real components
is met inside the ticket flow.
- `--criteria` names what the artboard illustrates. The Progress tab shows it under those
criteria, and replaces the empty half with the proof once a `proof ... --mock <id>` lands.
- `--note` states what the artboard shows that the implementation will not do.
- A spike deliverable's polished mocks (see **Mocks and datamodel changes**) can start from the
approved artboard. The built screens are still screenshotted for real.
## The epic index
The index lists the epic's stories in build order: the order they should be completed in, which
is not key order and not always the Jira link graph. Each worked ticket keeps its own row current.
The rest of the index is yours to seed and keep true.
- **Seed it** the first time a ticket under the epic is worked, and refresh it on later runs.
Search the epic's children (`parent = <EPIC> ORDER BY rank`). For each, record the title, the
estimate as `--hours`, the Story Risk Level as `--risk`, the stories it is blocked by as
`--after`, and `--status done` if Jira says Done: `ticket-page epic <EPIC> story <KEY> ...`.
Closed spikes go in with `epic <EPIC> closed <KEY> --title T`.
- **Set the order** with `ticket-page epic <EPIC> order <KEY> <KEY> ...`, listing every story. If
the epic already records a build order (a `summary.md` or plan in its folder), that order wins.
Otherwise order by the blocked-by links, then Jira rank. Write the reasons the order is what it
is with `epic <EPIC> why --file reasons.txt`, one reason per line.
- **Gib reorders by asking.** When he does, rerun `order` and update `why`.
- A story is marked done only by `--status done`, once it has merged or Jira says Done. The index
never guesses that.
## Reading it as an agent
`ticket-page md <KEY>` prints the ticket and the plan as markdown. Use it when you resume a
ticket, and hand it to the fresh reviewer as the ticket and plan in its reading order.
## Tickets from before the page
Tickets planned before the page existed have `resources/ticket.md` and `plan.md` and no
`ticket.data.js`. Leave those files alone. When Phase 0 resumes such a ticket, convert it
first: `init` from `resources/issue.raw.json`, `plan` from the plan's content, then `approve` and
`step ... done` for each step `git log` shows committed. From then on the page is the record.