diff --git a/runtime/history/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4.json b/runtime/history/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4.json
new file mode 100644
index 00000000..8a5a2384
--- /dev/null
+++ b/runtime/history/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4.json
@@ -0,0 +1,38 @@
+{
+ "schema_version": 1,
+ "channel": "homelab-runtime",
+ "command_id": "SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4",
+ "status": "FAIL",
+ "rc": 3,
+ "host": "pve01",
+ "mode": "change",
+ "component": "gram-support-codevipe-fix10-retry-footer-canary",
+ "started_at_utc": "2026-09-18T01:41:17Z",
+ "finished_at_utc": "2026-09-18T01:41:39Z",
+ "reference_register_checked": true,
+ "reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66",
+ "error_register_checked": true,
+ "error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0",
+ "command_sha256": "99a6ef7d6eedc3560e74c799b69fe2cb21f2f532df5f109a12dbe6a4509f4cbf",
+ "duplicate_failed_command_blocked": false,
+ "block_reason": null,
+ "execution_started": true,
+ "change_declared": true,
+ "result_contract_valid": true,
+ "result_contract_status": "FAIL",
+ "result_contract_error": null,
+ "command_rc": 3,
+ "changes_made": true,
+ "rollback_started": true,
+ "rollback_restored": false,
+ "mutation_outcome": "ROLLBACK_FAILED",
+ "sanitized": true,
+ "secrets_included": false,
+ "private_addresses_included": false,
+ "raw_evidence_retained_locally": true,
+ "raw_evidence_sha256": "4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53",
+ "sanitized_output_sha256": "4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53",
+ "output_truncated_in_json": false,
+ "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt",
+ "output": "GRAM513R3R4_WRAPPER_BEGIN=true\nERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nAUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED\nGRAM513R3R4_BEGIN=true\nMODE=CHANGE_CODEVIPE_FIX10_RETRY_FOOTER_CANARY\nNO_DELETE=true\nTARGET=codevipe.ru\nGRAM513R3R4_SAFE_REPORT={\"guest\":{\"configure\":{\"ok\":true,\"site_option\":\"gramSupportSiteId\",\"site_id\":\"codevipe\",\"permission_entries_written\":22,\"permission_jobs\":[],\"all_jobs\":[{\"job_id\":4,\"execute_class\":\"XF\\\\Job\\\\Cron\"},{\"job_id\":50,\"execute_class\":\"XF\\\\Job\\\\UpgradeCheck\"},{\"job_id\":64366,\"execute_class\":\"XF\\\\Job\\\\TrendingResult\"},{\"job_id\":64369,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"},{\"job_id\":64371,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"},{\"job_id\":64372,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"},{\"job_id\":64373,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"}],\"baseline_unrelated_allowed\":[{\"job_id\":4,\"execute_class\":\"XF\\\\Job\\\\Cron\"},{\"job_id\":50,\"execute_class\":\"XF\\\\Job\\\\UpgradeCheck\"}],\"job_loops\":0},\"verify\":{\"ok\":false,\"checks\":{\"addon\":true,\"board_active\":true,\"tables\":false,\"routes4\":true,\"counts\":true,\"permissions\":true,\"site_id\":true,\"perm_jobs_zero\":true,\"manifest\":true,\"error_log\":false,\"footer_v7\":true,\"services\":true,\"http\":true},\"state\":{\"addon\":{\"addon_id\":\"Gram/Support\",\"title\":\"Gram Support\",\"version_id\":1000120,\"version_string\":\"1.0.0 Alpha 3 Unified Fix 10\",\"active\":1,\"is_processing\":0,\"last_pending_action\":null},\"counts\":{\"xf_content_type_field\":1,\"xf_code_event_listener\":1,\"xf_option\":4,\"xf_option_group\":1,\"xf_permission\":9,\"xf_permission_interface_group\":1,\"xf_phrase\":54,\"xf_route\":4,\"xf_template\":13,\"xf_template_modification\":1},\"support_tables\":[\"xf_gram_support_attachment_meta\",\"xf_gram_support_delivery\",\"xf_gram_support_event\",\"xf_gram_support_event__conflict\",\"xf_gram_support_message\",\"xf_gram_support_message__conflict\",\"xf_gram_support_rate_limit\",\"xf_gram_support_ticket\",\"xf_gram_support_ticket__conflict\"],\"support_table_rows\":{\"xf_gram_support_attachment_meta\":0,\"xf_gram_support_delivery\":0,\"xf_gram_support_event\":0,\"xf_gram_support_event__conflict\":0,\"xf_gram_support_message\":0,\"xf_gram_support_message__conflict\":0,\"xf_gram_support_rate_limit\":0,\"xf_gram_support_ticket\":0,\"xf_gram_support_ticket__conflict\":0},\"routes\":[{\"route_type\":\"public\",\"route_prefix\":\"account\",\"sub_name\":\"support\",\"format\":\"support\",\"controller\":\"Gram\\\\Support:AccountSupport\",\"addon_id\":\"Gram/Support\"},{\"route_type\":\"public\",\"route_prefix\":\"support\",\"sub_name\":\"\",\"format\":\"\",\"controller\":\"Gram\\\\Support:Support\",\"addon_id\":\"Gram/Support\"},{\"route_type\":\"public\",\"route_prefix\":\"support\",\"sub_name\":\"service-worker\",\"format\":\"service-worker\",\"controller\":\"Gram\\\\Support:Pwa\",\"addon_id\":\"Gram/Support\"},{\"route_type\":\"public\",\"route_prefix\":\"support\",\"sub_name\":\"staff\",\"format\":\"staff\",\"controller\":\"Gram\\\\Support:StaffSupport\",\"addon_id\":\"Gram/Support\"}],\"options\":[{\"option_id\":\"gramSupportGuestRateLimitCount\",\"option_value\":\"5\",\"default_value\":\"5\"},{\"option_id\":\"gramSupportGuestRateLimitWindowSeconds\",\"option_value\":\"3600\",\"default_value\":\"3600\"},{\"option_id\":\"gramSupportGuestTokenTtlDays\",\"option_value\":\"30\",\"default_value\":\"30\"},{\"option_id\":\"gramSupportSiteId\",\"option_value\":\"codevipe\",\"default_value\":\"\"}],\"permission_entries\":[{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"create\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"replyOwn\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"view\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewOwn\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"assign\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"create\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"internalNotes\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"manage\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"replyOwn\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"view\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewAll\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewOwn\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewTechnicalContext\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"assign\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"create\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"internalNotes\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"manage\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"replyOwn\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"view\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewAll\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewOwn\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewTechnicalContext\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0}],\"permission_jobs\":[],\"all_jobs\":[{\"job_id\":4,\"execute_class\":\"XF\\\\Job\\\\Cron\",\"manual_execute\":0},{\"job_id\":50,\"execute_class\":\"XF\\\\Job\\\\UpgradeCheck\",\"manual_execute\":0},{\"job_id\":64366,\"execute_class\":\"XF\\\\Job\\\\TrendingResult\",\"manual_execute\":0},{\"job_id\":64369,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0},{\"job_id\":64371,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0},{\"job_id\":64372,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0},{\"job_id\":64373,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0}],\"footer_template\":{\"template_id\":1416,\"version_id\":1000100,\"version_string\":\"1.0.0 Alpha 3 Unified Fix 8\",\"sha256\":\"ced49dfb6a64c55b06292c2b0d283847608f9c52434d6411cd93d06375ae225b\",\"marker\":true,\"shift\":true},\"board_active\":\"1\",\"board_url\":\"https://codevipe.ru\",\"error_max\":3,\"xf\":{\"version_id\":2031170,\"version_string\":\"2.3.11\"},\"php\":\"8.3.32\"},\"manifest\":{\"file_count\":59,\"combined_sha256\":\"a31fc0535de726fc779ef67d1cac8fea3cb518f738e5e47412825cddb1a34a7a\",\"addon_files\":51,\"addon_sha256\":\"f0054b4417c13226fe105c815e24466fd4dc5a2e65c7e11a04090206a95d9948\",\"outside_files\":8,\"outside_sha256\":\"9e657ea8877f40c9336807faa12d681c21f0261db5ad1aad3501dc0b48fdde58\",\"paths\":[\"js/gram/support/access.js\",\"js/gram/support/access.min.js\",\"js/gram/support/pwa/icon-192.png\",\"js/gram/support/pwa/icon-512.png\",\"js/gram/support/pwa/manifest.webmanifest\",\"js/gram/support/pwa/offline.html\",\"js/gram/support/staff-pwa.js\",\"js/gram/support/staff-pwa.min.js\",\"src/addons/Gram/Support/Attachment/TicketHandler.php\",\"src/addons/Gram/Support/Entity/AttachmentMeta.php\",\"src/addons/Gram/Support/Entity/Delivery.php\",\"src/addons/Gram/Support/Entity/Message.php\",\"src/addons/Gram/Support/Entity/RateLimit.php\",\"src/addons/Gram/Support/Entity/SupportEvent.php\",\"src/addons/Gram/Support/Entity/Ticket.php\",\"src/addons/Gram/Support/Listener/SourcePageContext.php\",\"src/addons/Gram/Support/Notification/AlertConsumer.php\",\"src/addons/Gram/Support/Notification/DeliveryGate.php\",\"src/addons/Gram/Support/Notification/Dispatcher.php\",\"src/addons/Gram/Support/Notification/EmailConsumer.php\",\"src/addons/Gram/Support/Notification/EntityDeliveryGate.php\",\"src/addons/Gram/Support/Notification/EventDispatcher.php\",\"src/addons/Gram/Support/Notification/Policy.php\",\"src/addons/Gram/Support/Notification/RecipientKey.php\",\"src/addons/Gram/Support/Pub/Controller/AccountSupport.php\",\"src/addons/Gram/Support/Pub/Controller/Pwa.php\",\"src/addons/Gram/Support/Pub/Controller/StaffSupport.php\",\"src/addons/Gram/Support/Pub/Controller/Support.php\",\"src/addons/Gram/Support/Pub/View/PwaServiceWorker.php\",\"src/addons/Gram/Support/Repository/Message.php\",\"src/addons/Gram/Support/Repository/Ticket.php\",\"src/addons/Gram/Support/Security/GuestTicketSession.php\",\"src/addons/Gram/Support/Security/TicketAccess.php\",\"src/addons/Gram/Support/Service/GuestScreenshotService.php\",\"src/addons/Gram/Support/Service/GuestTicketCreateAttachmentFlow.php\",\"src/addons/Gram/Support/Service/RateLimiter.php\",\"src/addons/Gram/Support/Service/SourceContextResolver.php\",\"src/addons/Gram/Support/Service/Ticket/Creator.php\",\"src/addons/Gram/Support/Service/Ticket/Reply.php\",\"src/addons/Gram/Support/Service/Ticket/StaffUpdate.php\",\"src/addons/Gram/Support/Setup.php\",\"src/addons/Gram/Support/Util/GuestToken.php\",\"src/addons/Gram/Support/Util/PublicRef.php\",\"src/addons/Gram/Support/Util/RateKey.php\",\"src/addons/Gram/Support/Util/SafeContext.php\",\"src/addons/Gram/Support/Util/SiteConfig.php\",\"src/addons/Gram/Support/Util/StatusPolicy.php\",\"src/addons/Gram/Support/_data/code_event_listeners.xml\",\"src/addons/Gram/Support/_data/content_type_fields.xml\",\"src/addons/Gram/Support/_data/option_groups.xml\",\"src/addons/Gram/Support/_data/options.xml\",\"src/addons/Gram/Support/_data/permission_interface_groups.xml\",\"src/addons/Gram/Support/_data/permissions.xml\",\"src/addons/Gram/Support/_data/phrases.xml\",\"src/addons/Gram/Support/_data/routes.xml\",\"src/addons/Gram/Support/_data/template_modifications.xml\",\"src/addons/Gram/Support/_data/templates.xml\",\"src/addons/Gram/Support/addon.json\",\"src/addons/Gram/Support/hashes.json\"]},\"services\":{\"mariadb\":\"active\",\"nginx\":\"active\",\"php8.3-fpm\":\"active\"},\"permission_counts\":{\"2\":4,\"3\":9,\"4\":9},\"http\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"200\"},\"/support/create/\":{\"rc\":0,\"code\":\"200\"}}},\"rollback\":{\"ok\":false,\"state_sig\":\"50eff6fb3c6a602194eb2dec2ff41e47c09988cc6ea08541851dac4a933db295\",\"manifest_sha\":\"c49c44a866b3e91224cade4c43d9a4594537fc1530ba54333cb959f3afe12a32\"},\"backup\":\"/root/codevipe-gram-support-backups/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4\"},\"pre_http\":{\"codevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"dsmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"gamevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"hkmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"kingofwolk.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"zakrutim.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"newfi.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}}},\"post_http\":{\"codevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"dsmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"gamevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"hkmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"kingofwolk.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"zakrutim.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"newfi.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}}},\"artifact_sha256\":\"2e31f89d3626a83c1211910aa6fd279cc04689b75ba822899952865085cf551e\",\"target\":\"codevipe.ru\"}\nGRAM513R3R4_DECISION=FAIL_CODEVIPE_FIX10_RETRY_VERIFY\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4\",\"status\":\"FAIL\",\"changes_made\":true,\"rollback_started\":true,\"rollback_restored\":false}\n"
+}
diff --git a/runtime/history/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4.txt b/runtime/history/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4.txt
new file mode 100644
index 00000000..6231d1a1
--- /dev/null
+++ b/runtime/history/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4.txt
@@ -0,0 +1,43 @@
+CHAT_OUTPUT_BEGIN
+COMMAND_ID=SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4
+STATUS=FAIL
+RC=3
+HOST=pve01
+MODE=change
+COMPONENT=gram-support-codevipe-fix10-retry-footer-canary
+REFERENCE_REGISTER_CHECK=OK
+REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66
+ERROR_REGISTER_CHECK=OK
+ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0
+COMMAND_SHA256=99a6ef7d6eedc3560e74c799b69fe2cb21f2f532df5f109a12dbe6a4509f4cbf
+DUPLICATE_FAILED_COMMAND_BLOCKED=false
+EXECUTION_STARTED=true
+CHANGE_DECLARED=true
+RESULT_CONTRACT_VALID=true
+RESULT_CONTRACT_STATUS=FAIL
+RESULT_CONTRACT_ERROR=NONE
+COMMAND_RC=3
+CHANGES_MADE=true
+ROLLBACK_STARTED=true
+ROLLBACK_RESTORED=false
+MUTATION_OUTCOME=ROLLBACK_FAILED
+SANITIZED=yes
+SECRETS_INCLUDED=no
+PRIVATE_ADDRESSES_INCLUDED=no
+RAW_EVIDENCE_SHA256=4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53
+SANITIZED_OUTPUT_SHA256=4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53
+OUTPUT_BEGIN
+GRAM513R3R4_WRAPPER_BEGIN=true
+ERROR_REGISTER_CHECK=OK
+REFERENCE_CHECK=OK
+AUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED
+GRAM513R3R4_BEGIN=true
+MODE=CHANGE_CODEVIPE_FIX10_RETRY_FOOTER_CANARY
+NO_DELETE=true
+TARGET=codevipe.ru
+GRAM513R3R4_SAFE_REPORT={"guest":{"configure":{"ok":true,"site_option":"gramSupportSiteId","site_id":"codevipe","permission_entries_written":22,"permission_jobs":[],"all_jobs":[{"job_id":4,"execute_class":"XF\\Job\\Cron"},{"job_id":50,"execute_class":"XF\\Job\\UpgradeCheck"},{"job_id":64366,"execute_class":"XF\\Job\\TrendingResult"},{"job_id":64369,"execute_class":"XF\\Job\\IconUsage"},{"job_id":64371,"execute_class":"XF\\Job\\IconUsage"},{"job_id":64372,"execute_class":"XF\\Job\\IconUsage"},{"job_id":64373,"execute_class":"XF\\Job\\IconUsage"}],"baseline_unrelated_allowed":[{"job_id":4,"execute_class":"XF\\Job\\Cron"},{"job_id":50,"execute_class":"XF\\Job\\UpgradeCheck"}],"job_loops":0},"verify":{"ok":false,"checks":{"addon":true,"board_active":true,"tables":false,"routes4":true,"counts":true,"permissions":true,"site_id":true,"perm_jobs_zero":true,"manifest":true,"error_log":false,"footer_v7":true,"services":true,"http":true},"state":{"addon":{"addon_id":"Gram/Support","title":"Gram Support","version_id":1000120,"version_string":"1.0.0 Alpha 3 Unified Fix 10","active":1,"is_processing":0,"last_pending_action":null},"counts":{"xf_content_type_field":1,"xf_code_event_listener":1,"xf_option":4,"xf_option_group":1,"xf_permission":9,"xf_permission_interface_group":1,"xf_phrase":54,"xf_route":4,"xf_template":13,"xf_template_modification":1},"support_tables":["xf_gram_support_attachment_meta","xf_gram_support_delivery","xf_gram_support_event","xf_gram_support_event__conflict","xf_gram_support_message","xf_gram_support_message__conflict","xf_gram_support_rate_limit","xf_gram_support_ticket","xf_gram_support_ticket__conflict"],"support_table_rows":{"xf_gram_support_attachment_meta":0,"xf_gram_support_delivery":0,"xf_gram_support_event":0,"xf_gram_support_event__conflict":0,"xf_gram_support_message":0,"xf_gram_support_message__conflict":0,"xf_gram_support_rate_limit":0,"xf_gram_support_ticket":0,"xf_gram_support_ticket__conflict":0},"routes":[{"route_type":"public","route_prefix":"account","sub_name":"support","format":"support","controller":"Gram\\Support:AccountSupport","addon_id":"Gram/Support"},{"route_type":"public","route_prefix":"support","sub_name":"","format":"","controller":"Gram\\Support:Support","addon_id":"Gram/Support"},{"route_type":"public","route_prefix":"support","sub_name":"service-worker","format":"service-worker","controller":"Gram\\Support:Pwa","addon_id":"Gram/Support"},{"route_type":"public","route_prefix":"support","sub_name":"staff","format":"staff","controller":"Gram\\Support:StaffSupport","addon_id":"Gram/Support"}],"options":[{"option_id":"gramSupportGuestRateLimitCount","option_value":"5","default_value":"5"},{"option_id":"gramSupportGuestRateLimitWindowSeconds","option_value":"3600","default_value":"3600"},{"option_id":"gramSupportGuestTokenTtlDays","option_value":"30","default_value":"30"},{"option_id":"gramSupportSiteId","option_value":"codevipe","default_value":""}],"permission_entries":[{"permission_group_id":"gramSupport","permission_id":"create","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"replyOwn","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"view","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewOwn","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"assign","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"create","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"internalNotes","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"manage","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"replyOwn","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"view","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewAll","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewOwn","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewTechnicalContext","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"assign","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"create","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"internalNotes","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"manage","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"replyOwn","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"view","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewAll","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewOwn","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewTechnicalContext","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0}],"permission_jobs":[],"all_jobs":[{"job_id":4,"execute_class":"XF\\Job\\Cron","manual_execute":0},{"job_id":50,"execute_class":"XF\\Job\\UpgradeCheck","manual_execute":0},{"job_id":64366,"execute_class":"XF\\Job\\TrendingResult","manual_execute":0},{"job_id":64369,"execute_class":"XF\\Job\\IconUsage","manual_execute":0},{"job_id":64371,"execute_class":"XF\\Job\\IconUsage","manual_execute":0},{"job_id":64372,"execute_class":"XF\\Job\\IconUsage","manual_execute":0},{"job_id":64373,"execute_class":"XF\\Job\\IconUsage","manual_execute":0}],"footer_template":{"template_id":1416,"version_id":1000100,"version_string":"1.0.0 Alpha 3 Unified Fix 8","sha256":"ced49dfb6a64c55b06292c2b0d283847608f9c52434d6411cd93d06375ae225b","marker":true,"shift":true},"board_active":"1","board_url":"https://codevipe.ru","error_max":3,"xf":{"version_id":2031170,"version_string":"2.3.11"},"php":"8.3.32"},"manifest":{"file_count":59,"combined_sha256":"a31fc0535de726fc779ef67d1cac8fea3cb518f738e5e47412825cddb1a34a7a","addon_files":51,"addon_sha256":"f0054b4417c13226fe105c815e24466fd4dc5a2e65c7e11a04090206a95d9948","outside_files":8,"outside_sha256":"9e657ea8877f40c9336807faa12d681c21f0261db5ad1aad3501dc0b48fdde58","paths":["js/gram/support/access.js","js/gram/support/access.min.js","js/gram/support/pwa/icon-192.png","js/gram/support/pwa/icon-512.png","js/gram/support/pwa/manifest.webmanifest","js/gram/support/pwa/offline.html","js/gram/support/staff-pwa.js","js/gram/support/staff-pwa.min.js","src/addons/Gram/Support/Attachment/TicketHandler.php","src/addons/Gram/Support/Entity/AttachmentMeta.php","src/addons/Gram/Support/Entity/Delivery.php","src/addons/Gram/Support/Entity/Message.php","src/addons/Gram/Support/Entity/RateLimit.php","src/addons/Gram/Support/Entity/SupportEvent.php","src/addons/Gram/Support/Entity/Ticket.php","src/addons/Gram/Support/Listener/SourcePageContext.php","src/addons/Gram/Support/Notification/AlertConsumer.php","src/addons/Gram/Support/Notification/DeliveryGate.php","src/addons/Gram/Support/Notification/Dispatcher.php","src/addons/Gram/Support/Notification/EmailConsumer.php","src/addons/Gram/Support/Notification/EntityDeliveryGate.php","src/addons/Gram/Support/Notification/EventDispatcher.php","src/addons/Gram/Support/Notification/Policy.php","src/addons/Gram/Support/Notification/RecipientKey.php","src/addons/Gram/Support/Pub/Controller/AccountSupport.php","src/addons/Gram/Support/Pub/Controller/Pwa.php","src/addons/Gram/Support/Pub/Controller/StaffSupport.php","src/addons/Gram/Support/Pub/Controller/Support.php","src/addons/Gram/Support/Pub/View/PwaServiceWorker.php","src/addons/Gram/Support/Repository/Message.php","src/addons/Gram/Support/Repository/Ticket.php","src/addons/Gram/Support/Security/GuestTicketSession.php","src/addons/Gram/Support/Security/TicketAccess.php","src/addons/Gram/Support/Service/GuestScreenshotService.php","src/addons/Gram/Support/Service/GuestTicketCreateAttachmentFlow.php","src/addons/Gram/Support/Service/RateLimiter.php","src/addons/Gram/Support/Service/SourceContextResolver.php","src/addons/Gram/Support/Service/Ticket/Creator.php","src/addons/Gram/Support/Service/Ticket/Reply.php","src/addons/Gram/Support/Service/Ticket/StaffUpdate.php","src/addons/Gram/Support/Setup.php","src/addons/Gram/Support/Util/GuestToken.php","src/addons/Gram/Support/Util/PublicRef.php","src/addons/Gram/Support/Util/RateKey.php","src/addons/Gram/Support/Util/SafeContext.php","src/addons/Gram/Support/Util/SiteConfig.php","src/addons/Gram/Support/Util/StatusPolicy.php","src/addons/Gram/Support/_data/code_event_listeners.xml","src/addons/Gram/Support/_data/content_type_fields.xml","src/addons/Gram/Support/_data/option_groups.xml","src/addons/Gram/Support/_data/options.xml","src/addons/Gram/Support/_data/permission_interface_groups.xml","src/addons/Gram/Support/_data/permissions.xml","src/addons/Gram/Support/_data/phrases.xml","src/addons/Gram/Support/_data/routes.xml","src/addons/Gram/Support/_data/template_modifications.xml","src/addons/Gram/Support/_data/templates.xml","src/addons/Gram/Support/addon.json","src/addons/Gram/Support/hashes.json"]},"services":{"mariadb":"active","nginx":"active","php8.3-fpm":"active"},"permission_counts":{"2":4,"3":9,"4":9},"http":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"200"},"/support/create/":{"rc":0,"code":"200"}}},"rollback":{"ok":false,"state_sig":"50eff6fb3c6a602194eb2dec2ff41e47c09988cc6ea08541851dac4a933db295","manifest_sha":"c49c44a866b3e91224cade4c43d9a4594537fc1530ba54333cb959f3afe12a32"},"backup":"/root/codevipe-gram-support-backups/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4"},"pre_http":{"codevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"dsmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"gamevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"hkmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"kingofwolk.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"zakrutim.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"newfi.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}}},"post_http":{"codevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"dsmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"gamevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"hkmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"kingofwolk.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"zakrutim.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"newfi.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}}},"artifact_sha256":"2e31f89d3626a83c1211910aa6fd279cc04689b75ba822899952865085cf551e","target":"codevipe.ru"}
+GRAM513R3R4_DECISION=FAIL_CODEVIPE_FIX10_RETRY_VERIFY
+HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4","status":"FAIL","changes_made":true,"rollback_started":true,"rollback_restored":false}
+
+OUTPUT_END
+CHAT_OUTPUT_END
diff --git a/runtime/latest.json b/runtime/latest.json
index ee585491..8a5a2384 100644
--- a/runtime/latest.json
+++ b/runtime/latest.json
@@ -1,38 +1,38 @@
{
"schema_version": 1,
"channel": "homelab-runtime",
- "command_id": "SUPPORT-260918-GRAM-XF-CODEVIPE-NATIVE-RESUME-SCHEMA-RCA-513R3R3",
- "status": "OK",
- "rc": 0,
+ "command_id": "SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4",
+ "status": "FAIL",
+ "rc": 3,
"host": "pve01",
- "mode": "read-only",
- "component": "gram-support-codevipe-native-resume-schema-rca",
- "started_at_utc": "2026-09-18T01:33:03Z",
- "finished_at_utc": "2026-09-18T01:33:05Z",
+ "mode": "change",
+ "component": "gram-support-codevipe-fix10-retry-footer-canary",
+ "started_at_utc": "2026-09-18T01:41:17Z",
+ "finished_at_utc": "2026-09-18T01:41:39Z",
"reference_register_checked": true,
"reference_sha256": "5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66",
"error_register_checked": true,
"error_register_sha256": "3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0",
- "command_sha256": "d024725d107ae38e09893a322f7a365399e215a929d3c723a3099129609390bf",
+ "command_sha256": "99a6ef7d6eedc3560e74c799b69fe2cb21f2f532df5f109a12dbe6a4509f4cbf",
"duplicate_failed_command_blocked": false,
"block_reason": null,
"execution_started": true,
- "change_declared": false,
+ "change_declared": true,
"result_contract_valid": true,
- "result_contract_status": null,
+ "result_contract_status": "FAIL",
"result_contract_error": null,
- "command_rc": 0,
- "changes_made": false,
- "rollback_started": false,
- "rollback_restored": null,
- "mutation_outcome": "NO_MUTATION",
+ "command_rc": 3,
+ "changes_made": true,
+ "rollback_started": true,
+ "rollback_restored": false,
+ "mutation_outcome": "ROLLBACK_FAILED",
"sanitized": true,
"secrets_included": false,
"private_addresses_included": false,
"raw_evidence_retained_locally": true,
- "raw_evidence_sha256": "3356fd66c51344f1c1c25279dd2f3ad70b12040178c3a7513b0aa812b569ae94",
- "sanitized_output_sha256": "3356fd66c51344f1c1c25279dd2f3ad70b12040178c3a7513b0aa812b569ae94",
+ "raw_evidence_sha256": "4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53",
+ "sanitized_output_sha256": "4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53",
"output_truncated_in_json": false,
"full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt",
- "output": "GRAM513R3R3_WRAPPER_BEGIN=true\nERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nAUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED\nGRAM513R3R3_SAFE_REPORT={\"artifact\":{\"sha256\":\"2e31f89d3626a83c1211910aa6fd279cc04689b75ba822899952865085cf551e\",\"version_id\":1000120,\"version_string\":\"1.0.0 Alpha 3 Unified Fix 10\",\"setup_tables\":[\"xf_gram_support_ticket\",\"xf_gram_support_message\",\"xf_gram_support_event\",\"xf_gram_support_attachment_meta\",\"xf_gram_support_delivery\",\"xf_gram_support_rate_limit\"],\"setup_sha256\":\"4977f90ec0444e2e3a1e4ee9b79a4e88098c5a3ae37b30d63e77cff2e1fcb971\"},\"codevipe\":{\"ok\":true,\"tables\":{\"xf_gram_support_ticket\":{\"exists\":true,\"rows\":0,\"ddl_sha256\":\"3558077fc70b4453960d1d782998ad498b2d3b12ba587488e8b23785979f7ba8\",\"ddl\":\"CREATE TABLE `xf_gram_support_ticket` (\\n `ticket_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\\n `public_ref` varchar(64) NOT NULL,\\n `site_id` varchar(32) NOT NULL,\\n `user_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `guest_email` varchar(255) NOT NULL DEFAULT '',\\n `guest_access_token_hash` char(64) NOT NULL DEFAULT '',\\n `guest_access_expires` int(10) unsigned NOT NULL DEFAULT 0,\\n `node_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `thread_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `post_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `category` varchar(64) NOT NULL DEFAULT '',\\n `subject` varchar(255) NOT NULL DEFAULT '',\\n `status` varchar(32) NOT NULL DEFAULT 'NEW',\\n `assigned_user_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `created_date` int(10) unsigned NOT NULL DEFAULT 0,\\n `updated_date` int(10) unsigned NOT NULL DEFAULT 0,\\n `resolved_date` int(10) unsigned NOT NULL DEFAULT 0,\\n `context_json` mediumtext NOT NULL,\\n `last_message_id` int(10) unsigned NOT NULL DEFAULT 0,\\n PRIMARY KEY (`ticket_id`),\\n UNIQUE KEY `public_ref` (`public_ref`),\\n KEY `guest_token_hash` (`guest_access_token_hash`),\\n KEY `site_user_updated` (`site_id`,`user_id`,`updated_date`),\\n KEY `site_status_updated` (`site_id`,`status`,`updated_date`)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci\"},\"xf_gram_support_message\":{\"exists\":true,\"rows\":0,\"ddl_sha256\":\"a00e534c642179db3018c74060d1aa6cef4dc445dcb801eb847c04d770f8f884\",\"ddl\":\"CREATE TABLE `xf_gram_support_message` (\\n `message_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\\n `ticket_id` int(10) unsigned NOT NULL,\\n `user_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `is_staff` tinyint(3) unsigned NOT NULL DEFAULT 0,\\n `is_internal` tinyint(3) unsigned NOT NULL DEFAULT 0,\\n `message` mediumtext NOT NULL,\\n `message_date` int(10) unsigned NOT NULL DEFAULT 0,\\n PRIMARY KEY (`message_id`),\\n KEY `ticket_date` (`ticket_id`,`message_date`),\\n KEY `ticket_public_date` (`ticket_id`,`is_internal`,`message_date`)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci\"},\"xf_gram_support_event\":{\"exists\":true,\"rows\":0,\"ddl_sha256\":\"81b6328dbbcf3f6405891897ba185e29890c675f21d7a2f9caf827c0eddb42da\",\"ddl\":\"CREATE TABLE `xf_gram_support_event` (\\n `event_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\\n `ticket_id` int(10) unsigned NOT NULL,\\n `site_id` varchar(32) NOT NULL,\\n `actor_user_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `event_type` varchar(64) NOT NULL,\\n `event_date` int(10) unsigned NOT NULL DEFAULT 0,\\n `safe_payload_json` mediumtext NOT NULL,\\n PRIMARY KEY (`event_id`),\\n KEY `ticket_date` (`ticket_id`,`event_date`)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci\"},\"xf_gram_support_attachment_meta\":{\"exists\":true,\"rows\":0,\"ddl_sha256\":\"3c3d2ce4c5dae793687243dca37f60cd781895818b546a68e227aef9bfc9b6b2\",\"ddl\":\"CREATE TABLE `xf_gram_support_attachment_meta` (\\n `attachment_id` int(10) unsigned NOT NULL,\\n `ticket_id` int(10) unsigned NOT NULL,\\n `message_id` int(10) unsigned NOT NULL DEFAULT 0,\\n `is_internal` tinyint(3) unsigned NOT NULL DEFAULT 0,\\n `created_date` int(10) unsigned NOT NULL DEFAULT 0,\\n PRIMARY KEY (`attachment_id`),\\n KEY `ticket_internal` (`ticket_id`,`is_internal`),\\n KEY `message_id` (`message_id`)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci\"},\"xf_gram_support_delivery\":{\"exists\":true,\"rows\":0,\"ddl_sha256\":\"91f068994bdbe4b168ab1c82fa669180f13825e6d1a7f5b9e956ccc872d0410d\",\"ddl\":\"CREATE TABLE `xf_gram_support_delivery` (\\n `delivery_key` char(64) NOT NULL,\\n `event_id` int(10) unsigned NOT NULL,\\n `consumer` varchar(32) NOT NULL,\\n `recipient_key` varchar(96) NOT NULL,\\n `state` varchar(16) NOT NULL DEFAULT 'pending',\\n `lease_expires` int(10) unsigned NOT NULL DEFAULT 0,\\n `attempt_count` int(10) unsigned NOT NULL DEFAULT 0,\\n `last_failure_class` varchar(191) NOT NULL DEFAULT '',\\n `created_date` int(10) unsigned NOT NULL DEFAULT 0,\\n `updated_date` int(10) unsigned NOT NULL DEFAULT 0,\\n `sent_date` int(10) unsigned NOT NULL DEFAULT 0,\\n PRIMARY KEY (`delivery_key`),\\n KEY `event_consumer` (`event_id`,`consumer`),\\n KEY `state_lease` (`state`,`lease_expires`)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci\"},\"xf_gram_support_rate_limit\":{\"exists\":true,\"rows\":0,\"ddl_sha256\":\"f2271e20d520a8ba413b2094a4f8f6640395065c7d9c2e4f5b0a74b790d3dd8e\",\"ddl\":\"CREATE TABLE `xf_gram_support_rate_limit` (\\n `rate_key` char(64) NOT NULL,\\n `window_start` int(10) unsigned NOT NULL,\\n `hit_count` int(10) unsigned NOT NULL DEFAULT 0,\\n `updated_date` int(10) unsigned NOT NULL DEFAULT 0,\\n PRIMARY KEY (`rate_key`),\\n KEY `updated_date` (`updated_date`)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci\"}},\"addon\":null,\"schema_manager_class\":\"XF\\\\Db\\\\SchemaManager\",\"schema_methods\":{\"createTable\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\SchemaManager\",\"method\":\"createTable\",\"file\":\"SchemaManager.php\",\"start\":187,\"end\":200,\"sha256\":\"be6c143b9b8321148d841530fe0e5f8388b5fa178a96a8a1fe759e8208eb71a4\",\"source\":\"\\tpublic function createTable($tableName, \\\\Closure $toApply)\\n\\t{\\n\\t\\t$create = $this->newTable($tableName);\\n\\n\\t\\ttry\\n\\t\\t{\\n\\t\\t\\t$toApply($create);\\n\\t\\t\\t$create->apply();\\n\\t\\t}\\n\\t\\tcatch (\\\\Exception $e)\\n\\t\\t{\\n\\t\\t\\t$this->handleException($e, $tableName, $create);\\n\\t\\t}\\n\\t}\\n\",\"lines\":[{\"line\":187,\"text\":\"\\tpublic function createTable($tableName, \\\\Closure $toApply)\"},{\"line\":188,\"text\":\"\\t{\"},{\"line\":189,\"text\":\"\\t\\t$create = $this->newTable($tableName);\"},{\"line\":190,\"text\":\"\"},{\"line\":191,\"text\":\"\\t\\ttry\"},{\"line\":192,\"text\":\"\\t\\t{\"},{\"line\":193,\"text\":\"\\t\\t\\t$toApply($create);\"},{\"line\":194,\"text\":\"\\t\\t\\t$create->apply();\"},{\"line\":195,\"text\":\"\\t\\t}\"},{\"line\":196,\"text\":\"\\t\\tcatch (\\\\Exception $e)\"},{\"line\":197,\"text\":\"\\t\\t{\"},{\"line\":198,\"text\":\"\\t\\t\\t$this->handleException($e, $tableName, $create);\"},{\"line\":199,\"text\":\"\\t\\t}\"},{\"line\":200,\"text\":\"\\t}\"}]},\"newTable\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\SchemaManager\",\"method\":\"newTable\",\"file\":\"SchemaManager.php\",\"start\":239,\"end\":242,\"sha256\":\"482ad432f7e1304bb4289a1e56fb600d7dfb3708393ec2fd4d6ceba61f8d61de\",\"source\":\"\\tpublic function newTable($tableName)\\n\\t{\\n\\t\\treturn new Create($this->db, $this, $tableName);\\n\\t}\\n\",\"lines\":[{\"line\":239,\"text\":\"\\tpublic function newTable($tableName)\"},{\"line\":240,\"text\":\"\\t{\"},{\"line\":241,\"text\":\"\\t\\treturn new Create($this->db, $this, $tableName);\"},{\"line\":242,\"text\":\"\\t}\"}]},\"handleException\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\SchemaManager\",\"method\":\"handleException\",\"file\":\"SchemaManager.php\",\"start\":254,\"end\":270,\"sha256\":\"bcfbb554306aeb3c108d447c45183c8d6c2415d91e9e785a9671ea1900dbc103\",\"source\":\"\\tprotected function handleException($exception, $tableName, AbstractDdl $ddl)\\n\\t{\\n\\t\\t// The exception might have some extra useful stuff in it, so include attempt to modify the message directly.\\n\\n\\t\\ttry\\n\\t\\t{\\n\\t\\t\\t$reflectionClass = new \\\\ReflectionClass($exception);\\n\\t\\t\\t$messageProperty = $reflectionClass->getProperty('message');\\n\\t\\t\\t$messageProperty->setAccessible(true);\\n\\t\\t\\t$messageProperty->setValue($exception, $tableName . ': ' . $messageProperty->getValue($exception));\\n\\t\\t}\\n\\t\\tcatch (\\\\ReflectionException $ignored)\\n\\t\\t{\\n\\t\\t}\\n\\n\\t\\tthrow $exception;\\n\\t}\\n\",\"lines\":[{\"line\":254,\"text\":\"\\tprotected function handleException($exception, $tableName, AbstractDdl $ddl)\"},{\"line\":255,\"text\":\"\\t{\"},{\"line\":256,\"text\":\"\\t\\t// The exception might have some extra useful stuff in it, so include attempt to modify the message directly.\"},{\"line\":257,\"text\":\"\"},{\"line\":258,\"text\":\"\\t\\ttry\"},{\"line\":259,\"text\":\"\\t\\t{\"},{\"line\":260,\"text\":\"\\t\\t\\t$reflectionClass = new \\\\ReflectionClass($exception);\"},{\"line\":261,\"text\":\"\\t\\t\\t$messageProperty = $reflectionClass->getProperty('message');\"},{\"line\":262,\"text\":\"\\t\\t\\t$messageProperty->setAccessible(true);\"},{\"line\":263,\"text\":\"\\t\\t\\t$messageProperty->setValue($exception, $tableName . ': ' . $messageProperty->getValue($exception));\"},{\"line\":264,\"text\":\"\\t\\t}\"},{\"line\":265,\"text\":\"\\t\\tcatch (\\\\ReflectionException $ignored)\"},{\"line\":266,\"text\":\"\\t\\t{\"},{\"line\":267,\"text\":\"\\t\\t}\"},{\"line\":268,\"text\":\"\"},{\"line\":269,\"text\":\"\\t\\tthrow $exception;\"},{\"line\":270,\"text\":\"\\t}\"}]},\"alterTable\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\SchemaManager\",\"method\":\"alterTable\",\"file\":\"SchemaManager.php\",\"start\":150,\"end\":163,\"sha256\":\"5e9788e5e9344db7c332d6c7e728a050f83967ac6d9d8a06727d266dcbbcc787\",\"source\":\"\\tpublic function alterTable($tableName, \\\\Closure $toApply)\\n\\t{\\n\\t\\t$alter = $this->newAlter($tableName);\\n\\n\\t\\ttry\\n\\t\\t{\\n\\t\\t\\t$toApply($alter);\\n\\t\\t\\t$alter->apply();\\n\\t\\t}\\n\\t\\tcatch (\\\\Exception $e)\\n\\t\\t{\\n\\t\\t\\t$this->handleException($e, $tableName, $alter);\\n\\t\\t}\\n\\t}\\n\",\"lines\":[{\"line\":150,\"text\":\"\\tpublic function alterTable($tableName, \\\\Closure $toApply)\"},{\"line\":151,\"text\":\"\\t{\"},{\"line\":152,\"text\":\"\\t\\t$alter = $this->newAlter($tableName);\"},{\"line\":153,\"text\":\"\"},{\"line\":154,\"text\":\"\\t\\ttry\"},{\"line\":155,\"text\":\"\\t\\t{\"},{\"line\":156,\"text\":\"\\t\\t\\t$toApply($alter);\"},{\"line\":157,\"text\":\"\\t\\t\\t$alter->apply();\"},{\"line\":158,\"text\":\"\\t\\t}\"},{\"line\":159,\"text\":\"\\t\\tcatch (\\\\Exception $e)\"},{\"line\":160,\"text\":\"\\t\\t{\"},{\"line\":161,\"text\":\"\\t\\t\\t$this->handleException($e, $tableName, $alter);\"},{\"line\":162,\"text\":\"\\t\\t}\"},{\"line\":163,\"text\":\"\\t}\"}]},\"renameTable\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\SchemaManager\",\"method\":\"renameTable\",\"file\":\"SchemaManager.php\",\"start\":169,\"end\":181,\"sha256\":\"c352def9c86f9233a9c629670c5334a436092765a9c121807a21ef536510d7db\",\"source\":\"\\tpublic function renameTable($oldTableName, $newTableName)\\n\\t{\\n\\t\\t$alter = $this->newAlter($oldTableName)->renameTo($newTableName);\\n\\n\\t\\ttry\\n\\t\\t{\\n\\t\\t\\t$alter->apply();\\n\\t\\t}\\n\\t\\tcatch (\\\\Exception $e)\\n\\t\\t{\\n\\t\\t\\t$this->handleException($e, $oldTableName, $alter);\\n\\t\\t}\\n\\t}\\n\",\"lines\":[{\"line\":169,\"text\":\"\\tpublic function renameTable($oldTableName, $newTableName)\"},{\"line\":170,\"text\":\"\\t{\"},{\"line\":171,\"text\":\"\\t\\t$alter = $this->newAlter($oldTableName)->renameTo($newTableName);\"},{\"line\":172,\"text\":\"\"},{\"line\":173,\"text\":\"\\t\\ttry\"},{\"line\":174,\"text\":\"\\t\\t{\"},{\"line\":175,\"text\":\"\\t\\t\\t$alter->apply();\"},{\"line\":176,\"text\":\"\\t\\t}\"},{\"line\":177,\"text\":\"\\t\\tcatch (\\\\Exception $e)\"},{\"line\":178,\"text\":\"\\t\\t{\"},{\"line\":179,\"text\":\"\\t\\t\\t$this->handleException($e, $oldTableName, $alter);\"},{\"line\":180,\"text\":\"\\t\\t}\"},{\"line\":181,\"text\":\"\\t}\"}]},\"tableExists\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\SchemaManager\",\"method\":\"tableExists\",\"file\":\"SchemaManager.php\",\"start\":119,\"end\":124,\"sha256\":\"234d0c64067ebbf246972acbed6d58574c535e2ad78478d529afd97963551070\",\"source\":\"\\tpublic function tableExists($tableName)\\n\\t{\\n\\t\\t$status = $this->getTableStatus($tableName);\\n\\n\\t\\treturn $status ? true : false;\\n\\t}\\n\",\"lines\":[{\"line\":119,\"text\":\"\\tpublic function tableExists($tableName)\"},{\"line\":120,\"text\":\"\\t{\"},{\"line\":121,\"text\":\"\\t\\t$status = $this->getTableStatus($tableName);\"},{\"line\":122,\"text\":\"\"},{\"line\":123,\"text\":\"\\t\\treturn $status ? true : false;\"},{\"line\":124,\"text\":\"\\t}\"}]}},\"table_create_class\":\"XF\\\\Db\\\\Schema\\\\Create\",\"table_create_methods\":{\"apply\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\Schema\\\\Create\",\"method\":\"apply\",\"file\":\"AbstractDdl.php\",\"start\":152,\"end\":162,\"sha256\":\"70bf8158872ac741e410f19c8a3893809f6a4514907495ec2fe6af5204446493\",\"source\":\"\\tpublic function apply()\\n\\t{\\n\\t\\t$queries = $this->getQueries();\\n\\n\\t\\tforeach ($queries AS $query)\\n\\t\\t{\\n\\t\\t\\t$this->db->query($query);\\n\\t\\t}\\n\\n\\t\\treturn $queries;\\n\\t}\\n\",\"lines\":[{\"line\":152,\"text\":\"\\tpublic function apply()\"},{\"line\":153,\"text\":\"\\t{\"},{\"line\":154,\"text\":\"\\t\\t$queries = $this->getQueries();\"},{\"line\":155,\"text\":\"\"},{\"line\":156,\"text\":\"\\t\\tforeach ($queries AS $query)\"},{\"line\":157,\"text\":\"\\t\\t{\"},{\"line\":158,\"text\":\"\\t\\t\\t$this->db->query($query);\"},{\"line\":159,\"text\":\"\\t\\t}\"},{\"line\":160,\"text\":\"\"},{\"line\":161,\"text\":\"\\t\\treturn $queries;\"},{\"line\":162,\"text\":\"\\t}\"}]},\"getQueries\":{\"ok\":true,\"class\":\"XF\\\\Db\\\\Schema\\\\Create\",\"method\":\"getQueries\",\"file\":\"Create.php\",\"start\":26,\"end\":110,\"sha256\":\"86696c181f223784f11bf6591fd070796b316648462933706f2702ca20eff475\",\"source\":\"\\tpublic function getQueries()\\n\\t{\\n\\t\\t$tableName = $this->tableName;\\n\\n\\t\\t$queries = [];\\n\\n\\t\\t$query = 'CREATE TABLE';\\n\\n\\t\\tif ($this->checkExists)\\n\\t\\t{\\n\\t\\t\\t$query .= ' IF NOT EXISTS';\\n\\t\\t}\\n\\t\\telse\\n\\t\\t{\\n\\t\\t\\t$existing = $this->db->getSchemaManager()->getTableStatus($tableName);\\n\\t\\t\\tif ($existing)\\n\\t\\t\\t{\\n\\t\\t\\t\\t$existing = new static($this->db, $this->sm, $tableName);\\n\\t\\t\\t\\t$existing->setDefinition();\\n\\n\\t\\t\\t\\tif ($this->compare($existing))\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\t\\t// new table is identical, so just skip it\\n\\t\\t\\t\\t\\treturn [];\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\telse if ($this->forceChanges)\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\t\\t$conflictName = $tableName . '__conflict';\\n\\t\\t\\t\\t\\tif ($this->sm->tableExists($conflictName))\\n\\t\\t\\t\\t\\t{\\n\\t\\t\\t\\t\\t\\t$i = 2;\\n\\t\\t\\t\\t\\t\\twhile ($this->sm->tableExists($conflictName . $i))\\n\\t\\t\\t\\t\\t\\t{\\n\\t\\t\\t\\t\\t\\t\\t$i++;\\n\\t\\t\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\t\\t\\t$conflictName .= $i;\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t\\t$queries[] = \\\"ALTER TABLE `$tableName` RENAME TO `$conflictName`\\\";\\n\\n\\t\\t\\t\\t\\t$errorMessage = sprintf(\\n\\t\\t\\t\\t\\t\\t\\\"Renamed table %s to %s to avoid schema conflict\\\",\\n\\t\\t\\t\\t\\t\\t$tableName,\\n\\t\\t\\t\\t\\t\\t$conflictName\\n\\t\\t\\t\\t\\t);\\n\\n\\t\\t\\t\\t\\t\\\\XF::logError($errorMessage, true);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\telse\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\t\\tthrow new \\\\LogicException(\\\"$tableName already exists, but the structure does not match.\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\t$query .= \\\" `$tableName` (\\\\n\\\\t\\\";\\n\\n\\t\\t$tableDefinition = [];\\n\\t\\tforeach ($this->addColumns AS $column)\\n\\t\\t{\\n\\t\\t\\t$tableDefinition[] = $column->getDefinition();\\n\\t\\t}\\n\\t\\tforeach ($this->addIndexes AS $index)\\n\\t\\t{\\n\\t\\t\\t$tableDefinition[$index->getIndexName()] = $index->getDefinition();\\n\\t\\t}\\n\\n\\t\\t$query .= implode(\\\",\\\\n\\\\t\\\", $tableDefinition);\\n\\t\\t$query .= \\\"\\\\n)\\\";\\n\\t\\t$query .= ' ' . $this->db->getSchemaManager()->getTableConfigSql($this->engine ?: null);\\n\\n\\t\\tif ($this->comment)\\n\\t\\t{\\n\\t\\t\\t$query .= ' COMMENT=' . $this->db->quote($this->comment);\\n\\t\\t}\\n\\n\\t\\tif ($this->autoIncrementIndex !== null)\\n\\t\\t{\\n\\t\\t\\t$query .= ' AUTO_INCREMENT=' . $this->autoIncrementIndex;\\n\\t\\t}\\n\\n\\t\\t$queries[] = $query;\\n\\n\\t\\treturn $queries;\\n\\t}\\n\",\"lines\":[{\"line\":26,\"text\":\"\\tpublic function getQueries()\"},{\"line\":27,\"text\":\"\\t{\"},{\"line\":28,\"text\":\"\\t\\t$tableName = $this->tableName;\"},{\"line\":29,\"text\":\"\"},{\"line\":30,\"text\":\"\\t\\t$queries = [];\"},{\"line\":31,\"text\":\"\"},{\"line\":32,\"text\":\"\\t\\t$query = 'CREATE TABLE';\"},{\"line\":33,\"text\":\"\"},{\"line\":34,\"text\":\"\\t\\tif ($this->checkExists)\"},{\"line\":35,\"text\":\"\\t\\t{\"},{\"line\":36,\"text\":\"\\t\\t\\t$query .= ' IF NOT EXISTS';\"},{\"line\":37,\"text\":\"\\t\\t}\"},{\"line\":38,\"text\":\"\\t\\telse\"},{\"line\":39,\"text\":\"\\t\\t{\"},{\"line\":40,\"text\":\"\\t\\t\\t$existing = $this->db->getSchemaManager()->getTableStatus($tableName);\"},{\"line\":41,\"text\":\"\\t\\t\\tif ($existing)\"},{\"line\":42,\"text\":\"\\t\\t\\t{\"},{\"line\":43,\"text\":\"\\t\\t\\t\\t$existing = new static($this->db, $this->sm, $tableName);\"},{\"line\":44,\"text\":\"\\t\\t\\t\\t$existing->setDefinition();\"},{\"line\":45,\"text\":\"\"},{\"line\":46,\"text\":\"\\t\\t\\t\\tif ($this->compare($existing))\"},{\"line\":47,\"text\":\"\\t\\t\\t\\t{\"},{\"line\":48,\"text\":\"\\t\\t\\t\\t\\t// new table is identical, so just skip it\"},{\"line\":49,\"text\":\"\\t\\t\\t\\t\\treturn [];\"},{\"line\":50,\"text\":\"\\t\\t\\t\\t}\"},{\"line\":51,\"text\":\"\\t\\t\\t\\telse if ($this->forceChanges)\"},{\"line\":52,\"text\":\"\\t\\t\\t\\t{\"},{\"line\":53,\"text\":\"\\t\\t\\t\\t\\t$conflictName = $tableName . '__conflict';\"},{\"line\":54,\"text\":\"\\t\\t\\t\\t\\tif ($this->sm->tableExists($conflictName))\"},{\"line\":55,\"text\":\"\\t\\t\\t\\t\\t{\"},{\"line\":56,\"text\":\"\\t\\t\\t\\t\\t\\t$i = 2;\"},{\"line\":57,\"text\":\"\\t\\t\\t\\t\\t\\twhile ($this->sm->tableExists($conflictName . $i))\"},{\"line\":58,\"text\":\"\\t\\t\\t\\t\\t\\t{\"},{\"line\":59,\"text\":\"\\t\\t\\t\\t\\t\\t\\t$i++;\"},{\"line\":60,\"text\":\"\\t\\t\\t\\t\\t\\t}\"},{\"line\":61,\"text\":\"\"},{\"line\":62,\"text\":\"\\t\\t\\t\\t\\t\\t$conflictName .= $i;\"},{\"line\":63,\"text\":\"\\t\\t\\t\\t\\t}\"},{\"line\":64,\"text\":\"\\t\\t\\t\\t\\t$queries[] = \\\"ALTER TABLE `$tableName` RENAME TO `$conflictName`\\\";\"},{\"line\":65,\"text\":\"\"},{\"line\":66,\"text\":\"\\t\\t\\t\\t\\t$errorMessage = sprintf(\"},{\"line\":67,\"text\":\"\\t\\t\\t\\t\\t\\t\\\"Renamed table %s to %s to avoid schema conflict\\\",\"},{\"line\":68,\"text\":\"\\t\\t\\t\\t\\t\\t$tableName,\"},{\"line\":69,\"text\":\"\\t\\t\\t\\t\\t\\t$conflictName\"},{\"line\":70,\"text\":\"\\t\\t\\t\\t\\t);\"},{\"line\":71,\"text\":\"\"},{\"line\":72,\"text\":\"\\t\\t\\t\\t\\t\\\\XF::logError($errorMessage, true);\"},{\"line\":73,\"text\":\"\\t\\t\\t\\t}\"},{\"line\":74,\"text\":\"\\t\\t\\t\\telse\"},{\"line\":75,\"text\":\"\\t\\t\\t\\t{\"},{\"line\":76,\"text\":\"\\t\\t\\t\\t\\tthrow new \\\\LogicException(\\\"$tableName already exists, but the structure does not match.\\\");\"},{\"line\":77,\"text\":\"\\t\\t\\t\\t}\"},{\"line\":78,\"text\":\"\\t\\t\\t}\"},{\"line\":79,\"text\":\"\\t\\t}\"},{\"line\":80,\"text\":\"\"},{\"line\":81,\"text\":\"\\t\\t$query .= \\\" `$tableName` (\\\\n\\\\t\\\";\"},{\"line\":82,\"text\":\"\"},{\"line\":83,\"text\":\"\\t\\t$tableDefinition = [];\"},{\"line\":84,\"text\":\"\\t\\tforeach ($this->addColumns AS $column)\"},{\"line\":85,\"text\":\"\\t\\t{\"},{\"line\":86,\"text\":\"\\t\\t\\t$tableDefinition[] = $column->getDefinition();\"},{\"line\":87,\"text\":\"\\t\\t}\"},{\"line\":88,\"text\":\"\\t\\tforeach ($this->addIndexes AS $index)\"},{\"line\":89,\"text\":\"\\t\\t{\"},{\"line\":90,\"text\":\"\\t\\t\\t$tableDefinition[$index->getIndexName()] = $index->getDefinition();\"},{\"line\":91,\"text\":\"\\t\\t}\"},{\"line\":92,\"text\":\"\"},{\"line\":93,\"text\":\"\\t\\t$query .= implode(\\\",\\\\n\\\\t\\\", $tableDefinition);\"},{\"line\":94,\"text\":\"\\t\\t$query .= \\\"\\\\n)\\\";\"},{\"line\":95,\"text\":\"\\t\\t$query .= ' ' . $this->db->getSchemaManager()->getTableConfigSql($this->engine ?: null);\"},{\"line\":96,\"text\":\"\"},{\"line\":97,\"text\":\"\\t\\tif ($this->comment)\"},{\"line\":98,\"text\":\"\\t\\t{\"},{\"line\":99,\"text\":\"\\t\\t\\t$query .= ' COMMENT=' . $this->db->quote($this->comment);\"},{\"line\":100,\"text\":\"\\t\\t}\"},{\"line\":101,\"text\":\"\"},{\"line\":102,\"text\":\"\\t\\tif ($this->autoIncrementIndex !== null)\"},{\"line\":103,\"text\":\"\\t\\t{\"},{\"line\":104,\"text\":\"\\t\\t\\t$query .= ' AUTO_INCREMENT=' . $this->autoIncrementIndex;\"},{\"line\":105,\"text\":\"\\t\\t}\"},{\"line\":106,\"text\":\"\"},{\"line\":107,\"text\":\"\\t\\t$queries[] = $query;\"},{\"line\":108,\"text\":\"\"},{\"line\":109,\"text\":\"\\t\\treturn $queries;\"},{\"line\":110,\"text\":\"\\t}\"}]},\"getCreateQuery\":{\"ok\":false,\"class\":\"XF\\\\Db\\\\Schema\\\\Create\",\"method\":\"getCreateQuery\",\"error\":\"ReflectionException\"},\"exists\":{\"ok\":false,\"class\":\"XF\\\\Db\\\\Schema\\\\Create\",\"method\":\"exists\",\"error\":\"ReflectionException\"}},\"source_scans\":[{\"file\":\"src/XF/Cli/Command/AddOnActionTrait.php\",\"sha256\":\"265c7bd3e5dbeb5669b52e57fc9c67411261be00e493cc717aa6b5c991421287\",\"hits\":[{\"line\":15,\"text\":\"use XF\\\\AddOn\\\\StepResult;\"},{\"line\":118,\"text\":\"/** @var StepResult $result */\"},{\"line\":131,\"text\":\"$params['step'] = $result->step;\"},{\"line\":219,\"text\":\"'xf:addon-sub-action',\"}]},{\"file\":\"src/XF/Cli/Command/AddOnInstall.php\",\"sha256\":\"2407ad9ae20ca8ac1ca84b456ac2adc537f39c79534da5e258167a4d0df2a54f\",\"hits\":[{\"line\":20,\"text\":\"->setName('xf:addon-install')\"}]},{\"file\":\"src/XF/Cli/Command/AddOnList.php\",\"sha256\":\"3047ffa03d4fa488cb8a53c2f0c8c88edd8372e5804340f72b3fd761b7eff1ea\",\"hits\":[{\"line\":136,\"text\":\"'last_pending_action' => $installed->last_pending_action,\"},{\"line\":198,\"text\":\"$installed->last_pending_action ?: '-',\"}]},{\"file\":\"src/XF/Cli/Command/AddOnSubAction.php\",\"sha256\":\"4cbf315edc17bf5773c624da2d1af076f47dd588398462d657f709d832adbb46\",\"hits\":[{\"line\":18,\"text\":\"->setName('xf:addon-sub-action')\"},{\"line\":19,\"text\":\"->setDescription('Runs a add-on sub-action in a separate process. Do not run directly!')\"},{\"line\":46,\"text\":\"$output->writeln(\\\"Invalid sub-action confirmation key. Run from parent command.\\\");\"}]},{\"file\":\"src/XF/Cli/Command/Import.php\",\"sha256\":\"cbc8b5707e84a1b1293ca00f57dcc91bb0ded0d3810eb976d0b93327c1dd32f5\",\"hits\":[{\"line\":14,\"text\":\"use XF\\\\Import\\\\StepState;\"},{\"line\":39,\"text\":\"'If set, the import will be automatically finalized when the data import step completes.'\"},{\"line\":112,\"text\":\"function ($isComplete, $step, StepState $stepState, $importCompletion) use ($progressIndicator, &$progressStarted)\"},{\"line\":114,\"text\":\"$stepTitle = $stepState->title;\"},{\"line\":115,\"text\":\"if (!$stepTitle)\"},{\"line\":132,\"text\":\"$stepNumberStrlen = strlen((string) $importCompletion['total']);\"},{\"line\":133,\"text\":\"$stepNameStrlen = 25; // just arbitrary for now, but could be based on the strlen of the longest step title\"},{\"line\":135,\"text\":\"$stepInfo = sprintf(\"},{\"line\":136,\"text\":\"\\\"Step %{$stepNumberStrlen}d of %d: %-{$stepNameStrlen}s \\\",\"},{\"line\":139,\"text\":\"$stepTitle\"},{\"line\":142,\"text\":\"if ($stepState->complete)\"},{\"line\":145,\"text\":\"$stepInfo\"},{\"line\":146,\"text\":\". $this->getIntervalString($stepState->startDate, $stepState->completeDate)\"},{\"line\":147,\"text\":\". ' [' . \\\\XF::language()->numberFormat($stepState->imported) . ']'\"},{\"line\":154,\"text\":\"$stepInfo\"},{\"line\":155,\"text\":\". $this->getIntervalString($stepState->startDate, time()) . ' '\"},{\"line\":156,\"text\":\". $stepState->getCompletionOutput()\"}]},{\"file\":\"src/XF/Cli/Command/ImportChildProcess.php\",\"sha256\":\"4018331a7104801b8d7c73c6bf90374e198ed576897a7b4b01e5195c9d5133f9\",\"hits\":[{\"line\":24,\"text\":\"'step',\"},{\"line\":26,\"text\":\"'The name of the step to run.'\"},{\"line\":63,\"text\":\"$step = $input->getArgument('step');\"},{\"line\":67,\"text\":\"if (!$runner->validateChildProcessRun($step, $startAfter, $end, $error))\"},{\"line\":78,\"text\":\"$runner->runChildProcess($step, $startAfter, $end, $messageReceiver);\"}]},{\"file\":\"src/XF/Cli/Command/ImportCommandTrait.php\",\"sha256\":\"a4816d99b66aa795a1558e01dc42169c471af78028e103533326ced8365f970b\",\"hits\":[{\"line\":21,\"text\":\"$totalsTable->setHeaders(['Step', 'Total', 'Time taken']);\"}]},{\"file\":\"src/XF/Cli/Command/ImportFinalize.php\",\"sha256\":\"78b8ed78256f621c461fe11a6b206a3871819c9960660029feb8d76134ecfde8\",\"hits\":[{\"line\":64,\"text\":\"$jobs = $manager->getImporter($session->importerId)->getFinalizeJobs($session->getStepsRun());\"}]},{\"file\":\"src/XF/Cli/Command/Upgrade.php\",\"sha256\":\"9f58a531299befbb84458add55bb9e701fc18cd06f49d5c86c15fd5871af1a61\",\"hits\":[{\"line\":70,\"text\":\". ($lastUpgradeVersion['last_step'] ? \\\" (step $lastUpgradeVersion[last_step])\\\" : '')\"},{\"line\":75,\"text\":\"$upgradeComplete = ($lastUpgradeVersion['version_id'] === \\\\XF::$versionId && !$lastUpgradeVersion['last_step']);\"},{\"line\":104,\"text\":\"$step = 1;\"},{\"line\":106,\"text\":\"if ($lastUpgradeVersion['last_step'])\"},{\"line\":109,\"text\":\"$step = $lastUpgradeVersion['last_step'] + 1;\"},{\"line\":115,\"text\":\"$step = 1;\"},{\"line\":126,\"text\":\"$upgrader->assertValidUpgradeSteps($upgrade);\"},{\"line\":132,\"text\":\"while (method_exists($upgrade, 'step' . $step))\"},{\"line\":136,\"text\":\"$this->outputStatus($output, \\\"Running upgrade to $versionName, step $step ($position)...\\\");\"},{\"line\":140,\"text\":\"$this->outputStatus($output, \\\"Running upgrade to $versionName, step $step...\\\");\"},{\"line\":143,\"text\":\"$result = $upgrade->{'step' . $step}($position, $data, $controller);\"},{\"line\":146,\"text\":\"$this->clearStatus($output, 'This step must be completed via the web interface.');\"},{\"line\":151,\"text\":\"$this->clearStatus($output, \\\"Running upgrade to $versionName, step $step... done.\\\");\"},{\"line\":156,\"text\":\"$upgrader->insertUpgradeLog($runVersionId, $step);\"},{\"line\":158,\"text\":\"$this->clearStatus($output, \\\"Running upgrade to $versionName, step $step... done.\\\");\"},{\"line\":160,\"text\":\"$step++;\"},{\"line\":166,\"text\":\"// stay on the same step\"},{\"line\":172,\"text\":\"$this->clearStatus($output, 'The upgrade step returned an unexpected result.');\"},{\"line\":180,\"text\":\"$step = 1;\"},{\"line\":184,\"text\":\"$output->writeln(['All upgrade steps run up to version ' . \\\\XF::$version . '.', '']);\"}]},{\"file\":\"src/XF/Cli/Command/AddOn/AbstractSetupStep.php\",\"sha256\":\"86ac6e9eda2202a75f3566a6bf20b14b5cc5171a823e0a23de0e66d0e8c0a8b7\",\"hits\":[{\"line\":9,\"text\":\"use XF\\\\AddOn\\\\StepResult;\"},{\"line\":16,\"text\":\"abstract class AbstractSetupStep extends AbstractCommand\"},{\"line\":21,\"text\":\"abstract protected function getStepType();\"},{\"line\":27,\"text\":\"$command = $this->getStepType();\"},{\"line\":30,\"text\":\"->setName('xf-addon:' . $command . '-step')\"},{\"line\":31,\"text\":\"->setDescription('Runs a specific step from the specified add-on Setup class.')\"},{\"line\":60,\"text\":\"$step = $input->getArgument('step');\"},{\"line\":64,\"text\":\"$stepType = $this->getStepType();\"},{\"line\":65,\"text\":\"if ($stepType == 'upgrade')\"},{\"line\":70,\"text\":\"$setup->prepareForAction($stepType);\"},{\"line\":74,\"text\":\"$result = $this->runStep($setup, $output, $stepType, $step, $version, $params);\"},{\"line\":75,\"text\":\"if (!($result instanceof StepResult))\"},{\"line\":77,\"text\":\"$this->clearStatus($output, \\\"Must return a StepResult object.\\\");\"},{\"line\":104,\"text\":\"protected function runStep(AbstractSetup $setup, OutputInterface $output, $stepType, $step, $version = null, array $params = [])\"},{\"line\":106,\"text\":\"$method = $stepType;\"},{\"line\":112,\"text\":\"if ($step)\"},{\"line\":114,\"text\":\"$method .= 'Step' . $step;\"},{\"line\":119,\"text\":\"if ($version && $step)\"},{\"line\":121,\"text\":\"$method .= $version . 'Step' . $step;\"},{\"line\":129,\"text\":\"return new StepResult(true);\"},{\"line\":137,\"text\":\"$result = new StepResult(true);\"},{\"line\":142,\"text\":\"$result = new StepResult(false, $result);\"}]},{\"file\":\"src/XF/Cli/Command/AddOn/Create.php\",\"sha256\":\"4ff8f77caa12327158b9a6ba6ed2ffe85b959011279be5a70a8b3e77f75204f5\",\"hits\":[{\"line\":217,\"text\":\"$question = new ConfirmationQuestion(\\\"Does your Setup need to support running multiple steps? (y/n) \\\");\"},{\"line\":226,\"text\":\"use XF\\\\AddOn\\\\StepRunnerInstallTrait;\"},{\"line\":227,\"text\":\"use XF\\\\AddOn\\\\StepRunnerUninstallTrait;\"},{\"line\":228,\"text\":\"use XF\\\\AddOn\\\\StepRunnerUpgradeTrait;\"},{\"line\":232,\"text\":\"use StepRunnerInstallTrait;\"},{\"line\":233,\"text\":\"use StepRunnerUpgradeTrait;\"},{\"line\":234,\"text\":\"use StepRunnerUninstallTrait;\"},{\"line\":250,\"text\":\"public function install(array \\\\$stepParams = [])\"},{\"line\":255,\"text\":\"public function upgrade(array \\\\$stepParams = [])\"},{\"line\":260,\"text\":\"public function uninstall(array \\\\$stepParams = [])\"},{\"line\":283,\"text\":\"$output->writeln(\\\"If you change your mind, create a file named Setup.php in \\\" . dirname($setupPath) . \\\" which should extend AbstractSetup and optionally use one of the StepRunnerX traits.\\\");\"}]},{\"file\":\"src/XF/Cli/Command/AddOn/InstallStep.php\",\"sha256\":\"5536a7cdaa190b8ddff16e58733a546c3735ae8e55ab4c9d3cf1e1acce615ca2\",\"hits\":[{\"line\":7,\"text\":\"class InstallStep extends AbstractSetupStep\"},{\"line\":9,\"text\":\"protected function getStepType()\"},{\"line\":17,\"text\":\"'step',\"},{\"line\":19,\"text\":\"'The step number to run.'\"}]},{\"file\":\"src/XF/Cli/Command/AddOn/UninstallStep.php\",\"sha256\":\"d69b287acd3ea5c02bf23492e1bdef465fb75f22f00b45acdb4ffafe547260e5\",\"hits\":[{\"line\":7,\"text\":\"class UninstallStep extends AbstractSetupStep\"},{\"line\":9,\"text\":\"protected function getStepType()\"},{\"line\":17,\"text\":\"'step',\"},{\"line\":19,\"text\":\"'The step number to run.'\"}]},{\"file\":\"src/XF/Cli/Command/AddOn/UpgradeStep.php\",\"sha256\":\"51d6bcea38a819ab7a983340112de1b9778ed9efeb0a139f8d0b6c967b4e052f\",\"hits\":[{\"line\":7,\"text\":\"class UpgradeStep extends AbstractSetupStep\"},{\"line\":9,\"text\":\"protected function getStepType()\"},{\"line\":23,\"text\":\"'step',\"},{\"line\":25,\"text\":\"'The step number to run.'\"}]},{\"file\":\"src/XF/Cli/Command/Rebuild/AbstractRebuildCommand.php\",\"sha256\":\"9b019518b8fb2d2e3bf6d281acb57e181c4b48f2acbf654efdc81b87f294c7f4\",\"hits\":[{\"line\":56,\"text\":\"'resume',\"},{\"line\":73,\"text\":\"if ($input->getOption('resume'))\"},{\"line\":81,\"text\":\"$output->writeln(\\\"There are no pending jobs of this type to resume.\\\");\"}]},{\"file\":\"src/XF/Cli/Command/EmbedMetadata/AbstractEmbedMetadataCommand.php\",\"sha256\":\"d58bdc8eb04615e12b7838403db010fb05ff9238203467061fd7f0bb2d6274f9\",\"hits\":[{\"line\":74,\"text\":\"'resume',\"},{\"line\":77,\"text\":\"'Resume an existing pending job instead of starting a new one. Without this flag, re-running the command discards any prior progress and restarts from the beginning.'\"},{\"line\":92,\"text\":\"if ($input->getOption('resume'))\"},{\"line\":100,\"text\":\"$output->writeln(\\\"There are no pending jobs of this type to resume.\\\");\"}]},{\"file\":\"src/XF/Cli/Command/Development/UpgradeStep.php\",\"sha256\":\"6c91e119b41e5d2b83da72f7d37c02ff2f3d6149b7b7974e05ab3539f0e59fd5\",\"hits\":[{\"line\":18,\"text\":\"class UpgradeStep extends AbstractCommand implements CustomAppCommandInterface\"},{\"line\":30,\"text\":\"->setName('xf-dev:upgrade-step')\"},{\"line\":31,\"text\":\"->setDescription('Runs a specific upgrade step from a specified upgrade class.')\"},{\"line\":38,\"text\":\"'step',\"},{\"line\":40,\"text\":\"'The step number to run'\"},{\"line\":54,\"text\":\"$step = $input->getArgument('step');\"},{\"line\":60,\"text\":\"$returnCode = $this->runStep($upgrade, $output, $controller, $step, $position, $data);\"},{\"line\":73,\"text\":\"throw new \\\\LogicException(\\\"Step did not return an expected result\\\");\"},{\"line\":81,\"text\":\"protected function runStep(AbstractUpgrade $upgrade, OutputInterface $output, Upgrade $controller, $step, $position = 0, $data = [])\"},{\"line\":85,\"text\":\"if (!method_exists($upgrade, 'step' . $step))\"},{\"line\":87,\"text\":\"$this->clearStatus($output, \\\"Upgrade to version $versionName does not have a step$step() method.\\\");\"},{\"line\":93,\"text\":\"$this->outputStatus($output, \\\"Running upgrade to $versionName, step $step ($position)...\\\");\"},{\"line\":97,\"text\":\"$this->outputStatus($output, \\\"Running upgrade to $versionName, step $step...\\\");\"},{\"line\":100,\"text\":\"$result = $upgrade->{'step' . $step}($position, $data, $controller);\"},{\"line\":103,\"text\":\"$this->clearStatus($output, \\\"This step must be completed via the web interface.\\\");\"},{\"line\":108,\"text\":\"$this->clearStatus($output, \\\"Running upgrade to $versionName, step $step... done.\\\");\"},{\"line\":113,\"text\":\"// stay on the same step\"},{\"line\":118,\"text\":\"$this->clearStatus($output, \\\"The upgrade step returned an unexpected result.\\\");\"}]},{\"file\":\"src/XF/AddOn/AbstractSetup.php\",\"sha256\":\"6bdd3fe834e15b963a52c9357f54262f2d12f3c7c3686fc31333b549cddf2d88\",\"hits\":[{\"line\":21,\"text\":\"* @param array $stepParams\"},{\"line\":23,\"text\":\"* @return null|StepResult\"},{\"line\":25,\"text\":\"abstract public function install(array $stepParams = []);\"},{\"line\":28,\"text\":\"* @param array $stepParams\"},{\"line\":30,\"text\":\"* @return null|StepResult\"},{\"line\":32,\"text\":\"abstract public function upgrade(array $stepParams = []);\"},{\"line\":35,\"text\":\"* @param array $stepParams\"},{\"line\":37,\"text\":\"* @return null|StepResult\"},{\"line\":39,\"text\":\"abstract public function uninstall(array $stepParams = []);\"}]},{\"file\":\"src/XF/AddOn/AddOn.php\",\"sha256\":\"0e0346a046fff6bde9850cb53e9dc0d0b5379387029dc16925e562fa141ab422\",\"hits\":[{\"line\":346,\"text\":\"$lastAction = $this->installedAddOn->getLastActionStep('install');\"},{\"line\":349,\"text\":\"// we haven't completed the install steps yet, don't consider as installed\"},{\"line\":537,\"text\":\"public function updatePendingAction($action, $step)\"},{\"line\":541,\"text\":\"$this->installedAddOn->fastUpdate('last_pending_action', \\\"$action:$step\\\");\"},{\"line\":549,\"text\":\"$this->installedAddOn->fastUpdate('last_pending_action', null);\"},{\"line\":568,\"text\":\"'last_pending_action' => 'install:0',\"},{\"line\":653,\"text\":\"$installed->last_pending_action = 'uninstall:0';\"}]},{\"file\":\"src/XF/AddOn/StepResult.php\",\"sha256\":\"d486646b6b20370f7c03f473468ecec93e7cea3ef45cca8d72d6fe9b2701f9be\",\"hits\":[{\"line\":5,\"text\":\"class StepResult\"},{\"line\":9,\"text\":\"public $step;\"},{\"line\":12,\"text\":\"public function __construct($complete, array $params = [], $step = null, $version = null)\"},{\"line\":16,\"text\":\"$this->step = $step;\"}]},{\"file\":\"src/XF/AddOn/StepRunnerInstallTrait.php\",\"sha256\":\"1f441b8a3101b97009ae04e62c04e79062a89f1e01a08ae9e07c5e629c76d5f2\",\"hits\":[{\"line\":10,\"text\":\"trait StepRunnerInstallTrait\"},{\"line\":13,\"text\":\"* @param array $stepParams\"},{\"line\":15,\"text\":\"* @return null|StepResult\"},{\"line\":17,\"text\":\"public function install(array $stepParams = [])\"},{\"line\":19,\"text\":\"$stepParams = array_replace([\"},{\"line\":20,\"text\":\"'step' => 0,\"},{\"line\":21,\"text\":\"], $stepParams);\"},{\"line\":23,\"text\":\"$step = $stepParams['step'];\"},{\"line\":24,\"text\":\"if (!$step)\"},{\"line\":26,\"text\":\"$step = $this->getInstallResumeStep();\"},{\"line\":29,\"text\":\"return $this->installStepRunner($step, $stepParams);\"},{\"line\":32,\"text\":\"private function getInstallResumeStep()\"},{\"line\":37,\"text\":\"$lastActionStep = $installedAddOn->getLastActionStep('install');\"},{\"line\":38,\"text\":\"if ($lastActionStep)\"},{\"line\":40,\"text\":\"return $lastActionStep + 1; // this is the last completed step, so resume with the next\"},{\"line\":48,\"text\":\"* @param integer $step\"},{\"line\":49,\"text\":\"* @param array $stepParams\"},{\"line\":51,\"text\":\"* @return null|StepResult\"},{\"line\":53,\"text\":\"private function installStepRunner($step, array $stepParams)\"},{\"line\":55,\"text\":\"$fnPrefix = 'installStep';\"},{\"line\":56,\"text\":\"$fn = $fnPrefix . $step;\"},{\"line\":62,\"text\":\"$result = $this->$fn($stepParams);\"},{\"line\":65,\"text\":\"$result = new StepResult(true);\"},{\"line\":69,\"text\":\"$result = new StepResult(false, $result);\"},{\"line\":72,\"text\":\"if (!($result instanceof StepResult))\"},{\"line\":74,\"text\":\"throw new \\\\LogicException(\\\"Must return a StepResult object\\\");\"},{\"line\":77,\"text\":\"$result->step = $step;\"},{\"line\":81,\"text\":\"$this->addOn->updatePendingAction('install', $result->step);\"},{\"line\":83,\"text\":\"$nextStep = $step + 1;\"},{\"line\":84,\"text\":\"$nextFn = $fnPrefix . $nextStep;\"},{\"line\":90,\"text\":\"$result = new StepResult(false, [], $nextStep);\"}]},{\"file\":\"src/XF/AddOn/StepRunnerUninstallTrait.php\",\"sha256\":\"e58a9ab9c30e3cf3c41a0be392e8c5ac37f744578f7b91f76d663139649c49a9\",\"hits\":[{\"line\":10,\"text\":\"trait StepRunnerUninstallTrait\"},{\"line\":13,\"text\":\"* @param array $stepParams\"},{\"line\":15,\"text\":\"* @return null|StepResult\"},{\"line\":17,\"text\":\"public function uninstall(array $stepParams = [])\"},{\"line\":19,\"text\":\"$stepParams = array_replace([\"},{\"line\":20,\"text\":\"'step' => 0,\"},{\"line\":21,\"text\":\"], $stepParams);\"},{\"line\":23,\"text\":\"$step = $stepParams['step'];\"},{\"line\":24,\"text\":\"if (!$step)\"},{\"line\":26,\"text\":\"$step = $this->getUninstallResumeStep();\"},{\"line\":28,\"text\":\"return $this->uninstallStepRunner($step, $stepParams);\"},{\"line\":31,\"text\":\"private function getUninstallResumeStep()\"},{\"line\":36,\"text\":\"$lastActionStep = $installedAddOn->getLastActionStep('uninstall');\"},{\"line\":37,\"text\":\"if ($lastActionStep)\"},{\"line\":39,\"text\":\"return $lastActionStep + 1; // this is the last completed step, so resume with the next\"},{\"line\":47,\"text\":\"* @param integer $step\"},{\"line\":48,\"text\":\"* @param array $stepParams\"},{\"line\":50,\"text\":\"* @return null|StepResult\"},{\"line\":52,\"text\":\"private function uninstallStepRunner($step, array $stepParams)\"},{\"line\":54,\"text\":\"$fnPrefix = 'uninstallStep';\"},{\"line\":55,\"text\":\"$fn = $fnPrefix . $step;\"},{\"line\":61,\"text\":\"$result = $this->$fn($stepParams);\"},{\"line\":64,\"text\":\"$result = new StepResult(true);\"},{\"line\":68,\"text\":\"$result = new StepResult(false, $result);\"},{\"line\":71,\"text\":\"if (!($result instanceof StepResult))\"},{\"line\":73,\"text\":\"throw new \\\\LogicException(\\\"Must return a StepResult object\\\");\"},{\"line\":76,\"text\":\"$result->step = $step;\"},{\"line\":80,\"text\":\"$this->addOn->updatePendingAction('uninstall', $result->step);\"},{\"line\":82,\"text\":\"$nextStep = $step + 1;\"},{\"line\":83,\"text\":\"$nextFn = $fnPrefix . $nextStep;\"},{\"line\":89,\"text\":\"$result = new StepResult(false, [], $nextStep);\"}]},{\"file\":\"src/XF/AddOn/StepRunnerUpgradeTrait.php\",\"sha256\":\"b61698d9c20f094cc1b704ad48798148fe5843e2dc746592cb2db252b579d1b5\",\"hits\":[{\"line\":10,\"text\":\"trait StepRunnerUpgradeTrait\"},{\"line\":13,\"text\":\"* @param array $stepParams\"},{\"line\":15,\"text\":\"* @return null|StepResult\"},{\"line\":17,\"text\":\"public function upgrade(array $stepParams = [])\"},{\"line\":19,\"text\":\"$stepParams = $this->getStepParams($stepParams);\"},{\"line\":22,\"text\":\"$stepsGrouped = [];\"},{\"line\":27,\"text\":\"if (preg_match('/^upgrade(\\\\d+)Step(\\\\d+)$/', $method->name, $match))\"},{\"line\":30,\"text\":\"$step = intval($match[2]);\"},{\"line\":33,\"text\":\"$stepsGrouped[$versionId][$step] = $step;\"},{\"line\":42,\"text\":\"if (!$stepParams['version_id'])\"},{\"line\":44,\"text\":\"$resume = $this->getUpgradeResumeStep();\"},{\"line\":45,\"text\":\"$stepParams['version_id'] = $resume[0];\"},{\"line\":46,\"text\":\"$stepParams['step'] = $resume[1];\"},{\"line\":49,\"text\":\"$runStep = $stepParams['step'];\"},{\"line\":50,\"text\":\"if (!$runStep)\"},{\"line\":52,\"text\":\"$runStep = 1;\"},{\"line\":60,\"text\":\"if ($versionId >= $stepParams['version_id'])\"},{\"line\":62,\"text\":\"$versionSteps = $stepsGrouped[$versionId];\"},{\"line\":63,\"text\":\"if (isset($versionSteps[$runStep]))\"},{\"line\":65,\"text\":\"if ($versionId != $stepParams['version_id'] || $runStep != $stepParams['step'])\"},{\"line\":67,\"text\":\"// sanity check - don't pass params if we're changing versions or steps\"},{\"line\":68,\"text\":\"$stepParams = [];\"},{\"line\":73,\"text\":\"return $this->upgradeStepRunner($versionId, $runStep, $stepParams, $nextVersionId);\"},{\"line\":76,\"text\":\"// if we hit here, then the step couldn't be found, so move onto the next upgrade\"},{\"line\":77,\"text\":\"$runStep = 1;\"},{\"line\":78,\"text\":\"$stepParams = $this->getStepParams();\"},{\"line\":86,\"text\":\"protected function getStepParams(array $stepParams = [])\"},{\"line\":90,\"text\":\"'step' => 0,\"},{\"line\":91,\"text\":\"], $stepParams);\"},{\"line\":94,\"text\":\"private function getUpgradeResumeStep()\"},{\"line\":97,\"text\":\"$lastActionStep = $installedAddOn->getLastActionStep('upgrade');\"},{\"line\":98,\"text\":\"if ($lastActionStep)\"},{\"line\":100,\"text\":\"$lastActionStep[1]++; // we completed this step, so need to resume with the next\"},{\"line\":101,\"text\":\"return $lastActionStep;\"},{\"line\":109,\"text\":\"* @param integer $runStep\"},{\"line\":110,\"text\":\"* @param array $stepParams\"},{\"line\":113,\"text\":\"* @return null|StepResult\"},{\"line\":115,\"text\":\"private function upgradeStepRunner($runVersion, $runStep, array $stepParams, $nextVersionId)\"},{\"line\":117,\"text\":\"$fnPattern = 'upgrade%dStep%d';\"},{\"line\":118,\"text\":\"$fn = sprintf($fnPattern, $runVersion, $runStep);\"},{\"line\":121,\"text\":\"throw new \\\\LogicException(\\\"Step $fn doesn't exist. Should have been checked earlier.\\\");\"},{\"line\":124,\"text\":\"$result = $this->$fn($stepParams);\"},{\"line\":127,\"text\":\"$result = new StepResult(true);\"},{\"line\":131,\"text\":\"$result = new StepResult(false, $result);\"},{\"line\":134,\"text\":\"if (!($result instanceof StepResult))\"},{\"line\":136,\"text\":\"throw new \\\\LogicException(\\\"Must return a StepResult object\\\");\"},{\"line\":139,\"text\":\"$result->step = $runStep;\"},{\"line\":144,\"text\":\"$this->addOn->updatePendingAction('upgrade', $result->version . ':' . $result->step);\"},{\"line\":146,\"text\":\"$nextStep = $runStep + 1;\"},{\"line\":147,\"text\":\"$nextStepFn = sprintf($fnPattern, $runVersion, $nextStep);\"},{\"line\":148,\"text\":\"if (method_exists($this, $nextStepFn))\"},{\"line\":150,\"text\":\"$result = new StepResult(false, [], $nextStep, $runVersion);\"},{\"line\":166,\"text\":\"$result = new StepResult(false, [], 1, $nextVersionId);\"}]},{\"file\":\"src/XF/AddOn/DataType/AbstractDataType.php\",\"sha256\":\"a4f6ec14e4009be0029548b07272dc77c6ad96f4cca4e067a7d3ea0004126815\",\"hits\":[{\"line\":165,\"text\":\"protected function resume($maxRunTime, $startTime)\"}]}]},\"assessment\":{\"all_six_tables_present\":true,\"all_six_tables_empty\":true,\"duplicate_create_appears_safe\":true,\"native_resume_signal\":true},\"policy\":{\"delete_performed\":false,\"mutation_performed\":false,\"goal\":\"select a no-delete native or bounded bridge install path\"}}\nGRAM513R3R3_DECISION=PASS_NATIVE_RESUME_SCHEMA_RCA\nGRAM513R3R3_NEXT_GATE=READY_FOR_DIRECT_NATIVE_RETRY_CANARY_513R3R4\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260918-GRAM-XF-CODEVIPE-NATIVE-RESUME-SCHEMA-RCA-513R3R3\",\"status\":\"OK\",\"changes_made\":false,\"rollback_started\":false,\"rollback_restored\":null}\n"
+ "output": "GRAM513R3R4_WRAPPER_BEGIN=true\nERROR_REGISTER_CHECK=OK\nREFERENCE_CHECK=OK\nAUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED\nGRAM513R3R4_BEGIN=true\nMODE=CHANGE_CODEVIPE_FIX10_RETRY_FOOTER_CANARY\nNO_DELETE=true\nTARGET=codevipe.ru\nGRAM513R3R4_SAFE_REPORT={\"guest\":{\"configure\":{\"ok\":true,\"site_option\":\"gramSupportSiteId\",\"site_id\":\"codevipe\",\"permission_entries_written\":22,\"permission_jobs\":[],\"all_jobs\":[{\"job_id\":4,\"execute_class\":\"XF\\\\Job\\\\Cron\"},{\"job_id\":50,\"execute_class\":\"XF\\\\Job\\\\UpgradeCheck\"},{\"job_id\":64366,\"execute_class\":\"XF\\\\Job\\\\TrendingResult\"},{\"job_id\":64369,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"},{\"job_id\":64371,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"},{\"job_id\":64372,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"},{\"job_id\":64373,\"execute_class\":\"XF\\\\Job\\\\IconUsage\"}],\"baseline_unrelated_allowed\":[{\"job_id\":4,\"execute_class\":\"XF\\\\Job\\\\Cron\"},{\"job_id\":50,\"execute_class\":\"XF\\\\Job\\\\UpgradeCheck\"}],\"job_loops\":0},\"verify\":{\"ok\":false,\"checks\":{\"addon\":true,\"board_active\":true,\"tables\":false,\"routes4\":true,\"counts\":true,\"permissions\":true,\"site_id\":true,\"perm_jobs_zero\":true,\"manifest\":true,\"error_log\":false,\"footer_v7\":true,\"services\":true,\"http\":true},\"state\":{\"addon\":{\"addon_id\":\"Gram/Support\",\"title\":\"Gram Support\",\"version_id\":1000120,\"version_string\":\"1.0.0 Alpha 3 Unified Fix 10\",\"active\":1,\"is_processing\":0,\"last_pending_action\":null},\"counts\":{\"xf_content_type_field\":1,\"xf_code_event_listener\":1,\"xf_option\":4,\"xf_option_group\":1,\"xf_permission\":9,\"xf_permission_interface_group\":1,\"xf_phrase\":54,\"xf_route\":4,\"xf_template\":13,\"xf_template_modification\":1},\"support_tables\":[\"xf_gram_support_attachment_meta\",\"xf_gram_support_delivery\",\"xf_gram_support_event\",\"xf_gram_support_event__conflict\",\"xf_gram_support_message\",\"xf_gram_support_message__conflict\",\"xf_gram_support_rate_limit\",\"xf_gram_support_ticket\",\"xf_gram_support_ticket__conflict\"],\"support_table_rows\":{\"xf_gram_support_attachment_meta\":0,\"xf_gram_support_delivery\":0,\"xf_gram_support_event\":0,\"xf_gram_support_event__conflict\":0,\"xf_gram_support_message\":0,\"xf_gram_support_message__conflict\":0,\"xf_gram_support_rate_limit\":0,\"xf_gram_support_ticket\":0,\"xf_gram_support_ticket__conflict\":0},\"routes\":[{\"route_type\":\"public\",\"route_prefix\":\"account\",\"sub_name\":\"support\",\"format\":\"support\",\"controller\":\"Gram\\\\Support:AccountSupport\",\"addon_id\":\"Gram/Support\"},{\"route_type\":\"public\",\"route_prefix\":\"support\",\"sub_name\":\"\",\"format\":\"\",\"controller\":\"Gram\\\\Support:Support\",\"addon_id\":\"Gram/Support\"},{\"route_type\":\"public\",\"route_prefix\":\"support\",\"sub_name\":\"service-worker\",\"format\":\"service-worker\",\"controller\":\"Gram\\\\Support:Pwa\",\"addon_id\":\"Gram/Support\"},{\"route_type\":\"public\",\"route_prefix\":\"support\",\"sub_name\":\"staff\",\"format\":\"staff\",\"controller\":\"Gram\\\\Support:StaffSupport\",\"addon_id\":\"Gram/Support\"}],\"options\":[{\"option_id\":\"gramSupportGuestRateLimitCount\",\"option_value\":\"5\",\"default_value\":\"5\"},{\"option_id\":\"gramSupportGuestRateLimitWindowSeconds\",\"option_value\":\"3600\",\"default_value\":\"3600\"},{\"option_id\":\"gramSupportGuestTokenTtlDays\",\"option_value\":\"30\",\"default_value\":\"30\"},{\"option_id\":\"gramSupportSiteId\",\"option_value\":\"codevipe\",\"default_value\":\"\"}],\"permission_entries\":[{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"create\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"replyOwn\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"view\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewOwn\",\"user_group_id\":2,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"assign\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"create\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"internalNotes\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"manage\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"replyOwn\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"view\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewAll\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewOwn\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewTechnicalContext\",\"user_group_id\":3,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"assign\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"create\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"internalNotes\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"manage\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"replyOwn\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"view\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewAll\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewOwn\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0},{\"permission_group_id\":\"gramSupport\",\"permission_id\":\"viewTechnicalContext\",\"user_group_id\":4,\"user_id\":0,\"permission_value\":\"allow\",\"permission_value_int\":0}],\"permission_jobs\":[],\"all_jobs\":[{\"job_id\":4,\"execute_class\":\"XF\\\\Job\\\\Cron\",\"manual_execute\":0},{\"job_id\":50,\"execute_class\":\"XF\\\\Job\\\\UpgradeCheck\",\"manual_execute\":0},{\"job_id\":64366,\"execute_class\":\"XF\\\\Job\\\\TrendingResult\",\"manual_execute\":0},{\"job_id\":64369,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0},{\"job_id\":64371,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0},{\"job_id\":64372,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0},{\"job_id\":64373,\"execute_class\":\"XF\\\\Job\\\\IconUsage\",\"manual_execute\":0}],\"footer_template\":{\"template_id\":1416,\"version_id\":1000100,\"version_string\":\"1.0.0 Alpha 3 Unified Fix 8\",\"sha256\":\"ced49dfb6a64c55b06292c2b0d283847608f9c52434d6411cd93d06375ae225b\",\"marker\":true,\"shift\":true},\"board_active\":\"1\",\"board_url\":\"https://codevipe.ru\",\"error_max\":3,\"xf\":{\"version_id\":2031170,\"version_string\":\"2.3.11\"},\"php\":\"8.3.32\"},\"manifest\":{\"file_count\":59,\"combined_sha256\":\"a31fc0535de726fc779ef67d1cac8fea3cb518f738e5e47412825cddb1a34a7a\",\"addon_files\":51,\"addon_sha256\":\"f0054b4417c13226fe105c815e24466fd4dc5a2e65c7e11a04090206a95d9948\",\"outside_files\":8,\"outside_sha256\":\"9e657ea8877f40c9336807faa12d681c21f0261db5ad1aad3501dc0b48fdde58\",\"paths\":[\"js/gram/support/access.js\",\"js/gram/support/access.min.js\",\"js/gram/support/pwa/icon-192.png\",\"js/gram/support/pwa/icon-512.png\",\"js/gram/support/pwa/manifest.webmanifest\",\"js/gram/support/pwa/offline.html\",\"js/gram/support/staff-pwa.js\",\"js/gram/support/staff-pwa.min.js\",\"src/addons/Gram/Support/Attachment/TicketHandler.php\",\"src/addons/Gram/Support/Entity/AttachmentMeta.php\",\"src/addons/Gram/Support/Entity/Delivery.php\",\"src/addons/Gram/Support/Entity/Message.php\",\"src/addons/Gram/Support/Entity/RateLimit.php\",\"src/addons/Gram/Support/Entity/SupportEvent.php\",\"src/addons/Gram/Support/Entity/Ticket.php\",\"src/addons/Gram/Support/Listener/SourcePageContext.php\",\"src/addons/Gram/Support/Notification/AlertConsumer.php\",\"src/addons/Gram/Support/Notification/DeliveryGate.php\",\"src/addons/Gram/Support/Notification/Dispatcher.php\",\"src/addons/Gram/Support/Notification/EmailConsumer.php\",\"src/addons/Gram/Support/Notification/EntityDeliveryGate.php\",\"src/addons/Gram/Support/Notification/EventDispatcher.php\",\"src/addons/Gram/Support/Notification/Policy.php\",\"src/addons/Gram/Support/Notification/RecipientKey.php\",\"src/addons/Gram/Support/Pub/Controller/AccountSupport.php\",\"src/addons/Gram/Support/Pub/Controller/Pwa.php\",\"src/addons/Gram/Support/Pub/Controller/StaffSupport.php\",\"src/addons/Gram/Support/Pub/Controller/Support.php\",\"src/addons/Gram/Support/Pub/View/PwaServiceWorker.php\",\"src/addons/Gram/Support/Repository/Message.php\",\"src/addons/Gram/Support/Repository/Ticket.php\",\"src/addons/Gram/Support/Security/GuestTicketSession.php\",\"src/addons/Gram/Support/Security/TicketAccess.php\",\"src/addons/Gram/Support/Service/GuestScreenshotService.php\",\"src/addons/Gram/Support/Service/GuestTicketCreateAttachmentFlow.php\",\"src/addons/Gram/Support/Service/RateLimiter.php\",\"src/addons/Gram/Support/Service/SourceContextResolver.php\",\"src/addons/Gram/Support/Service/Ticket/Creator.php\",\"src/addons/Gram/Support/Service/Ticket/Reply.php\",\"src/addons/Gram/Support/Service/Ticket/StaffUpdate.php\",\"src/addons/Gram/Support/Setup.php\",\"src/addons/Gram/Support/Util/GuestToken.php\",\"src/addons/Gram/Support/Util/PublicRef.php\",\"src/addons/Gram/Support/Util/RateKey.php\",\"src/addons/Gram/Support/Util/SafeContext.php\",\"src/addons/Gram/Support/Util/SiteConfig.php\",\"src/addons/Gram/Support/Util/StatusPolicy.php\",\"src/addons/Gram/Support/_data/code_event_listeners.xml\",\"src/addons/Gram/Support/_data/content_type_fields.xml\",\"src/addons/Gram/Support/_data/option_groups.xml\",\"src/addons/Gram/Support/_data/options.xml\",\"src/addons/Gram/Support/_data/permission_interface_groups.xml\",\"src/addons/Gram/Support/_data/permissions.xml\",\"src/addons/Gram/Support/_data/phrases.xml\",\"src/addons/Gram/Support/_data/routes.xml\",\"src/addons/Gram/Support/_data/template_modifications.xml\",\"src/addons/Gram/Support/_data/templates.xml\",\"src/addons/Gram/Support/addon.json\",\"src/addons/Gram/Support/hashes.json\"]},\"services\":{\"mariadb\":\"active\",\"nginx\":\"active\",\"php8.3-fpm\":\"active\"},\"permission_counts\":{\"2\":4,\"3\":9,\"4\":9},\"http\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"200\"},\"/support/create/\":{\"rc\":0,\"code\":\"200\"}}},\"rollback\":{\"ok\":false,\"state_sig\":\"50eff6fb3c6a602194eb2dec2ff41e47c09988cc6ea08541851dac4a933db295\",\"manifest_sha\":\"c49c44a866b3e91224cade4c43d9a4594537fc1530ba54333cb959f3afe12a32\"},\"backup\":\"/root/codevipe-gram-support-backups/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4\"},\"pre_http\":{\"codevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"dsmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"gamevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"hkmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"kingofwolk.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"zakrutim.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"newfi.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}}},\"post_http\":{\"codevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"dsmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"gamevipe.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"hkmods.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"kingofwolk.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"zakrutim.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}},\"newfi.ru\":{\"/\":{\"rc\":0,\"code\":\"200\"},\"/support/\":{\"rc\":0,\"code\":\"404\"}}},\"artifact_sha256\":\"2e31f89d3626a83c1211910aa6fd279cc04689b75ba822899952865085cf551e\",\"target\":\"codevipe.ru\"}\nGRAM513R3R4_DECISION=FAIL_CODEVIPE_FIX10_RETRY_VERIFY\nHOMELAB_RESULT_CONTRACT={\"version\":1,\"command_id\":\"SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4\",\"status\":\"FAIL\",\"changes_made\":true,\"rollback_started\":true,\"rollback_restored\":false}\n"
}
diff --git a/runtime/latest.txt b/runtime/latest.txt
index a8a41087..6231d1a1 100644
--- a/runtime/latest.txt
+++ b/runtime/latest.txt
@@ -1,40 +1,43 @@
CHAT_OUTPUT_BEGIN
-COMMAND_ID=SUPPORT-260918-GRAM-XF-CODEVIPE-NATIVE-RESUME-SCHEMA-RCA-513R3R3
-STATUS=OK
-RC=0
+COMMAND_ID=SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4
+STATUS=FAIL
+RC=3
HOST=pve01
-MODE=read-only
-COMPONENT=gram-support-codevipe-native-resume-schema-rca
+MODE=change
+COMPONENT=gram-support-codevipe-fix10-retry-footer-canary
REFERENCE_REGISTER_CHECK=OK
REFERENCE_SHA256=5a3d8e5154c41cb582a4e0aca68090be1f0138918bf82131a948df326f9d8d66
ERROR_REGISTER_CHECK=OK
ERROR_REGISTER_SHA256=3b09a553ec0f527ed3afeed4753f52a74ee3036045bbfb3c685e9f8af4ba7ba0
-COMMAND_SHA256=d024725d107ae38e09893a322f7a365399e215a929d3c723a3099129609390bf
+COMMAND_SHA256=99a6ef7d6eedc3560e74c799b69fe2cb21f2f532df5f109a12dbe6a4509f4cbf
DUPLICATE_FAILED_COMMAND_BLOCKED=false
EXECUTION_STARTED=true
-CHANGE_DECLARED=false
+CHANGE_DECLARED=true
RESULT_CONTRACT_VALID=true
-RESULT_CONTRACT_STATUS=NOT_APPLICABLE
+RESULT_CONTRACT_STATUS=FAIL
RESULT_CONTRACT_ERROR=NONE
-COMMAND_RC=0
-CHANGES_MADE=false
-ROLLBACK_STARTED=false
-ROLLBACK_RESTORED=null
-MUTATION_OUTCOME=NO_MUTATION
+COMMAND_RC=3
+CHANGES_MADE=true
+ROLLBACK_STARTED=true
+ROLLBACK_RESTORED=false
+MUTATION_OUTCOME=ROLLBACK_FAILED
SANITIZED=yes
SECRETS_INCLUDED=no
PRIVATE_ADDRESSES_INCLUDED=no
-RAW_EVIDENCE_SHA256=3356fd66c51344f1c1c25279dd2f3ad70b12040178c3a7513b0aa812b569ae94
-SANITIZED_OUTPUT_SHA256=3356fd66c51344f1c1c25279dd2f3ad70b12040178c3a7513b0aa812b569ae94
+RAW_EVIDENCE_SHA256=4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53
+SANITIZED_OUTPUT_SHA256=4aa3abf9fe7e8dde43edc9387706aee50802ba4b5a7ef3ae0494969c6dc30f53
OUTPUT_BEGIN
-GRAM513R3R3_WRAPPER_BEGIN=true
+GRAM513R3R4_WRAPPER_BEGIN=true
ERROR_REGISTER_CHECK=OK
REFERENCE_CHECK=OK
AUTHORITY_CHECK_SCOPE=READABILITY_ONLY_INCIDENTS_NOT_CLOSED
-GRAM513R3R3_SAFE_REPORT={"artifact":{"sha256":"2e31f89d3626a83c1211910aa6fd279cc04689b75ba822899952865085cf551e","version_id":1000120,"version_string":"1.0.0 Alpha 3 Unified Fix 10","setup_tables":["xf_gram_support_ticket","xf_gram_support_message","xf_gram_support_event","xf_gram_support_attachment_meta","xf_gram_support_delivery","xf_gram_support_rate_limit"],"setup_sha256":"4977f90ec0444e2e3a1e4ee9b79a4e88098c5a3ae37b30d63e77cff2e1fcb971"},"codevipe":{"ok":true,"tables":{"xf_gram_support_ticket":{"exists":true,"rows":0,"ddl_sha256":"3558077fc70b4453960d1d782998ad498b2d3b12ba587488e8b23785979f7ba8","ddl":"CREATE TABLE `xf_gram_support_ticket` (\n `ticket_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n `public_ref` varchar(64) NOT NULL,\n `site_id` varchar(32) NOT NULL,\n `user_id` int(10) unsigned NOT NULL DEFAULT 0,\n `guest_email` varchar(255) NOT NULL DEFAULT '',\n `guest_access_token_hash` char(64) NOT NULL DEFAULT '',\n `guest_access_expires` int(10) unsigned NOT NULL DEFAULT 0,\n `node_id` int(10) unsigned NOT NULL DEFAULT 0,\n `thread_id` int(10) unsigned NOT NULL DEFAULT 0,\n `post_id` int(10) unsigned NOT NULL DEFAULT 0,\n `category` varchar(64) NOT NULL DEFAULT '',\n `subject` varchar(255) NOT NULL DEFAULT '',\n `status` varchar(32) NOT NULL DEFAULT 'NEW',\n `assigned_user_id` int(10) unsigned NOT NULL DEFAULT 0,\n `created_date` int(10) unsigned NOT NULL DEFAULT 0,\n `updated_date` int(10) unsigned NOT NULL DEFAULT 0,\n `resolved_date` int(10) unsigned NOT NULL DEFAULT 0,\n `context_json` mediumtext NOT NULL,\n `last_message_id` int(10) unsigned NOT NULL DEFAULT 0,\n PRIMARY KEY (`ticket_id`),\n UNIQUE KEY `public_ref` (`public_ref`),\n KEY `guest_token_hash` (`guest_access_token_hash`),\n KEY `site_user_updated` (`site_id`,`user_id`,`updated_date`),\n KEY `site_status_updated` (`site_id`,`status`,`updated_date`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"},"xf_gram_support_message":{"exists":true,"rows":0,"ddl_sha256":"a00e534c642179db3018c74060d1aa6cef4dc445dcb801eb847c04d770f8f884","ddl":"CREATE TABLE `xf_gram_support_message` (\n `message_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n `ticket_id` int(10) unsigned NOT NULL,\n `user_id` int(10) unsigned NOT NULL DEFAULT 0,\n `is_staff` tinyint(3) unsigned NOT NULL DEFAULT 0,\n `is_internal` tinyint(3) unsigned NOT NULL DEFAULT 0,\n `message` mediumtext NOT NULL,\n `message_date` int(10) unsigned NOT NULL DEFAULT 0,\n PRIMARY KEY (`message_id`),\n KEY `ticket_date` (`ticket_id`,`message_date`),\n KEY `ticket_public_date` (`ticket_id`,`is_internal`,`message_date`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"},"xf_gram_support_event":{"exists":true,"rows":0,"ddl_sha256":"81b6328dbbcf3f6405891897ba185e29890c675f21d7a2f9caf827c0eddb42da","ddl":"CREATE TABLE `xf_gram_support_event` (\n `event_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n `ticket_id` int(10) unsigned NOT NULL,\n `site_id` varchar(32) NOT NULL,\n `actor_user_id` int(10) unsigned NOT NULL DEFAULT 0,\n `event_type` varchar(64) NOT NULL,\n `event_date` int(10) unsigned NOT NULL DEFAULT 0,\n `safe_payload_json` mediumtext NOT NULL,\n PRIMARY KEY (`event_id`),\n KEY `ticket_date` (`ticket_id`,`event_date`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"},"xf_gram_support_attachment_meta":{"exists":true,"rows":0,"ddl_sha256":"3c3d2ce4c5dae793687243dca37f60cd781895818b546a68e227aef9bfc9b6b2","ddl":"CREATE TABLE `xf_gram_support_attachment_meta` (\n `attachment_id` int(10) unsigned NOT NULL,\n `ticket_id` int(10) unsigned NOT NULL,\n `message_id` int(10) unsigned NOT NULL DEFAULT 0,\n `is_internal` tinyint(3) unsigned NOT NULL DEFAULT 0,\n `created_date` int(10) unsigned NOT NULL DEFAULT 0,\n PRIMARY KEY (`attachment_id`),\n KEY `ticket_internal` (`ticket_id`,`is_internal`),\n KEY `message_id` (`message_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"},"xf_gram_support_delivery":{"exists":true,"rows":0,"ddl_sha256":"91f068994bdbe4b168ab1c82fa669180f13825e6d1a7f5b9e956ccc872d0410d","ddl":"CREATE TABLE `xf_gram_support_delivery` (\n `delivery_key` char(64) NOT NULL,\n `event_id` int(10) unsigned NOT NULL,\n `consumer` varchar(32) NOT NULL,\n `recipient_key` varchar(96) NOT NULL,\n `state` varchar(16) NOT NULL DEFAULT 'pending',\n `lease_expires` int(10) unsigned NOT NULL DEFAULT 0,\n `attempt_count` int(10) unsigned NOT NULL DEFAULT 0,\n `last_failure_class` varchar(191) NOT NULL DEFAULT '',\n `created_date` int(10) unsigned NOT NULL DEFAULT 0,\n `updated_date` int(10) unsigned NOT NULL DEFAULT 0,\n `sent_date` int(10) unsigned NOT NULL DEFAULT 0,\n PRIMARY KEY (`delivery_key`),\n KEY `event_consumer` (`event_id`,`consumer`),\n KEY `state_lease` (`state`,`lease_expires`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"},"xf_gram_support_rate_limit":{"exists":true,"rows":0,"ddl_sha256":"f2271e20d520a8ba413b2094a4f8f6640395065c7d9c2e4f5b0a74b790d3dd8e","ddl":"CREATE TABLE `xf_gram_support_rate_limit` (\n `rate_key` char(64) NOT NULL,\n `window_start` int(10) unsigned NOT NULL,\n `hit_count` int(10) unsigned NOT NULL DEFAULT 0,\n `updated_date` int(10) unsigned NOT NULL DEFAULT 0,\n PRIMARY KEY (`rate_key`),\n KEY `updated_date` (`updated_date`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci"}},"addon":null,"schema_manager_class":"XF\\Db\\SchemaManager","schema_methods":{"createTable":{"ok":true,"class":"XF\\Db\\SchemaManager","method":"createTable","file":"SchemaManager.php","start":187,"end":200,"sha256":"be6c143b9b8321148d841530fe0e5f8388b5fa178a96a8a1fe759e8208eb71a4","source":"\tpublic function createTable($tableName, \\Closure $toApply)\n\t{\n\t\t$create = $this->newTable($tableName);\n\n\t\ttry\n\t\t{\n\t\t\t$toApply($create);\n\t\t\t$create->apply();\n\t\t}\n\t\tcatch (\\Exception $e)\n\t\t{\n\t\t\t$this->handleException($e, $tableName, $create);\n\t\t}\n\t}\n","lines":[{"line":187,"text":"\tpublic function createTable($tableName, \\Closure $toApply)"},{"line":188,"text":"\t{"},{"line":189,"text":"\t\t$create = $this->newTable($tableName);"},{"line":190,"text":""},{"line":191,"text":"\t\ttry"},{"line":192,"text":"\t\t{"},{"line":193,"text":"\t\t\t$toApply($create);"},{"line":194,"text":"\t\t\t$create->apply();"},{"line":195,"text":"\t\t}"},{"line":196,"text":"\t\tcatch (\\Exception $e)"},{"line":197,"text":"\t\t{"},{"line":198,"text":"\t\t\t$this->handleException($e, $tableName, $create);"},{"line":199,"text":"\t\t}"},{"line":200,"text":"\t}"}]},"newTable":{"ok":true,"class":"XF\\Db\\SchemaManager","method":"newTable","file":"SchemaManager.php","start":239,"end":242,"sha256":"482ad432f7e1304bb4289a1e56fb600d7dfb3708393ec2fd4d6ceba61f8d61de","source":"\tpublic function newTable($tableName)\n\t{\n\t\treturn new Create($this->db, $this, $tableName);\n\t}\n","lines":[{"line":239,"text":"\tpublic function newTable($tableName)"},{"line":240,"text":"\t{"},{"line":241,"text":"\t\treturn new Create($this->db, $this, $tableName);"},{"line":242,"text":"\t}"}]},"handleException":{"ok":true,"class":"XF\\Db\\SchemaManager","method":"handleException","file":"SchemaManager.php","start":254,"end":270,"sha256":"bcfbb554306aeb3c108d447c45183c8d6c2415d91e9e785a9671ea1900dbc103","source":"\tprotected function handleException($exception, $tableName, AbstractDdl $ddl)\n\t{\n\t\t// The exception might have some extra useful stuff in it, so include attempt to modify the message directly.\n\n\t\ttry\n\t\t{\n\t\t\t$reflectionClass = new \\ReflectionClass($exception);\n\t\t\t$messageProperty = $reflectionClass->getProperty('message');\n\t\t\t$messageProperty->setAccessible(true);\n\t\t\t$messageProperty->setValue($exception, $tableName . ': ' . $messageProperty->getValue($exception));\n\t\t}\n\t\tcatch (\\ReflectionException $ignored)\n\t\t{\n\t\t}\n\n\t\tthrow $exception;\n\t}\n","lines":[{"line":254,"text":"\tprotected function handleException($exception, $tableName, AbstractDdl $ddl)"},{"line":255,"text":"\t{"},{"line":256,"text":"\t\t// The exception might have some extra useful stuff in it, so include attempt to modify the message directly."},{"line":257,"text":""},{"line":258,"text":"\t\ttry"},{"line":259,"text":"\t\t{"},{"line":260,"text":"\t\t\t$reflectionClass = new \\ReflectionClass($exception);"},{"line":261,"text":"\t\t\t$messageProperty = $reflectionClass->getProperty('message');"},{"line":262,"text":"\t\t\t$messageProperty->setAccessible(true);"},{"line":263,"text":"\t\t\t$messageProperty->setValue($exception, $tableName . ': ' . $messageProperty->getValue($exception));"},{"line":264,"text":"\t\t}"},{"line":265,"text":"\t\tcatch (\\ReflectionException $ignored)"},{"line":266,"text":"\t\t{"},{"line":267,"text":"\t\t}"},{"line":268,"text":""},{"line":269,"text":"\t\tthrow $exception;"},{"line":270,"text":"\t}"}]},"alterTable":{"ok":true,"class":"XF\\Db\\SchemaManager","method":"alterTable","file":"SchemaManager.php","start":150,"end":163,"sha256":"5e9788e5e9344db7c332d6c7e728a050f83967ac6d9d8a06727d266dcbbcc787","source":"\tpublic function alterTable($tableName, \\Closure $toApply)\n\t{\n\t\t$alter = $this->newAlter($tableName);\n\n\t\ttry\n\t\t{\n\t\t\t$toApply($alter);\n\t\t\t$alter->apply();\n\t\t}\n\t\tcatch (\\Exception $e)\n\t\t{\n\t\t\t$this->handleException($e, $tableName, $alter);\n\t\t}\n\t}\n","lines":[{"line":150,"text":"\tpublic function alterTable($tableName, \\Closure $toApply)"},{"line":151,"text":"\t{"},{"line":152,"text":"\t\t$alter = $this->newAlter($tableName);"},{"line":153,"text":""},{"line":154,"text":"\t\ttry"},{"line":155,"text":"\t\t{"},{"line":156,"text":"\t\t\t$toApply($alter);"},{"line":157,"text":"\t\t\t$alter->apply();"},{"line":158,"text":"\t\t}"},{"line":159,"text":"\t\tcatch (\\Exception $e)"},{"line":160,"text":"\t\t{"},{"line":161,"text":"\t\t\t$this->handleException($e, $tableName, $alter);"},{"line":162,"text":"\t\t}"},{"line":163,"text":"\t}"}]},"renameTable":{"ok":true,"class":"XF\\Db\\SchemaManager","method":"renameTable","file":"SchemaManager.php","start":169,"end":181,"sha256":"c352def9c86f9233a9c629670c5334a436092765a9c121807a21ef536510d7db","source":"\tpublic function renameTable($oldTableName, $newTableName)\n\t{\n\t\t$alter = $this->newAlter($oldTableName)->renameTo($newTableName);\n\n\t\ttry\n\t\t{\n\t\t\t$alter->apply();\n\t\t}\n\t\tcatch (\\Exception $e)\n\t\t{\n\t\t\t$this->handleException($e, $oldTableName, $alter);\n\t\t}\n\t}\n","lines":[{"line":169,"text":"\tpublic function renameTable($oldTableName, $newTableName)"},{"line":170,"text":"\t{"},{"line":171,"text":"\t\t$alter = $this->newAlter($oldTableName)->renameTo($newTableName);"},{"line":172,"text":""},{"line":173,"text":"\t\ttry"},{"line":174,"text":"\t\t{"},{"line":175,"text":"\t\t\t$alter->apply();"},{"line":176,"text":"\t\t}"},{"line":177,"text":"\t\tcatch (\\Exception $e)"},{"line":178,"text":"\t\t{"},{"line":179,"text":"\t\t\t$this->handleException($e, $oldTableName, $alter);"},{"line":180,"text":"\t\t}"},{"line":181,"text":"\t}"}]},"tableExists":{"ok":true,"class":"XF\\Db\\SchemaManager","method":"tableExists","file":"SchemaManager.php","start":119,"end":124,"sha256":"234d0c64067ebbf246972acbed6d58574c535e2ad78478d529afd97963551070","source":"\tpublic function tableExists($tableName)\n\t{\n\t\t$status = $this->getTableStatus($tableName);\n\n\t\treturn $status ? true : false;\n\t}\n","lines":[{"line":119,"text":"\tpublic function tableExists($tableName)"},{"line":120,"text":"\t{"},{"line":121,"text":"\t\t$status = $this->getTableStatus($tableName);"},{"line":122,"text":""},{"line":123,"text":"\t\treturn $status ? true : false;"},{"line":124,"text":"\t}"}]}},"table_create_class":"XF\\Db\\Schema\\Create","table_create_methods":{"apply":{"ok":true,"class":"XF\\Db\\Schema\\Create","method":"apply","file":"AbstractDdl.php","start":152,"end":162,"sha256":"70bf8158872ac741e410f19c8a3893809f6a4514907495ec2fe6af5204446493","source":"\tpublic function apply()\n\t{\n\t\t$queries = $this->getQueries();\n\n\t\tforeach ($queries AS $query)\n\t\t{\n\t\t\t$this->db->query($query);\n\t\t}\n\n\t\treturn $queries;\n\t}\n","lines":[{"line":152,"text":"\tpublic function apply()"},{"line":153,"text":"\t{"},{"line":154,"text":"\t\t$queries = $this->getQueries();"},{"line":155,"text":""},{"line":156,"text":"\t\tforeach ($queries AS $query)"},{"line":157,"text":"\t\t{"},{"line":158,"text":"\t\t\t$this->db->query($query);"},{"line":159,"text":"\t\t}"},{"line":160,"text":""},{"line":161,"text":"\t\treturn $queries;"},{"line":162,"text":"\t}"}]},"getQueries":{"ok":true,"class":"XF\\Db\\Schema\\Create","method":"getQueries","file":"Create.php","start":26,"end":110,"sha256":"86696c181f223784f11bf6591fd070796b316648462933706f2702ca20eff475","source":"\tpublic function getQueries()\n\t{\n\t\t$tableName = $this->tableName;\n\n\t\t$queries = [];\n\n\t\t$query = 'CREATE TABLE';\n\n\t\tif ($this->checkExists)\n\t\t{\n\t\t\t$query .= ' IF NOT EXISTS';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$existing = $this->db->getSchemaManager()->getTableStatus($tableName);\n\t\t\tif ($existing)\n\t\t\t{\n\t\t\t\t$existing = new static($this->db, $this->sm, $tableName);\n\t\t\t\t$existing->setDefinition();\n\n\t\t\t\tif ($this->compare($existing))\n\t\t\t\t{\n\t\t\t\t\t// new table is identical, so just skip it\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\telse if ($this->forceChanges)\n\t\t\t\t{\n\t\t\t\t\t$conflictName = $tableName . '__conflict';\n\t\t\t\t\tif ($this->sm->tableExists($conflictName))\n\t\t\t\t\t{\n\t\t\t\t\t\t$i = 2;\n\t\t\t\t\t\twhile ($this->sm->tableExists($conflictName . $i))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$i++;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$conflictName .= $i;\n\t\t\t\t\t}\n\t\t\t\t\t$queries[] = \"ALTER TABLE `$tableName` RENAME TO `$conflictName`\";\n\n\t\t\t\t\t$errorMessage = sprintf(\n\t\t\t\t\t\t\"Renamed table %s to %s to avoid schema conflict\",\n\t\t\t\t\t\t$tableName,\n\t\t\t\t\t\t$conflictName\n\t\t\t\t\t);\n\n\t\t\t\t\t\\XF::logError($errorMessage, true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthrow new \\LogicException(\"$tableName already exists, but the structure does not match.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t$query .= \" `$tableName` (\\n\\t\";\n\n\t\t$tableDefinition = [];\n\t\tforeach ($this->addColumns AS $column)\n\t\t{\n\t\t\t$tableDefinition[] = $column->getDefinition();\n\t\t}\n\t\tforeach ($this->addIndexes AS $index)\n\t\t{\n\t\t\t$tableDefinition[$index->getIndexName()] = $index->getDefinition();\n\t\t}\n\n\t\t$query .= implode(\",\\n\\t\", $tableDefinition);\n\t\t$query .= \"\\n)\";\n\t\t$query .= ' ' . $this->db->getSchemaManager()->getTableConfigSql($this->engine ?: null);\n\n\t\tif ($this->comment)\n\t\t{\n\t\t\t$query .= ' COMMENT=' . $this->db->quote($this->comment);\n\t\t}\n\n\t\tif ($this->autoIncrementIndex !== null)\n\t\t{\n\t\t\t$query .= ' AUTO_INCREMENT=' . $this->autoIncrementIndex;\n\t\t}\n\n\t\t$queries[] = $query;\n\n\t\treturn $queries;\n\t}\n","lines":[{"line":26,"text":"\tpublic function getQueries()"},{"line":27,"text":"\t{"},{"line":28,"text":"\t\t$tableName = $this->tableName;"},{"line":29,"text":""},{"line":30,"text":"\t\t$queries = [];"},{"line":31,"text":""},{"line":32,"text":"\t\t$query = 'CREATE TABLE';"},{"line":33,"text":""},{"line":34,"text":"\t\tif ($this->checkExists)"},{"line":35,"text":"\t\t{"},{"line":36,"text":"\t\t\t$query .= ' IF NOT EXISTS';"},{"line":37,"text":"\t\t}"},{"line":38,"text":"\t\telse"},{"line":39,"text":"\t\t{"},{"line":40,"text":"\t\t\t$existing = $this->db->getSchemaManager()->getTableStatus($tableName);"},{"line":41,"text":"\t\t\tif ($existing)"},{"line":42,"text":"\t\t\t{"},{"line":43,"text":"\t\t\t\t$existing = new static($this->db, $this->sm, $tableName);"},{"line":44,"text":"\t\t\t\t$existing->setDefinition();"},{"line":45,"text":""},{"line":46,"text":"\t\t\t\tif ($this->compare($existing))"},{"line":47,"text":"\t\t\t\t{"},{"line":48,"text":"\t\t\t\t\t// new table is identical, so just skip it"},{"line":49,"text":"\t\t\t\t\treturn [];"},{"line":50,"text":"\t\t\t\t}"},{"line":51,"text":"\t\t\t\telse if ($this->forceChanges)"},{"line":52,"text":"\t\t\t\t{"},{"line":53,"text":"\t\t\t\t\t$conflictName = $tableName . '__conflict';"},{"line":54,"text":"\t\t\t\t\tif ($this->sm->tableExists($conflictName))"},{"line":55,"text":"\t\t\t\t\t{"},{"line":56,"text":"\t\t\t\t\t\t$i = 2;"},{"line":57,"text":"\t\t\t\t\t\twhile ($this->sm->tableExists($conflictName . $i))"},{"line":58,"text":"\t\t\t\t\t\t{"},{"line":59,"text":"\t\t\t\t\t\t\t$i++;"},{"line":60,"text":"\t\t\t\t\t\t}"},{"line":61,"text":""},{"line":62,"text":"\t\t\t\t\t\t$conflictName .= $i;"},{"line":63,"text":"\t\t\t\t\t}"},{"line":64,"text":"\t\t\t\t\t$queries[] = \"ALTER TABLE `$tableName` RENAME TO `$conflictName`\";"},{"line":65,"text":""},{"line":66,"text":"\t\t\t\t\t$errorMessage = sprintf("},{"line":67,"text":"\t\t\t\t\t\t\"Renamed table %s to %s to avoid schema conflict\","},{"line":68,"text":"\t\t\t\t\t\t$tableName,"},{"line":69,"text":"\t\t\t\t\t\t$conflictName"},{"line":70,"text":"\t\t\t\t\t);"},{"line":71,"text":""},{"line":72,"text":"\t\t\t\t\t\\XF::logError($errorMessage, true);"},{"line":73,"text":"\t\t\t\t}"},{"line":74,"text":"\t\t\t\telse"},{"line":75,"text":"\t\t\t\t{"},{"line":76,"text":"\t\t\t\t\tthrow new \\LogicException(\"$tableName already exists, but the structure does not match.\");"},{"line":77,"text":"\t\t\t\t}"},{"line":78,"text":"\t\t\t}"},{"line":79,"text":"\t\t}"},{"line":80,"text":""},{"line":81,"text":"\t\t$query .= \" `$tableName` (\\n\\t\";"},{"line":82,"text":""},{"line":83,"text":"\t\t$tableDefinition = [];"},{"line":84,"text":"\t\tforeach ($this->addColumns AS $column)"},{"line":85,"text":"\t\t{"},{"line":86,"text":"\t\t\t$tableDefinition[] = $column->getDefinition();"},{"line":87,"text":"\t\t}"},{"line":88,"text":"\t\tforeach ($this->addIndexes AS $index)"},{"line":89,"text":"\t\t{"},{"line":90,"text":"\t\t\t$tableDefinition[$index->getIndexName()] = $index->getDefinition();"},{"line":91,"text":"\t\t}"},{"line":92,"text":""},{"line":93,"text":"\t\t$query .= implode(\",\\n\\t\", $tableDefinition);"},{"line":94,"text":"\t\t$query .= \"\\n)\";"},{"line":95,"text":"\t\t$query .= ' ' . $this->db->getSchemaManager()->getTableConfigSql($this->engine ?: null);"},{"line":96,"text":""},{"line":97,"text":"\t\tif ($this->comment)"},{"line":98,"text":"\t\t{"},{"line":99,"text":"\t\t\t$query .= ' COMMENT=' . $this->db->quote($this->comment);"},{"line":100,"text":"\t\t}"},{"line":101,"text":""},{"line":102,"text":"\t\tif ($this->autoIncrementIndex !== null)"},{"line":103,"text":"\t\t{"},{"line":104,"text":"\t\t\t$query .= ' AUTO_INCREMENT=' . $this->autoIncrementIndex;"},{"line":105,"text":"\t\t}"},{"line":106,"text":""},{"line":107,"text":"\t\t$queries[] = $query;"},{"line":108,"text":""},{"line":109,"text":"\t\treturn $queries;"},{"line":110,"text":"\t}"}]},"getCreateQuery":{"ok":false,"class":"XF\\Db\\Schema\\Create","method":"getCreateQuery","error":"ReflectionException"},"exists":{"ok":false,"class":"XF\\Db\\Schema\\Create","method":"exists","error":"ReflectionException"}},"source_scans":[{"file":"src/XF/Cli/Command/AddOnActionTrait.php","sha256":"265c7bd3e5dbeb5669b52e57fc9c67411261be00e493cc717aa6b5c991421287","hits":[{"line":15,"text":"use XF\\AddOn\\StepResult;"},{"line":118,"text":"/** @var StepResult $result */"},{"line":131,"text":"$params['step'] = $result->step;"},{"line":219,"text":"'xf:addon-sub-action',"}]},{"file":"src/XF/Cli/Command/AddOnInstall.php","sha256":"2407ad9ae20ca8ac1ca84b456ac2adc537f39c79534da5e258167a4d0df2a54f","hits":[{"line":20,"text":"->setName('xf:addon-install')"}]},{"file":"src/XF/Cli/Command/AddOnList.php","sha256":"3047ffa03d4fa488cb8a53c2f0c8c88edd8372e5804340f72b3fd761b7eff1ea","hits":[{"line":136,"text":"'last_pending_action' => $installed->last_pending_action,"},{"line":198,"text":"$installed->last_pending_action ?: '-',"}]},{"file":"src/XF/Cli/Command/AddOnSubAction.php","sha256":"4cbf315edc17bf5773c624da2d1af076f47dd588398462d657f709d832adbb46","hits":[{"line":18,"text":"->setName('xf:addon-sub-action')"},{"line":19,"text":"->setDescription('Runs a add-on sub-action in a separate process. Do not run directly!')"},{"line":46,"text":"$output->writeln(\"Invalid sub-action confirmation key. Run from parent command.\");"}]},{"file":"src/XF/Cli/Command/Import.php","sha256":"cbc8b5707e84a1b1293ca00f57dcc91bb0ded0d3810eb976d0b93327c1dd32f5","hits":[{"line":14,"text":"use XF\\Import\\StepState;"},{"line":39,"text":"'If set, the import will be automatically finalized when the data import step completes.'"},{"line":112,"text":"function ($isComplete, $step, StepState $stepState, $importCompletion) use ($progressIndicator, &$progressStarted)"},{"line":114,"text":"$stepTitle = $stepState->title;"},{"line":115,"text":"if (!$stepTitle)"},{"line":132,"text":"$stepNumberStrlen = strlen((string) $importCompletion['total']);"},{"line":133,"text":"$stepNameStrlen = 25; // just arbitrary for now, but could be based on the strlen of the longest step title"},{"line":135,"text":"$stepInfo = sprintf("},{"line":136,"text":"\"Step %{$stepNumberStrlen}d of %d: %-{$stepNameStrlen}s \","},{"line":139,"text":"$stepTitle"},{"line":142,"text":"if ($stepState->complete)"},{"line":145,"text":"$stepInfo"},{"line":146,"text":". $this->getIntervalString($stepState->startDate, $stepState->completeDate)"},{"line":147,"text":". ' [' . \\XF::language()->numberFormat($stepState->imported) . ']'"},{"line":154,"text":"$stepInfo"},{"line":155,"text":". $this->getIntervalString($stepState->startDate, time()) . ' '"},{"line":156,"text":". $stepState->getCompletionOutput()"}]},{"file":"src/XF/Cli/Command/ImportChildProcess.php","sha256":"4018331a7104801b8d7c73c6bf90374e198ed576897a7b4b01e5195c9d5133f9","hits":[{"line":24,"text":"'step',"},{"line":26,"text":"'The name of the step to run.'"},{"line":63,"text":"$step = $input->getArgument('step');"},{"line":67,"text":"if (!$runner->validateChildProcessRun($step, $startAfter, $end, $error))"},{"line":78,"text":"$runner->runChildProcess($step, $startAfter, $end, $messageReceiver);"}]},{"file":"src/XF/Cli/Command/ImportCommandTrait.php","sha256":"a4816d99b66aa795a1558e01dc42169c471af78028e103533326ced8365f970b","hits":[{"line":21,"text":"$totalsTable->setHeaders(['Step', 'Total', 'Time taken']);"}]},{"file":"src/XF/Cli/Command/ImportFinalize.php","sha256":"78b8ed78256f621c461fe11a6b206a3871819c9960660029feb8d76134ecfde8","hits":[{"line":64,"text":"$jobs = $manager->getImporter($session->importerId)->getFinalizeJobs($session->getStepsRun());"}]},{"file":"src/XF/Cli/Command/Upgrade.php","sha256":"9f58a531299befbb84458add55bb9e701fc18cd06f49d5c86c15fd5871af1a61","hits":[{"line":70,"text":". ($lastUpgradeVersion['last_step'] ? \" (step $lastUpgradeVersion[last_step])\" : '')"},{"line":75,"text":"$upgradeComplete = ($lastUpgradeVersion['version_id'] === \\XF::$versionId && !$lastUpgradeVersion['last_step']);"},{"line":104,"text":"$step = 1;"},{"line":106,"text":"if ($lastUpgradeVersion['last_step'])"},{"line":109,"text":"$step = $lastUpgradeVersion['last_step'] + 1;"},{"line":115,"text":"$step = 1;"},{"line":126,"text":"$upgrader->assertValidUpgradeSteps($upgrade);"},{"line":132,"text":"while (method_exists($upgrade, 'step' . $step))"},{"line":136,"text":"$this->outputStatus($output, \"Running upgrade to $versionName, step $step ($position)...\");"},{"line":140,"text":"$this->outputStatus($output, \"Running upgrade to $versionName, step $step...\");"},{"line":143,"text":"$result = $upgrade->{'step' . $step}($position, $data, $controller);"},{"line":146,"text":"$this->clearStatus($output, 'This step must be completed via the web interface.');"},{"line":151,"text":"$this->clearStatus($output, \"Running upgrade to $versionName, step $step... done.\");"},{"line":156,"text":"$upgrader->insertUpgradeLog($runVersionId, $step);"},{"line":158,"text":"$this->clearStatus($output, \"Running upgrade to $versionName, step $step... done.\");"},{"line":160,"text":"$step++;"},{"line":166,"text":"// stay on the same step"},{"line":172,"text":"$this->clearStatus($output, 'The upgrade step returned an unexpected result.');"},{"line":180,"text":"$step = 1;"},{"line":184,"text":"$output->writeln(['All upgrade steps run up to version ' . \\XF::$version . '.', '']);"}]},{"file":"src/XF/Cli/Command/AddOn/AbstractSetupStep.php","sha256":"86ac6e9eda2202a75f3566a6bf20b14b5cc5171a823e0a23de0e66d0e8c0a8b7","hits":[{"line":9,"text":"use XF\\AddOn\\StepResult;"},{"line":16,"text":"abstract class AbstractSetupStep extends AbstractCommand"},{"line":21,"text":"abstract protected function getStepType();"},{"line":27,"text":"$command = $this->getStepType();"},{"line":30,"text":"->setName('xf-addon:' . $command . '-step')"},{"line":31,"text":"->setDescription('Runs a specific step from the specified add-on Setup class.')"},{"line":60,"text":"$step = $input->getArgument('step');"},{"line":64,"text":"$stepType = $this->getStepType();"},{"line":65,"text":"if ($stepType == 'upgrade')"},{"line":70,"text":"$setup->prepareForAction($stepType);"},{"line":74,"text":"$result = $this->runStep($setup, $output, $stepType, $step, $version, $params);"},{"line":75,"text":"if (!($result instanceof StepResult))"},{"line":77,"text":"$this->clearStatus($output, \"Must return a StepResult object.\");"},{"line":104,"text":"protected function runStep(AbstractSetup $setup, OutputInterface $output, $stepType, $step, $version = null, array $params = [])"},{"line":106,"text":"$method = $stepType;"},{"line":112,"text":"if ($step)"},{"line":114,"text":"$method .= 'Step' . $step;"},{"line":119,"text":"if ($version && $step)"},{"line":121,"text":"$method .= $version . 'Step' . $step;"},{"line":129,"text":"return new StepResult(true);"},{"line":137,"text":"$result = new StepResult(true);"},{"line":142,"text":"$result = new StepResult(false, $result);"}]},{"file":"src/XF/Cli/Command/AddOn/Create.php","sha256":"4ff8f77caa12327158b9a6ba6ed2ffe85b959011279be5a70a8b3e77f75204f5","hits":[{"line":217,"text":"$question = new ConfirmationQuestion(\"Does your Setup need to support running multiple steps? (y/n) \");"},{"line":226,"text":"use XF\\AddOn\\StepRunnerInstallTrait;"},{"line":227,"text":"use XF\\AddOn\\StepRunnerUninstallTrait;"},{"line":228,"text":"use XF\\AddOn\\StepRunnerUpgradeTrait;"},{"line":232,"text":"use StepRunnerInstallTrait;"},{"line":233,"text":"use StepRunnerUpgradeTrait;"},{"line":234,"text":"use StepRunnerUninstallTrait;"},{"line":250,"text":"public function install(array \\$stepParams = [])"},{"line":255,"text":"public function upgrade(array \\$stepParams = [])"},{"line":260,"text":"public function uninstall(array \\$stepParams = [])"},{"line":283,"text":"$output->writeln(\"If you change your mind, create a file named Setup.php in \" . dirname($setupPath) . \" which should extend AbstractSetup and optionally use one of the StepRunnerX traits.\");"}]},{"file":"src/XF/Cli/Command/AddOn/InstallStep.php","sha256":"5536a7cdaa190b8ddff16e58733a546c3735ae8e55ab4c9d3cf1e1acce615ca2","hits":[{"line":7,"text":"class InstallStep extends AbstractSetupStep"},{"line":9,"text":"protected function getStepType()"},{"line":17,"text":"'step',"},{"line":19,"text":"'The step number to run.'"}]},{"file":"src/XF/Cli/Command/AddOn/UninstallStep.php","sha256":"d69b287acd3ea5c02bf23492e1bdef465fb75f22f00b45acdb4ffafe547260e5","hits":[{"line":7,"text":"class UninstallStep extends AbstractSetupStep"},{"line":9,"text":"protected function getStepType()"},{"line":17,"text":"'step',"},{"line":19,"text":"'The step number to run.'"}]},{"file":"src/XF/Cli/Command/AddOn/UpgradeStep.php","sha256":"51d6bcea38a819ab7a983340112de1b9778ed9efeb0a139f8d0b6c967b4e052f","hits":[{"line":7,"text":"class UpgradeStep extends AbstractSetupStep"},{"line":9,"text":"protected function getStepType()"},{"line":23,"text":"'step',"},{"line":25,"text":"'The step number to run.'"}]},{"file":"src/XF/Cli/Command/Rebuild/AbstractRebuildCommand.php","sha256":"9b019518b8fb2d2e3bf6d281acb57e181c4b48f2acbf654efdc81b87f294c7f4","hits":[{"line":56,"text":"'resume',"},{"line":73,"text":"if ($input->getOption('resume'))"},{"line":81,"text":"$output->writeln(\"There are no pending jobs of this type to resume.\");"}]},{"file":"src/XF/Cli/Command/EmbedMetadata/AbstractEmbedMetadataCommand.php","sha256":"d58bdc8eb04615e12b7838403db010fb05ff9238203467061fd7f0bb2d6274f9","hits":[{"line":74,"text":"'resume',"},{"line":77,"text":"'Resume an existing pending job instead of starting a new one. Without this flag, re-running the command discards any prior progress and restarts from the beginning.'"},{"line":92,"text":"if ($input->getOption('resume'))"},{"line":100,"text":"$output->writeln(\"There are no pending jobs of this type to resume.\");"}]},{"file":"src/XF/Cli/Command/Development/UpgradeStep.php","sha256":"6c91e119b41e5d2b83da72f7d37c02ff2f3d6149b7b7974e05ab3539f0e59fd5","hits":[{"line":18,"text":"class UpgradeStep extends AbstractCommand implements CustomAppCommandInterface"},{"line":30,"text":"->setName('xf-dev:upgrade-step')"},{"line":31,"text":"->setDescription('Runs a specific upgrade step from a specified upgrade class.')"},{"line":38,"text":"'step',"},{"line":40,"text":"'The step number to run'"},{"line":54,"text":"$step = $input->getArgument('step');"},{"line":60,"text":"$returnCode = $this->runStep($upgrade, $output, $controller, $step, $position, $data);"},{"line":73,"text":"throw new \\LogicException(\"Step did not return an expected result\");"},{"line":81,"text":"protected function runStep(AbstractUpgrade $upgrade, OutputInterface $output, Upgrade $controller, $step, $position = 0, $data = [])"},{"line":85,"text":"if (!method_exists($upgrade, 'step' . $step))"},{"line":87,"text":"$this->clearStatus($output, \"Upgrade to version $versionName does not have a step$step() method.\");"},{"line":93,"text":"$this->outputStatus($output, \"Running upgrade to $versionName, step $step ($position)...\");"},{"line":97,"text":"$this->outputStatus($output, \"Running upgrade to $versionName, step $step...\");"},{"line":100,"text":"$result = $upgrade->{'step' . $step}($position, $data, $controller);"},{"line":103,"text":"$this->clearStatus($output, \"This step must be completed via the web interface.\");"},{"line":108,"text":"$this->clearStatus($output, \"Running upgrade to $versionName, step $step... done.\");"},{"line":113,"text":"// stay on the same step"},{"line":118,"text":"$this->clearStatus($output, \"The upgrade step returned an unexpected result.\");"}]},{"file":"src/XF/AddOn/AbstractSetup.php","sha256":"6bdd3fe834e15b963a52c9357f54262f2d12f3c7c3686fc31333b549cddf2d88","hits":[{"line":21,"text":"* @param array $stepParams"},{"line":23,"text":"* @return null|StepResult"},{"line":25,"text":"abstract public function install(array $stepParams = []);"},{"line":28,"text":"* @param array $stepParams"},{"line":30,"text":"* @return null|StepResult"},{"line":32,"text":"abstract public function upgrade(array $stepParams = []);"},{"line":35,"text":"* @param array $stepParams"},{"line":37,"text":"* @return null|StepResult"},{"line":39,"text":"abstract public function uninstall(array $stepParams = []);"}]},{"file":"src/XF/AddOn/AddOn.php","sha256":"0e0346a046fff6bde9850cb53e9dc0d0b5379387029dc16925e562fa141ab422","hits":[{"line":346,"text":"$lastAction = $this->installedAddOn->getLastActionStep('install');"},{"line":349,"text":"// we haven't completed the install steps yet, don't consider as installed"},{"line":537,"text":"public function updatePendingAction($action, $step)"},{"line":541,"text":"$this->installedAddOn->fastUpdate('last_pending_action', \"$action:$step\");"},{"line":549,"text":"$this->installedAddOn->fastUpdate('last_pending_action', null);"},{"line":568,"text":"'last_pending_action' => 'install:0',"},{"line":653,"text":"$installed->last_pending_action = 'uninstall:0';"}]},{"file":"src/XF/AddOn/StepResult.php","sha256":"d486646b6b20370f7c03f473468ecec93e7cea3ef45cca8d72d6fe9b2701f9be","hits":[{"line":5,"text":"class StepResult"},{"line":9,"text":"public $step;"},{"line":12,"text":"public function __construct($complete, array $params = [], $step = null, $version = null)"},{"line":16,"text":"$this->step = $step;"}]},{"file":"src/XF/AddOn/StepRunnerInstallTrait.php","sha256":"1f441b8a3101b97009ae04e62c04e79062a89f1e01a08ae9e07c5e629c76d5f2","hits":[{"line":10,"text":"trait StepRunnerInstallTrait"},{"line":13,"text":"* @param array $stepParams"},{"line":15,"text":"* @return null|StepResult"},{"line":17,"text":"public function install(array $stepParams = [])"},{"line":19,"text":"$stepParams = array_replace(["},{"line":20,"text":"'step' => 0,"},{"line":21,"text":"], $stepParams);"},{"line":23,"text":"$step = $stepParams['step'];"},{"line":24,"text":"if (!$step)"},{"line":26,"text":"$step = $this->getInstallResumeStep();"},{"line":29,"text":"return $this->installStepRunner($step, $stepParams);"},{"line":32,"text":"private function getInstallResumeStep()"},{"line":37,"text":"$lastActionStep = $installedAddOn->getLastActionStep('install');"},{"line":38,"text":"if ($lastActionStep)"},{"line":40,"text":"return $lastActionStep + 1; // this is the last completed step, so resume with the next"},{"line":48,"text":"* @param integer $step"},{"line":49,"text":"* @param array $stepParams"},{"line":51,"text":"* @return null|StepResult"},{"line":53,"text":"private function installStepRunner($step, array $stepParams)"},{"line":55,"text":"$fnPrefix = 'installStep';"},{"line":56,"text":"$fn = $fnPrefix . $step;"},{"line":62,"text":"$result = $this->$fn($stepParams);"},{"line":65,"text":"$result = new StepResult(true);"},{"line":69,"text":"$result = new StepResult(false, $result);"},{"line":72,"text":"if (!($result instanceof StepResult))"},{"line":74,"text":"throw new \\LogicException(\"Must return a StepResult object\");"},{"line":77,"text":"$result->step = $step;"},{"line":81,"text":"$this->addOn->updatePendingAction('install', $result->step);"},{"line":83,"text":"$nextStep = $step + 1;"},{"line":84,"text":"$nextFn = $fnPrefix . $nextStep;"},{"line":90,"text":"$result = new StepResult(false, [], $nextStep);"}]},{"file":"src/XF/AddOn/StepRunnerUninstallTrait.php","sha256":"e58a9ab9c30e3cf3c41a0be392e8c5ac37f744578f7b91f76d663139649c49a9","hits":[{"line":10,"text":"trait StepRunnerUninstallTrait"},{"line":13,"text":"* @param array $stepParams"},{"line":15,"text":"* @return null|StepResult"},{"line":17,"text":"public function uninstall(array $stepParams = [])"},{"line":19,"text":"$stepParams = array_replace(["},{"line":20,"text":"'step' => 0,"},{"line":21,"text":"], $stepParams);"},{"line":23,"text":"$step = $stepParams['step'];"},{"line":24,"text":"if (!$step)"},{"line":26,"text":"$step = $this->getUninstallResumeStep();"},{"line":28,"text":"return $this->uninstallStepRunner($step, $stepParams);"},{"line":31,"text":"private function getUninstallResumeStep()"},{"line":36,"text":"$lastActionStep = $installedAddOn->getLastActionStep('uninstall');"},{"line":37,"text":"if ($lastActionStep)"},{"line":39,"text":"return $lastActionStep + 1; // this is the last completed step, so resume with the next"},{"line":47,"text":"* @param integer $step"},{"line":48,"text":"* @param array $stepParams"},{"line":50,"text":"* @return null|StepResult"},{"line":52,"text":"private function uninstallStepRunner($step, array $stepParams)"},{"line":54,"text":"$fnPrefix = 'uninstallStep';"},{"line":55,"text":"$fn = $fnPrefix . $step;"},{"line":61,"text":"$result = $this->$fn($stepParams);"},{"line":64,"text":"$result = new StepResult(true);"},{"line":68,"text":"$result = new StepResult(false, $result);"},{"line":71,"text":"if (!($result instanceof StepResult))"},{"line":73,"text":"throw new \\LogicException(\"Must return a StepResult object\");"},{"line":76,"text":"$result->step = $step;"},{"line":80,"text":"$this->addOn->updatePendingAction('uninstall', $result->step);"},{"line":82,"text":"$nextStep = $step + 1;"},{"line":83,"text":"$nextFn = $fnPrefix . $nextStep;"},{"line":89,"text":"$result = new StepResult(false, [], $nextStep);"}]},{"file":"src/XF/AddOn/StepRunnerUpgradeTrait.php","sha256":"b61698d9c20f094cc1b704ad48798148fe5843e2dc746592cb2db252b579d1b5","hits":[{"line":10,"text":"trait StepRunnerUpgradeTrait"},{"line":13,"text":"* @param array $stepParams"},{"line":15,"text":"* @return null|StepResult"},{"line":17,"text":"public function upgrade(array $stepParams = [])"},{"line":19,"text":"$stepParams = $this->getStepParams($stepParams);"},{"line":22,"text":"$stepsGrouped = [];"},{"line":27,"text":"if (preg_match('/^upgrade(\\d+)Step(\\d+)$/', $method->name, $match))"},{"line":30,"text":"$step = intval($match[2]);"},{"line":33,"text":"$stepsGrouped[$versionId][$step] = $step;"},{"line":42,"text":"if (!$stepParams['version_id'])"},{"line":44,"text":"$resume = $this->getUpgradeResumeStep();"},{"line":45,"text":"$stepParams['version_id'] = $resume[0];"},{"line":46,"text":"$stepParams['step'] = $resume[1];"},{"line":49,"text":"$runStep = $stepParams['step'];"},{"line":50,"text":"if (!$runStep)"},{"line":52,"text":"$runStep = 1;"},{"line":60,"text":"if ($versionId >= $stepParams['version_id'])"},{"line":62,"text":"$versionSteps = $stepsGrouped[$versionId];"},{"line":63,"text":"if (isset($versionSteps[$runStep]))"},{"line":65,"text":"if ($versionId != $stepParams['version_id'] || $runStep != $stepParams['step'])"},{"line":67,"text":"// sanity check - don't pass params if we're changing versions or steps"},{"line":68,"text":"$stepParams = [];"},{"line":73,"text":"return $this->upgradeStepRunner($versionId, $runStep, $stepParams, $nextVersionId);"},{"line":76,"text":"// if we hit here, then the step couldn't be found, so move onto the next upgrade"},{"line":77,"text":"$runStep = 1;"},{"line":78,"text":"$stepParams = $this->getStepParams();"},{"line":86,"text":"protected function getStepParams(array $stepParams = [])"},{"line":90,"text":"'step' => 0,"},{"line":91,"text":"], $stepParams);"},{"line":94,"text":"private function getUpgradeResumeStep()"},{"line":97,"text":"$lastActionStep = $installedAddOn->getLastActionStep('upgrade');"},{"line":98,"text":"if ($lastActionStep)"},{"line":100,"text":"$lastActionStep[1]++; // we completed this step, so need to resume with the next"},{"line":101,"text":"return $lastActionStep;"},{"line":109,"text":"* @param integer $runStep"},{"line":110,"text":"* @param array $stepParams"},{"line":113,"text":"* @return null|StepResult"},{"line":115,"text":"private function upgradeStepRunner($runVersion, $runStep, array $stepParams, $nextVersionId)"},{"line":117,"text":"$fnPattern = 'upgrade%dStep%d';"},{"line":118,"text":"$fn = sprintf($fnPattern, $runVersion, $runStep);"},{"line":121,"text":"throw new \\LogicException(\"Step $fn doesn't exist. Should have been checked earlier.\");"},{"line":124,"text":"$result = $this->$fn($stepParams);"},{"line":127,"text":"$result = new StepResult(true);"},{"line":131,"text":"$result = new StepResult(false, $result);"},{"line":134,"text":"if (!($result instanceof StepResult))"},{"line":136,"text":"throw new \\LogicException(\"Must return a StepResult object\");"},{"line":139,"text":"$result->step = $runStep;"},{"line":144,"text":"$this->addOn->updatePendingAction('upgrade', $result->version . ':' . $result->step);"},{"line":146,"text":"$nextStep = $runStep + 1;"},{"line":147,"text":"$nextStepFn = sprintf($fnPattern, $runVersion, $nextStep);"},{"line":148,"text":"if (method_exists($this, $nextStepFn))"},{"line":150,"text":"$result = new StepResult(false, [], $nextStep, $runVersion);"},{"line":166,"text":"$result = new StepResult(false, [], 1, $nextVersionId);"}]},{"file":"src/XF/AddOn/DataType/AbstractDataType.php","sha256":"a4f6ec14e4009be0029548b07272dc77c6ad96f4cca4e067a7d3ea0004126815","hits":[{"line":165,"text":"protected function resume($maxRunTime, $startTime)"}]}]},"assessment":{"all_six_tables_present":true,"all_six_tables_empty":true,"duplicate_create_appears_safe":true,"native_resume_signal":true},"policy":{"delete_performed":false,"mutation_performed":false,"goal":"select a no-delete native or bounded bridge install path"}}
-GRAM513R3R3_DECISION=PASS_NATIVE_RESUME_SCHEMA_RCA
-GRAM513R3R3_NEXT_GATE=READY_FOR_DIRECT_NATIVE_RETRY_CANARY_513R3R4
-HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-GRAM-XF-CODEVIPE-NATIVE-RESUME-SCHEMA-RCA-513R3R3","status":"OK","changes_made":false,"rollback_started":false,"rollback_restored":null}
+GRAM513R3R4_BEGIN=true
+MODE=CHANGE_CODEVIPE_FIX10_RETRY_FOOTER_CANARY
+NO_DELETE=true
+TARGET=codevipe.ru
+GRAM513R3R4_SAFE_REPORT={"guest":{"configure":{"ok":true,"site_option":"gramSupportSiteId","site_id":"codevipe","permission_entries_written":22,"permission_jobs":[],"all_jobs":[{"job_id":4,"execute_class":"XF\\Job\\Cron"},{"job_id":50,"execute_class":"XF\\Job\\UpgradeCheck"},{"job_id":64366,"execute_class":"XF\\Job\\TrendingResult"},{"job_id":64369,"execute_class":"XF\\Job\\IconUsage"},{"job_id":64371,"execute_class":"XF\\Job\\IconUsage"},{"job_id":64372,"execute_class":"XF\\Job\\IconUsage"},{"job_id":64373,"execute_class":"XF\\Job\\IconUsage"}],"baseline_unrelated_allowed":[{"job_id":4,"execute_class":"XF\\Job\\Cron"},{"job_id":50,"execute_class":"XF\\Job\\UpgradeCheck"}],"job_loops":0},"verify":{"ok":false,"checks":{"addon":true,"board_active":true,"tables":false,"routes4":true,"counts":true,"permissions":true,"site_id":true,"perm_jobs_zero":true,"manifest":true,"error_log":false,"footer_v7":true,"services":true,"http":true},"state":{"addon":{"addon_id":"Gram/Support","title":"Gram Support","version_id":1000120,"version_string":"1.0.0 Alpha 3 Unified Fix 10","active":1,"is_processing":0,"last_pending_action":null},"counts":{"xf_content_type_field":1,"xf_code_event_listener":1,"xf_option":4,"xf_option_group":1,"xf_permission":9,"xf_permission_interface_group":1,"xf_phrase":54,"xf_route":4,"xf_template":13,"xf_template_modification":1},"support_tables":["xf_gram_support_attachment_meta","xf_gram_support_delivery","xf_gram_support_event","xf_gram_support_event__conflict","xf_gram_support_message","xf_gram_support_message__conflict","xf_gram_support_rate_limit","xf_gram_support_ticket","xf_gram_support_ticket__conflict"],"support_table_rows":{"xf_gram_support_attachment_meta":0,"xf_gram_support_delivery":0,"xf_gram_support_event":0,"xf_gram_support_event__conflict":0,"xf_gram_support_message":0,"xf_gram_support_message__conflict":0,"xf_gram_support_rate_limit":0,"xf_gram_support_ticket":0,"xf_gram_support_ticket__conflict":0},"routes":[{"route_type":"public","route_prefix":"account","sub_name":"support","format":"support","controller":"Gram\\Support:AccountSupport","addon_id":"Gram/Support"},{"route_type":"public","route_prefix":"support","sub_name":"","format":"","controller":"Gram\\Support:Support","addon_id":"Gram/Support"},{"route_type":"public","route_prefix":"support","sub_name":"service-worker","format":"service-worker","controller":"Gram\\Support:Pwa","addon_id":"Gram/Support"},{"route_type":"public","route_prefix":"support","sub_name":"staff","format":"staff","controller":"Gram\\Support:StaffSupport","addon_id":"Gram/Support"}],"options":[{"option_id":"gramSupportGuestRateLimitCount","option_value":"5","default_value":"5"},{"option_id":"gramSupportGuestRateLimitWindowSeconds","option_value":"3600","default_value":"3600"},{"option_id":"gramSupportGuestTokenTtlDays","option_value":"30","default_value":"30"},{"option_id":"gramSupportSiteId","option_value":"codevipe","default_value":""}],"permission_entries":[{"permission_group_id":"gramSupport","permission_id":"create","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"replyOwn","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"view","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewOwn","user_group_id":2,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"assign","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"create","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"internalNotes","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"manage","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"replyOwn","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"view","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewAll","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewOwn","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewTechnicalContext","user_group_id":3,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"assign","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"create","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"internalNotes","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"manage","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"replyOwn","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"view","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewAll","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewOwn","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0},{"permission_group_id":"gramSupport","permission_id":"viewTechnicalContext","user_group_id":4,"user_id":0,"permission_value":"allow","permission_value_int":0}],"permission_jobs":[],"all_jobs":[{"job_id":4,"execute_class":"XF\\Job\\Cron","manual_execute":0},{"job_id":50,"execute_class":"XF\\Job\\UpgradeCheck","manual_execute":0},{"job_id":64366,"execute_class":"XF\\Job\\TrendingResult","manual_execute":0},{"job_id":64369,"execute_class":"XF\\Job\\IconUsage","manual_execute":0},{"job_id":64371,"execute_class":"XF\\Job\\IconUsage","manual_execute":0},{"job_id":64372,"execute_class":"XF\\Job\\IconUsage","manual_execute":0},{"job_id":64373,"execute_class":"XF\\Job\\IconUsage","manual_execute":0}],"footer_template":{"template_id":1416,"version_id":1000100,"version_string":"1.0.0 Alpha 3 Unified Fix 8","sha256":"ced49dfb6a64c55b06292c2b0d283847608f9c52434d6411cd93d06375ae225b","marker":true,"shift":true},"board_active":"1","board_url":"https://codevipe.ru","error_max":3,"xf":{"version_id":2031170,"version_string":"2.3.11"},"php":"8.3.32"},"manifest":{"file_count":59,"combined_sha256":"a31fc0535de726fc779ef67d1cac8fea3cb518f738e5e47412825cddb1a34a7a","addon_files":51,"addon_sha256":"f0054b4417c13226fe105c815e24466fd4dc5a2e65c7e11a04090206a95d9948","outside_files":8,"outside_sha256":"9e657ea8877f40c9336807faa12d681c21f0261db5ad1aad3501dc0b48fdde58","paths":["js/gram/support/access.js","js/gram/support/access.min.js","js/gram/support/pwa/icon-192.png","js/gram/support/pwa/icon-512.png","js/gram/support/pwa/manifest.webmanifest","js/gram/support/pwa/offline.html","js/gram/support/staff-pwa.js","js/gram/support/staff-pwa.min.js","src/addons/Gram/Support/Attachment/TicketHandler.php","src/addons/Gram/Support/Entity/AttachmentMeta.php","src/addons/Gram/Support/Entity/Delivery.php","src/addons/Gram/Support/Entity/Message.php","src/addons/Gram/Support/Entity/RateLimit.php","src/addons/Gram/Support/Entity/SupportEvent.php","src/addons/Gram/Support/Entity/Ticket.php","src/addons/Gram/Support/Listener/SourcePageContext.php","src/addons/Gram/Support/Notification/AlertConsumer.php","src/addons/Gram/Support/Notification/DeliveryGate.php","src/addons/Gram/Support/Notification/Dispatcher.php","src/addons/Gram/Support/Notification/EmailConsumer.php","src/addons/Gram/Support/Notification/EntityDeliveryGate.php","src/addons/Gram/Support/Notification/EventDispatcher.php","src/addons/Gram/Support/Notification/Policy.php","src/addons/Gram/Support/Notification/RecipientKey.php","src/addons/Gram/Support/Pub/Controller/AccountSupport.php","src/addons/Gram/Support/Pub/Controller/Pwa.php","src/addons/Gram/Support/Pub/Controller/StaffSupport.php","src/addons/Gram/Support/Pub/Controller/Support.php","src/addons/Gram/Support/Pub/View/PwaServiceWorker.php","src/addons/Gram/Support/Repository/Message.php","src/addons/Gram/Support/Repository/Ticket.php","src/addons/Gram/Support/Security/GuestTicketSession.php","src/addons/Gram/Support/Security/TicketAccess.php","src/addons/Gram/Support/Service/GuestScreenshotService.php","src/addons/Gram/Support/Service/GuestTicketCreateAttachmentFlow.php","src/addons/Gram/Support/Service/RateLimiter.php","src/addons/Gram/Support/Service/SourceContextResolver.php","src/addons/Gram/Support/Service/Ticket/Creator.php","src/addons/Gram/Support/Service/Ticket/Reply.php","src/addons/Gram/Support/Service/Ticket/StaffUpdate.php","src/addons/Gram/Support/Setup.php","src/addons/Gram/Support/Util/GuestToken.php","src/addons/Gram/Support/Util/PublicRef.php","src/addons/Gram/Support/Util/RateKey.php","src/addons/Gram/Support/Util/SafeContext.php","src/addons/Gram/Support/Util/SiteConfig.php","src/addons/Gram/Support/Util/StatusPolicy.php","src/addons/Gram/Support/_data/code_event_listeners.xml","src/addons/Gram/Support/_data/content_type_fields.xml","src/addons/Gram/Support/_data/option_groups.xml","src/addons/Gram/Support/_data/options.xml","src/addons/Gram/Support/_data/permission_interface_groups.xml","src/addons/Gram/Support/_data/permissions.xml","src/addons/Gram/Support/_data/phrases.xml","src/addons/Gram/Support/_data/routes.xml","src/addons/Gram/Support/_data/template_modifications.xml","src/addons/Gram/Support/_data/templates.xml","src/addons/Gram/Support/addon.json","src/addons/Gram/Support/hashes.json"]},"services":{"mariadb":"active","nginx":"active","php8.3-fpm":"active"},"permission_counts":{"2":4,"3":9,"4":9},"http":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"200"},"/support/create/":{"rc":0,"code":"200"}}},"rollback":{"ok":false,"state_sig":"50eff6fb3c6a602194eb2dec2ff41e47c09988cc6ea08541851dac4a933db295","manifest_sha":"c49c44a866b3e91224cade4c43d9a4594537fc1530ba54333cb959f3afe12a32"},"backup":"/root/codevipe-gram-support-backups/SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4"},"pre_http":{"codevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"dsmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"gamevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"hkmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"kingofwolk.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"zakrutim.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"newfi.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}}},"post_http":{"codevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"dsmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"gamevipe.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"hkmods.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"kingofwolk.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"zakrutim.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}},"newfi.ru":{"/":{"rc":0,"code":"200"},"/support/":{"rc":0,"code":"404"}}},"artifact_sha256":"2e31f89d3626a83c1211910aa6fd279cc04689b75ba822899952865085cf551e","target":"codevipe.ru"}
+GRAM513R3R4_DECISION=FAIL_CODEVIPE_FIX10_RETRY_VERIFY
+HOMELAB_RESULT_CONTRACT={"version":1,"command_id":"SUPPORT-260918-GRAM-XF-CODEVIPE-FIX10-RETRY-FOOTER-CANARY-513R3R4","status":"FAIL","changes_made":true,"rollback_started":true,"rollback_restored":false}
OUTPUT_END
CHAT_OUTPUT_END