Assignee is not "who owns this". It is who has to act next.
The ticket is a ball. Assignee is whoever is holding it right now.
If you transition a ticket and do not change the Assignee, you have thrown the ball and left your own name on it.
Assignee — changes at almost every transition
Standard Jira field. The single person who must do the next thing. It changes six or seven times over a ticket's life — from PO, to Tech Lead, to the engineer, to QA, to DevOps, back to the engineer, and finally back to the requester.
Developer — set once, never changes
customfield_10148, a user array. The engineer who wrote the code. Set once, at Evaluation → To Do, and never touched again — not when QA rejects, not when it ships. It is how the standup dashboard groups work, and it is why a rejected ticket still shows up under the right person.
Every rejection is exactly three moves, in this order
-
Comment
What you did, what you expected (quote the acceptance criterion verbatim), what actually happened, the evidence, the environment and the build. Written before anything else, so the reason is attached to the ticket and not to a Slack thread.
-
Reassign
Set Assignee to the person who must act — normally the engineer named in the Developer field. Leave the Developer field alone. It is not a punishment field; it is a grouping field.
-
Transition
Move the status last. Doing it in this order means the ticket is never visible in a new column with the wrong face on it, not even for a second.
Two of three is worse than none. A transition without a reassign produces a ticket that looks handled and is not. A reassign without a comment produces an engineer who has the ball and no idea why. If you cannot do all three, do none and go and talk to the person.
Six actors. Each has a role to play on the same infinite loop.
Product Owner
Tech Lead
Developer
Reviewer
QA Engineer
DevOps / ReleaseNames below are placeholders — swap in your own on the day. What matters is the role, the columns it owns, and the line it must not cross.
| Role | Owns | Never |
|---|---|---|
Ana / Fernanda |
The Backlog, Refinement, Release Verification and Done. Writes acceptance criteria, sets priority, decides what gets refined and what gets parked. The last signature before Done. | Never estimates on the team's behalf, never assigns a developer, and never closes a ticket they have not seen working on production. |
Hector / Abdullah |
Planning, Evaluation and Ready for Tech. Sets the Developer and Assignee fields at the To Do handover. Signs off production health after a release. | Never lets a ticket into To Do with an empty Developer field, and never uses the hotfix door on ordinary work. |
Hector / Abdullah / Afaq / Adnan / Nadeem / Hamid / Sajaad |
To Do and In Progress. Writes the code and the tests, keeps the pipeline green, opens the PR, addresses review, merges, and hands over to QA with notes. | Never moves their own ticket past Ready for QA. Never transitions to Ready for QA without reassigning to QA in the same breath. |
Hector / Abdullah / Afaq / Adnan / Nadeem / Hamid / Sajaad |
A peer engineer. Owns the pull request, not a Jira column. Approves or requests changes, and is the second pair of eyes on anything touching auth, money or migrations. | Never merges someone else's PR for them, and never approves a PR whose checks are red. |
Pablo |
Ready for QA and In QA. The only actor who decides pass or reject. Verifies every acceptance criterion, hunts the edges, and attaches the evidence either way. | Never fixes the code, never re-estimates, never passes something on a hunch, and never quietly opens a Bug instead of rejecting. |
Hector / Abdullah / Afaq / Adnan |
Ready for Prod Release and Cloud (Pre-Production). Batches the release train, cuts the tags, runs the production pipeline, owns the rollback decision. | Never decides whether a feature is correct — that is QA's call, then the requester's. Never moves on a partially-green run. |
-
01
Backlog → Refinement
- Triaged and deduped
- Issue type set
- Priority set
- Parked out loud if not next
- No estimate, no sprint, no developer — not at this station
Stays with the PO, or unassigned · Ideas Backlog
-
02
Refinement → Planning
Write numbered, verifiable acceptance criteria and name every affected portal and service. The Tech Lead adds the technical note. Split anything bigger than a sprint.
Stays with the PO
-
⋮
Nine stations in other hands — 03 Planning to 11 Ready for Tech
-
12
Release Verification → Done or ⛔ To Do
Walk the acceptance criteria against production — a real customer org, real volumes, the real role.
Unchanged — the requester closes it
-
01
Backlog → Refinement
- Search before you create. Open
JNETtickets first, the Ideas Backlog second. A duplicate gets linked, never silently closed — the requester is watching the one they filed - One user, one problem, one outcome. Two problems is two tickets — a ticket with two acceptance sets cannot be rejected by half
- Issue type, decided not defaulted. Story for a user-visible change, Bug for something that worked and stopped, Task for work with no user-visible outcome, Epic as a container only
- Priority is an order, not a mood. If two things are highest, neither is — Planning reads this column to sequence
- Name the requester in the ticket. Station 12 hands it back to them, so "someone asked in Slack" leaves nobody to close it
- No estimate, no sprint, no developer, no solution — every one of those belongs to a later station, and guessing one here is what Evaluation sends back
Stays with the PO, or unassigned · Ideas Backlog
- Search before you create. Open
-
02
Refinement → Planning
- Every criterion numbered, and verifiable by someone else. "Works for at least 50 patents in one request" passes or fails. "Works fast" needs Ana in the room to adjudicate
- Every affected portal and service named.
organizer-portal,documents-manager-api— by repository, not by feature — this is what Planning sequences and Evaluation prices - The technical note is in, from someone who could build it. Refinement is not finished because the PO finished writing
- Designs attached to the ticket. A mock-up in a Slack thread is not on the ticket
- Bigger than a sprint means split it here. If it will not split, it is an Epic and the first slice comes out now
- Read it as a stranger. If it only makes sense to someone who was in the refinement call, it is not refined — To Do is where questions are still free, but only the ones this ticket left answerable
- No open question that blocks a start — a blocker sitting in a comment is not refined, it is parked with extra steps
Stays with the PO · Definition of Ready is this list
-
↳
/plan /agile-product-owner<the request, in the requester's words>Drafts the numbered criteria and hands back the questions it could not answer — which is the list to take into refinement, not skip it with.
-
03
Planning → Evaluation
Sequence it against its dependencies and set the target sprint. Confirm nothing blocking sits ahead of it.
Stays with the Tech Lead
-
04
Evaluation → To Do
Estimate story points, confirm the capacity exists, and name the engineer. An estimate that surprises anyone goes back to Refinement.
⚑ Both Developer and Assignee set to the engineer
-
⋮
Six stations in other hands — 05 To Do to 10 Cloud (Pre-Production)
-
11
Ready for Tech → Release Verification
Confirm production health over a real interval — alarms quiet, 5xx flat, new endpoints answering, dead-letter queue empty.
⚑ Reassign to the requester
-
↳
/aws-review<account, after the release>Walks alarms, Lambda health, EventBridge and the dead-letter queues — the same four things this station is asking about, read off the account rather than off a dashboard someone remembers.
-
05
To Do → In Progress
Read the whole ticket and ask every question now, while it is still free. Nothing is written yet.
Unchanged — the developer already holds it
-
↳
/plan /jnet-dev /jnet-portal<jira-ticket-url>Plan mode: reads the ticket and both codebases, proposes the work, and changes nothing until you approve it.
-
06
In Progress → Ready for QA
Implement with tests, open the PR, get every check green, get it reviewed, merge, deploy to dev. Review happens here — there is no Code Review column.
⚑ Reassign to QA in the same action
None — the only actor who holds none.
Review happens inside station 06 In Progress, on the pull request, while the ticket stays with the Developer. There is no Code Review column and no Reviewer in the Assignee field, so a ticket never sits waiting on this role. The Reviewer owns the PR; the board never knows their name.
-
06
Claude Code Review → still your approval
- Finds — inline, on the line, tagged 🔴 Important · 🟡 Nit · 🟣 Pre-existing
- Never gates — the check run is neutral, so it cannot block a merge
- Never approves. That line is a person's, and here it is yours
-
↳
@claude review<top-level PR comment>Any mode, drafts included. Re-run will not restart it — comment again, or push.
-
07
Ready for QA → In QA
Nothing. This is a queue, not an activity: a QA engineer claims it themselves.
Unchanged — QA already holds it
-
08
In QA → Ready for Prod Release or ⛔ To Do
Verify every acceptance criterion one at a time, regression-test around the change, push the edges, and attach evidence for passes and failures.
⚑ Reassign to DevOps, or back to the Developer
-
09
Ready for Prod Release → Cloud (Pre-Production)
Batch it into the next release train, decide the version bump, write the changelog entry.
Unchanged — DevOps holds it
-
↳
/release-manager<the tickets in this train>Batches the train, picks the version bump and writes the changelog from the tickets — station 09's three jobs, in the order it does them.
-
10
Cloud (Pre-Production) → Ready for Tech
Cut the tag and run the production pipeline: deploy, migrations, cache invalidation, smoke suite.
⚑ Reassign to the Tech Lead
Thirteen stations, and who hands off to whom
Each station is held by exactly one actor — the person whose name belongs in the Assignee field while the ticket sits there. Read the last column first: that is where hand-offs break.
| # | Station | What happens here | Held by | Moves to | Assignee change |
|---|---|---|---|---|---|
| 01 | Backlog | PO triages, dedupes and prioritises, and sets the issue type. No estimate, no sprint, no developer. | PO | Refinement | Stays with the PO, or unassigned |
| 02 | Refinement | Write numbered, verifiable acceptance criteria; name every affected portal and service; Tech Lead adds the technical note; split anything bigger than a sprint. | PO | Planning | Stays with the PO |
| 03 | Planning | Sequence it against its dependencies and set the target sprint. Confirm nothing blocking sits ahead of it. | Tech Lead | Evaluation | Stays with the Tech Lead |
| 04 | Evaluation | Estimate story points, confirm the capacity exists, and name the engineer. An estimate that surprises anyone goes back to Refinement. | Tech Lead | To Do | ⚑ Both Developer and Assignee set to the engineer |
| 05 | To Do | Read the whole ticket and ask every question now, while it is still free. Nothing is written yet. | Developer | In Progress | Unchanged — the developer already holds it |
| 06 | In Progress | Implement with tests, open the PR, get every check green, get it reviewed, merge, deploy to dev. Review happens here — there is no Code Review column. | Developer | Ready for QA | ⚑ Developer reassigns to QA in the same action |
| 07 | Ready for QA | Nothing. This is a queue, not an activity: a QA engineer claims it themselves. | QA | In QA | Unchanged — QA already holds it |
| 08 | In QA | Verify every acceptance criterion one at a time, regression-test around the change, push the edges, and attach evidence for passes and failures. | QA | Ready for Prod Release or ⛔ To Do | ⚑ QA reassigns to DevOps or back to the Developer |
| 09 | Ready for Prod Release | Batch it into the next release train, decide the version bump, write the changelog entry. | DevOps | Cloud (Pre-Production) | Unchanged — DevOps holds it |
| 10 | Cloud (Pre-Production) | Cut the tag and run the production pipeline: deploy, migrations, cache invalidation, smoke suite. | DevOps | Ready for Tech | ⚑ DevOps reassigns to the Tech Lead |
| 11 | Ready for Tech | Confirm production health over a real interval — alarms quiet, 5xx flat, new endpoints answering, dead-letter queue empty. | Tech Lead | Release Verification | ⚑ Tech Lead reassigns to the requester |
| 12 | Release Verification | The requester walks the acceptance criteria against production, with a real customer org, real volumes and the real role. | Requester (PO) | Done or ⛔ To Do | Unchanged — the requester closes it |
| 13 | Done | Nothing. Terminal. Reopen only through the Done → Release Verification transition. | Requester (PO) | Release Verification (reopen) | Reopen sends it back to the requester |
The scope call, stated once. An unmet acceptance criterion on the ticket under test means reject. A separate, pre-existing defect means a new linked Bug — and this ticket can still pass. This is the distinction people get wrong most often.
What the Product Owner actually does at 01 and 02
Two of the thirteen stations belong to the PO at the start, and they are the two whose output everybody else is then stuck with. Planning sequences what Refinement named. Evaluation prices what Refinement scoped. QA passes or fails the criteria Refinement numbered. Station 12 hands the ticket back to whoever Backlog recorded as the requester. None of those actors can repair a bad ticket — they can only send it back, and sending it back costs the three moves. So the checks below are not administration; they are the cheapest place in the whole line to catch the thing.
01 Backlog — what gets decided here, and what must not
Triage is not "reading the new tickets". It is a short list of decisions that are cheap because nothing downstream has been committed to yet — no estimate, no sprint, nobody's week — and a shorter list that belongs to somebody else entirely. This is the last station where changing your mind costs nothing at all.
- Does this already exist? Search open
JNETtickets, then the Ideas Backlog. If it does, link the two and say which is the survivor — a duplicate that is silently closed reads as "ignored" to the person who filed it, and they will file it a third time. - Is it one thing? One user, one problem, one outcome. A ticket carrying two problems cannot be half-rejected at station 08, so QA either fails work that was fine or passes work that was not.
- What type is it, decided rather than defaulted? Story — a user-visible change. Bug — something that worked and stopped. Task — necessary work with no user-visible outcome (a migration, a credential rotation). Epic — a container that is never worked directly. The type is what tells the room whether an estimate is even meaningful.
- Where does it sit in the order? Priority is a sequence, not a temperature. If two tickets are both the highest, Planning is the one that has to break the tie, and it will break it on something other than product value.
- Who asked? Name them in the description. Station 12 reassigns the ticket to the requester, so "someone raised it in Slack" produces a ticket on production that nobody is entitled to close.
- And if it is not next: park it out loud. A comment saying not this quarter, because X is a decision. Silence is also a decision, but the requester has to guess which one, and they usually guess wrong in the direction of asking again.
The temptation at this station is to be helpful. Story points, a sprint, an assignee, or a sentence describing how to build it — each one feels like progress and each one belongs to a station that has not happened yet. A number invented here is the number Evaluation has to argue with, and an assignee invented here is why the Developer field is trusted by nobody.
02 Refinement — until a stranger could build it
Refinement is finished when someone who was not in the conversation could pick the ticket up and start. Not when the PO has finished writing — those are different moments, and the gap between them is where sprints go. The Definition of Ready below is the gate; this is the work that gets you through it.
- Number the acceptance criteria, and make each one somebody else's to judge. The test is not "is it true" but "can Pablo mark this pass or fail without asking me what I meant". See the table below.
- Name every affected portal and every affected service, by repository.
organizer-portalanddocuments-manager-api, not "the invoices screen". This is the field Planning reads to sequence against dependencies and Evaluation reads to price the work — a missing repository is a missing estimate. - Name what is not affected, when it is close enough to be assumed. "
udm-portalunchanged" saves an argument in Evaluation and a regression sweep in QA. - Get the technical note in from someone who could build it. That is the Tech Lead's line on this station and it is a hand-off inside the station, not after it. A ticket whose only technical content is the PO's own guess is a ticket that gets re-refined during the sprint.
- Attach the designs, or describe the UI in words. On the ticket. A mock-up living in a Slack thread is not on the ticket, and the developer at station 05 will not find it.
- Split anything larger than one sprint, here. If it genuinely will not split, it is an Epic — and the first slice still has to come out before anything moves to Planning.
- Close every question that blocks a start. Station 05 is where questions are still free, but only the answerable ones. A blocking question sitting in a comment is not a refined ticket, it is a parked ticket with extra steps.
The wording is most of the job. These are the same four criteria as the worked example above, written both ways:
| QA cannot pass or fail this | QA can |
|---|---|
| Download works properly | AC 1 — selecting 3 patents and choosing Download selected returns one file containing exactly those 3 |
| Handles a big result set | AC 3 — a request for 50 patents in one action returns a single file, with no partial result and no timeout |
| Sensible filename | AC 4 — the filename is <org-code>-patents-YYYY-MM-DD, using the org of the signed-in user |
| Handles errors gracefully | AC 5 — if one selected patent is unavailable, the file still contains the others and the response names the one omitted |
| Works on the portals | Scope — organizer-portal only; udm-portal unchanged |
The left column is not lazier than the right — it is the same intention with the judgement left in the PO's head. Every one of those rows becomes a conversation during QA, on the day the sprint is trying to end.
You find out whether Refinement worked at station 04. "An estimate that surprises anyone goes back to Refinement" is the feedback loop for this station, and it is worth watching as a number: tickets bouncing from Evaluation are not an estimating problem, they are a scoping problem wearing an estimating costume. The other signal arrives much later and costs much more — a rejection at station 08 or 12 against a criterion that was never verifiable in the first place.
A squad is the smallest team that can finish a ticket
Everything so far has been about one ticket and the people holding it. Here is how those people are actually grouped: five seats, and the rule that a squad with an empty seat has to borrow one. Borrowing is where hand-offs start to slip, which is why the shape is deliberately this small.
Either engineering seat can be filled by a full-stack engineer, and one person can hold two seats — but the seat still exists, and somebody has to answer for it.
Three squads, and the seat they share
JunctionNet
- AdnanFull-stack
- FernandaProduct Owner
13 SP per person, per one-week sprint
ceiling 26 SP
CargoNaut
- Abdullah
- Nadeem
- Hamid
- AnaProduct Owner
10 SP per person, per one-week sprint
ceiling 40 SP
VIA
- Afaq
- Sajaad
- Wen
- Manuel
10 SP per person, per one-week sprint
ceiling 20 SP
The platform and QA seats are the ones held in common — Hector across all three squads, Pablo across two. The product seats are not shared, and that asymmetry is on purpose: pipelines and test standards are worth holding in common, product decisions are not.
The sprintCapacity is a ceiling, and the sprint in flight is closed
Sprints run one week. The cap is per person, not per squad, so a squad's ceiling is only real if every seat in it is actually free that week — and the platform seat never is, because it is the same person in all three squads.
| Squad | Per person / week | Squad ceiling |
|---|---|---|
| JunctionNet | 13 SP | 26 SP |
| CargoNaut | 10 SP | 40 SP |
| VIA | 10 SP | 20 SP |
An estimate that pushes a person past their cap is not a scheduling problem to solve later — it is the signal to split the ticket, at Evaluation, before it reaches To Do.
Four buckets, and only one of them is closed
| Bucket | What goes in it | The rule |
|---|---|---|
| Sprint | The week in flight | Closed. Nothing new is added to a sprint that has already started. If something truly cannot wait it displaces something, and the PO says out loud what it displaced. |
| Next Sprint | Very High and High priority | The only bucket the next week is pulled from. If it is not in here, it is not starting next week. |
| Following Sprint | Medium and High priority | Where High lands when Next Sprint is already at the cap. Reviewed every week, not once a quarter. |
| Future Sprint | Low to Medium priority | Not a promise — a parking place with a priority attached. Anything here that still matters gets pulled forward at Refinement. |
"Can you just squeeze this in?" is the question this ladder exists to answer. The answer is Next Sprint, and it is not a refusal — it is the difference between a sprint that means something and a list of things people are simultaneously half-doing. The one exception is the hotfix door, and it is a door, not a habit.
Recommended rituals: a week shaped like the workflow
Sprints run one week, so the cadence below is the sprint. Each ritual exists to move a ticket across a specific hand-off, and it belongs to exactly one actor — the same rule as the Assignee field, applied to the calendar. If a meeting on your week does not move a ticket between two stations, it is not on this list, and that is deliberate.
| When | Ritual | Owned by | What it has to produce | Stations |
|---|---|---|---|---|
| Mon · 60 | Refinement | PO, with the Tech Lead in the room | Tickets that pass Definition of Ready: numbered criteria, every affected portal and service named, the technical note in. Anything bigger than the week gets split here. | 01 → 02 |
| Mon · 45 | Planning and Evaluation | Tech Lead | The week sequenced against its dependencies, estimated inside each person's cap, and the Developer and Assignee fields set. An estimate that surprises anyone goes back to Refinement rather than into the sprint. | 02 → 03 → 04 |
| Daily · 15 | Standup | Tech Lead runs it | The board read by Assignee, not by whoever is talking. Two things get raised first: any ticket in To Do with an empty Developer field, and the age of the oldest open PR. | all |
| Wed · 20 | Bucket review | PO | Next, Following and Future re-sorted, and anything displaced from the sprint in flight said out loud. This is the ritual that keeps Following Sprint from turning into a graveyard. | feeds 01 |
| Thu · 30 | Release train | DevOps | The batch decided, the version bump chosen, the changelog written from the tickets. Same day every week, so nobody negotiates the date. | 09 → 10 |
| Thu · after | Production health window | Tech Lead | A real interval watched, not a glance: alarms quiet, 5xx flat, new endpoints answering, dead-letter queues empty. Then the ticket goes back to the requester. | 10 → 11 |
| Fri · 30 | Verification and close | The requester, usually the PO | Acceptance criteria walked on production with a real customer org and the real role. Done, or ⛔ back to To Do with the three moves. | 12 → 13 |
| Fri · 30 | Retro | Everyone | Exactly three things to stop, taken from the anti-patterns list. Three, not ten — a retro that produces a list nobody can hold is a retro that changes nothing. | — |
Stagger the squads, because the platform seat is one person. Three squads running Refinement and Planning on Monday morning is three meetings competing for the same human — the seat that sits in all three. Give each squad its own slot, and treat that person's calendar as the real constraint rather than the room's.
If the week gets compressed, cut in this order. The bucket review goes first — it is recoverable next week. The retro goes second, and only once. Refinement is never the one you cut: skipping it does not save an hour, it moves that hour into Evaluation as an argument about scope, and then into QA as a criterion nobody can pass or fail.
What has to be true before each transition is legal
If you cannot tick every box in the row, the transition is premature. Say so out loud rather than moving the card and hoping.
Definition of Ready, Definition of Done
Definition of Ready — leaving Refinement
- A user and a problem, not a solution shopping list
- Acceptance criteria written as verifiable statements, numbered
- Every affected portal named (
organizer-portal, …) - Every affected service named (
documents-manager-api, …) - A technical note from someone who could build it
- Designs or a described UI, attached to the ticket
- Fits inside one sprint, or it has been split
- No open question blocking a start
# What that looks like on JNET-2801, the ticket used later in this workshop
AC 1 Select multiple patents from the results table
AC 2 A single Download selected action
AC 3 Works for at least 50 patents in one request
AC 4 Filename carries the org code and the date
Definition of Done — leaving Release Verification
- Every acceptance criterion ticked, by the requester, on production
- QA evidence attached — screenshots, request ids, log links
- Merged to
mainin every repository it touched - Version tag cut and the changelog entry written
- Production pipeline green on the
cloudstage - Production healthy — alarms quiet, no new dead letters
- Any follow-up raised as its own ticket, linked, not as a comment
- Assignee is the requester, not the developer
Seven phases. The board only has columns for four of them.
The thirteen stations are a board. The life cycle underneath them is the older, duller list every team has seen: plan, code, build, test, release, operate, monitor. They are not the same thing, and the mismatch is where work goes missing.
| Phase | Stations | Held by | Where the evidence lives |
|---|---|---|---|
| Planning & Design | 01 Backlog → 04 Evaluation | PO, Tech Lead | The ticket: acceptance criteria, technical note, estimate |
| Code | 05 To Do → 06 In Progress | Developer | The branch and the pull request |
| Build | no column | Developer | CI on the PR. Red means the ticket does not move |
| Test | 07 Ready for QA → 08 In QA | QA | Evidence attached to the ticket, pass or reject |
| Release | 09 Ready for Prod Release | DevOps | The release branch, the tag, the changelog |
| Deploy & Operate | 10 Cloud → 11 Ready for Tech | DevOps, Tech Lead | The production pipeline run |
| Monitor | 12 Release Verification → 13 Done | Tech Lead, PO | Alarms, dead letters, and the requester's own eyes |
Read the third row again. Build has no column, and neither does code review — both live entirely on the pull request. That is deliberate: a column implies someone is holding the ticket, and during CI nobody is. It also means the board cannot tell you the build is broken, so the pipeline has to.
Phases are a vocabulary, not a second workflow. Nobody moves a ticket "into the Build phase". The phase names exist so that when something is late, the room can say which phase it is stuck in, rather than arguing about a column name.
The developer's first move is not code. It is one line.
The station is In Progress, the Assignee is you, and the Developer field has your name on it for good. Before a branch exists, this is the line that opens the ticket — and it deliberately cannot change a single file until you have read what it proposes back.
/plan /jnet-dev /jnet-portal https://cargonaut-team.atlassian.net/browse/JNET-2787
# /plan → plan mode: it may read everything and change nothing
# /jnet-dev → the backend skill: Handler → Middleware → Factory/DI →
# Service → Repository → DB, pytest, Alembic, the shared bus
# /jnet-portal → the portal skill: Vue 3, PrimeVue, Nx, per-portal tags
# the URL → the ticket, and where the branch name comes from
Both skills are named on purpose. You do not yet know whether the ticket is backend-only — the plan decides that, not you. On JNET-2787 it turns out to be backend-only, so the portal half correctly finds nothing to do; on a full-stack ticket both halves light up.
What actually happens, in order
Every step up to the gate is reading. The first thing that changes a file happens at 10, on the far side of an approval you have to give out loud.
| # | What happens | Where |
|---|---|---|
| 01 | The ticket comes off the board, not out of a conversation. It is picked from Ideas Backlog (filter 10567), already triaged and prioritised by the PO. No ticket means no line — creating one is the PO's move, not something to invent at the keyboard. | filter 10567 |
| 02 | The CLI expands the one command it recognises and the session enters plan mode. Read, grep and glob stay available; edits, pushes and deploys are refused until you approve something. | plan mode on |
| 03 | Only that leading command was expanded — the rest of the line arrived as ordinary prompt text. Claude loads jnet-dev, then jnet-portal. Both skills are in context before a single file is opened. | two skills loaded |
| 04 | The URL is resolved and the ticket is read: summary, description, acceptance criteria, the column it is actually in, the Assignee, and the Developer field. | JNET-2787 |
| 05 | The ticket names Organizer, so the search starts in that repository — not at the monorepo root. The symbols quoted in the description are grepped for by name. | ../organizer |
| 06 | The failing modules are read end to end, to confirm the described cause is the actual cause and not merely a plausible one. | read, not run |
| 07 | State is checked before anything is proposed: current branch, whether a JNET-2787-* branch already exists, whether a PR is open, whether the fix already landed on main. | git · gh pr list |
| 08 | The column is taken seriously. This ticket sits in Cloud (Pre-Production), so what comes back is a verification plan — prove the deployed build carries the fix — not a plan to write code that already exists. | status shapes the plan |
| 09 | The gate. The plan is presented and the session stops. Nothing has been edited, branched, pushed, deployed, commented on or transitioned. You approve it, rewrite it, or throw it away. | your call |
| 10 | Only after approval: the branch JNET-2787-<desc>, the edits, the tests, and a commit whose message opens with JNET-2787: because the hook rejects anything else. | nothing before this |
| 11 | The pipeline runs — and you read it by the rule above: the three Required rows, not the summary line. | back to green |
No ticket, no line. There is no branch, no commit and no pull request on this board without a JNET- id — the commit-msg hook rejects the message outright. If the work has no ticket yet, it belongs in Ideas Backlog first, where the PO triages it into Refinement.
Branch names carry the ticket, so the tooling can too
One convention, three parts: ticket reference, category, short description. The reference comes first so that a branch sorts, autocompletes and greps by ticket — and so the id is the first thing anyone reads. It is not decoration: it is what lets a pipeline, a PR template and a standup dashboard find each other without anyone copying an id by hand.
# reference - category - description
JNET-2801-feature-bulk-patent-download
JNET-2844-hotfix-organizer-500
JNET-2851-fix-presigned-url-ttl
# the reference is the contract: it links branch → PR → ticket → release note
A branch with no ticket reference is invisible work. It will not appear on the standup dashboard, it will not be in the changelog, and when it breaks production at 02:00 nobody can find out why it was written.
What "green" means, per repository
A red pipeline is not a status. It is a developer with unfinished work. Nothing in this workflow moves on a red build — the ticket stays exactly where it is, In Progress, until every check passes.
# Nx monorepo · Vue 3 · PrimeVue · Vite · yarn
yarn lint ✓ ESLint, zero errors
yarn type-check ✓ tsc compiles
yarn test ✓ Vitest, coverage held
nx build --configuration=production ✓
security scan ✓ no new advisories
bundle analysis ✓ inside budget
# Per-portal release tags — each portal ships on its own clock.
# Never tag the whole repo against one version.
organizer-v1.31.0 admin-vX entrywriter-vX udm-vX workspace-vX
# Python 3.11 · Lambda Powertools · SQLAlchemy 2 · Serverless
pytest --cov=src ✓ unit + integration
lint + type checks ✓
alembic revision applies cleanly ✓
serverless package builds ✓
submodules resolve ✓ python-lambda-common
deploy job green on target stage ✓
# Stages
dev → AWS 225725557140 → *.api.junctionnet.dev
cloud → AWS 894898254520 → *.api.junctionnet.com
shared bus: Platform-Apps-events-{ENV}
The gate is the Required label, not GitHub's summary line
GitHub will tell you the run is unfinished on a pull request that is entirely mergeable. Read the rows, not the headline — this is a real JNET PR, seconds before it merged.
⏳ "Some checks haven't completed yet"
1 cancelled · 3 skipped · 10 successful · 1 pending review
✓ ci / Display Configuration Info 3s
✓ ci / Infra Apply (Dev) / Terragrunt apply (dev)
✓ ci / Pipeline Summary + Ticket Comment
✓ ci / PR Notification 6s
✓ ci / Run E2E Tests (Ticket Dev) [Required]
✓ ci / Run Unit Tests [Required] 52s
✓ ci / Verify (Ticket Dev) [Required] 5s
✓ WIP — Ready for review 1s
⋯ 2 successful, 1 cancelled, 3 skipped — collapsed below the fold
# MERGEABLE. All three Required checks successful. Nothing cancelled,
# skipped or merely requested carries a ruleset requirement.
| Row | Not success — and not a failure |
|---|---|
| Cancelled | You merged while the ticket deploy was still running. The merge fires the ticket-environment Remove job, which cancels the in-flight deploy — and on portals-ui and blueprint takes the Terraform state lock out from under it. A red check, not broken code. Confirm it by diffing your branch against main, not by the merge commit title. |
| Skipped | Path filters. A PR touching one portal skips the other portals' jobs; an API PR outside the allowlist skips the deploy job. Skipped is the pipeline being correct. |
| Pending review | Requested, not required. What you chase is PR age, not this row. |
| Looks green | Is actually broken |
|---|---|
| Waiting for status | A Required check that never started reports as Expected — Waiting for status, not as a failure. The require-ticket-deploy-dev ruleset matches check names as strings, and those names are ci /-prefixed in some repos and bare in others. A prefix mismatch can never be satisfied, so the PR waits forever looking almost fine. |
| Green, then CFN | The dev event-bus create script prints success even when the account is already at the 100-bus cap. CloudFormation then fails six minutes later with an error that points somewhere else entirely. |
| Deployed nothing | A green CD run is not proof the code shipped. Check the function's LastModified, not the run's colour. On portals-ui, merging to main deploys dev and cloud, while .tech needs a new tag plus manual approval — and the newest tag may not contain your commit. |
Code review has no Jira column, and that is deliberate. Review lives on the pull request, not on the board. A ticket under review stays In Progress with the developer as Assignee, because the developer is still the person who has to act — on the reviewer's comments. What you chase in standup is the PR age, not the ticket status.
The automated first pass, in summary
Claude Code Review reads a pull request with a fleet of agents, each hunting a different class of problem, and a verification step then checks each candidate against what the code actually does before anything is posted. Findings arrive as inline comments on the lines they concern, ranked by severity, with a tally in the review body and a full table behind the Claude Code Review check run's Details link.
It is deliberately incapable of being a gate. The check run always completes with a neutral conclusion, so it can neither block a merge nor authorise one, and nothing in the workflow above changes: station 06 still ends when a human reviewer approves and the developer merges. Treat it as a first pass that arrives before the human one, and whose value is the round trip it saves the author — not as a reviewer.
- 🔴 Important — a bug to fix before merging · 🟡 Nit — worth fixing, not blocking · 🟣 Pre-existing — real, but this PR did not introduce it
- When it runs is set per repository: once when the PR opens, on every push, or manual only. Every-push costs the most, and reviews average $15–25 each, billed as usage credits rather than against the plan.
- Replying to a finding does nothing. Fix the code and push. On a push-subscribed PR the next run resolves the thread itself.
- Tuning lives in the repo. A newly introduced
CLAUDE.mdviolation comes back as a nit — so the files we already keep for Claude Code are doing double duty. AREVIEW.mdat the repo root is injected into every review agent at highest priority: use it to redefine what Important means here, cap nit volume, or skip generated paths.
| Command | What it does |
|---|---|
| @claude review | One review now. Does not subscribe the PR to later pushes. |
| @claude review always | Reviews now and on every subsequent push to the branch. |
| @claude review once | Identical to the bare command. Kept for anyone who scripted it. |
Post it as a top-level PR comment with the command at the start of the comment — an inline comment on a diff line will not trigger anything. You need owner, member or collaborator access, and the PR has to be open; unlike the automatic triggers, a manual request runs on a draft. If a review is already in flight the request queues behind it. And when a run errors or times out, GitHub's Re-run button does not restart it — comment again or push.
Before any of that, the same review runs locally: /code-review
in a Claude Code session reads your branch's commits ahead of upstream plus whatever is still
uncommitted, so it can be the last thing you do before opening the PR rather than the first
thing that happens after. --fix applies what it finds,
--comment posts the findings to the PR. It reads
CLAUDE.md like any session, but not
REVIEW.md.
Two things this does not change. A red pipeline is still unfinished work — a neutral review comment on a red PR means nothing, and the ticket does not move. And the Reviewer's own line holds: never approve a PR whose checks are red, and never merge someone else's PR for them, no matter how clean the automated pass came back.
Between "merged" and "on production" there is a branch strategy
Stations 09 and 10 hide an entire discipline. QA passing a ticket does not put it on production — a release does, and a release is a branch, a tag and a decision about what travels together.
Trunk-based — what we do
Short-lived ticket branches cut from main and merged back within days. main is always releasable. Fewer branches alive at once means less drift, and CI has one obvious thing to protect.
Gitflow — what we do not
Features branch off a long-lived develop, not main. Bigger commits, longer-lived branches, more drift, and two branches that both claim to be the truth. It solves a release cadence we do not have.
# the whole flow, and the only four moves in it
main ──┬──────────────────────────────┬──► main
│ │
├─ JNET-2801-feature-… ────────┘ 1. ticket branch off main, merged back
│
└─ release/v1.32.0 ──┬──► tag v1.32.0 ──► production
│ 2. release branch cut from main
└─ fix branch ─┘ 3. patches land on the release branch
4. release merges back into main
| Rule | Why it exists |
|---|---|
Treat main as always releasable | Every other rule depends on this one being true |
| Cut a release branch only for an actual release | A standing release branch is a second main, and it drifts |
Patch on the release branch, never on main | The single biggest source of merge conflicts, and the one rule to keep if you keep only one |
| Do not cherry-pick | Two commits with the same change and different hashes make history a guess |
Rebase long-running branches on main weekly | Drift is cheap to fix on Monday and expensive to fix at release |
Merge the release branch back into main | Otherwise the fixes made during the release exist only on production |
Never merge main into a release branch | It drags in work that was never tested for this release |
| Tag, do not remember | A tag is immutable and points at one commit; "the version we shipped Tuesday" is not |
Versions are semantic, and the tag is what deploys
MAJOR.MINOR.PATCH: major for a breaking change, minor for a
backward-compatible feature, patch for a fix. The tag — not a branch, not a green build —
is what the production pipeline runs from, which is why the tag is cut at station 09 and
not before.
The hotfix door, finally explained. A hotfix branches from the last released tag, not from main, so it carries the fix and nothing else. It merges into main and into any open release branch, and main gets a new patch tag. On the board this is the Any → Cloud transition: Tech Lead or DevOps decision, PO informed first, retroactive QA pass logged within 24 hours.
Steps 1–6: the train leaves, and the requester closes it
- Fixed, green, handed back → Ready for QA. The zip moves into a Step Function; the endpoint returns
202with a job id and the client polls. New PRs on both repos, all checks green, both merged, dev redeployed. Karim's handover says the one thing that matters: "re-test the 62-file case and the original 5-file case — the happy path changed, it is asynchronous now." - Both cases pass → Ready for Prod Release. Pablo re-tests the 62-file case and the 5-file regression, attaches the evidence, ticks all four criteria, reassigns to Adnan and transitions. QA decides whether it is correct, never whether it ships.
- The train leaves → Cloud (Pre-Production). Adnan batches JNET-2801 with four other passed tickets, decides the version bump, writes the changelog entry, cuts the tags, and the production pipeline runs against the
cloudstage. - Every job green — only then does it move → Ready for Tech. A partially-green production run is a rollback decision, not a transition. This is where the pipeline stops being a developer concern and becomes a release gate.
- Technical sign-off, then back to the person who asked → Release Verification. Hector watches production for thirty minutes, not thirty seconds: alarms quiet, 5xx flat against the previous hour,
POST /patents/bulk-downloadreturning202s, nothing new in the dead-letter queue. Then he reassigns to Fer. - Verified on production, then Done. Fer runs all four criteria against a real Hutchison Ports org with 71 patents — precisely the case Karim flagged as untestable in his very first handover comment. All four pass. Only the requester closes.
# Step 22 — the release train
tag organizer-v1.31.0
tag documents-manager-api-v2.14.0
AWS 894898254520 · stage cloud
alembic migration ✓
serverless deploy ✓
s3 sync + CF invalidate ✓
smoke suite ✓
Had Fer found the filename wrong at step 17, the move would have been identical to Pablo's at step 10: comment, reassign to Karim, global To Do. It does not matter that the code is already on production. The ticket is not Done until the person who asked says it is.
The teaching ticket is invented. JNET-2801 and its history were written for this workshop — they are not a real audit log. The workflow, the status names, the transition ids, the repositories, the AWS accounts and the pipeline checks are all real.
Ten ways this workflow gets broken, and the fix for each
Read these aloud in the room. Ask, honestly, which ones happened last sprint.
| What it looks like | The fix |
|---|---|
| Transition without reassign. The column changes, the avatar does not. The board says Ready for QA and QA's filter never shows it. | Reassign first, transition second. Every time. Make it muscle memory. |
| QA fixes the bug themselves. It is a one-line change and it is faster. Now nobody independent has tested the fix. | QA rejects. The developer fixes. QA re-tests. The extra twenty minutes buys you the only independent check you have. |
| A new Bug ticket for an unmet AC. The story passes with a Bug hanging off it, and reaches Done half-finished. | Unmet criterion on the ticket under test → reject to To Do. Genuinely separate pre-existing defect → new linked Bug, and this ticket can still pass. |
| The developer closes their own ticket. Straight from In Progress or Ready for QA to Done, because it obviously works. | Nobody verifies their own work. The last two columns exist precisely to make that impossible. |
| Ready for QA with no notes. A ticket in QA's queue with no dev URL, no build, no scope, no known gaps. | The handover comment is part of the transition, not a nicety. No comment, no move. |
| Using the hotfix door routinely. Any → Cloud (Pre-Production) because the release train is slow. | Fix the train. If the door is being used weekly, the queue is the problem, not the process. |
| Bulk-closing at sprint end. Nine tickets to Done in ninety seconds so the burndown lands. | The burndown is a readout, not a target. A ticket closes when the requester says so and not before. |
| Empty Developer field. The ticket drops out of the workload rollup and gets grouped under "— No Developer set". | The Tech Lead sets Developer and Assignee together at Evaluation → To Do. One action, two fields. |
| Moving on a red pipeline. The check will pass on retry, probably, and the ticket is already in QA's queue. | A red pipeline means the ticket stays In Progress. There is no status for "nearly green". |
| Reopening by editing. A Done ticket gets edited back into In Progress, and the failure disappears from the history. | Use Done → Release Verification, then the normal reject path. The second lap should be visible — that is the data that tells you where quality is leaking. |
Facilitator run sheet — 09:00 to 12:45
Have the board open on a second screen the whole time. Every abstract point gets pointed at a real ticket within thirty seconds, or it gets cut.
The timings follow the six actor cards, because that is where the thirteen stations are now taught — an actor, then the stations they hold, then the command they run. The stations table is page-only reference and never goes on the projector, so there is no block for it below. Two roles carry more than one body: the PO has four cards and the Reviewer three, which is where the minutes go.
| Time | Min | What |
|---|---|---|
| 09:00 | 15 | Open: the one rule. Put the live board on screen first. Let the room look at where tickets are actually sitting before you explain anything. |
| 09:15 | 15 | The cast — roles only. The roster, then each role's Owns and Never. Have each person say aloud which columns they own; write the names on the whiteboard. Stations come next, so resist walking them here. |
| 09:30 | 20 | Quiz — the two field questions. Run them live: show of hands before you reveal, then argue the wrong answers. The disagreement is the content. |
| 09:50 | 25 | PO and Tech Lead cards — stations 01–04. Land the Developer/Assignee split at Evaluation → To Do; it is the hinge of the whole day. Spend real time on the PO's two check cards: a criterion that only Ana can adjudicate is what every later station pays for. |
| 10:15 | 15 | Break |
| 10:30 | 30 | Developer and Reviewer cards — stations 05–06. Review has no column and CI red moves nothing. Include the automated first pass and be blunt about its limit: it finds, it never approves, and a neutral check run is not a sign-off. |
| 11:00 | 35 | The reject loop. Journey steps 9 and 10 on the screen, then walk the three moves against a real rejection from last sprint. This is the centre of the workshop; protect the time. |
| 11:35 | 10 | Break |
| 11:45 | 25 | QA and DevOps cards — stations 07–13. The pass/reject call, then the release train, the tag, and the production-health sign-off that hands the ticket back to the requester. |
| 12:10 | 20 | Quiz — the remaining questions, then the live board. Finish the quiz, then put the board on the projector and check the open tickets against the answers the room just gave. |
| 12:30 | 15 | The week ahead, and commitments. Put the recommended rituals on screen and get each ritual an owner and a slot before anyone leaves — an unowned ritual is not a ritual. Then have the team pick exactly three anti-patterns to stop this sprint. Three, not ten. |
| 12:45 | — | End |
Two definitions to confirm on the day. Ready for Tech and Release Verification are described here as technical sign-off on production health followed by acceptance by the requester. That is the most coherent reading of the workflow's shape, but it is an interpretation — put both on the whiteboard in the first fifteen minutes and get the team to agree the wording before you teach the rest.
This is Part 0 for a reason. Everything after this — building, deploying, wiring pipelines — assumes a ticket that somebody is actually holding. Get the hand-offs right first, then go and build. Part 1 starts with an empty folder and Claude Code.