Problem
Several skill output formats render a ticket reference in human-facing headings, and each site re-derives the display form on its own. Today the rule "if ticket_ref_prefix == '#', prepend #; else use ticket_id as-is" is implicit at every site:
summarize-change: # {TICKET} {title} (line ~44) — {TICKET} is an undocumented placeholder.
review-change: # Code review: {TICKET}: {description} (line ~66, branch scope).
review-change: # Commit review: {TICKET} [{WORK_TYPE}] - {description} (line ~143, commit scope).
respond-to-review: # Change summary: {TICKET}: {description} (line ~84).
create-ticket: # {ticket_id}: {title} (line ~139) — uses {ticket_id} literally, which silently produces # 461: Foo on GitHub-style projects (missing the # sigil). Latent bug.
#461 introduced ticket_ref to get-session-context as the canonical display form. Now that it exists, all five sites should consume it.
Context
ticket_ref is the rendered display form: '#' + ticket_id when ticket_ref_prefix == '#', equal to ticket_id for Jira-style IDs, and null when no ticket is in session. It is exposed by get-session-context and consumed by create-pr (for the body's Closes line, shipped in #461). Heading sites are the next-largest cluster of consumers.
Solution
- Reader sites (
summarize-change, review-change ×2 templates, respond-to-review): in the step that calls get-session-context, add ticket_ref to the obtained fields.
- Writer site (
create-ticket): after step 5 assigns the new ticket's ticket_id, compute ticket_ref using the same logic as get-session-context: if ticket_ref_prefix == '#', then ticket_ref = '#' + ticket_id; otherwise ticket_ref = ticket_id. Both inputs are already in scope from step 1; no new lookup is needed. get-session-context is not the source here because the ticket ID doesn't exist when create-ticket is invoked.
- Replace the implicit display-form placeholder with
{ticket_ref}:
summarize-change: # {TICKET} {title} → # {ticket_ref} {title}.
review-change (both scopes): {TICKET} → {ticket_ref}.
respond-to-review: {TICKET} → {ticket_ref}.
create-ticket: # {ticket_id}: {title} → # {ticket_ref}: {title}. Fixes the latent bug where the heading on GitHub-style projects was missing the # sigil.
- Document the null case for each reader site: when
ticket_ref is null (no ticket on the branch), omit the {ticket_ref} portion so the heading reads naturally without it. Not applicable to create-ticket, which always assigns or auto-generates an ID.
- Where the skill has a worked example or narrative, update it to reference
ticket_ref rather than implicitly hand-rolling #.
YAML frontmatter (ticket_id: '461') remains unchanged — frontmatter is machine-readable and uses the storage form. File paths (tickets/{ticket_id}/) also remain unchanged — # is invalid in paths.
Out of scope
- Other display contexts not enumerated above. They're migrated as they're identified.
- Title-prefix decoration for PRs/commits (e.g.,
pr.ticket_prefix with {id} template substitution). Tracked separately.
Acceptance criteria
Depends on
Problem
Several skill output formats render a ticket reference in human-facing headings, and each site re-derives the display form on its own. Today the rule "if
ticket_ref_prefix == '#', prepend#; else useticket_idas-is" is implicit at every site:summarize-change:# {TICKET} {title}(line ~44) —{TICKET}is an undocumented placeholder.review-change:# Code review: {TICKET}: {description}(line ~66, branch scope).review-change:# Commit review: {TICKET} [{WORK_TYPE}] - {description}(line ~143, commit scope).respond-to-review:# Change summary: {TICKET}: {description}(line ~84).create-ticket:# {ticket_id}: {title}(line ~139) — uses{ticket_id}literally, which silently produces# 461: Fooon GitHub-style projects (missing the#sigil). Latent bug.#461 introduced
ticket_reftoget-session-contextas the canonical display form. Now that it exists, all five sites should consume it.Context
ticket_refis the rendered display form:'#' + ticket_idwhenticket_ref_prefix == '#', equal toticket_idfor Jira-style IDs, andnullwhen no ticket is in session. It is exposed byget-session-contextand consumed bycreate-pr(for the body'sClosesline, shipped in #461). Heading sites are the next-largest cluster of consumers.Solution
summarize-change,review-change×2 templates,respond-to-review): in the step that callsget-session-context, addticket_refto the obtained fields.create-ticket): after step 5 assigns the new ticket'sticket_id, computeticket_refusing the same logic asget-session-context: ifticket_ref_prefix == '#', thenticket_ref = '#' + ticket_id; otherwiseticket_ref = ticket_id. Both inputs are already in scope from step 1; no new lookup is needed.get-session-contextis not the source here because the ticket ID doesn't exist whencreate-ticketis invoked.{ticket_ref}:summarize-change:# {TICKET} {title}→# {ticket_ref} {title}.review-change(both scopes):{TICKET}→{ticket_ref}.respond-to-review:{TICKET}→{ticket_ref}.create-ticket:# {ticket_id}: {title}→# {ticket_ref}: {title}. Fixes the latent bug where the heading on GitHub-style projects was missing the#sigil.ticket_refis null (no ticket on the branch), omit the{ticket_ref}portion so the heading reads naturally without it. Not applicable tocreate-ticket, which always assigns or auto-generates an ID.ticket_refrather than implicitly hand-rolling#.YAML frontmatter (
ticket_id: '461') remains unchanged — frontmatter is machine-readable and uses the storage form. File paths (tickets/{ticket_id}/) also remain unchanged —#is invalid in paths.Out of scope
pr.ticket_prefixwith{id}template substitution). Tracked separately.Acceptance criteria
{ticket_ref}in their heading templates. The four reader sites (summarize-change,review-change,respond-to-review) obtain it fromget-session-context;create-ticketcomputes it locally as'#' + ticket_idwhenticket_ref_prefix == '#'(elseticket_id) after the remote ticket is assigned.{ticket_ref}portion).create-ticket's heading produces# #461: Fooon GitHub-style projects (where it previously produced# 461: Foo).ticket_refrather than hand-rolled#prepending.Depends on
Closesline to PRs and centralize ticket-ID display form #461 (introducesticket_ref). ✅ Merged in 18e97c6.