PO bewegt sich nicht mehr faelschlich fuer Agenten-eigene wip-Wechsel

Statuswechsel von/zu "in_arbeit" (Label "wip") loest ein Agent selbst aus,
wenn er ein Ticket nimmt bzw. abgibt, und meldet die Bewegung ueber seinen
eigenen state. detectUnassignedTicketChanges() zaehlte diese Wechsel
bislang trotzdem als "niemandem zugeordnet" und liess zusaetzlich den PO
dafuer zum Board laufen.

Schliesst #32
This commit is contained in:
fds2610-bot 2026-08-03 19:23:09 +02:00
parent 40c48ed46a
commit fe95035a0a
2 changed files with 27 additions and 5 deletions

View file

@ -624,9 +624,17 @@ export const PO_DISPLAY_NAME = "PO";
// und damit Sache des PO. // und damit Sache des PO.
const PO_UNASSIGNED_EXCLUDED_COLUMNS = new Set(["fertig", "done"]); const PO_UNASSIGNED_EXCLUDED_COLUMNS = new Set(["fertig", "done"]);
// Issue #32: Wechsel von/zu "in_arbeit" (Label "wip") setzt bzw. entfernt der Agent selbst, der
// das Ticket nimmt bzw. abgibt - er meldet diese Bewegung ueber seinen eigenen state (POST
// /api/v1/agents/{id}/activity, siehe resolveAgentVisualState()), nicht der PO. Ohne diesen
// Ausschluss lief bislang faelschlich zusaetzlich der PO zum Board, sobald ein Agent ein Ticket
// nahm oder abgab.
const AGENT_OWNED_COLUMN = "in_arbeit";
/** /**
* Erkennt Ticket-Statuswechsel, die keiner Rolle zugeordnet sind (Gegenstueck zu * Erkennt Ticket-Statuswechsel, die keiner Rolle zugeordnet sind (Gegenstueck zu
* detectDoorVisits() fuer die bereits zugeordneten Faelle). Neu angelegte Tickets zaehlen hier * detectDoorVisits() fuer die bereits zugeordneten Faelle, sowie zu den vom Agenten selbst
* gemeldeten "in_arbeit"-Wechseln, siehe AGENT_OWNED_COLUMN). Neu angelegte Tickets zaehlen hier
* nicht mit - die sind bereits Sache von detectDoorVisits()/NEW_BACKLOG_TICKET. * nicht mit - die sind bereits Sache von detectDoorVisits()/NEW_BACKLOG_TICKET.
* *
* @param {Array<{id: number, column_name: string}>} previousTickets * @param {Array<{id: number, column_name: string}>} previousTickets
@ -645,6 +653,9 @@ export function detectUnassignedTicketChanges(previousTickets = [], currentTicke
if (PO_UNASSIGNED_EXCLUDED_COLUMNS.has(ticket.column_name)) { if (PO_UNASSIGNED_EXCLUDED_COLUMNS.has(ticket.column_name)) {
continue; continue;
} }
if (before.column_name === AGENT_OWNED_COLUMN || ticket.column_name === AGENT_OWNED_COLUMN) {
continue;
}
changes.push({ ticketId: ticket.id, column: ticket.column_name }); changes.push({ ticketId: ticket.id, column: ticket.column_name });
} }

View file

@ -551,6 +551,20 @@ test("detectUnassignedTicketChanges ignoriert Tickets ohne Spaltenwechsel", () =
assert.deepEqual(detectUnassignedTicketChanges(before, after), []); assert.deepEqual(detectUnassignedTicketChanges(before, after), []);
}); });
test("detectUnassignedTicketChanges ignoriert Wechsel von/zu in_arbeit (Label wip - Sache des Agenten, Issue #32)", () => {
const before = [
{ id: 1, column_name: "bereit" },
{ id: 2, column_name: "in_arbeit" },
{ id: 3, column_name: "in_arbeit" },
];
const after = [
{ id: 1, column_name: "in_arbeit" },
{ id: 2, column_name: "testing" },
{ id: 3, column_name: "backlog" },
];
assert.deepEqual(detectUnassignedTicketChanges(before, after), []);
});
test("detectUnassignedTicketChanges verarbeitet mehrere gleichzeitige Wechsel", () => { test("detectUnassignedTicketChanges verarbeitet mehrere gleichzeitige Wechsel", () => {
const before = [ const before = [
{ id: 1, column_name: "backlog" }, { id: 1, column_name: "backlog" },
@ -562,10 +576,7 @@ test("detectUnassignedTicketChanges verarbeitet mehrere gleichzeitige Wechsel",
{ id: 2, column_name: "in_arbeit" }, { id: 2, column_name: "in_arbeit" },
{ id: 3, column_name: "fertig" }, { id: 3, column_name: "fertig" },
]; ];
assert.deepEqual(detectUnassignedTicketChanges(before, after), [ assert.deepEqual(detectUnassignedTicketChanges(before, after), [{ ticketId: 1, column: "bereit" }]);
{ ticketId: 1, column: "bereit" },
{ ticketId: 2, column: "in_arbeit" },
]);
}); });
test("advancePoVisitStage durchlaeuft alle Stages und liefert am Ende null", () => { test("advancePoVisitStage durchlaeuft alle Stages und liefert am Ende null", () => {