Эпик 1 (Благорост): контракт capital — займы, расходы программы, L2-роли #3
Reference in New Issue
Block a user
Delete Branch "feat/blagorost-E1-contract"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Зонтичный PR Эпика 1 — контрактный слой Благорост
Закрывает 11 stories из спринт-плана Благорост (blago issues 51F-13…51F-23). Целиком замыкает контрактный слой одной волной — дальше Эпики 2 (cooptypes) и 4 (controller) могут идти без возвратов в C++.
Зеркало github PR coopenomics/mono#402 (миграция с github на gitea).
Stories и commits
debtpaydcln+ статусPAY_PENDING— откат outpay без удаления долгаsettledebt— прямое погашение деньгами, REPAY 80/58, статусSETTLEDmarkdebtoverd+due_at = now + 1 годвdebtpaycnfrm, статусOVERDUEexppaycnfrm.cpp:35— новая операцияo.cap.expns(BLAGOROST_FUND → SOV_EXPENSES)createpgexp/apprvpgexp/authpgexp/pgexppay/declpgexp+ таблицаprogexpensesprogram_expense_pool+program_expense_reservedвglobal_state; actiontopupprogexprequestrole/approverole/declinerole/inviterole/acceptinvite/declinvite/requestrateu+rolerequestsapproved_rate_per_hourвsegments;createcmmtберёт approved-ставку, fallback наcontributorsprint()вstartvoting.cpp;[[deprecated]]наprogram_invest(remove after 2026-07)require_recipientво всех новых actions (кроме batchmarkdebtoverd)capital-blagorost.test.ts— 21 it.todo по новым ветвямcapital::closedebt— закрытие долга через создание НМА (Дт 04/Кт 08) + write-off (Дт 80/Кт 58)Финальный канон debt-операций невозврата (commit
c3a433b591)Утверждено автором 2026-05-19. Семантика операции через имя, группировка по сущности (
dbtдля debt-операций):o.cap.crtnmao.cap.dbtwrfw.cap.nmacapital::closedebtsettledebt)writeoffСемантика, важная для следующих эпиков
declineinvite→declinvite, программные расходы —createpgexp/apprvpgexp/authpgexp/pgexppay/declpgexp. Эпик 2 (cooptypes) должен использовать эти имена.p.cap.expnsи операцииo.cap.crtnma/o.cap.dbtwrfзарегистрированы вOPERATION_REGISTRY.contributors.rate_per_hour— глобальная (fallback),segments.approved_rate_per_hour— мастерская на проекте.created → approved → authorized ↔ pay_pending → paid → (overdue) → settled | writeoff. Веткаwriteoff— автоматическое закрытие черезclosedebtприproject.status == cancelled, без подписи пайщика.Не входит в этот PR
allocate/diallocate/regshare/initprj/cmpltvoting/...) — вынесена за пределы эпика «Благорост» как нерелевантная PRD.it.todo, реализуется по мере появления helper'ов в Эпике 4 (controller).Test plan
Story 1.7 эпика «Благорост» (blago issue 51F-19). PRD-D1/D3/D4: «двухуровневые допуски, мастер компонента валидирует исполнителей и ставку часа на сегменте». До этого коммита actions L2-цикла в контракте не существовало; ставки фиксировались только глобально через editcontrib. Изменения: - domain/entities/role_requests.hpp: таблица rolerequests, статусы pending/approved/declined, направление request/invite, тип role/rateupdate, helpers create/approve/decline - 7 новых cpp actions в app/participation_management/roles/: - requestrole — пайщик просит L2-роль (creator/author/contributor) + ставку - approverole — мастер одобряет: фиксация approved-ставки в сегменте через Capital::Segments::set_approved_rate (Story 1.8) - declinerole — мастер отклоняет с причиной (запись для аудита остаётся) - inviterole — мастер инициирует обратный поток, приглашает кандидата - acceptinvite — кандидат принимает инвайт → applied к сегменту - declinvite — кандидат отказывается (имя укорочено с declineinvite — лимит 12 chars) - requestrateu — пайщик просит обновить approved-ставку (тот же flow, RequestType::RATE_UPDATE); approverole с новой ставкой → новая approved в сегменте - name declineinvite сокращена до declinvite (13 → 10 chars, eosio лимит 12) Авторизация на текущем этапе — require_auth(coopname); backend проверяет master-роль приглашающего/одобряющего перед отправкой action. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Story 1.9 эпика «Благорост» (blago issue 51F-21). PRD: «удалить отладочные print() в startvoting.cpp; пометить progrinvests deprecated до 07.2026». Логирующие print() в returntopool.cpp и lvlnotify.cpp оставлены — они несут смысл, не отладочные маркеры. Изменения: - startvoting.cpp: убраны 5 маркеров print("z"/"a"/"b"/"c"/"d") - program_invests.hpp: атрибут [[deprecated("remove after 2026-07")]] на struct program_invest + расширенный doxygen-комментарий с пояснением жизненного цикла Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>role_requests: — role строго {creator, author, master}; contributor — L1, в role_requests не попадает — validate_role_or_fail() — валидация на уровне requestrole/inviterole — description (std::string, может быть пустой) — текст заявки/приглашения от пайщика к мастеру и наоборот — apply_role_to_project(): inline addauthor для role=author, setmaster для role=master, creator → no-op (фиксируется при первом createcmmt) Actions: — requestrole/inviterole/requestrateu: добавлено description в сигнатуру + проброс в RoleRequests::create — approverole/acceptinvite: после approve/segment.set_approved_rate вызывают apply_role_to_project — заявленная роль немедленно отражается в реестре участников (раньше creator становился creator только после первого commit'а) — inviterole: уточнено в комментарии что master-параметр может быть председателем при приглашении кандидата на роль master (когда мастера в проекте ещё нет) Ставка часа всегда подаётся явно (rate_per_hour, hours_per_day) — это ставка пайщика именно под этот проект; фронт по дефолту подставляет contributors.rate_per_hour, но пайщик может изменить под конкретный проект. createcmmt берёт approved_rate сегмента, не глобальную из contributors.Канон имён в ledger2-онтологии — самодокументирующиеся английские термины без аббревиатур. Префикс контракта (cap) не дублировать в имени. Переименования (старые имена — отвергнутый рабочий драфт; нигде больше не используются): o.cap.dflt → o.cap.seize (SEIZE_COLLATERAL — изъятие обеспечения) o.cap.lnwoff → o.cap.wroff (WRITE_OFF_LOAN — списание займа) w.cap.coopn → w.cap.nma (NMA — НМА кооператива) capital::dfltdebt → capital::seizecollat state defaulted (virtual) → seized (Status::SEIZED + mark_seized) Story 1.13 — action capital::seizecollat: - guard: debt.status ∈ {paid, overdue} ∧ project.status == cancelled; - apply o.cap.seize (TRANSFER w.cap.gen → w.cap.nma, Дт 04 / Кт 08); - apply o.cap.wroff (BURN w.cap.loan, Дт 80 / Кт 58); - decrease segment.debt_amount + active_debts_count; - subtract project.used_for_compensation; - decrease contributors.debt_amount; - mark debt SEIZED (mark_seized); - inline Loan::settle_debt (loan-контракт); - require_recipient(username, coopname); - require_auth(coopname) — без подписи пайщика, без сбора совета. Решения 2026-05-19 (Игорь Смуров / Алексей Муравьёв): - срок займа фикс — 1 год; - проводки невозврата: Дт 04 / Кт 08 + Дт 80 / Кт 58; - автоматизм без подписи пайщика и без сбора совета. Compile: cdt-cpp v4.1.0 OK (warnings only Ricardian + deprecation). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Поправить
@@ -7,1 +6,3 @@# • o.cap.repay — возврат займа из акта-2 (TRANSFER w.cap.loan → w.wal.share, Дт 80 / Кт 58)# Многоактовый процесс с авторизацией советом. Четыре операции:# • o.cap.lend — выдача займа на момент авторизации (ISSUE → w.cap.loan, Дт 58 / Кт 51)# • o.cap.repay — возврат займа из акта-2 (TRANSFER w.cap.loan → w.wal.share, Дт 80 / Кт 58)и никакого акта-2 у нас не существует. Есть один акт просто вторая подпись на нем.
@@ -281,6 +356,39 @@ operations:(Кт 58), сумма зачитывается в паевой фонд (Дт 80) и появляется какдоступный остаток на SHARE_FUND_PAY пайщика.- ledger_code: o.cap.crtnmaСтандарты должны описываться бизнес-языком для председателей и бухгалтеров! Смотри скилл /coop-standarts
@@ -22,0 +24,4 @@// loan не знает доменного контекста (проекта, программы) — это ответственность// вызывающего контракта; ему же принадлежит и локальная привязка debt_hash.// binary_extension: таблица в продакшене (пустая), новые поля только хвостом.binary_extension<name> source_contract;Ну так если таблица пустая - зачем здесь расширение то? Не надо! просто name.
Раунд 1 фиксов в gitea (commit
24663bdaac3)Три замечания закрыты.
1.
loan.debts.source_contract— убранаbinary_extensioncomponents/contracts/cpp/lib/domain/table_loan_debts.hpp:27— теперь простоname source_contract. Таблица в продакшене пустая, обёртка не нужна. Соответственно вloan::createdebt:39—d.source_contract = payer;вместо.emplace(payer).2. Стандарт
p.cap.debt.standard.yaml— бизнес-языкПолностью переписан под аудиторию председатель / бухгалтер / пайщик по правилам skill
/coop-standards. Из прозаических полей (purpose,actions[].purpose,states[].description,scenario,alternatives) убраны:w.cap.*)o.cap.*)Дт 04 / Кт 08)Технические детали остались только в structured-секциях:
registry_id,stored_in;ledger_code,wallet_op,debit/credit,wallet_from/wallet_to,user_wallet/user_ref/available_deltaдля USER_SHARED (добавил L3 вo.cap.repay— зачисление наw.wal.shareпайщика).В
roles— русские названия (Пайщик / Председатель / Совет / Кассир) вместо ролевых кодов.3. «акт-2» — убран
Терминология поправлена: у проекта один акт, на нём ставится вторая подпись. Везде в стандарте (
states.paid.description,scenario.step 4,operations.o.cap.repay.description,related.note) сейчас «сдача результата работ по проекту (вторая подпись на акте)».Сборка
cdt-cpp v4.1.0черезdicoop/blockchain:latest— exit 0 для loan и capital.