Navan had printed the Jira workflow on four sheets of A4 paper taped together. It hung on the wall next to his desk like a wanted poster for complexity.
The workflow had fourteen statuses. Not the simple Open-In Progress-Done pipeline that tutorials promised. Fourteen statuses with twenty-seven transitions between them, each transition guarded by validators, conditions, and post-functions. A ticket in the "Awaiting Review" status could move to "In Review" only if the assignee was a member of the Reviewers group AND the ticket had at least one attachment AND the current sprint was active. If any of those conditions failed, the transition button wouldn't even render in the real Jira UI.
The twin had to replicate all of it.
"The state machine itself isn't the hard part," Navan told Jay, who had pulled a chair over to study the wall chart. "States and transitions, that's freshman CS. The hard part is the side effects."
"Side effects?"
"Post-functions. When a ticket transitions from In Progress to Code Review, three things happen automatically. The assignee changes to the reviewer. A comment gets added saying who requested the review. And a webhook fires to notify the CI system." Navan traced the arrows on his chart with his finger. "If the twin doesn't execute those post-functions in the right order, everything downstream breaks. The Slack twin is listening for that webhook. The scenario expects a Slack notification within two seconds of the transition."
Jay studied the chart. "What about validators?"
"Validators run before the transition happens. They can block it. The twin has a Resolution field validator on the Done transition—you can't close a ticket without setting a resolution. Sounds simple, but there are eight resolution types, and only three are valid for Bug issue types versus Story issue types." Navan pointed at a cluster of red annotations. "And then there are the screen schemes. Different transitions show different fields. The Reopen transition shows a comment field but not a resolution field. The Close transition shows both. The twin has to know which fields are available on which transition screen."
"How did you map all this?" Jay asked.
"Behavioral capture. We recorded traffic from a real Jira instance. Every API call, every response. Then the agents analyzed the recordings and built the behavioral model. But the recordings can't capture everything. Some transitions are so rare that nobody triggered them during the capture window. Those, I had to describe in the spec by hand."
"By hand meaning you wrote the description for an agent."
"Right. I described the expected behavior. The agent generated the implementation. But I had to know what the behavior should be first, which meant reading Atlassian's documentation, which is..." Navan paused, searching for a diplomatic word.
"Extensive," Jay offered.
"I was going to say labyrinthine. There's a page about workflow validators that links to a page about conditions that links to a page about post-functions that links back to the workflow validators page. It's a directed cycle in the documentation graph."
Jay laughed. "So you're modeling a state machine whose documentation is itself a state machine."
Navan taped a fifth sheet of paper to the wall. The workflow was expanding. It would keep expanding. That was the nature of Jira: workflows grew, they never shrank. And the twin had to grow with them, transition by transition, validator by validator, post-function by post-function.
"At least the twin doesn't charge per user," Navan said.
Fourteen statuses? That's cute. Our production Jira has twenty-three. I weep for whoever has to model that twin.