Skip to content

Instantly share code, notes, and snippets.

@0xack13
Created May 7, 2025 21:50
Show Gist options
  • Save 0xack13/83b3b00884251b3fcdbe1022c224fd5f to your computer and use it in GitHub Desktop.
Save 0xack13/83b3b00884251b3fcdbe1022c224fd5f to your computer and use it in GitHub Desktop.
FSM-escalation
const THRESHOLDS = {
ESCALATE_TO_BUG: 5,
ESCALATE_TO_P2: 10,
};
const PRIORITY = {
P1: 'P1',
P2: 'P2',
P3: 'P3',
};
const ISSUE_TYPE = {
STORY: 'story',
BUG: 'bug',
};
class TicketEscalationFSM {
constructor(context) {
this.context = {
...context,
type: ISSUE_TYPE.STORY,
priority: PRIORITY.P3,
};
this.machine = this._createMachine({
initialState: 'created',
states: {
created: {
actions: {
onEnter: (ctx) =>
console.log(`[${ctx.issueId}] Created as STORY (P3)`),
onExit: (ctx) =>
console.log(`[${ctx.issueId}] Exiting 'created' state`),
},
transitions: {
escalateToBug: {
condition: (ctx) => ctx.occurrences > THRESHOLDS.ESCALATE_TO_BUG,
target: 'bugP3',
action: (ctx) => {
ctx.type = ISSUE_TYPE.BUG;
console.log(`[${ctx.issueId}] Escalated to BUG (P3)`);
},
},
},
},
bugP3: {
actions: {
onEnter: (ctx) =>
console.log(`[${ctx.issueId}] Entered Bug P3`),
onExit: (ctx) =>
console.log(`[${ctx.issueId}] Exiting 'bugP3' state`),
},
transitions: {
escalateToP2: {
condition: (ctx) => ctx.occurrences > THRESHOLDS.ESCALATE_TO_P2,
target: 'bugP2',
action: (ctx) => {
ctx.priority = PRIORITY.P2;
console.log(`[${ctx.issueId}] Escalated priority to P2`);
},
},
},
},
bugP2: {
actions: {
onEnter: (ctx) =>
console.log(`[${ctx.issueId}] Final state: Bug P2`),
},
transitions: {},
},
},
});
}
_createMachine(definition) {
const machine = {
value: definition.initialState,
transition: () => {
const stateDef = definition.states[machine.value];
for (const [_, transition] of Object.entries(stateDef.transitions)) {
if (!transition.condition || transition.condition(this.context)) {
stateDef.actions?.onExit?.(this.context);
transition.action?.(this.context);
machine.value = transition.target;
definition.states[machine.value].actions?.onEnter?.(this.context);
return machine.value;
}
}
return machine.value;
},
};
// Initial entry action
definition.states[machine.value].actions?.onEnter?.(this.context);
return machine;
}
escalate(occurrences) {
this.context.occurrences = occurrences;
return this.machine.transition();
}
getState() {
return this.machine.value;
}
getContext() {
return this.context;
}
}
const ticket1 = new TicketEscalationFSM({ issueId: 'TICKET-001' });
ticket1.escalate(6); // Escalates to bugP3
ticket1.escalate(11); // Escalates to bugP2
console.log(ticket1.getState()); // 'bugP2'
console.log('\n----\n');
const ticket2 = new TicketEscalationFSM({ issueId: 'TICKET-002' });
ticket2.escalate(3); // No escalation
console.log(ticket2.getState()); // 'created'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment