[ { "id": "T001", "description": "Migration smoke: all seven new tables exist after migrate with composite (tenant, id) PKs, FKs, defaults (is_required true, completed false, source 'manual'), and RLS policies; migrate:down removes them cleanly.", "implemented": true, "featureIds": [ "F001", "F002", "F003", "F004", "F005", "F006" ] }, { "id": "T002", "description": "Migration: permissions table gains { resource 'ticket', action 'close_override' } per tenant and role_permissions grants it to Admin (verified against a freshly migrated database; the migration itself uses get-or-insert idempotency).", "implemented": true, "featureIds": [ "F007" ] }, { "id": "T003", "description": "Migration: notification_subtypes contains the auto-close-warning subtype under the Tickets category and system_email_templates has a matching row whose name equals the string used by the warn phase.", "implemented": true, "featureIds": [ "F008", "F032" ] }, { "id": "T004", "description": "Unit: getBoardCloseRules returns all-gates-off defaults when no row exists; upsertBoardCloseRules persists and round-trips config; required_fields outside the allowed set is rejected.", "implemented": true, "featureIds": [ "F009" ] }, { "id": "T005", "description": "Unit: auto-close rule actions reject close_to_status_id that is not is_closed, trigger_status_id that is closed, warning_days_before >= inactivity_days, and a duplicate (board_id, trigger_status_id) pair.", "implemented": true, "featureIds": [ "F010" ] }, { "id": "T006", "description": "Unit: validateTicketClosure returns allowed=true when the board has no board_close_rules row and when is_enabled=false, without running any gate queries.", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T007", "description": "Unit: resolution-comment gate fails with no qualifying comment; passes with a comments.is_resolution=true row; passes with metadata closes_ticket=true; ignores comments on other tickets/tenants.", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T008", "description": "Unit: time-entry gate fails with zero time entries; passes with one time_entries row (work_item_type 'ticket'); ignores time entries with other work_item_types or other tickets.", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T009", "description": "Unit: checklist gate fails while any is_required item is incomplete; passes when all required items are complete even if optional items remain unchecked; passes on a ticket with no checklist items.", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T010", "description": "Unit: open-children gate fails when a child ticket (master_ticket_id set) has closed_at IS NULL; passes once all children are closed; passes for non-master tickets.", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T011", "description": "Unit: required-fields gate fails listing each null configured field (e.g. category_id, assigned_to) in failures meta; passes when all configured fields are set; unconfigured fields are ignored.", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T012", "description": "Unit: multiple failing gates produce one failure entry per gate in a single result (not first-failure-only).", "implemented": true, "featureIds": [ "F021" ] }, { "id": "T013", "description": "Unit: override with ticket:close_override permission yields allowed=true and a CLOSE_RULES_OVERRIDDEN audit write including the failure list and reason; override without the permission is refused (still blocked).", "implemented": true, "featureIds": [ "F022" ] }, { "id": "T014", "description": "Unit: bypass skips gate evaluation and writes CLOSE_RULES_BYPASSED with the source only when the board has enabled gates; no audit noise on ungated boards.", "implemented": true, "featureIds": [ "F022" ] }, { "id": "T015", "description": "Integration: updateTicket to a closed status on a gated board throws TicketCloseValidationError with the ticket row untouched, and the same action with overrideCloseRules (permission granted) closes the ticket and writes the override audit with the reason.", "implemented": true, "featureIds": [ "F023" ] }, { "id": "T016", "description": "Integration: updateTicket close succeeds once all gates pass — closure fields set, TICKET_CLOSED published, audit row written (regression: identical to pre-feature behavior on ungated boards).", "implemented": true, "featureIds": [ "F023" ] }, { "id": "T017", "description": "Integration: updateTicketInTransaction blocks a gated close — transaction aborts, status/is_closed/closed_at/closed_by untouched, no TICKET_CLOSED published — and closes normally once gates pass (covers TicketDetails/board-view/bulk callers).", "implemented": true, "featureIds": [ "F024" ] }, { "id": "T018", "description": "Integration: bulkUpdateTicketStatus to a closed status with a mix of passing and failing tickets closes the passing ones and returns per-ticket results with failures for the blocked ones; no batch-wide abort.", "implemented": true, "featureIds": [ "F024", "F028" ] }, { "id": "T019", "description": "Integration: checkTicketClosure (the UI pre-close check the API enforcement shares its evaluator with) returns wouldClose/structured failures/canOverride keyed to the close_override permission; non-closing status changes are always allowed. HTTP-level 422 shape is exercised in the manual smoke pass.", "implemented": true, "featureIds": [ "F025" ] }, { "id": "T020", "description": "Integration: exempt sources bypass gates through enforceTicketCloseRules/auditCloseRulesBypassIfGated with a CLOSE_RULES_BYPASSED audit row carrying the source; the workflow tickets.close and CSV import paths call this same helper (wiring verified by type-check and review; end-to-end by smoke).", "implemented": true, "featureIds": [ "F026" ] }, { "id": "T021", "description": "Integration: portal updateTicketStatus to a closed status sets is_closed/closed_at/closed_by (portal user id), publishes TICKET_CLOSED, and is never gate-blocked; moving back to open clears the closure fields. Regression: closure emails/SLA recording fire for portal closes.", "implemented": true, "featureIds": [ "F029" ] }, { "id": "T022", "description": "Integration: checklist item lifecycle — add, edit, reorder, delete via ticketChecklistActions; ordering persists; tenant isolation enforced (cannot touch another tenant's items).", "implemented": true, "featureIds": [ "F013" ] }, { "id": "T023", "description": "Integration: setChecklistItemCompleted(true) stamps completed_by = acting user and completed_at; (false) clears both; each transition writes the matching CHECKLIST_ITEM_* audit row, with the uncheck row preserving the prior signoff in details.", "implemented": true, "featureIds": [ "F013", "F016" ] }, { "id": "T024", "description": "Integration: applyChecklistTemplateToTicket copies items with order, is_required, source and template_id provenance; calling it again for the same template is a no-op (idempotent); two different templates stack their items.", "implemented": true, "featureIds": [ "F015" ] }, { "id": "T025", "description": "Integration: template edits after application do not alter items already copied onto tickets.", "implemented": true, "featureIds": [ "F015", "F014" ] }, { "id": "T026", "description": "Integration: auto-apply on ticket creation — a rule matching the new ticket's board/category attaches the template; null matcher fields match any; non-matching rules don't fire; disabled rules don't fire.", "implemented": true, "featureIds": [ "F017" ] }, { "id": "T027", "description": "Integration: auto-apply on board/category change — moving a ticket into a matching board/category attaches the template once; moving it back and forth does not duplicate items.", "implemented": true, "featureIds": [ "F017" ] }, { "id": "T028", "description": "Integration: workflow-sourced checklist application (applyChecklistTemplateToTicket with source 'workflow', the helper the tickets.apply_checklist action delegates to) applies idempotently and stamps workflow provenance on the items.", "implemented": true, "featureIds": [ "F030" ] }, { "id": "T029", "description": "Integration: template/apply-rule/item CRUD actions reject callers without settings-admin permission; checklist item actions reject callers without ticket update permission.", "implemented": true, "featureIds": [ "F013", "F014" ] }, { "id": "T030", "description": "Integration (scan match): a ticket in a rule's trigger status with stale activity gets a ticket_auto_close_state row with scheduled_close_at = last_activity + inactivity_days; new activity (comment) on the next run recomputes/clears the row; status change away from the trigger status clears it; disabling the rule clears it.", "implemented": true, "featureIds": [ "F031" ] }, { "id": "T031", "description": "Integration (scan warn): warning sent exactly once when inside the window — notification service called with the ticket-auto-close-warning template, warning_sent_at stamped, AUTO_CLOSE_WARNING_SENT audit row — not resent on subsequent runs, and not sent at all when warning_days_before is null. Tenant/subtype gating lives inside the shared notification service.", "implemented": true, "featureIds": [ "F032" ] }, { "id": "T032", "description": "Integration (scan close): a due ticket — on a board with enabled close gates it cannot satisfy — closes to close_to_status_id with is_closed/closed_at set, closed_by null, system-attributed CLOSED audit row, automatic comment (metadata.source=auto_close), CLOSE_RULES_BYPASSED (source 'auto_close') audit entry, and TICKET_CLOSED published with a SYSTEM actor and no closedByUserId.", "implemented": true, "featureIds": [ "F033", "F022" ] }, { "id": "T033", "description": "Integration (scan race): activity recorded between the match snapshot and the close phase prevents the close (in-transaction revalidation); re-running the scan after a completed close is a no-op (idempotent).", "implemented": true, "featureIds": [ "F033" ] }, { "id": "T035", "description": "Integration (scan resilience): a ticket that throws during the close phase (e.g. deleted target status) is skipped with the error recorded, and the remaining due tickets in the same run still close.", "implemented": true, "featureIds": [ "F031", "F033" ] }, { "id": "T037", "description": "Integration: tenant isolation across the scan — tenant A's rules never match tenant B's tickets, and state/warning/close writes stay within the rule's tenant.", "implemented": true, "featureIds": [ "F031", "F033" ] }, { "id": "T046", "description": "Regression: closing a ticket on a board with no close rules behaves byte-for-byte as before (no validation queries in the hot path beyond the single board_close_rules lookup, no new audit entries, identical events).", "implemented": true, "featureIds": [ "F021", "F023", "F024" ] }, { "id": "T047", "description": "Regression: reopening a closed ticket still clears is_closed/closed_at/closed_by and publishes TICKET_REOPENED on every wired path, including the portal after F029.", "implemented": true, "featureIds": [ "F023", "F024", "F029" ] } ]