Single-edit (api/update_ticket.php) and Bearer API (api/ticket_status_api.php) paths log status changes via AuditLogModel::logTicketUpdate() with a {'status': {'from': X, 'to': Y}} shape. models/BulkOperationsModel.php instead logs ['status' => 'Closed', 'bulk_operation_id' => ...] — a bare string.
Impact — two downstream consumers silently degrade for bulk-originated rows:
views/TicketView.php (~lines 67-74, case 'update':) — the field-name extractor requires is_array($v) && isset($v['from'],$v['to']); a bare string fails this, so the ticket timeline shows generic "updated this ticket" for a bulk status change instead of "updated status" (which single-edit/API paths correctly get).
api/notifications.php (~lines 229-231) — $details['status']['from'] on a string triggers a PHP array-offset-on-string warning and falls through to ?? '?' for both from/to, producing a broken in-app notification title: "{actor} changed status on #NNN: ? → ?" for any notification derived from a bulk status change.
Fix: Change BulkOperationsModel's audit log call to use the same {'status': {'from': ..., 'to': ...}} shape as AuditLogModel::logTicketUpdate(), keeping bulk_operation_id as an additional metadata field alongside it.
**Severity:** Medium
Single-edit (`api/update_ticket.php`) and Bearer API (`api/ticket_status_api.php`) paths log status changes via `AuditLogModel::logTicketUpdate()` with a `{'status': {'from': X, 'to': Y}}` shape. `models/BulkOperationsModel.php` instead logs `['status' => 'Closed', 'bulk_operation_id' => ...]` — a bare string.
**Impact — two downstream consumers silently degrade for bulk-originated rows:**
1. `views/TicketView.php` (~lines 67-74, `case 'update':`) — the field-name extractor requires `is_array($v) && isset($v['from'],$v['to'])`; a bare string fails this, so the ticket timeline shows generic "updated this ticket" for a bulk status change instead of "updated status" (which single-edit/API paths correctly get).
2. `api/notifications.php` (~lines 229-231) — `$details['status']['from']` on a string triggers a PHP array-offset-on-string warning and falls through to `?? '?'` for both `from`/`to`, producing a broken in-app notification title: `"{actor} changed status on #NNN: ? → ?"` for any notification derived from a bulk status change.
**Fix:** Change `BulkOperationsModel`'s audit log call to use the same `{'status': {'from': ..., 'to': ...}}` shape as `AuditLogModel::logTicketUpdate()`, keeping `bulk_operation_id` as an additional metadata field alongside it.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: Medium
Single-edit (
api/update_ticket.php) and Bearer API (api/ticket_status_api.php) paths log status changes viaAuditLogModel::logTicketUpdate()with a{'status': {'from': X, 'to': Y}}shape.models/BulkOperationsModel.phpinstead logs['status' => 'Closed', 'bulk_operation_id' => ...]— a bare string.Impact — two downstream consumers silently degrade for bulk-originated rows:
views/TicketView.php(~lines 67-74,case 'update':) — the field-name extractor requiresis_array($v) && isset($v['from'],$v['to']); a bare string fails this, so the ticket timeline shows generic "updated this ticket" for a bulk status change instead of "updated status" (which single-edit/API paths correctly get).api/notifications.php(~lines 229-231) —$details['status']['from']on a string triggers a PHP array-offset-on-string warning and falls through to?? '?'for bothfrom/to, producing a broken in-app notification title:"{actor} changed status on #NNN: ? → ?"for any notification derived from a bulk status change.Fix: Change
BulkOperationsModel's audit log call to use the same{'status': {'from': ..., 'to': ...}}shape asAuditLogModel::logTicketUpdate(), keepingbulk_operation_idas an additional metadata field alongside it.