Ticket Lifecycle Workflow

Complete workflow from starting a ticket to delivering work.

Prerequisites

GitHub Issues

Workflow Overview

In GitHub Issues, tickets flow through these statuses:

  1. Backlog - New issues created by anyone. Product maintains the backlog, ordering items so top items are ready to work on.
  2. Ready - Tickets ready to be picked up. Both Product and Engineers can move tickets from Backlog to Ready.
  3. Planning - Engineer is planning the implementation (auto-transitioned when you run wseng start).
  4. In Progress - Active development (auto-transitioned when you save your plan via wseng ws save-plan).
  5. Review - Code is ready for review. PRs are linked via keywords (automatically) or manually in GitHub UI.
  6. Done - Development complete, awaiting product acceptance.
  7. Accepted - Product has accepted the work.

Project Board

All tickets across products and teams are tracked in a single GitHub Project. Tickets created in any of our repositories automatically appear here.

Built-in views:

View Scope Description
My Board Personal Kanban board of your active tickets
My Backlog Personal Your upcoming/unstarted tickets
Completed by me Personal Tickets you've finished
Board Team-wide All active tickets across the department
Backlog Team-wide All upcoming tickets across the department
Completed Team-wide All completed tickets across the department

Custom views: Each team or project can create additional views by clicking "Add view" in the project. Filter by labels, assignees, milestones, or any combination to match your workflow.

Working with Ticket Fields

Ticket data lives in three places: project custom fields on the right-hand panel, a computed fields comment, and an output comment. Each has different editability and purpose.

Project Custom Fields

All issues across all products and teams share a single GitHub Project (#553). Custom fields are visible and editable from the right-hand panel in GitHub Issues — expand the project section to see them.

Field Type Description Auto-managed
Status Single select Workflow status Mostly — CLI transitions it, but you can change it manually too
Project Single select Product assignment (e.g., WS, Acely) Yes, defaulted on creation
Priority Single select Issue priority Yes, defaulted on creation
Story Points Number Effort estimation No, set by the platform estimator; wseng ws infer-breakdown estimates on demand
Demo Recording URL Text Link to demo video Yes, set by wseng demo
Demo Environment URL Text Link to deployed demo environment Yes, set by CLI
Estimation URL Text Link to estimation/plan PR Yes, set by wseng ws save-plan
RCA URL Text Root cause analysis document link Yes, set by CLI
Epic Design URL Text Epic design document link Yes, set by CLI
Completed At Date When work was completed Only by an explicit wseng tk update-computed-fields run
Accepted At Date When work was accepted Only by an explicit wseng tk update-computed-fields run

Most fields are auto-filled or defaulted by the CLI. Status is the one you'll change manually most often. Completed At and Accepted At exist as project fields (rather than only in the computed fields comment) so they can be used for sorting and filtering in project views. They are written only when someone runs wseng tk update-computed-fields by hand; nothing sets them on a status transition.

Computed Fields Comment

A read-only comment marked with <!-- TICKET_COMPUTED_FIELDS --> that the CLI writes when a computed-fields command runs. Nothing recomputes it automatically: issue creation and board transitions no longer trigger it, because the platform derives implementer and reviewer itself and the CLI heuristics posted wrong values. It renders as a markdown table:

Field Source
Implementer PR author, falling back to GitHub assignee history
Reviewer QC assignment
Approver Timeline
Created At Issue creation date
Completed At Status transition to Done
Delivered At Status transition to Delivered
Accepted At Status transition to Accepted
LoC Code change stats
LoC - AI AI-generated code stats
QC Status QC workflow outcomes (e.g., First Time Pass ✅, Failed ❌)

Do not edit this comment. These fields update when you run CLI workflow commands (wseng qc start, wseng qc pass, and the other wseng qc outcomes) or explicitly via wseng tk update-computed-fields. Board status moves alone no longer trigger recomputation.

Correcting a wrong Implementer, Reviewer or Approver

Editing the comment by hand does not work — the next recomputation overwrites it. Implementer, Reviewer and Approver are all preserved once set, so all three can land wrong and stay wrong. Correct any of them with:

wseng tk set-computed-field <repo>/<number> --field implementer --value <github-username> --production --reason "<why>"
wseng tk set-computed-field <repo>/<number> --field reviewer    --value <github-username> --production --reason "<why>"
wseng tk set-computed-field <repo>/<number> --field approver    --value <github-username> --production --reason "<why>"

wseng tk set-implementer ... --implementer <github-username> still works as an alias for the first form.

Things to know before using it:

  • An Implementer or Approver override is one-way. Once set, wseng tk update-computed-fields preserves the manual value and stops recomputing that field for that ticket, and no command restores automatic recomputation — the only way out is another set-computed-field naming a different person. Get it right the first time.
  • A Reviewer override is weaker. It survives only while the ticket’s second assignee is unchanged: if a different second assignee appears, the sticky-reviewer logic replaces your value with that person on the next update-computed-fields run. Re-run the command if that happens.
  • The username must be on the team roster. The command refuses a GitHub login it cannot find, because a typo would silently drop the ticket's story points from every engineer's leaderboard total rather than fail. Note the asymmetry with the automation, which can store an off-roster login (it falls back to the raw PR-author login when that person is not on the roster): such a value cannot be reproduced or restored with this command.
  • --production is not the default. Without it the command reads and writes the test spreadsheet, so a real row stays wrong.

The command records the previous value, the new value and your reason as a comment on the ticket, so a later reader can tell a deliberate correction from a stuck one. That note is only posted for a --production run, since a test-spreadsheet write does not change the row anyone reads.

Only the field you name is written; every other column in the row survives untouched.

Note on the computed-fields comment. Any command that writes computed fields refreshes the TICKET_COMPUTED_FIELDS comment only when --production is passed. A test-spreadsheet write leaves the real ticket alone rather than publishing test values onto it, and the commands tell you which of the two surfaces actually changed.

If the comment sync fails after the row was written, re-run the same set-computed-field command with --production: it republishes the comment from the stored row even though the row itself no longer needs changing.

Output Comment

A comment at the top of the issue marked with <!-- TICKET_OUTPUT_SECTION -->. The CLI creates it automatically when you start a ticket so it stays pinned near the top of the conversation, not buried under activity.

What to put here:

  • Testing instructions for reviewers
  • Links to deployed environments
  • Key implementation notes

Note: demo video links go in the Demo Recording URL project custom field, not here. The Output section is for content that doesn't fit a single URL field — detailed testing steps, multiple environment links, etc.

How to edit: Find the comment with the # Output header on the issue, click the ··· menu → Edit. Keep the HTML marker as the first line:

<!-- TICKET_OUTPUT_SECTION -->
# Output
## Testing Instructions
1. Run `npm test` to verify all tests pass
2. Start dev server: `npm run dev`
3. Navigate to http://localhost:3000/profile
4. Verify the new profile icon appears

CLI automation: Commands like wseng demo and wseng changelog automatically prepend content to this comment with a --- separator. Your manual content is preserved below.

wseng finish writes here, not into the issue body. wseng finish pushes your local .context/output.md into this marked comment (creating it if missing). Never write an Output section into the issue description — the marked comment is the single home for Output content, and automation (including Nex) looks for it there.

output.md house style: keep it scannable — flat key: value lines for the facts (environment URLs, test credentials, relevant links), plus at most one short prose paragraph (e.g. testing instructions). The comment layout is:

<!-- TICKET_OUTPUT_SECTION -->
# Output
Environment: https://pr123.example.dev
Test user: learner@example.com / <see secrets>

To verify: enrol in any course, submit the assignment, confirm the grade email arrives.

Time Tracking

Time tracking is not managed in GitHub. Previously tracked via Jira custom fields (billed time, etc.), these metrics now live in the Personal Dashboards spreadsheet, which includes delivery metrics, time spent breakdowns, and per-ticket efficiency data.

Non-Interactive Use (--ci)

Several lifecycle commands prompt interactively — start-ticket asks about deleting stale branches during git-sync, finish asks whether to transition the ticket to Review. In a non-interactive shell (scripts, agents, CI), those prompts crash or hang the command, and a crash mid-start-ticket can leave the ticket transitioned with no branch or PR created.

Pass the global --ci flag to disable all interactive prompts:

wseng start-ticket my-repo/123 --ci
wseng finish --ci

Use --ci on every wseng invocation that runs unattended.

The Standard Flow

# 1. Start ticket (transitions Backlog/Ready → Planning)
wseng start ws-eng-cli/123
# Or just use issue number if in current repo:
wseng start 123

# 2. Plan implementation
# Edit .context/plan/plan.md with your approach

# 3. Save plan (transitions Planning → In Progress)
wseng ws save-plan

# 4. Make code changes

# 5. Commit
wseng commit

# 6. Generate changelog
wseng changelog

# 7. Record demo
wseng demo

# 8. Move ticket to Review (manual in GitHub UI)

Step 1: Start the Ticket

wseng start ws-eng-cli/123
# Or just the issue number if working in the repo:
wseng start 123

What this does:

  • Creates branch and pull request
  • Downloads ticket description to .context/ticket.md
  • Auto-generates blank plan at .context/plan/plan.md
  • Transitions ticket from Backlog or Ready to Planning status
  • Links PR to the issue (via keywords)

Step 2: Write the Plan

Open .context/plan/plan.md and document your implementation approach. Use Cursor or your IDE to explore the codebase and understand requirements from .context/ticket.md.

Good plan structure:

## Files to Create/Modify

- src/services/user.service.ts
- src/resolvers/user.resolver.ts

## Implementation Steps

1. Add getUserProfile method to UserService
2. Expose via GraphQL resolver
3. Add unit tests for service
4. Add E2E test for GraphQL query

Step 3: Save the Plan

wseng ws save-plan

Saves plan to repository and transitions ticket from Planning to In Progress.

Step 4-6: Implement, Commit, Document

Make your changes, then:

# AI-generated commit messages
wseng commit

# Generate summary of changes
wseng changelog

Step 7: Record Demo

wseng demo

Records screen with OBS Studio, uploads to Google Drive, links to ticket/PR. See command reference for OBS setup.

Common Variations

NO-TICKET branches:

wseng start NO-TICKET "quick fix description"

Create new ticket:

wseng start NEW "feature description"

This creates a GitHub Issue in the current repository. The issue is automatically added to the shared GitHub Project, and ticket types/defaults are filled automatically.

Sub-Issues (Subtasks)

GitHub sub-issues are hierarchical - you can create sub-issues of sub-issues up to 8 levels deep, with up to 100 sub-issues per parent. Sub-issues can span repositories (parent and child can be in different repos).

Create sub-issue via CLI:

wseng subtask ws-eng-cli/123 --type backend --start

Create sub-issue via GitHub UI:

Click the "Create sub-issue" button at the bottom of any issue description. You can also add existing issues as sub-issues via the dropdown.

Auto-create sub-issues from plan:

The save-plan command can automatically create sub-issues if you set subtasks: true in the plan frontmatter.

Key differences from old Jira subtasks:

  • Sub-issues are fully-featured issues (not a limited subtask type)
  • Hierarchical: sub-issues can have their own sub-issues
  • Cross-repo: parent and child issues can be in different repositories
  • Progress tracking: GitHub Projects shows sub-issue completion progress automatically

Ticket ID Format

GitHub Issues use the format repo/number (e.g., ws-eng-cli/123). If you're working in the current repository, you can just use the issue number (e.g., 123). This can be overridden using project-level or repository-level configuration.

Common Pitfalls

❌ Bad: Starting ticket assigned to someone else

wseng start ws-eng-cli/123
# Error: Ticket assigned to another engineer

Solution: Use --force-assignment to override.

❌ Bad: Skipping the plan

Starting to code immediately without writing a plan leaves the ticket in "Planning" status and makes story point calculation inaccurate.

Solution: Always write and save your plan before coding. It forces you to think through the approach.


RCA Workflow

Special workflow for bugs requiring root cause analysis.

Code Review Workflow

What happens during QC and how to address feedback.

Command Reference

Full reference for all commands used in this workflow.