From d861de5ead41b4977083b4aee08fc668c35e5b34 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sat, 3 Oct 2026 11:38:08 +0300 Subject: [PATCH 1/5] spec: simplify runtime requirements Preserve identity isolation and financial integrity while accepting cross-tab reauthentication and on-demand candle history. Align portfolio freshness with persisted reads and keep income consistency at the backend owner. --- .../spec.md | 2 +- openspec/specs/portfolio-view/spec.md | 28 +++++++++++++++---- openspec/specs/user-authentication/spec.md | 14 ++++++++-- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/openspec/specs/brokerage-account-income-analytics/spec.md b/openspec/specs/brokerage-account-income-analytics/spec.md index 075c588..40117b0 100644 --- a/openspec/specs/brokerage-account-income-analytics/spec.md +++ b/openspec/specs/brokerage-account-income-analytics/spec.md @@ -156,7 +156,7 @@ ### Requirement: Income payments remain traceable to exact Ledger Entries -В разделе «Выплаты» страница MUST показывать единый список карточек точных исполненных Ledger Entries применённого периода в исходном серверном порядке entries. Каждая выплата MUST иметь собственную сразу видимую карточку с описанием, датой, доступной identity Instrument и signed Money в исходной валюте. Страница MUST NOT добавлять внешние группировочные карточки или заголовки по Instrument либо валюте, subtotals инструмента или количество выплат инструмента. Список MUST сохранять отрицательные корректировки и повторяющиеся operation IDs как отдельные записи и MUST NOT включать записи вне аналитического итога. Отказ от группировочного UI MUST NOT отменять проверки принадлежности entries к instrumentKey, валюты и receipt count ответа или приводить к пересчёту денежных итогов на клиенте. +В разделе «Выплаты» страница MUST показывать единый список карточек точных исполненных Ledger Entries применённого периода в исходном серверном порядке entries. Каждая выплата MUST иметь собственную сразу видимую карточку с описанием, датой, доступной identity Instrument и signed Money в исходной валюте. Страница MUST NOT добавлять внешние группировочные карточки или заголовки по Instrument либо валюте, subtotals инструмента или количество выплат инструмента. Список MUST сохранять отрицательные корректировки и повторяющиеся operation IDs как отдельные записи и MUST NOT включать записи вне аналитического итога. Backend MUST обеспечивать согласованность entries, instrumentKey, валюты и receipt count при формировании ответа из одного набора записей. Frontend SHALL доверять типизированному contract без второго runtime consistency validator и MUST NOT пересчитывать денежные итоги. #### Scenario: Каждая выплата показана отдельной карточкой diff --git a/openspec/specs/portfolio-view/spec.md b/openspec/specs/portfolio-view/spec.md index a234991..92646ae 100644 --- a/openspec/specs/portfolio-view/spec.md +++ b/openspec/specs/portfolio-view/spec.md @@ -94,20 +94,29 @@ Portfolio Snapshot является результатом наблюдения - **THEN** система передаёт её как строку `"-0.5"` ### Requirement: Свежесть и fallback полного Portfolio Snapshot -Система MUST кэшировать полный успешный Portfolio Snapshot отдельно для каждой пары User и Brokerage Account в памяти на 30 секунд. После истечения свежего кэша система MUST получить новый полный снимок; при временной upstream-недоступности она SHALL вернуть последний успешный полный снимок, если ему не более пяти минут, с `isStale: true`. Metadata инструмента MUST NOT влиять на успешность или свежесть Portfolio Snapshot, но MUST быть получено до формирования нового Snapshot, чтобы при доступном upstream-ответе вернуть отображаемое имя инструмента. +Система MUST хранить последний полный успешный Portfolio Snapshot в SQLite +с принадлежностью User, экземпляру подключения и Brokerage Account. Обычный +GET MUST читать сохранённые данные без ожидания T-Bank; missing/stale источники +обновляются в фоне по пользовательскому запросу. Portfolio source свеж 60 секунд. +Ошибка обновления MUST сохранять прежний полный Snapshot и его время без +пятиминутного лимита fallback. Metadata MUST NOT определять успешность или +свежесть финансового Snapshot; при её отсутствии используется доступный fallback. -Система MUST очищать все Portfolio Snapshot User после успешной замены или удаления его T-Bank connection. Успешные metadata инструмента и подтверждённое отсутствие инструмента MUST кэшироваться глобально по FIGI на 24 часа; ошибка metadata lookup MUST NOT кэшироваться. +Система MUST делать прежние личные datasets недоступными после успешной замены +или удаления подключения. Поздняя работа прежнего подключения MUST NOT +публиковаться в новом. Общие metadata и подтверждённое отсутствие инструмента +сохраняются по UID/FIGI на 24 часа; ошибка lookup не подтверждает отсутствие. #### Scenario: Свежий Snapshot -- **WHEN** User повторно запрашивает тот же Portfolio в течение 30 секунд после успешного получения +- **WHEN** User повторно запрашивает тот же Portfolio в течение 60 секунд после успешного получения - **THEN** система возвращает свежий Snapshot без нового обращения к T-Bank #### Scenario: Медленный lookup инструмента - **WHEN** metadata инструмента ещё отсутствует и его lookup не завершился -- **THEN** система ожидает lookup в пределах gRPC deadline и возвращает name при успешном ответе upstream +- **THEN** система не задерживает локальный ответ ради lookup и показывает доступную identity; сохранённая успешная metadata используется последующим чтением #### Scenario: Fallback после временной upstream-ошибки -- **WHEN** обновление устаревшего Snapshot неуспешно из-за временной недоступности T-Bank, а последний полный успешный Snapshot получен не более пяти минут назад +- **WHEN** обновление устаревшего Snapshot неуспешно из-за временной недоступности T-Bank, а в текущей границе подключения есть полный успешный Snapshot - **THEN** система отвечает `200` этим Snapshot с `isStale: true` и исходным `lastSuccessfulAt` #### Scenario: Недействительный token не маскируется fallback-данными @@ -118,7 +127,14 @@ Portfolio Snapshot является результатом наблюдения Клиент SHALL загружать Portfolio при открытии защищённого маршрута `/accounts/:accountId`. Он MUST использовать успешный ответ в течение -30 секунд, без automatic retry, polling или refetch при возврате фокуса. +30 секунд, без automatic retry или refetch при возврате фокуса. +Polling допускается только для известной работы открытого экрана; +data GET наблюдения использует `sync=observe` и MUST NOT запускать новый импорт. +Status сообщает state/errorCode без hash notifications и численных progress counters. +После ухода или завершения работы polling MUST прекращаться. + +Предзагрузка всей истории свечей бумаг портфеля MUST NOT выполняться. +Новый диапазон свечей загружается при его открытии; initial loading допустим. При загрузке без ранее полученного успешного ответа для этого же Brokerage Account клиент MUST показывать структурное skeleton-состояние ожидаемого содержимого, включая сводку, без вымышленных сумм. Область загрузки MUST diff --git a/openspec/specs/user-authentication/spec.md b/openspec/specs/user-authentication/spec.md index 7f77af7..577ff4f 100644 --- a/openspec/specs/user-authentication/spec.md +++ b/openspec/specs/user-authentication/spec.md @@ -53,11 +53,21 @@ #### Scenario: Истёкшая сессия - **WHEN** клиент отправляет refresh-cookie Session, не обновлявшейся более 7 дней -- **THEN** система удаляет refresh-cookie и отвечает `401` Problem Details с code `UNAUTHORIZED` +- **THEN** система отвечает `401` Problem Details с code `UNAUTHORIZED`, не изменяя cookie неуспешным refresh #### Scenario: Повторное использование refresh token - **WHEN** клиент отправляет refresh token, заменённый предыдущим успешным refresh -- **THEN** система удаляет refresh-cookie и отвечает `401` Problem Details с code `UNAUTHORIZED`, не отзывая связанную Session только из-за этого запроса +- **THEN** система отвечает `401` Problem Details с code `UNAUTHORIZED`, не изменяет cookie и не отзывает связанную Session только из-за этого запроса + +### Requirement: Межвкладочная координация не требуется +Frontend MUST сохранять изоляцию данных текущей identity внутри вкладки. +Он MUST NOT требовать cross-tab synchronization для auth flow. После смены +auth-состояния в другой вкладке допускаются reload или повторная авторизация. +Неуспешный refresh MUST NOT удалять cookie успешного конкурентного запроса. + +#### Scenario: Конкурентный refresh проигрывает в другой вкладке +- **WHEN** вкладка получает `401` после ротации общей cookie другой вкладкой +- **THEN** она может перейти на login; cookie победителя остаётся доступной для последующего восстановления ### Requirement: Завершение сессии Система SHALL позволять завершить текущую Session через logout. Logout MUST отозвать Session, если refresh-cookie соответствует активной Session, и MUST удалить refresh-cookie. Logout MUST быть идемпотентным и не раскрывать существование Session. -- 2.54.0 From 33cc4f3e0c20ed3d6f5814cdc609724ffb8564ac Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sat, 3 Oct 2026 19:47:30 +0300 Subject: [PATCH 2/5] fix(deps): patch release tooling advisories Scope patched basic-ftp and undici overrides to release-it. Keep the existing development-dependency security gate. --- package-lock.json | 172 +++++++++++++++++++++++----------------------- package.json | 6 ++ 2 files changed, 92 insertions(+), 86 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1d9a26e..f660d1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,13 +81,13 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.0.tgz", - "integrity": "sha512-t7AzNHAKeIdo/3NRGwzpufKHsKkPHmFs/56N2Fnsh0/r0rGtnQzTxk6vnFgjaGr4hdSQKNB50/KAhR9Yk4LJKA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.3.tgz", + "integrity": "sha512-JQ13v0GafSM4fBYX8UowSy++07Was20auq0NcTdnzSEq6/05Cq5GBUMIfKkqjzyBwC9sJFmPpKWgLLhH7cygkw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "ajv": "^8.11.0" }, "engines": { @@ -95,13 +95,13 @@ } }, "node_modules/@commitlint/ensure": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.0.tgz", - "integrity": "sha512-76IF9vDNS13lAzEEik9eKwzt8f9hYhWiwVXZ2AnyLCz5/f511FsEQ3pw1X3/zSQpdRLQU7i5qDMVKyXi1GWjSg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.3.tgz", + "integrity": "sha512-gEjNKgRocbODI5/sMx2Qc9XOf2/zFTNV2aEK1QZ4gKDKxDC/VR7us3QtIX1C5d5xxHxx0I/tEbYbdSP1Am2LwA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "es-toolkit": "^1.46.0" }, "engines": { @@ -119,13 +119,13 @@ } }, "node_modules/@commitlint/format": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.2.tgz", - "integrity": "sha512-v6fvxZSc/AvVMROlr3H34+1766bZSYApRUSCAMjWamStPjKMvZ8GdvVA5YW/VQNgbFTmcMz6OYmSTJEvIjPrfA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.3.tgz", + "integrity": "sha512-KKwCjXYqA8r295uhLnulDXL9yekdXmj2yp2Q0XsBPhxQ2iPuvRE8F43j7g7yexo69wTdmUQmFz15jpderluzUQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "picocolors": "^1.1.1" }, "engines": { @@ -133,13 +133,13 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.2.tgz", - "integrity": "sha512-9UoKNgfFE3LU7FrzierCvk3CdDfMDeVGC86qZiT/n0TIjfq/dmZ9MHuXd45OTNRa26ZanmJRxEtmiXk/lEJihg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.3.tgz", + "integrity": "sha512-Ng4nRj/LBAOvc+GQu7bsFW4/fL89LvZ14OOC/ERLbUpnG6QBwWRzY/1oXGwPs3C8YHWjJObin4kLYo2YeEn70w==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "semver": "^7.6.0" }, "engines": { @@ -147,32 +147,32 @@ } }, "node_modules/@commitlint/lint": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.2.tgz", - "integrity": "sha512-Fy8JxEBzdmsYWFude/61GxXu5O+wEymwiRK2z9GL9R8mCsXphCoGxAFc5iHn5mjlfcSrhiiONE+ksf4KOjnaPg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.3.tgz", + "integrity": "sha512-lUZcSuVLLEDkhge9ERk8Rp+FXQtrUhCK+h328BFnzKXrTuXGdqiYMEpTlNWdZaOrjyMhMJaz354ZaWEGJxcLeg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^21.2.2", - "@commitlint/parse": "^21.2.2", - "@commitlint/rules": "^21.2.2", - "@commitlint/types": "^21.2.0" + "@commitlint/is-ignored": "^21.2.3", + "@commitlint/parse": "^21.2.3", + "@commitlint/rules": "^21.2.3", + "@commitlint/types": "^21.2.3" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@commitlint/load": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.2.tgz", - "integrity": "sha512-0Tt6wDPX167cjKC5D4zhm0+20wJJG+TN/TKovMOspfSe78rOnKX+MNzlVNiu6HyQPZChPJ8QBH31MVt6Bb8fCg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.3.tgz", + "integrity": "sha512-cDrL8lOo23Lk7knGzQdjbFcq7z2JgvjwV6PhbESVvEc+Fe21MeLjPKBJi8nKjg7j+jh79CVbVSUbZc104thXRw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^21.2.0", + "@commitlint/config-validator": "^21.2.3", "@commitlint/execute-rule": "^21.0.1", - "@commitlint/resolve-extends": "^21.2.2", - "@commitlint/types": "^21.2.0", + "@commitlint/resolve-extends": "^21.2.3", + "@commitlint/types": "^21.2.3", "cosmiconfig": "^9.0.1", "cosmiconfig-typescript-loader": "^6.1.0", "es-toolkit": "^1.46.0", @@ -194,13 +194,13 @@ } }, "node_modules/@commitlint/parse": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.2.tgz", - "integrity": "sha512-MEkobPfvRp+z06Wro8HMG1BDGHzZmj82A1LH1nWeG3ipHpg/x4m6v3wEDvMBIKjRFUnfR3nBeFs3MVCr7UdAmg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.3.tgz", + "integrity": "sha512-Jt61QpF1xA88damCELe8I0FlDZPSpXNc8IhN7z5kZ0EcDYPjdZ+ZHPvsSXl69r2MIlLnNKeHhOn2cmVpziFE9w==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "conventional-changelog-angular": "^9.0.0", "conventional-commits-parser": "^7.0.0" }, @@ -209,14 +209,14 @@ } }, "node_modules/@commitlint/read": { - "version": "21.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.1.tgz", - "integrity": "sha512-hUW7EJQnNTL0vPOmVMNK4CrnrNBN0nN+JJHReFkdHO5y4iyHeEmTBwuC15OCqUTjxWo7idnH1LftfpWVIaPWIA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.3.tgz", + "integrity": "sha512-szAepuLA1vTTr7fuudEg7jYyVHudf+FH+vptU91bhxE1WnE8TKrfTAi44HVllz8XpI8Pvp4GjR/iP5Nshgh+og==", "dev": true, "license": "MIT", "dependencies": { "@commitlint/top-level": "^21.2.0", - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "@conventional-changelog/git-client": "^3.0.0", "tinyexec": "^1.0.0" }, @@ -225,14 +225,14 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.2.tgz", - "integrity": "sha512-RPkJ/IFi7sMUUVbZLqwWFtWw/zRDcfFsmrPSiTMrt5wb7AdxOr86EGQFvmGzef5QKV5IPBWWCujqVTw1RWX44A==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.3.tgz", + "integrity": "sha512-bqJdmAtXgAQel+l02uIsF7rHgKgx1AGZdGBjam7uK4XW54ZAQtB6XAIUXezYprQiCcRMpBh4fHs5JodXK4mVZA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^21.2.0", - "@commitlint/types": "^21.2.0", + "@commitlint/config-validator": "^21.2.3", + "@commitlint/types": "^21.2.3", "es-toolkit": "^1.46.0", "global-directory": "^5.0.0", "resolve-from": "^5.0.0" @@ -242,16 +242,16 @@ } }, "node_modules/@commitlint/rules": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.2.tgz", - "integrity": "sha512-eplQzyYkBjYB1HyyRj8hkcK11Y9DU9nuBz7uOKEd6NpE9NGDytLFCAnlRE+OoiK/5sHEJsaz2RGhuWBvYzIbNA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.3.tgz", + "integrity": "sha512-5+YnI/LuTx3JDl9GjqfP2z9x96M8KKDrd+4jOel/T0L1BB3oAmBlSN8xppf63QsudiVEgR8C0gRoAMrPVrms6g==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^21.2.0", + "@commitlint/ensure": "^21.2.3", "@commitlint/message": "^21.2.0", "@commitlint/to-lines": "^21.0.1", - "@commitlint/types": "^21.2.0" + "@commitlint/types": "^21.2.3" }, "engines": { "node": ">=22.12.0" @@ -281,9 +281,9 @@ } }, "node_modules/@commitlint/types": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.0.tgz", - "integrity": "sha512-7zVFCDB2reMvJH5dmbKnOQPjZEvjdJTH8jc0U/PIPU1r3/+vf5pD1HlfitV2MWsWXrvu7u39iY1lyLUPOaN0Gw==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.3.tgz", + "integrity": "sha512-sGEA473TlCvhCGNoTBY9OXZVWdscIXdGt0dm8EpB+2MRfmt8LNh/X56P/T3nCtEB+eH5qGEa3odphSAoUxSfSQ==", "dev": true, "license": "MIT", "dependencies": { @@ -972,9 +972,9 @@ } }, "node_modules/@types/node": { - "version": "26.5.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.5.1.tgz", - "integrity": "sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==", + "version": "26.6.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.4.tgz", + "integrity": "sha512-ldVPDCzj7fsaGZrLB0NuHuTvJcsNasysBAqMolr/cgxrLd1xbqxIr3XJiPnHHJUCxj5sNF1vnRj9aWnrVh5Jcg==", "dev": true, "license": "MIT", "peer": true, @@ -1377,9 +1377,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", - "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", "dev": true, "license": "MIT", "engines": { @@ -1446,9 +1446,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", - "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-6.2.1.tgz", + "integrity": "sha512-bK67isD+lKq46AU8vNtjvMaT2ZqAOAmNCbxUHlFBRD4k15NWxyEjmaKtZPlgce58So4BNTjITGQOVTjL9y0ECA==", "dev": true, "license": "MIT", "engines": { @@ -1470,9 +1470,9 @@ "license": "MIT" }, "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.1.tgz", + "integrity": "sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==", "dev": true, "license": "MIT", "dependencies": { @@ -1672,9 +1672,9 @@ "license": "MIT" }, "node_modules/content-type": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-3.1.0.tgz", - "integrity": "sha512-z26wZR7iXahgpSK7XgnB4IbRVmUNSODvsX9qC9TAru7AcWGiqn5YKy+OH3PLRrwyAnewykKhCqnD+VV3a8uT8Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-3.1.1.tgz", + "integrity": "sha512-GW4qUsfFo59d0HbUibDlWv5wPz+vAAcaTWbKIuKCf0JkC7wWkSyf8f13IpXn5JkeMlB2P8iTSSIjwXljorg2vA==", "dev": true, "license": "MIT", "engines": { @@ -2093,9 +2093,9 @@ } }, "node_modules/exsolve": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", - "integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.3.tgz", + "integrity": "sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA==", "dev": true, "license": "MIT" }, @@ -2124,9 +2124,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", - "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -2189,9 +2189,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", - "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", "dev": true, "license": "MIT", "engines": { @@ -2355,9 +2355,9 @@ } }, "node_modules/ip-address": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", - "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.3.tgz", + "integrity": "sha512-A1kdq/tSb5QjvKvAMgIoEvDBIgL7qaqVP/jkvSwYYRZ9iEzvPpopxp2wQfu3SuZRHtpHNxMn8Fs0bS+gf5Xmwg==", "dev": true, "license": "MIT", "engines": { @@ -3316,9 +3316,9 @@ } }, "node_modules/string-width": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", - "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", + "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3439,9 +3439,9 @@ } }, "node_modules/undici": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", - "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", + "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", "dev": true, "license": "MIT", "engines": { @@ -3590,9 +3590,9 @@ } }, "node_modules/yargs": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", - "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz", + "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 355e5a5..722676f 100644 --- a/package.json +++ b/package.json @@ -17,5 +17,11 @@ "@release-it/conventional-changelog": "12.0.0", "conventional-changelog-conventionalcommits": "10.4.0", "release-it": "21.0.2" + }, + "overrides": { + "release-it": { + "basic-ftp": "6.2.1", + "undici": "7.29.1" + } } } -- 2.54.0 From 0fd148ffbb39ea883a7e7799aa1b87c93b31fa17 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 7 Oct 2026 14:18:14 +0300 Subject: [PATCH 3/5] chore: run commitlint in commit-msg hook Local commits now get the same commitlint --strict check as CI. --- .githooks/commit-msg | 2 ++ package.json | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100755 .githooks/commit-msg diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 0000000..fcc7fea --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,2 @@ +#!/bin/sh +npx --no-install commitlint --edit "$1" --strict diff --git a/package.json b/package.json index 722676f..885321e 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "verify": "git diff --check", "release:preview": "release-it --dry-run --ci", "release:prepare": "release-it --ci", - "commitlint": "commitlint" + "commitlint": "commitlint", + "prepare": "git config core.hooksPath .githooks" }, "devDependencies": { "@commitlint/cli": "21.2.2", -- 2.54.0 From a1b0e99bddb91f7b7ca729ddf6b7d6c688fdca41 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 7 Oct 2026 14:01:23 +0300 Subject: [PATCH 4/5] spec: add reduce-screen-sync-polling change OpenSpec change: screen sync status polling and observe reads run every five seconds during active sync; terminal state observes resources immediately. --- .../reduce-screen-sync-polling/.openspec.yaml | 2 + .../reduce-screen-sync-polling/design.md | 104 ++++++++++++++++++ .../reduce-screen-sync-polling/proposal.md | 50 +++++++++ .../specs/frontend-data-resilience/spec.md | 85 ++++++++++++++ .../reduce-screen-sync-polling/tasks.md | 30 +++++ 5 files changed, 271 insertions(+) create mode 100644 openspec/changes/reduce-screen-sync-polling/.openspec.yaml create mode 100644 openspec/changes/reduce-screen-sync-polling/design.md create mode 100644 openspec/changes/reduce-screen-sync-polling/proposal.md create mode 100644 openspec/changes/reduce-screen-sync-polling/specs/frontend-data-resilience/spec.md create mode 100644 openspec/changes/reduce-screen-sync-polling/tasks.md diff --git a/openspec/changes/reduce-screen-sync-polling/.openspec.yaml b/openspec/changes/reduce-screen-sync-polling/.openspec.yaml new file mode 100644 index 0000000..9123314 --- /dev/null +++ b/openspec/changes/reduce-screen-sync-polling/.openspec.yaml @@ -0,0 +1,2 @@ +schema: wealth-ledger-sdd +created: 2026-10-07 diff --git a/openspec/changes/reduce-screen-sync-polling/design.md b/openspec/changes/reduce-screen-sync-polling/design.md new file mode 100644 index 0000000..acf4c40 --- /dev/null +++ b/openspec/changes/reduce-screen-sync-polling/design.md @@ -0,0 +1,104 @@ +## Context + +`useScreenSync` уже является общим module для экранной синхронизации. Его +interface принимает scope и набор resource queries; реализация опрашивает +статусы выполняющейся работы и вызывает `observe()` для ресурсов того же +экрана. Один интервал в 1 секунду управляет обоими видами запросов, поэтому +страницы с несколькими ресурсами умножают фоновый трафик. + +Нужна меньшая частота обновления при сохранении текущей cache identity, +автоматического восстановления, защиты доступа и итогового обновления сразу +после завершения работы. + +## Goals / Non-Goals + +**Goals:** + +- Сократить периодический HTTP-трафик выполняющейся экранной синхронизации + примерно в пять раз. +- Сохранить небольшую и прежнюю interface `useScreenSync` для всех page VMs. +- Сразу обновлять ресурсы после terminal state синхронизации. +- Проверять поведение на HTTP seam, а не детали реализации TanStack Query. + +**Non-Goals:** + +- Изменять backend status contract, resource endpoints или модель синхронизации. +- Вводить отдельный polling module, второй cache или push-канал. +- Менять пользовательское представление загрузки и ошибок. + +## Decisions + +### Preserve one screen-sync module and lengthen its interval + +`useScreenSync` остаётся единственным module, который владеет связью между +статусом экранной синхронизации и observe reads. Его implementation заменяет +интервал status polling с одной секунды на пять секунд. Поскольку effect уже +наблюдает ресурсы после нового status response, это одним изменением +ограничивает оба потока запросов без расширения interface для callers. + +Alternative: добавить второй timer только для observe reads при status polling +раз в секунду. Отклонено: status traffic останется частым, а два независимых +ритма увеличат implementation и риск дублирующих наблюдений без требуемой +пользы. + +Alternative: читать ресурсы только после terminal state. Отклонено: это +устранит промежуточную публикацию уже готовых данных и изменит существующее +поведение сильнее, чем требуется. + +### Keep completion observation driven by the terminal status response + +Текущий effect уже distinguishes running и completed status: для terminal state +он observes every resource, включая тот, который был fetching. Этот путь +сохраняется. Terminal response не ждёт отдельного timer, поэтому итоговый +результат появляется в обработке того же status response; максимальная +задержка возникает только до следующей пятиисекундной проверки. + +### Test the public HTTP outcome at the screen-sync seam + +Colocated tests `screen-sync` будут использовать MSW и fake timers, чтобы +проверить отсутствие повторного status/read traffic до пяти секунд, следующий +цикл после интервала и одно итоговое observe read при terminal status. Existing +tests продолжат доказывать, что уход с экрана останавливает polling и что +observe reads не создают новую импортирующую работу. + +## UI/UX Applicability and Package + +**Applicability and scope:** N/A. Изменяется только частота невидимых фоновых +запросов; экраны, состояния, interactions и responsive behavior не меняются. + +## Delivery Map + +| Area | Status | Architectural outcome or N/A reason | +| --- | --- | --- | +| frontend | affected | `useScreenSync` реже опрашивает статус и тем самым реже наблюдает ресурсы, сохраняя немедленное обновление после terminal state. | +| backend | N/A | Status и resource contracts не меняются. | +| specs | affected | Delta фиксирует пятиисекундную верхнюю частоту и итоговое наблюдение после terminal state. | +| docs | N/A | Пользовательские и эксплуатационные инструкции не меняются. | + +## Risks / Trade-offs + +- Промежуточно готовые данные могут появиться до четырёх секунд позже, чем + раньше; пользователь явно выбрал меньший трафик в обмен на эту задержку. +- Terminal state обнаруживается следующей status-проверкой, поэтому его + отображение также может ждать до пяти секунд после фактического завершения + backend work. После обнаружения дополнительной задержки нет. +- Смена только общей константы затрагивает все экраны-потребители; тесты + module защищают единое ожидаемое поведение. + +## Migration Plan + +1. Изменить policy interval у существующего screen-sync module. +2. Адаптировать и дополнить его seam tests для пятиисекундного ритма и + terminal refresh. +3. Выполнить локальные frontend quality gates перед поставкой. + +### Rollback Contract + +| Field | Decision | +| --- | --- | +| Status | `N/A` | +| Reason | Изменение локальной frontend polling policy не меняет данные, публичный contract, security или миграции; rollback состоит в возврате прежнего значения интервала. | +| Trigger | N/A | +| Actions | N/A | +| Data safety | N/A | +| Verification | N/A | diff --git a/openspec/changes/reduce-screen-sync-polling/proposal.md b/openspec/changes/reduce-screen-sync-polling/proposal.md new file mode 100644 index 0000000..3de0478 --- /dev/null +++ b/openspec/changes/reduce-screen-sync-polling/proposal.md @@ -0,0 +1,50 @@ +## Why + +Пока экран ожидает синхронизацию T-Bank, клиент опрашивает её состояние каждую +секунду. Каждый новый ответ запускает наблюдение всех ресурсов открытого экрана. +На экранах с несколькими финансовыми выборками это создаёт непропорционально +много запросов при том, что пользователь готов увидеть промежуточный результат +с небольшой задержкой. + +## What Changes + +- Во время выполняющейся экранной синхронизации приложение реже проверяет её + состояние и обновляет наблюдаемые финансовые ресурсы не чаще одного раза за + пять секунд. +- После terminal state синхронизации приложение сразу наблюдает ресурсы + открытого экрана, чтобы отобразить итоговый результат без дополнительной + задержки. +- Существующие состояния ожидания, доступные частичные результаты, + автоматическое восстановление чтения и прекращение работы после ухода с + экрана сохраняются. + +Ожидаемый результат: длительная синхронизация создаёт существенно меньше +фоновых HTTP-запросов, а пользователь получает промежуточные результаты с +задержкой не более пяти секунд и итоговые данные сразу после завершения. + +Non-goals: + +- Изменять запуск синхронизации, её scope, доступ к данным или финансовые + расчёты. +- Добавлять новые пользовательские элементы, ручное управление частотой или + отдельный канал доставки изменений. +- Гарантировать обновления финансовых данных в реальном времени. + +## Capabilities + +### New Capabilities + + + +### Modified Capabilities + +- `specs/frontend-data-resilience/spec.md`: ограниченная частота наблюдения + ресурсов во время выполняющейся синхронизации и немедленное наблюдение после + terminal state. + +## Impact + +Изменение затрагивает финансовые экраны, использующие экранную синхронизацию: +счета, детали счёта, операции, доходы, события и страницы инструментов. Оно +сокращает фоновый HTTP-трафик при продолжающейся синхронизации, сохраняя +автоматическое отображение готовых данных и существующие правила устойчивости. diff --git a/openspec/changes/reduce-screen-sync-polling/specs/frontend-data-resilience/spec.md b/openspec/changes/reduce-screen-sync-polling/specs/frontend-data-resilience/spec.md new file mode 100644 index 0000000..cb58273 --- /dev/null +++ b/openspec/changes/reduce-screen-sync-polling/specs/frontend-data-resilience/spec.md @@ -0,0 +1,85 @@ +## MODIFIED Requirements + +### Requirement: Временные сбои чтения восстанавливаются автоматически + +Frontend SHALL автоматически повторять временно неуспешное чтение и +восстанавливать получение необходимых текущему экрану данных без ручного +обновления. Повторы одной попытки MUST иметь конечный предел и паузы, +исключающие непрерывную череду запросов. При исчерпании предела доступные данные +SHALL сохраняться, а при их отсутствии SHALL показываться локальная +недоступность. Возвращение сети, возвращение пользователя к открытому экрану и +повторное открытие экрана MUST возобновлять получение отсутствующих или +требующих обновления данных без перезагрузки страницы. Свежий полный результат +MUST NOT требовать обращения к источнику только из-за такого события. + +Наблюдая выполняющуюся экранную синхронизацию, frontend MUST проверять её +состояние и повторно читать связанные ресурсы не чаще одного раза за пять +секунд. После получения terminal state этой синхронизации frontend MUST сразу +наблюдать ресурсы текущего экрана, не ожидая следующего пятиисекундного +интервала. + +Восстановление MUST учитывать сбой чтения результата и сбой самого получения +данных из источника, даже если чтение состояния завершилось успешно. Наблюдение +уже выполняющейся работы MUST NOT запускать её повторно. Уход с экрана MUST +прекращать новые попытки его восстановления; это не требует отменять уже +начатую работу источника. Автоматическое восстановление MUST NOT повторять +запросы, требующие исправления ввода, входа или восстановления доступа, и MUST +NOT переносить старые параметры в новую пользовательскую выборку. + +#### Scenario: Кратковременный сбой чтения +- **WHEN** чтение текущей выборки временно не удалось, а следующая разрешённая + автоматическая попытка успешна +- **THEN** экран самостоятельно показывает результат без ручного действия и без + сообщения о сбое или восстановлении + +#### Scenario: Экранная синхронизация продолжается +- **WHEN** экран наблюдает синхронизацию, которая остаётся в состоянии running + после очередной проверки +- **THEN** frontend выполняет следующую проверку состояния и наблюдение + связанных ресурсов не ранее чем через пять секунд + +#### Scenario: Экранная синхронизация завершилась +- **WHEN** очередная проверка экранной синхронизации возвращает terminal state +- **THEN** frontend сразу наблюдает связанные ресурсы текущего экрана, чтобы + показать итоговый результат без ожидания следующего интервала + +#### Scenario: Источник завершил работу ошибкой +- **WHEN** чтение сохранённых данных успешно, но получение необходимых новых + данных из источника временно не удалось +- **THEN** приложение применяет ограниченное автоматическое восстановление к + неуспешной работе, а не считает успешное чтение доказательством её успеха + +#### Scenario: Повторы исчерпаны +- **WHEN** временная недоступность сохраняется после конечного предела + автоматических попыток +- **THEN** приложение прекращает серию повторов, сохраняет доступный результат + либо локальную недоступность без бесконечной загрузки и ожидает следующего + события восстановления + +#### Scenario: Сеть или пользователь вернулись +- **WHEN** после временного сбоя восстановилась сеть либо пользователь вернулся + к экрану с отсутствующим или требующим обновления результатом +- **THEN** получение данных возобновляется автоматически для текущей выборки и + при успехе заменяет состояние недоступности содержимым + +#### Scenario: Несколько событий восстановления совпали +- **WHEN** сеть восстановилась одновременно с возвращением пользователя на экран +- **THEN** приложение не запускает дублирующую работу получения одного набора + данных + +#### Scenario: Работа источника ещё выполняется +- **WHEN** приложение восстанавливает чтение состояния уже выполняющейся работы +- **THEN** оно продолжает получение её результата без повторного запуска той же + работы + +#### Scenario: Пользователь покинул экран +- **WHEN** пользователь ушёл со страницы с ожидающим восстановлением +- **THEN** новые попытки для покинутого экрана прекращаются, а уже начатая работа + не изменяет содержимое другой выборки + +#### Scenario: Ошибка требует действия пользователя +- **WHEN** подтверждены недействительное подключение, отсутствие доступа или + некорректный ввод +- **THEN** автоматическая серия повторов прекращается и появляется + соответствующее действие или локальная ошибка без технической кнопки повторной + загрузки diff --git a/openspec/changes/reduce-screen-sync-polling/tasks.md b/openspec/changes/reduce-screen-sync-polling/tasks.md new file mode 100644 index 0000000..4530ba0 --- /dev/null +++ b/openspec/changes/reduce-screen-sync-polling/tasks.md @@ -0,0 +1,30 @@ +## 1. Screen synchronization policy + +- [x] 1.1 [frontend] Change the screen-sync status polling policy from one + second to five seconds while keeping the existing `useScreenSync` interface + and terminal-state resource observation. + - **Covers:** `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически` + - **Verification:** Run the colocated screen-sync test file and confirm its + MSW assertions show no subsequent status or observe request before five + seconds, with resources observed on a terminal status response. + +- [x] 1.2 [frontend] Update colocated screen-sync tests with fake timers to + cover the five-second running cadence, immediate terminal observation, and + existing stop-on-unmount behavior. + - **Covers:** `frontend-data-resilience` — `Временные сбои чтения восстанавливаются автоматически` + - **Verification:** `nvm use --silent && npm test -- screen-sync.test.tsx` + +## 2. Frontend delivery + +- [x] 2.1 [frontend] Run the frontend's canonical verification after the + polling-policy and regression-test changes. + - **Covers:** `N/A` — This task verifies the affected frontend delivery; it + introduces no separate observable behavior beyond the requirement covered + by tasks 1.1 and 1.2. + - **Verification:** `nvm use --silent && npm run verify` + +- [x] 2.2 [specs] Verify the completed OpenSpec change against the + `wealth-ledger-specs` store before implementation review. + - **Covers:** `N/A` — This task validates the planning artifacts and their + traceability; it does not introduce runtime behavior. + - **Verification:** `openspec validate --change reduce-screen-sync-polling --store wealth-ledger-specs` -- 2.54.0 From 1ee31e3b492c0c7b4e6131de8b29e75337033adc Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 7 Oct 2026 18:13:58 +0300 Subject: [PATCH 5/5] chore(release): 0.1.3 --- CHANGELOG.md | 15 +++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f68d9..9f46a22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [0.1.3](https://git.personal.ksv741.ru/WealthLedger/specs/compare/v0.1.2...v0.1.3) (2026-10-07) + +### Bug Fixes + +* **deps:** patch release tooling advisories ([33cc4f3](https://git.personal.ksv741.ru/WealthLedger/specs/commit/33cc4f3e0c20ed3d6f5814cdc609724ffb8564ac)) + +### Specifications + +* add reduce-screen-sync-polling change ([a1b0e99](https://git.personal.ksv741.ru/WealthLedger/specs/commit/a1b0e99bddb91f7b7ca729ddf6b7d6c688fdca41)) +* simplify runtime requirements ([d861de5](https://git.personal.ksv741.ru/WealthLedger/specs/commit/d861de5ead41b4977083b4aee08fc668c35e5b34)) + +### Maintenance + +* run commitlint in commit-msg hook ([0fd148f](https://git.personal.ksv741.ru/WealthLedger/specs/commit/0fd148ffbb39ea883a7e7799aa1b87c93b31fa17)) + ## [0.1.2](https://git.personal.ksv741.ru/WealthLedger/specs/compare/v0.1.1...v0.1.2) (2026-09-26) ### Specifications diff --git a/package-lock.json b/package-lock.json index f660d1b..780a527 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wealth-ledger-specs", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wealth-ledger-specs", - "version": "0.1.2", + "version": "0.1.3", "devDependencies": { "@commitlint/cli": "21.2.2", "@commitlint/config-conventional": "21.2.2", diff --git a/package.json b/package.json index 885321e..7ad2ecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wealth-ledger-specs", - "version": "0.1.2", + "version": "0.1.3", "private": true, "engines": { "node": "24.21.0" -- 2.54.0