From 5168ad7d80def3e467e37ce7e091ff47903a20d8 Mon Sep 17 00:00:00 2001 From: homelab-runtime-publisher Date: Sat, 1 Aug 2026 10:57:09 +0000 Subject: [PATCH] runtime: publish GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z --- ...RDION-V29-ATOMIC-FIX-20260801T105500Z.json | 38 +++++++++++++++++++ ...ORDION-V29-ATOMIC-FIX-20260801T105500Z.txt | 34 +++++++++++++++++ runtime/latest.json | 26 ++++++------- runtime/latest.txt | 24 ++++++------ 4 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.json create mode 100644 runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.txt diff --git a/runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.json b/runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.json new file mode 100644 index 0000000..b722c1a --- /dev/null +++ b/runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "channel": "homelab-runtime", + "command_id": "GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z", + "status": "OK", + "rc": 0, + "host": "pve01", + "mode": "change", + "component": "gram1-charts-v29-ui-fix", + "started_at_utc": "2026-08-01T10:56:54Z", + "finished_at_utc": "2026-08-01T10:57:08Z", + "reference_register_checked": true, + "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", + "error_register_checked": true, + "error_register_sha256": "24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83", + "command_sha256": "bf15c2f625e2df3ea246d9564920c832ff74e708c06dec7470eecd7f888bd187", + "duplicate_failed_command_blocked": false, + "block_reason": null, + "execution_started": true, + "change_declared": true, + "result_contract_valid": true, + "result_contract_status": "OK", + "result_contract_error": null, + "command_rc": 0, + "changes_made": true, + "rollback_started": false, + "rollback_restored": null, + "mutation_outcome": "MUTATED", + "sanitized": true, + "secrets_included": false, + "private_addresses_included": false, + "raw_evidence_retained_locally": true, + "raw_evidence_sha256": "b42cd112ab0748a9b3376f5cf25a9198ff0bb9c9cdb363a10a85734ea545fb36", + "sanitized_output_sha256": "76a5bf7b4e8d90b3c60595c2e537343c79ba09652531d5652b7df7cf41359141", + "output_truncated_in_json": false, + "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", + "output": "HOMELAB_RESULT_CONTRACT={\"changes_made\":true,\"command_id\":\"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"mutation_outcome\":\"MUTATED\",\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\n{\"changes_made\":true,\"command_id\":\"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"control_plane_error\":null,\"gitea_changed\":false,\"mutation_outcome\":\"MUTATED\",\"pinned_host_key_aliases\":[\"[PRIVATE_IP]\"],\"production_site_changed\":true,\"rc\":0,\"remote_result\":{\"backup_path\":\"/var/lib/homelab-change-rollback/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"baseline_capsule_sha256\":\"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b\",\"baseline_command_id\":\"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z\",\"baseline_metadata_sha256\":\"fee67cb4877e96dca3113a17d1ec2facc8ecacaa97def7d83db86c1a545f1f53\",\"changed_paths\":[\"templates/index.html\"],\"changes_made\":true,\"command_id\":\"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"control_plane_error\":null,\"deployment\":{\"chart_cache\":{\"all_present\":true,\"symbols\":{\"AVAX\":72,\"HBAR\":84,\"LINK\":92,\"POL\":24}},\"container_hashes\":[{\"path\":\"templates/index.html\",\"service\":\"web\",\"sha256\":\"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4\"},{\"path\":\"app.py\",\"service\":\"web\",\"sha256\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\"},{\"path\":\"worker.py\",\"service\":\"worker\",\"sha256\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"}],\"running\":[\"web\",\"worker\"]},\"diagnostic_capsule_sha256\":\"f164b187dcae620c21210581687553e6216e9c1643ec8a29a7f63f086bde483c\",\"diagnostic_command_id\":\"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z\",\"duration_seconds\":13.202,\"gitea_changed\":false,\"idempotent\":false,\"installed_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"mutation_outcome\":\"MUTATED\",\"old_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"production_site_changed\":true,\"rc\":0,\"rollback_restored\":null,\"rollback_started\":false,\"schema\":1,\"semantic_checks\":{\"all_symbols\":true,\"api_v4\":true,\"api_v5\":true,\"legacy_hidden\":true,\"normalization\":true,\"same_origin\":true,\"script_v3\":true,\"shell_before_library\":true,\"style_v3\":true,\"visible_errors\":true},\"status\":\"OK\",\"target_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"ui_facts\":{\"candle_normalization\":true,\"chart_layout\":\"EXCLUSIVE_ACCORDION\",\"first_open\":\"HBAR\",\"legacy_no_data_hidden\":true,\"library_api\":\"V4_AND_V5\",\"shell_mount\":\"BEFORE_LIBRARY_WAIT\"}},\"rollback_restored\":null,\"rollback_started\":false,\"schema\":1,\"selected_method\":\"ALIAS_PINNED_AS_DEBIAN\",\"ssh_method_probes\":[{\"duration_seconds\":0.12,\"identity_count\":null,\"identity_sudo_read_ok\":true,\"name\":\"ALIAS_PINNED_AS_DEBIAN\",\"rc\":0,\"stderr\":\"\"},{\"duration_seconds\":0.123,\"identity_count\":2,\"identity_sudo_read_ok\":true,\"name\":\"DIRECT_PINNED_AS_DEBIAN_NO_PROXY\",\"rc\":0,\"stderr\":\"\"}],\"status\":\"OK\"}\n" +} diff --git a/runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.txt b/runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.txt new file mode 100644 index 0000000..22d8733 --- /dev/null +++ b/runtime/history/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z.txt @@ -0,0 +1,34 @@ +CHAT_OUTPUT_BEGIN +COMMAND_ID=GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z +STATUS=OK +RC=0 +HOST=pve01 +MODE=change +COMPONENT=gram1-charts-v29-ui-fix +REFERENCE_REGISTER_CHECK=OK +REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e +ERROR_REGISTER_CHECK=OK +ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83 +COMMAND_SHA256=bf15c2f625e2df3ea246d9564920c832ff74e708c06dec7470eecd7f888bd187 +DUPLICATE_FAILED_COMMAND_BLOCKED=false +EXECUTION_STARTED=true +CHANGE_DECLARED=true +RESULT_CONTRACT_VALID=true +RESULT_CONTRACT_STATUS=OK +RESULT_CONTRACT_ERROR=NONE +COMMAND_RC=0 +CHANGES_MADE=true +ROLLBACK_STARTED=false +ROLLBACK_RESTORED=null +MUTATION_OUTCOME=MUTATED +SANITIZED=yes +SECRETS_INCLUDED=no +PRIVATE_ADDRESSES_INCLUDED=no +RAW_EVIDENCE_SHA256=b42cd112ab0748a9b3376f5cf25a9198ff0bb9c9cdb363a10a85734ea545fb36 +SANITIZED_OUTPUT_SHA256=76a5bf7b4e8d90b3c60595c2e537343c79ba09652531d5652b7df7cf41359141 +OUTPUT_BEGIN +HOMELAB_RESULT_CONTRACT={"changes_made":true,"command_id":"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","mutation_outcome":"MUTATED","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} +{"changes_made":true,"command_id":"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"MUTATED","pinned_host_key_aliases":["[PRIVATE_IP]"],"production_site_changed":true,"rc":0,"remote_result":{"backup_path":"/var/lib/homelab-change-rollback/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","baseline_capsule_sha256":"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b","baseline_command_id":"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z","baseline_metadata_sha256":"fee67cb4877e96dca3113a17d1ec2facc8ecacaa97def7d83db86c1a545f1f53","changed_paths":["templates/index.html"],"changes_made":true,"command_id":"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","control_plane_error":null,"deployment":{"chart_cache":{"all_present":true,"symbols":{"AVAX":72,"HBAR":84,"LINK":92,"POL":24}},"container_hashes":[{"path":"templates/index.html","service":"web","sha256":"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4"},{"path":"app.py","service":"web","sha256":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20"},{"path":"worker.py","service":"worker","sha256":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"}],"running":["web","worker"]},"diagnostic_capsule_sha256":"f164b187dcae620c21210581687553e6216e9c1643ec8a29a7f63f086bde483c","diagnostic_command_id":"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z","duration_seconds":13.202,"gitea_changed":false,"idempotent":false,"installed_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"mutation_outcome":"MUTATED","old_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"production_site_changed":true,"rc":0,"rollback_restored":null,"rollback_started":false,"schema":1,"semantic_checks":{"all_symbols":true,"api_v4":true,"api_v5":true,"legacy_hidden":true,"normalization":true,"same_origin":true,"script_v3":true,"shell_before_library":true,"style_v3":true,"visible_errors":true},"status":"OK","target_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"ui_facts":{"candle_normalization":true,"chart_layout":"EXCLUSIVE_ACCORDION","first_open":"HBAR","legacy_no_data_hidden":true,"library_api":"V4_AND_V5","shell_mount":"BEFORE_LIBRARY_WAIT"}},"rollback_restored":null,"rollback_started":false,"schema":1,"selected_method":"ALIAS_PINNED_AS_DEBIAN","ssh_method_probes":[{"duration_seconds":0.12,"identity_count":null,"identity_sudo_read_ok":true,"name":"ALIAS_PINNED_AS_DEBIAN","rc":0,"stderr":""},{"duration_seconds":0.123,"identity_count":2,"identity_sudo_read_ok":true,"name":"DIRECT_PINNED_AS_DEBIAN_NO_PROXY","rc":0,"stderr":""}],"status":"OK"} + +OUTPUT_END +CHAT_OUTPUT_END diff --git a/runtime/latest.json b/runtime/latest.json index 9c328ae..b722c1a 100644 --- a/runtime/latest.json +++ b/runtime/latest.json @@ -1,38 +1,38 @@ { "schema_version": 1, "channel": "homelab-runtime", - "command_id": "GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z", + "command_id": "GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z", "status": "OK", "rc": 0, "host": "pve01", - "mode": "verify", - "component": "gram1-charts-v28-redirect-diag", - "started_at_utc": "2026-08-01T10:40:35Z", - "finished_at_utc": "2026-08-01T10:40:36Z", + "mode": "change", + "component": "gram1-charts-v29-ui-fix", + "started_at_utc": "2026-08-01T10:56:54Z", + "finished_at_utc": "2026-08-01T10:57:08Z", "reference_register_checked": true, "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e", "error_register_checked": true, "error_register_sha256": "24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83", - "command_sha256": "98af2a3d5e9c35d738d720d709b5d1bc33f6497016ebe05567f476baa93d9c2b", + "command_sha256": "bf15c2f625e2df3ea246d9564920c832ff74e708c06dec7470eecd7f888bd187", "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": "OK", "result_contract_error": null, "command_rc": 0, - "changes_made": false, + "changes_made": true, "rollback_started": false, "rollback_restored": null, - "mutation_outcome": "NO_MUTATION", + "mutation_outcome": "MUTATED", "sanitized": true, "secrets_included": false, "private_addresses_included": false, "raw_evidence_retained_locally": true, - "raw_evidence_sha256": "b6a56141a8cd4f0df4c91b72560fa95477d9cd1a4f37e624b33d8fbdebbab62a", - "sanitized_output_sha256": "d42000ea7905c64d8e19e55149a81d3750ab5f9aa692923a7805001cf247c48b", + "raw_evidence_sha256": "b42cd112ab0748a9b3376f5cf25a9198ff0bb9c9cdb363a10a85734ea545fb36", + "sanitized_output_sha256": "76a5bf7b4e8d90b3c60595c2e537343c79ba09652531d5652b7df7cf41359141", "output_truncated_in_json": false, "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt", - "output": "HOMELAB_RESULT_CONTRACT={\"changes_made\":false,\"command_id\":\"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z\",\"mutation_outcome\":\"NO_MUTATION\",\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\n{\"changes_made\":false,\"command_id\":\"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z\",\"control_plane_error\":null,\"gitea_changed\":false,\"mutation_outcome\":\"NO_MUTATION\",\"pinned_host_key_aliases\":[\"[PRIVATE_IP]\"],\"previous_capsule_sha256\":\"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b\",\"previous_command_id\":\"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z\",\"production_site_changed\":false,\"rc\":0,\"remote_result\":{\"changes_made\":false,\"chart_libraries\":[{\"api_symbols\":{\"CandlestickSeries\":1,\"ColorType\":1,\"addCandlestickSeries\":0,\"addSeries\":6,\"createChart\":2},\"bytes\":196203,\"http_status\":200,\"sha256\":\"c0992580867c4912cc9385b3c2728315bcc1a76c7f1087dca908430fccdf31d7\",\"url\":\"/vendor/lightweight-charts.js\",\"versions\":[\"5.2.0\"]}],\"command_id\":\"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z\",\"compose_services\":[\"web\",\"worker\"],\"control_plane_error\":null,\"diagnosis\":[\"LOCAL_HOME_REDIRECT_STATUS_303\",\"CANDLE_SCHEMA_INVALID:HBAR,POL,AVAX,LINK\",\"PUBLIC_ENDPOINT_SERVES_DIFFERENT_OR_CACHED_HTML:gram1.ru\",\"LEGACY_NO_DATA_FALLBACK_REMAINS_IN_HTML\"],\"duration_seconds\":0.678,\"exact_state\":{\"backup_metadata_sha256\":\"fee67cb4877e96dca3113a17d1ec2facc8ecacaa97def7d83db86c1a545f1f53\",\"compose_sha256\":\"6d344e46b3de94ad86131a914df2ff3ff25e9d82f7ce0557cbffa468b8cdc1b8\",\"current_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"exact_v26_target_installed\":true,\"v26_target_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"}},\"gitea_changed\":false,\"headless_browser\":{\"available\":false,\"ports\":[8000,5000,8080,3000,80,36645]},\"local_runtime\":{\"api\":[{\"count\":0,\"http_bytes\":27,\"http_sha256\":\"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9\",\"http_status\":401,\"issues\":[],\"lightweight_charts_schema_ok\":false,\"sample\":[],\"status\":null,\"symbol\":\"HBAR\"},{\"count\":0,\"http_bytes\":27,\"http_sha256\":\"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9\",\"http_status\":401,\"issues\":[],\"lightweight_charts_schema_ok\":false,\"sample\":[],\"status\":null,\"symbol\":\"POL\"},{\"count\":0,\"http_bytes\":27,\"http_sha256\":\"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9\",\"http_status\":401,\"issues\":[],\"lightweight_charts_schema_ok\":false,\"sample\":[],\"status\":null,\"symbol\":\"AVAX\"},{\"count\":0,\"http_bytes\":27,\"http_sha256\":\"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9\",\"http_status\":401,\"issues\":[],\"lightweight_charts_schema_ok\":false,\"sample\":[],\"status\":null,\"symbol\":\"LINK\"}],\"homepage\":{\"bytes\":32738,\"id_contexts\":{\"chart\":[{\"context\":\"y=\\\"RUB\\\">RUB
Стоимость портфеля
Вложено
Прибыль / убыток0%
Обновление рынкакаждые 5 минут

График цены

7 дней
Загрузка

Резкие движения

Позиции портфеля

Количество и средняя цена покупки
АктивЦенаКапитализацияКоличествоСредняя покупка (USD)ВложеноСейчасP/L

Новое оповещение

<\",\"match\":\"

\",\"offset\":4985}],\"tvCharts\":[]},\"label\":\"installed_template_due_local_redirect\",\"markers\":{\"accordion_style\":1,\"chart_error_text\":1,\"details_creator\":1,\"loading_text\":2,\"no_data_text\":3,\"tvCharts\":3,\"v1_script\":0,\"v26_script\":1},\"no_data_contexts\":[{\"context\":\"tep=\\\\\\\"any\\\\\\\" value=\\\\\\\"\\\"+inputPrice(h.avg_buy)+\\\"\\\\\\\">\\\"+money(cost,0)+\\\"\\\"+money(value,2)+\\\"=0?\\\"good\\\":\\\"bad\\\")+\\\"\\\\\\\">\\\"+money(p,2)+\\\"\\\"}).join(\\\"\\\");document.querySelectorAll(\\\"#rows tr\\\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\\\"asset-cell\\\");let img=document.createElement(\\\"img\\\");img.className=\\\"coin-icon table-coin-icon\\\";img.src=\\\"/coin-icon/\\\"+id;img.alt=state.coins[id];img.loading=\\\"lazy\\\";td.prepend(img);let symbol=td.querySelector(\\\"b\\\");if(symbol)symbol.classList.add(\\\"asset-symbol\\\")});totalEl=total;document.getElementById(\\\"total\\\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\\\"good\\\":\\\"bad\\\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\\\"%\\\";day.textContent=(daily>=0?\\\"+\\\":\\\"\\\")+money(daily,2)+\\\" за 24ч\\\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\\\"ru-RU\\\"):\\\"нет данных\\\";marketStatus.textContent=Object.keys(m).length===2?\\\"Рынок обновлён\\\":\\\"Нет данных\\\";marketStatus.className=\\\"status \\\"+(Object.keys(m).length===2?\\\"good\\\":\\\"bad\\\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\\\"\\\").join(\\\"\\\")}function bindInputs(){document.querySelectorAll(\\\".qty,.avg\\\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\\\".qty[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let a=document.querySelector(\\\".avg[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let avg=currency===\\\"RUB\\\"?Number(a)/fx():Number(a);await fetch(\\\"/api/holding\\\",{method:\\\"POST\\\",headers:{\\\"Content-Type\\\":\\\"application/json\\\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\\\" · \\\"+state.coins[selected]+\\\"/\\\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\\\"\\\"+money(value,2)+\\\"=0?\\\"good\\\":\\\"bad\\\")+\\\"\\\\\\\">\\\"+money(p,2)+\\\"\\\"}).join(\\\"\\\");document.querySelectorAll(\\\"#rows tr\\\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\\\"asset-cell\\\");let img=document.createElement(\\\"img\\\");img.className=\\\"coin-icon table-coin-icon\\\";img.src=\\\"/coin-icon/\\\"+id;img.alt=state.coins[id];img.loading=\\\"lazy\\\";td.prepend(img);let symbol=td.querySelector(\\\"b\\\");if(symbol)symbol.classList.add(\\\"asset-symbol\\\")});totalEl=total;document.getElementById(\\\"total\\\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\\\"good\\\":\\\"bad\\\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\\\"%\\\";day.textContent=(daily>=0?\\\"+\\\":\\\"\\\")+money(daily,2)+\\\" за 24ч\\\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\\\"ru-RU\\\"):\\\"нет данных\\\";marketStatus.textContent=Object.keys(m).length===2?\\\"Рынок обновлён\\\":\\\"Нет данных\\\";marketStatus.className=\\\"status \\\"+(Object.keys(m).length===2?\\\"good\\\":\\\"bad\\\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\\\"\\\").join(\\\"\\\")}function bindInputs(){document.querySelectorAll(\\\".qty,.avg\\\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\\\".qty[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let a=document.querySelector(\\\".avg[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let avg=currency===\\\"RUB\\\"?Number(a)/fx():Number(a);await fetch(\\\"/api/holding\\\",{method:\\\"POST\\\",headers:{\\\"Content-Type\\\":\\\"application/json\\\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\\\" · \\\"+state.coins[selected]+\\\"/\\\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\\\"История ещё загружается\\\";return}let min=Math.min(...a),max=Math\",\"match\":\"Нет данных\",\"offset\":10538},{\"context\":\"ls=[\\\"HBAR\\\",\\\"POL\\\",\\\"AVAX\\\",\\\"LINK\\\"]; const charts=new Map(); const candleCache=new Map(); const afterLayout=()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve))); const loadCandles=async symbol=>{ if(candleCache.has(symbol))return candleCache.get(symbol); const task=(async()=>{ const response=await fetch(\\\"/api/klines/\\\"+encodeURIComponent(symbol)+\\\"?limit=1000&interval=1M\\\",{cache:\\\"no-store\\\",credentials:\\\"same-origin\\\"}); if(response.status===401){location=\\\"/login\\\";throw new Error(\\\"Требуется повторный вход\\\")} if(!response.ok)throw new Error(\\\"HTTP \\\"+response.status); const data=await response.json(); const candles=Array.isArray(data.candles)?data.candles:(data.result&&Array.isArray(data.result.candles)?data.result.candles:[]); if(data.status&&data.status!==\\\"OK\\\")throw new Error(String(data.error||data.message||data.status)); if(!candles.length)throw new Error(\\\"Нет данных для \\\"+symbol); return candles; })(); candleCache.set(symbol,task); try{return await task}catch(error){candleCache.delete(symbol);throw error} }; const widthOf=box=>Math.max(320,Math.floor(box.getBoundingClientRect().width||box.clientWidth||900)); const ensureChart=card=>{ if(card.dataset.chartState===\\\"ready\\\")return Promise.resolve(charts.get(card.dataset.symbol)); if(card.dataset.chartState===\\\"loading\\\"&&card._chartPromise)return card._chartPromise; const symbol=card.dataset.symbol; const box=card.querySelector(\\\".tv-widget-slot\\\"); const errorBox=card.querySelector(\\\".tv-chart-error\\\"); card.dataset.chartState=\\\"loading\\\"; errorBox.textContent=\\\"Загрузка...\\\"; card._chartPromise=(async()=>{ try{ const candles=await loadCandles(symbol); await afterLayout(); if(!card.open){card.dataset.chartState=\\\"idle\\\";return null} const api=LightweightCharts.createCha\",\"match\":\"Нет данных\",\"offset\":25676}],\"scripts\":[{\"async\":false,\"body_bytes\":7045,\"body_sha256\":\"e6afa17d7b94d9da5036d55bf6b8c623ec036ca05e9dea9c789432631c1b6ca7\",\"contains_v26\":false,\"defer\":false,\"id\":null,\"order\":0,\"src\":null},{\"async\":false,\"body_bytes\":4775,\"body_sha256\":\"f30846a0a26517bd6e8303d552aeba19887576c54b4a70678e234a5e1f6e7582\",\"contains_v26\":false,\"defer\":false,\"id\":\"ALERT_CREATE_OVERRIDE_V3\",\"order\":1,\"src\":null},{\"async\":false,\"body_bytes\":4605,\"body_sha256\":\"b6fedba59295891e784ab98cef7690efe81553715d35a9cf6a31c30d08efb5a9\",\"contains_v26\":false,\"defer\":false,\"id\":\"ALERT_LIST_RENDERER_V5\",\"order\":2,\"src\":null},{\"async\":false,\"body_bytes\":0,\"body_sha256\":null,\"contains_v26\":false,\"defer\":false,\"id\":null,\"order\":3,\"src\":\"/vendor/lightweight-charts.js\"},{\"async\":false,\"body_bytes\":6016,\"body_sha256\":\"084f5447f052e941f4eef6784b1431399a6dd17b28dba277fe310fca903224d9\",\"contains_v26\":true,\"defer\":false,\"id\":\"LOCAL_TRADINGVIEW_CHARTS_V2_LAZY_ACCORDION\",\"order\":4,\"src\":null},{\"async\":false,\"body_bytes\":642,\"body_sha256\":\"90a765a83fb8a5a0542dee1abf8c32af0f248aa411aa203848f73758bc3f9b40\",\"contains_v26\":false,\"defer\":false,\"id\":\"MOVE_CHARTS_TO_BOTTOM_ALLTIME_V1\",\"order\":5,\"src\":null}],\"sha256\":\"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536\"},\"homepage_headers\":{\"cache-control\":null,\"content-type\":null,\"etag\":null,\"last-modified\":null,\"location\":\"/login\"},\"homepage_redirect\":{\"location\":\"/login\",\"status\":303},\"homepage_source\":\"installed_template_due_local_redirect\",\"homepage_status\":303},\"mutation_outcome\":\"NO_MUTATION\",\"previous_capsule_sha256\":\"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b\",\"previous_command_id\":\"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z\",\"production_site_changed\":false,\"public_hosts\":[\"gram1.ru\"],\"public_runtime\":[{\"bytes\":1088,\"final_url\":\"https://gram1.ru/login\",\"headers\":{\"age\":null,\"cache-control\":null,\"cf-cache-status\":null,\"content-type\":\"text/html; charset=utf-8\",\"etag\":null,\"last-modified\":null,\"server\":null},\"host\":\"gram1.ru\",\"markers\":{\"accordion_style\":0,\"no_data\":0,\"tvCharts\":0,\"v26_script\":0},\"sha256\":\"66b06909949879d84757d0f96be74eebf1db40f35de22b625ea67e85e1bbdae2\",\"status\":200}],\"rc\":0,\"rollback_restored\":null,\"rollback_started\":false,\"schema\":1,\"status\":\"OK\",\"template\":{\"bytes\":32738,\"id_contexts\":{\"chart\":[{\"context\":\"y=\\\"RUB\\\">RUB

Стоимость портфеля
Вложено
Прибыль / убыток0%
Обновление рынкакаждые 5 минут

График цены

7 дней
Загрузка

Резкие движения

Позиции портфеля

Количество и средняя цена покупки
АктивЦенаКапитализацияКоличествоСредняя покупка (USD)ВложеноСейчасP/L

Новое оповещение

<\",\"match\":\"

\",\"offset\":4985}],\"tvCharts\":[]},\"label\":\"production_template\",\"markers\":{\"accordion_style\":1,\"chart_error_text\":1,\"details_creator\":1,\"loading_text\":2,\"no_data_text\":3,\"tvCharts\":3,\"v1_script\":0,\"v26_script\":1},\"no_data_contexts\":[{\"context\":\"tep=\\\\\\\"any\\\\\\\" value=\\\\\\\"\\\"+inputPrice(h.avg_buy)+\\\"\\\\\\\">\\\"+money(cost,0)+\\\"\\\"+money(value,2)+\\\"=0?\\\"good\\\":\\\"bad\\\")+\\\"\\\\\\\">\\\"+money(p,2)+\\\"\\\"}).join(\\\"\\\");document.querySelectorAll(\\\"#rows tr\\\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\\\"asset-cell\\\");let img=document.createElement(\\\"img\\\");img.className=\\\"coin-icon table-coin-icon\\\";img.src=\\\"/coin-icon/\\\"+id;img.alt=state.coins[id];img.loading=\\\"lazy\\\";td.prepend(img);let symbol=td.querySelector(\\\"b\\\");if(symbol)symbol.classList.add(\\\"asset-symbol\\\")});totalEl=total;document.getElementById(\\\"total\\\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\\\"good\\\":\\\"bad\\\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\\\"%\\\";day.textContent=(daily>=0?\\\"+\\\":\\\"\\\")+money(daily,2)+\\\" за 24ч\\\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\\\"ru-RU\\\"):\\\"нет данных\\\";marketStatus.textContent=Object.keys(m).length===2?\\\"Рынок обновлён\\\":\\\"Нет данных\\\";marketStatus.className=\\\"status \\\"+(Object.keys(m).length===2?\\\"good\\\":\\\"bad\\\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\\\"\\\").join(\\\"\\\")}function bindInputs(){document.querySelectorAll(\\\".qty,.avg\\\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\\\".qty[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let a=document.querySelector(\\\".avg[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let avg=currency===\\\"RUB\\\"?Number(a)/fx():Number(a);await fetch(\\\"/api/holding\\\",{method:\\\"POST\\\",headers:{\\\"Content-Type\\\":\\\"application/json\\\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\\\" · \\\"+state.coins[selected]+\\\"/\\\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\\\"\\\"+money(value,2)+\\\"=0?\\\"good\\\":\\\"bad\\\")+\\\"\\\\\\\">\\\"+money(p,2)+\\\"\\\"}).join(\\\"\\\");document.querySelectorAll(\\\"#rows tr\\\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\\\"asset-cell\\\");let img=document.createElement(\\\"img\\\");img.className=\\\"coin-icon table-coin-icon\\\";img.src=\\\"/coin-icon/\\\"+id;img.alt=state.coins[id];img.loading=\\\"lazy\\\";td.prepend(img);let symbol=td.querySelector(\\\"b\\\");if(symbol)symbol.classList.add(\\\"asset-symbol\\\")});totalEl=total;document.getElementById(\\\"total\\\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\\\"good\\\":\\\"bad\\\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\\\"%\\\";day.textContent=(daily>=0?\\\"+\\\":\\\"\\\")+money(daily,2)+\\\" за 24ч\\\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\\\"ru-RU\\\"):\\\"нет данных\\\";marketStatus.textContent=Object.keys(m).length===2?\\\"Рынок обновлён\\\":\\\"Нет данных\\\";marketStatus.className=\\\"status \\\"+(Object.keys(m).length===2?\\\"good\\\":\\\"bad\\\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\\\"\\\").join(\\\"\\\")}function bindInputs(){document.querySelectorAll(\\\".qty,.avg\\\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\\\".qty[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let a=document.querySelector(\\\".avg[data-id=\\\\\\\"\\\"+id+\\\"\\\\\\\"]\\\").value;let avg=currency===\\\"RUB\\\"?Number(a)/fx():Number(a);await fetch(\\\"/api/holding\\\",{method:\\\"POST\\\",headers:{\\\"Content-Type\\\":\\\"application/json\\\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\\\" · \\\"+state.coins[selected]+\\\"/\\\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\\\"История ещё загружается\\\";return}let min=Math.min(...a),max=Math\",\"match\":\"Нет данных\",\"offset\":10538},{\"context\":\"ls=[\\\"HBAR\\\",\\\"POL\\\",\\\"AVAX\\\",\\\"LINK\\\"]; const charts=new Map(); const candleCache=new Map(); const afterLayout=()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve))); const loadCandles=async symbol=>{ if(candleCache.has(symbol))return candleCache.get(symbol); const task=(async()=>{ const response=await fetch(\\\"/api/klines/\\\"+encodeURIComponent(symbol)+\\\"?limit=1000&interval=1M\\\",{cache:\\\"no-store\\\",credentials:\\\"same-origin\\\"}); if(response.status===401){location=\\\"/login\\\";throw new Error(\\\"Требуется повторный вход\\\")} if(!response.ok)throw new Error(\\\"HTTP \\\"+response.status); const data=await response.json(); const candles=Array.isArray(data.candles)?data.candles:(data.result&&Array.isArray(data.result.candles)?data.result.candles:[]); if(data.status&&data.status!==\\\"OK\\\")throw new Error(String(data.error||data.message||data.status)); if(!candles.length)throw new Error(\\\"Нет данных для \\\"+symbol); return candles; })(); candleCache.set(symbol,task); try{return await task}catch(error){candleCache.delete(symbol);throw error} }; const widthOf=box=>Math.max(320,Math.floor(box.getBoundingClientRect().width||box.clientWidth||900)); const ensureChart=card=>{ if(card.dataset.chartState===\\\"ready\\\")return Promise.resolve(charts.get(card.dataset.symbol)); if(card.dataset.chartState===\\\"loading\\\"&&card._chartPromise)return card._chartPromise; const symbol=card.dataset.symbol; const box=card.querySelector(\\\".tv-widget-slot\\\"); const errorBox=card.querySelector(\\\".tv-chart-error\\\"); card.dataset.chartState=\\\"loading\\\"; errorBox.textContent=\\\"Загрузка...\\\"; card._chartPromise=(async()=>{ try{ const candles=await loadCandles(symbol); await afterLayout(); if(!card.open){card.dataset.chartState=\\\"idle\\\";return null} const api=LightweightCharts.createCha\",\"match\":\"Нет данных\",\"offset\":25676}],\"scripts\":[{\"async\":false,\"body_bytes\":7045,\"body_sha256\":\"e6afa17d7b94d9da5036d55bf6b8c623ec036ca05e9dea9c789432631c1b6ca7\",\"contains_v26\":false,\"defer\":false,\"id\":null,\"order\":0,\"src\":null},{\"async\":false,\"body_bytes\":4775,\"body_sha256\":\"f30846a0a26517bd6e8303d552aeba19887576c54b4a70678e234a5e1f6e7582\",\"contains_v26\":false,\"defer\":false,\"id\":\"ALERT_CREATE_OVERRIDE_V3\",\"order\":1,\"src\":null},{\"async\":false,\"body_bytes\":4605,\"body_sha256\":\"b6fedba59295891e784ab98cef7690efe81553715d35a9cf6a31c30d08efb5a9\",\"contains_v26\":false,\"defer\":false,\"id\":\"ALERT_LIST_RENDERER_V5\",\"order\":2,\"src\":null},{\"async\":false,\"body_bytes\":0,\"body_sha256\":null,\"contains_v26\":false,\"defer\":false,\"id\":null,\"order\":3,\"src\":\"/vendor/lightweight-charts.js\"},{\"async\":false,\"body_bytes\":6016,\"body_sha256\":\"084f5447f052e941f4eef6784b1431399a6dd17b28dba277fe310fca903224d9\",\"contains_v26\":true,\"defer\":false,\"id\":\"LOCAL_TRADINGVIEW_CHARTS_V2_LAZY_ACCORDION\",\"order\":4,\"src\":null},{\"async\":false,\"body_bytes\":642,\"body_sha256\":\"90a765a83fb8a5a0542dee1abf8c32af0f248aa411aa203848f73758bc3f9b40\",\"contains_v26\":false,\"defer\":false,\"id\":\"MOVE_CHARTS_TO_BOTTOM_ALLTIME_V1\",\"order\":5,\"src\":null}],\"sha256\":\"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536\"}},\"rollback_restored\":null,\"rollback_started\":false,\"schema\":1,\"selected_method\":\"ALIAS_PINNED_AS_DEBIAN\",\"ssh_method_probes\":[{\"duration_seconds\":0.132,\"identity_count\":null,\"identity_sudo_read_ok\":true,\"name\":\"ALIAS_PINNED_AS_DEBIAN\",\"rc\":0,\"stderr\":\"\"},{\"duration_seconds\":0.136,\"identity_count\":2,\"identity_sudo_read_ok\":true,\"name\":\"DIRECT_PINNED_AS_DEBIAN_NO_PROXY\",\"rc\":0,\"stderr\":\"\"}],\"status\":\"OK\"}\n" + "output": "HOMELAB_RESULT_CONTRACT={\"changes_made\":true,\"command_id\":\"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"mutation_outcome\":\"MUTATED\",\"rollback_restored\":null,\"rollback_started\":false,\"status\":\"OK\",\"version\":1}\n{\"changes_made\":true,\"command_id\":\"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"control_plane_error\":null,\"gitea_changed\":false,\"mutation_outcome\":\"MUTATED\",\"pinned_host_key_aliases\":[\"[PRIVATE_IP]\"],\"production_site_changed\":true,\"rc\":0,\"remote_result\":{\"backup_path\":\"/var/lib/homelab-change-rollback/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"baseline_capsule_sha256\":\"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b\",\"baseline_command_id\":\"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z\",\"baseline_metadata_sha256\":\"fee67cb4877e96dca3113a17d1ec2facc8ecacaa97def7d83db86c1a545f1f53\",\"changed_paths\":[\"templates/index.html\"],\"changes_made\":true,\"command_id\":\"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z\",\"control_plane_error\":null,\"deployment\":{\"chart_cache\":{\"all_present\":true,\"symbols\":{\"AVAX\":72,\"HBAR\":84,\"LINK\":92,\"POL\":24}},\"container_hashes\":[{\"path\":\"templates/index.html\",\"service\":\"web\",\"sha256\":\"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4\"},{\"path\":\"app.py\",\"service\":\"web\",\"sha256\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\"},{\"path\":\"worker.py\",\"service\":\"worker\",\"sha256\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"}],\"running\":[\"web\",\"worker\"]},\"diagnostic_capsule_sha256\":\"f164b187dcae620c21210581687553e6216e9c1643ec8a29a7f63f086bde483c\",\"diagnostic_command_id\":\"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z\",\"duration_seconds\":13.202,\"gitea_changed\":false,\"idempotent\":false,\"installed_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"mutation_outcome\":\"MUTATED\",\"old_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"production_site_changed\":true,\"rc\":0,\"rollback_restored\":null,\"rollback_started\":false,\"schema\":1,\"semantic_checks\":{\"all_symbols\":true,\"api_v4\":true,\"api_v5\":true,\"legacy_hidden\":true,\"normalization\":true,\"same_origin\":true,\"script_v3\":true,\"shell_before_library\":true,\"style_v3\":true,\"visible_errors\":true},\"status\":\"OK\",\"target_hashes\":{\"app.py\":\"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20\",\"templates/index.html\":\"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4\",\"worker.py\":\"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c\"},\"ui_facts\":{\"candle_normalization\":true,\"chart_layout\":\"EXCLUSIVE_ACCORDION\",\"first_open\":\"HBAR\",\"legacy_no_data_hidden\":true,\"library_api\":\"V4_AND_V5\",\"shell_mount\":\"BEFORE_LIBRARY_WAIT\"}},\"rollback_restored\":null,\"rollback_started\":false,\"schema\":1,\"selected_method\":\"ALIAS_PINNED_AS_DEBIAN\",\"ssh_method_probes\":[{\"duration_seconds\":0.12,\"identity_count\":null,\"identity_sudo_read_ok\":true,\"name\":\"ALIAS_PINNED_AS_DEBIAN\",\"rc\":0,\"stderr\":\"\"},{\"duration_seconds\":0.123,\"identity_count\":2,\"identity_sudo_read_ok\":true,\"name\":\"DIRECT_PINNED_AS_DEBIAN_NO_PROXY\",\"rc\":0,\"stderr\":\"\"}],\"status\":\"OK\"}\n" } diff --git a/runtime/latest.txt b/runtime/latest.txt index 313244f..22d8733 100644 --- a/runtime/latest.txt +++ b/runtime/latest.txt @@ -1,34 +1,34 @@ CHAT_OUTPUT_BEGIN -COMMAND_ID=GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z +COMMAND_ID=GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z STATUS=OK RC=0 HOST=pve01 -MODE=verify -COMPONENT=gram1-charts-v28-redirect-diag +MODE=change +COMPONENT=gram1-charts-v29-ui-fix REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83 -COMMAND_SHA256=98af2a3d5e9c35d738d720d709b5d1bc33f6497016ebe05567f476baa93d9c2b +COMMAND_SHA256=bf15c2f625e2df3ea246d9564920c832ff74e708c06dec7470eecd7f888bd187 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=OK RESULT_CONTRACT_ERROR=NONE COMMAND_RC=0 -CHANGES_MADE=false +CHANGES_MADE=true ROLLBACK_STARTED=false ROLLBACK_RESTORED=null -MUTATION_OUTCOME=NO_MUTATION +MUTATION_OUTCOME=MUTATED SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no -RAW_EVIDENCE_SHA256=b6a56141a8cd4f0df4c91b72560fa95477d9cd1a4f37e624b33d8fbdebbab62a -SANITIZED_OUTPUT_SHA256=d42000ea7905c64d8e19e55149a81d3750ab5f9aa692923a7805001cf247c48b +RAW_EVIDENCE_SHA256=b42cd112ab0748a9b3376f5cf25a9198ff0bb9c9cdb363a10a85734ea545fb36 +SANITIZED_OUTPUT_SHA256=76a5bf7b4e8d90b3c60595c2e537343c79ba09652531d5652b7df7cf41359141 OUTPUT_BEGIN -HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z","mutation_outcome":"NO_MUTATION","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} -{"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"NO_MUTATION","pinned_host_key_aliases":["[PRIVATE_IP]"],"previous_capsule_sha256":"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b","previous_command_id":"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z","production_site_changed":false,"rc":0,"remote_result":{"changes_made":false,"chart_libraries":[{"api_symbols":{"CandlestickSeries":1,"ColorType":1,"addCandlestickSeries":0,"addSeries":6,"createChart":2},"bytes":196203,"http_status":200,"sha256":"c0992580867c4912cc9385b3c2728315bcc1a76c7f1087dca908430fccdf31d7","url":"/vendor/lightweight-charts.js","versions":["5.2.0"]}],"command_id":"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z","compose_services":["web","worker"],"control_plane_error":null,"diagnosis":["LOCAL_HOME_REDIRECT_STATUS_303","CANDLE_SCHEMA_INVALID:HBAR,POL,AVAX,LINK","PUBLIC_ENDPOINT_SERVES_DIFFERENT_OR_CACHED_HTML:gram1.ru","LEGACY_NO_DATA_FALLBACK_REMAINS_IN_HTML"],"duration_seconds":0.678,"exact_state":{"backup_metadata_sha256":"fee67cb4877e96dca3113a17d1ec2facc8ecacaa97def7d83db86c1a545f1f53","compose_sha256":"6d344e46b3de94ad86131a914df2ff3ff25e9d82f7ce0557cbffa468b8cdc1b8","current_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"exact_v26_target_installed":true,"v26_target_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"}},"gitea_changed":false,"headless_browser":{"available":false,"ports":[8000,5000,8080,3000,80,36645]},"local_runtime":{"api":[{"count":0,"http_bytes":27,"http_sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","http_status":401,"issues":[],"lightweight_charts_schema_ok":false,"sample":[],"status":null,"symbol":"HBAR"},{"count":0,"http_bytes":27,"http_sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","http_status":401,"issues":[],"lightweight_charts_schema_ok":false,"sample":[],"status":null,"symbol":"POL"},{"count":0,"http_bytes":27,"http_sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","http_status":401,"issues":[],"lightweight_charts_schema_ok":false,"sample":[],"status":null,"symbol":"AVAX"},{"count":0,"http_bytes":27,"http_sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","http_status":401,"issues":[],"lightweight_charts_schema_ok":false,"sample":[],"status":null,"symbol":"LINK"}],"homepage":{"bytes":32738,"id_contexts":{"chart":[{"context":"y=\"RUB\">RUB

Стоимость портфеля
Вложено
Прибыль / убыток0%
Обновление рынкакаждые 5 минут

График цены

7 дней
Загрузка

Резкие движения

Позиции портфеля

Количество и средняя цена покупки
АктивЦенаКапитализацияКоличествоСредняя покупка (USD)ВложеноСейчасP/L

Новое оповещение

<","match":"

","offset":4985}],"tvCharts":[]},"label":"installed_template_due_local_redirect","markers":{"accordion_style":1,"chart_error_text":1,"details_creator":1,"loading_text":2,"no_data_text":3,"tvCharts":3,"v1_script":0,"v26_script":1},"no_data_contexts":[{"context":"tep=\\\"any\\\" value=\\\"\"+inputPrice(h.avg_buy)+\"\\\">\"+money(cost,0)+\"\"+money(value,2)+\"=0?\"good\":\"bad\")+\"\\\">\"+money(p,2)+\"\"}).join(\"\");document.querySelectorAll(\"#rows tr\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\"asset-cell\");let img=document.createElement(\"img\");img.className=\"coin-icon table-coin-icon\";img.src=\"/coin-icon/\"+id;img.alt=state.coins[id];img.loading=\"lazy\";td.prepend(img);let symbol=td.querySelector(\"b\");if(symbol)symbol.classList.add(\"asset-symbol\")});totalEl=total;document.getElementById(\"total\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\" · \"+state.coins[selected]+\"/\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\"\"+money(value,2)+\"=0?\"good\":\"bad\")+\"\\\">\"+money(p,2)+\"\"}).join(\"\");document.querySelectorAll(\"#rows tr\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\"asset-cell\");let img=document.createElement(\"img\");img.className=\"coin-icon table-coin-icon\";img.src=\"/coin-icon/\"+id;img.alt=state.coins[id];img.loading=\"lazy\";td.prepend(img);let symbol=td.querySelector(\"b\");if(symbol)symbol.classList.add(\"asset-symbol\")});totalEl=total;document.getElementById(\"total\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\" · \"+state.coins[selected]+\"/\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\"История ещё загружается\";return}let min=Math.min(...a),max=Math","match":"Нет данных","offset":10538},{"context":"ls=[\"HBAR\",\"POL\",\"AVAX\",\"LINK\"]; const charts=new Map(); const candleCache=new Map(); const afterLayout=()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve))); const loadCandles=async symbol=>{ if(candleCache.has(symbol))return candleCache.get(symbol); const task=(async()=>{ const response=await fetch(\"/api/klines/\"+encodeURIComponent(symbol)+\"?limit=1000&interval=1M\",{cache:\"no-store\",credentials:\"same-origin\"}); if(response.status===401){location=\"/login\";throw new Error(\"Требуется повторный вход\")} if(!response.ok)throw new Error(\"HTTP \"+response.status); const data=await response.json(); const candles=Array.isArray(data.candles)?data.candles:(data.result&&Array.isArray(data.result.candles)?data.result.candles:[]); if(data.status&&data.status!==\"OK\")throw new Error(String(data.error||data.message||data.status)); if(!candles.length)throw new Error(\"Нет данных для \"+symbol); return candles; })(); candleCache.set(symbol,task); try{return await task}catch(error){candleCache.delete(symbol);throw error} }; const widthOf=box=>Math.max(320,Math.floor(box.getBoundingClientRect().width||box.clientWidth||900)); const ensureChart=card=>{ if(card.dataset.chartState===\"ready\")return Promise.resolve(charts.get(card.dataset.symbol)); if(card.dataset.chartState===\"loading\"&&card._chartPromise)return card._chartPromise; const symbol=card.dataset.symbol; const box=card.querySelector(\".tv-widget-slot\"); const errorBox=card.querySelector(\".tv-chart-error\"); card.dataset.chartState=\"loading\"; errorBox.textContent=\"Загрузка...\"; card._chartPromise=(async()=>{ try{ const candles=await loadCandles(symbol); await afterLayout(); if(!card.open){card.dataset.chartState=\"idle\";return null} const api=LightweightCharts.createCha","match":"Нет данных","offset":25676}],"scripts":[{"async":false,"body_bytes":7045,"body_sha256":"e6afa17d7b94d9da5036d55bf6b8c623ec036ca05e9dea9c789432631c1b6ca7","contains_v26":false,"defer":false,"id":null,"order":0,"src":null},{"async":false,"body_bytes":4775,"body_sha256":"f30846a0a26517bd6e8303d552aeba19887576c54b4a70678e234a5e1f6e7582","contains_v26":false,"defer":false,"id":"ALERT_CREATE_OVERRIDE_V3","order":1,"src":null},{"async":false,"body_bytes":4605,"body_sha256":"b6fedba59295891e784ab98cef7690efe81553715d35a9cf6a31c30d08efb5a9","contains_v26":false,"defer":false,"id":"ALERT_LIST_RENDERER_V5","order":2,"src":null},{"async":false,"body_bytes":0,"body_sha256":null,"contains_v26":false,"defer":false,"id":null,"order":3,"src":"/vendor/lightweight-charts.js"},{"async":false,"body_bytes":6016,"body_sha256":"084f5447f052e941f4eef6784b1431399a6dd17b28dba277fe310fca903224d9","contains_v26":true,"defer":false,"id":"LOCAL_TRADINGVIEW_CHARTS_V2_LAZY_ACCORDION","order":4,"src":null},{"async":false,"body_bytes":642,"body_sha256":"90a765a83fb8a5a0542dee1abf8c32af0f248aa411aa203848f73758bc3f9b40","contains_v26":false,"defer":false,"id":"MOVE_CHARTS_TO_BOTTOM_ALLTIME_V1","order":5,"src":null}],"sha256":"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536"},"homepage_headers":{"cache-control":null,"content-type":null,"etag":null,"last-modified":null,"location":"/login"},"homepage_redirect":{"location":"/login","status":303},"homepage_source":"installed_template_due_local_redirect","homepage_status":303},"mutation_outcome":"NO_MUTATION","previous_capsule_sha256":"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b","previous_command_id":"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z","production_site_changed":false,"public_hosts":["gram1.ru"],"public_runtime":[{"bytes":1088,"final_url":"https://gram1.ru/login","headers":{"age":null,"cache-control":null,"cf-cache-status":null,"content-type":"text/html; charset=utf-8","etag":null,"last-modified":null,"server":null},"host":"gram1.ru","markers":{"accordion_style":0,"no_data":0,"tvCharts":0,"v26_script":0},"sha256":"66b06909949879d84757d0f96be74eebf1db40f35de22b625ea67e85e1bbdae2","status":200}],"rc":0,"rollback_restored":null,"rollback_started":false,"schema":1,"status":"OK","template":{"bytes":32738,"id_contexts":{"chart":[{"context":"y=\"RUB\">RUB

Стоимость портфеля
Вложено
Прибыль / убыток0%
Обновление рынкакаждые 5 минут

График цены

7 дней
Загрузка

Резкие движения

Позиции портфеля

Количество и средняя цена покупки
АктивЦенаКапитализацияКоличествоСредняя покупка (USD)ВложеноСейчасP/L

Новое оповещение

<","match":"

","offset":4985}],"tvCharts":[]},"label":"production_template","markers":{"accordion_style":1,"chart_error_text":1,"details_creator":1,"loading_text":2,"no_data_text":3,"tvCharts":3,"v1_script":0,"v26_script":1},"no_data_contexts":[{"context":"tep=\\\"any\\\" value=\\\"\"+inputPrice(h.avg_buy)+\"\\\">\"+money(cost,0)+\"\"+money(value,2)+\"=0?\"good\":\"bad\")+\"\\\">\"+money(p,2)+\"\"}).join(\"\");document.querySelectorAll(\"#rows tr\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\"asset-cell\");let img=document.createElement(\"img\");img.className=\"coin-icon table-coin-icon\";img.src=\"/coin-icon/\"+id;img.alt=state.coins[id];img.loading=\"lazy\";td.prepend(img);let symbol=td.querySelector(\"b\");if(symbol)symbol.classList.add(\"asset-symbol\")});totalEl=total;document.getElementById(\"total\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\" · \"+state.coins[selected]+\"/\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\"\"+money(value,2)+\"=0?\"good\":\"bad\")+\"\\\">\"+money(p,2)+\"\"}).join(\"\");document.querySelectorAll(\"#rows tr\").forEach((tr,i)=>{let id=ids[i];let td=tr.cells[0];td.classList.add(\"asset-cell\");let img=document.createElement(\"img\");img.className=\"coin-icon table-coin-icon\";img.src=\"/coin-icon/\"+id;img.alt=state.coins[id];img.loading=\"lazy\";td.prepend(img);let symbol=td.querySelector(\"b\");if(symbol)symbol.classList.add(\"asset-symbol\")});totalEl=total;document.getElementById(\"total\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:id,quantity:Number(q),avg_buy:avg})});load()})}function draw(){let c=coin();chartTitle.textContent=(c.name||selected)+\" · \"+state.coins[selected]+\"/\"+currency;let a=c.sparkline_7d||[];if(a.length<2){chart.innerHTML=\"История ещё загружается\";return}let min=Math.min(...a),max=Math","match":"Нет данных","offset":10538},{"context":"ls=[\"HBAR\",\"POL\",\"AVAX\",\"LINK\"]; const charts=new Map(); const candleCache=new Map(); const afterLayout=()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve))); const loadCandles=async symbol=>{ if(candleCache.has(symbol))return candleCache.get(symbol); const task=(async()=>{ const response=await fetch(\"/api/klines/\"+encodeURIComponent(symbol)+\"?limit=1000&interval=1M\",{cache:\"no-store\",credentials:\"same-origin\"}); if(response.status===401){location=\"/login\";throw new Error(\"Требуется повторный вход\")} if(!response.ok)throw new Error(\"HTTP \"+response.status); const data=await response.json(); const candles=Array.isArray(data.candles)?data.candles:(data.result&&Array.isArray(data.result.candles)?data.result.candles:[]); if(data.status&&data.status!==\"OK\")throw new Error(String(data.error||data.message||data.status)); if(!candles.length)throw new Error(\"Нет данных для \"+symbol); return candles; })(); candleCache.set(symbol,task); try{return await task}catch(error){candleCache.delete(symbol);throw error} }; const widthOf=box=>Math.max(320,Math.floor(box.getBoundingClientRect().width||box.clientWidth||900)); const ensureChart=card=>{ if(card.dataset.chartState===\"ready\")return Promise.resolve(charts.get(card.dataset.symbol)); if(card.dataset.chartState===\"loading\"&&card._chartPromise)return card._chartPromise; const symbol=card.dataset.symbol; const box=card.querySelector(\".tv-widget-slot\"); const errorBox=card.querySelector(\".tv-chart-error\"); card.dataset.chartState=\"loading\"; errorBox.textContent=\"Загрузка...\"; card._chartPromise=(async()=>{ try{ const candles=await loadCandles(symbol); await afterLayout(); if(!card.open){card.dataset.chartState=\"idle\";return null} const api=LightweightCharts.createCha","match":"Нет данных","offset":25676}],"scripts":[{"async":false,"body_bytes":7045,"body_sha256":"e6afa17d7b94d9da5036d55bf6b8c623ec036ca05e9dea9c789432631c1b6ca7","contains_v26":false,"defer":false,"id":null,"order":0,"src":null},{"async":false,"body_bytes":4775,"body_sha256":"f30846a0a26517bd6e8303d552aeba19887576c54b4a70678e234a5e1f6e7582","contains_v26":false,"defer":false,"id":"ALERT_CREATE_OVERRIDE_V3","order":1,"src":null},{"async":false,"body_bytes":4605,"body_sha256":"b6fedba59295891e784ab98cef7690efe81553715d35a9cf6a31c30d08efb5a9","contains_v26":false,"defer":false,"id":"ALERT_LIST_RENDERER_V5","order":2,"src":null},{"async":false,"body_bytes":0,"body_sha256":null,"contains_v26":false,"defer":false,"id":null,"order":3,"src":"/vendor/lightweight-charts.js"},{"async":false,"body_bytes":6016,"body_sha256":"084f5447f052e941f4eef6784b1431399a6dd17b28dba277fe310fca903224d9","contains_v26":true,"defer":false,"id":"LOCAL_TRADINGVIEW_CHARTS_V2_LAZY_ACCORDION","order":4,"src":null},{"async":false,"body_bytes":642,"body_sha256":"90a765a83fb8a5a0542dee1abf8c32af0f248aa411aa203848f73758bc3f9b40","contains_v26":false,"defer":false,"id":"MOVE_CHARTS_TO_BOTTOM_ALLTIME_V1","order":5,"src":null}],"sha256":"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536"}},"rollback_restored":null,"rollback_started":false,"schema":1,"selected_method":"ALIAS_PINNED_AS_DEBIAN","ssh_method_probes":[{"duration_seconds":0.132,"identity_count":null,"identity_sudo_read_ok":true,"name":"ALIAS_PINNED_AS_DEBIAN","rc":0,"stderr":""},{"duration_seconds":0.136,"identity_count":2,"identity_sudo_read_ok":true,"name":"DIRECT_PINNED_AS_DEBIAN_NO_PROXY","rc":0,"stderr":""}],"status":"OK"} +HOMELAB_RESULT_CONTRACT={"changes_made":true,"command_id":"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","mutation_outcome":"MUTATED","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} +{"changes_made":true,"command_id":"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"MUTATED","pinned_host_key_aliases":["[PRIVATE_IP]"],"production_site_changed":true,"rc":0,"remote_result":{"backup_path":"/var/lib/homelab-change-rollback/GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","baseline_capsule_sha256":"568b0311741b93ae8ece3a3346c287f195c3f727ce6d04d4e28bdf87a5a4a88b","baseline_command_id":"GRAM1-SITE-CHARTS-LAZY-ACCORDION-V26-ATOMIC-FIX-20260801T093500Z","baseline_metadata_sha256":"fee67cb4877e96dca3113a17d1ec2facc8ecacaa97def7d83db86c1a545f1f53","changed_paths":["templates/index.html"],"changes_made":true,"command_id":"GRAM1-SITE-CHARTS-STATIC-COMPAT-ACCORDION-V29-ATOMIC-FIX-20260801T105500Z","control_plane_error":null,"deployment":{"chart_cache":{"all_present":true,"symbols":{"AVAX":72,"HBAR":84,"LINK":92,"POL":24}},"container_hashes":[{"path":"templates/index.html","service":"web","sha256":"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4"},{"path":"app.py","service":"web","sha256":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20"},{"path":"worker.py","service":"worker","sha256":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"}],"running":["web","worker"]},"diagnostic_capsule_sha256":"f164b187dcae620c21210581687553e6216e9c1643ec8a29a7f63f086bde483c","diagnostic_command_id":"GRAM1-SITE-CHARTS-BROWSER-RUNTIME-V28-REDIRECT-AWARE-READ-ONLY-EXACT-DIAG-20260801T103600Z","duration_seconds":13.202,"gitea_changed":false,"idempotent":false,"installed_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"mutation_outcome":"MUTATED","old_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"db9a1605bd37fca7d6ff651921dd3bc0ccac991f2e8f221179c4dddc3b2c3536","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"production_site_changed":true,"rc":0,"rollback_restored":null,"rollback_started":false,"schema":1,"semantic_checks":{"all_symbols":true,"api_v4":true,"api_v5":true,"legacy_hidden":true,"normalization":true,"same_origin":true,"script_v3":true,"shell_before_library":true,"style_v3":true,"visible_errors":true},"status":"OK","target_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"e9e723c9b916383ce10dffe8f8bbdb4049b78d89c5b139e2de5ed82194a27be4","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"ui_facts":{"candle_normalization":true,"chart_layout":"EXCLUSIVE_ACCORDION","first_open":"HBAR","legacy_no_data_hidden":true,"library_api":"V4_AND_V5","shell_mount":"BEFORE_LIBRARY_WAIT"}},"rollback_restored":null,"rollback_started":false,"schema":1,"selected_method":"ALIAS_PINNED_AS_DEBIAN","ssh_method_probes":[{"duration_seconds":0.12,"identity_count":null,"identity_sudo_read_ok":true,"name":"ALIAS_PINNED_AS_DEBIAN","rc":0,"stderr":""},{"duration_seconds":0.123,"identity_count":2,"identity_sudo_read_ok":true,"name":"DIRECT_PINNED_AS_DEBIAN_NO_PROXY","rc":0,"stderr":""}],"status":"OK"} OUTPUT_END CHAT_OUTPUT_END