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

8.4 KiB

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.

{
  "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.