From f8d2b21cf681abf7e613a743624134dfd073f835 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Tue, 13 Oct 2026 15:53:06 +0700 Subject: [PATCH] =?UTF-8?q?chore(tests):=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=B8=D1=82=D1=8C=20=D0=B4=D0=BE=D1=81=D1=82=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D1=83=20Telegram=20=D0=B8=20=D1=81=D0=BE=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=82=D1=8C=20=D0=B3=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=86=D1=8B=20=D0=BF=D0=BE=D0=B2=D1=82=D0=BE=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acceptance/telegram-outbox-live.mjs | 107 ++++++++++++++++++ docs/ux-ui-external-acceptance.md | 16 ++- docs/ux-ui-plan.md | 6 +- docs/ux-ui-progress.md | 14 ++- docs/ux-ui-remaining-acceptance.md | 18 ++- docs/ux-ui-stage-12.md | 14 ++- docs/ux-ui-test-server.md | 16 ++- .../telegram197-dry-result-2026-10-13.json | 57 ++++++++++ .../telegram197-partial-2026-10-13.json | 30 +++++ .../telegram197-resume-result-2026-10-13.json | 48 ++++++++ .../telegram197-summary-2026-10-13.json | 42 +++++++ 11 files changed, 356 insertions(+), 12 deletions(-) create mode 100644 backend/scripts/acceptance/telegram-outbox-live.mjs create mode 100644 docs/ux-ui/acceptance/telegram197-dry-result-2026-10-13.json create mode 100644 docs/ux-ui/acceptance/telegram197-partial-2026-10-13.json create mode 100644 docs/ux-ui/acceptance/telegram197-resume-result-2026-10-13.json create mode 100644 docs/ux-ui/acceptance/telegram197-summary-2026-10-13.json diff --git a/backend/scripts/acceptance/telegram-outbox-live.mjs b/backend/scripts/acceptance/telegram-outbox-live.mjs new file mode 100644 index 00000000..83c28706 --- /dev/null +++ b/backend/scripts/acceptance/telegram-outbox-live.mjs @@ -0,0 +1,107 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import {spawn} from 'node:child_process' + +// Never part of test:all: full mode sends three messages; resume mode sends one intentional duplicate. +const resume=process.env.MMAPP_LIVE_TELEGRAM_RESUME==='manual-retry-only' +const database=process.env.MMAPP_OWN_SQL_DB +assert(/^mm_accept_166_\d+$/.test(database??''),'An explicitly owned test database is required') +const url=new URL(process.env.DATABASE_URL) +assert.equal(url.pathname,'/'+database);assert.equal(url.username,database) +assert.equal(process.env.MMAPP_LIVE_TELEGRAM_SEND_ACK,'owned-test-chat') +assert.equal(process.env.MMAPP_LIVE_TELEGRAM_ACK_DUPLICATE,'yes') +const bot=JSON.parse(fs.readFileSync(process.env.MMAPP_LIVE_TELEGRAM_PRIVATE_FILE)) +assert.equal(bot.chatId,process.env.MMAPP_LIVE_TELEGRAM_CHAT_ACK) +assert(/^\d+:[A-Za-z0-9_-]+$/.test(bot.token)) +const portal=JSON.parse(fs.readFileSync(process.env.MMAPP_LIVE_PORTAL_PRIVATE_FILE)) +assert.equal(process.env.AUTH_REQUIRED,'true');assert.equal(process.env.AUTH_JWT_SECRET,portal.jwtSecret) + +const {pool,closePool}=await import('/app/backend/dist/db/index.js') +const {initDatabase}=await import('/app/backend/dist/db/bootstrap.js') +const {updateTelegramSettings}=await import('/app/backend/dist/services/alerts-service.js') +const {enqueueTelegramOutbox,dispatchPendingOutbox,getAlertsOutboxOverview}=await import('/app/backend/dist/services/alert-engine/outbox.js') +assert.equal((await pool.query('SELECT current_database() AS name')).rows[0].name,database) +const permissions=(await pool.query('SELECT rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user')).rows[0] +assert(Object.values(permissions).every(v=>v===false)) +const root='/app/backend/acceptance',prefix='own-live197-'+Date.now(),ownedUsers=[],cases=[] +const report={date:'2026-10-13',block:'12.5.197',database,resumeOnly:resume,scope:'Production compiled outbox, owned PostgreSQL, actual Portal JWT and real Telegram provider',cases,providerSendCalls:0,providerAcceptanceIds:[],ownPortalUsersRemoved:false,passed:false} +let app,adminToken,originalFetch=globalThis.fetch +const portalUrl='http://portal:8080' +async function portalCall(path,method='GET',body,token){ + const r=await originalFetch(portalUrl+path,{method,headers:{...(body!==undefined?{'content-type':'application/json'}:{}),...(token?{Authorization:'Bearer '+token}:{})},body:body===undefined?undefined:JSON.stringify(body)}) + const text=await r.text();return {status:r.status,data:text?JSON.parse(text):null} +} +const payload=(number)=>({text:`TEST197 №${number} — очередь Telegram. ${number===1?'Проверка dedupe и двух отправителей.':'Проверка unknown и намеренного ручного повтора.'}`,chatId:bot.chatId, + history:{id:prefix+'-history'+number,ruleId:null,groupId:null,ruleName:'Own TEST197 №'+number,severity:'info',message:'Контролируемая приёмка очереди Telegram',firedAt:new Date().toISOString()}}) +async function sender(){ + const code=`import assert from 'node:assert/strict';import {pool,closePool} from '/app/backend/dist/db/index.js';import {dispatchPendingOutbox} from '/app/backend/dist/services/alert-engine/outbox.js';assert.equal((await pool.query('SELECT current_database() AS name')).rows[0].name,process.env.MMAPP_OWN_SQL_DB);let calls=0,ids=[];const native=globalThis.fetch;globalThis.fetch=async(...args)=>{const r=await native(...args);if(new URL(String(args[0])).pathname.endsWith('/sendMessage')){calls++;const d=await r.clone().json();if(d.ok)ids.push(d.result.message_id)}return r};try{const result=await dispatchPendingOutbox(1);console.log(JSON.stringify({result,calls,ids}))}finally{await closePool()}` + return new Promise((resolve,reject)=>{ + const child=spawn(process.execPath,['--input-type=module','-e',code],{env:process.env,stdio:['ignore','pipe','pipe']}) + let output='',error='';child.stdout.on('data',b=>output+=b);child.stderr.on('data',b=>error+=b) + child.on('error',reject);child.on('exit',status=>{if(status!==0)return reject(Error('Owned sender failed: '+error));try{resolve(JSON.parse(output.trim()))}catch(e){reject(e)}}) + }) +} +let suppressReceipt=false +try{ + await initDatabase();assert.equal(Number((await pool.query('SELECT count(*) AS n FROM alert_outbox')).rows[0].n),0) + await updateTelegramSettings({token:bot.token,chatId:bot.chatId,messageThreadId:null}) + const login=await portalCall('/api/v1/auth/login','POST',{email:portal.email,password:portal.password});assert.equal(login.status,200);adminToken=login.data.access_token + const readerEmail=prefix+'@mmapp.test' + const created=await portalCall('/api/v1/admin/users','POST',{email:readerEmail,password:portal.password,name:'Own TEST197 reader',apps:['mm'],permissions:['mm:alerts:read']},adminToken) + assert.equal(created.status,201);ownedUsers.push(created.data.id) + fs.writeFileSync(root+'/owned-portal-users-private.json',JSON.stringify(ownedUsers),{mode:0o600}) + const readerLogin=await portalCall('/api/v1/auth/login','POST',{email:readerEmail,password:portal.password});assert.equal(readerLogin.status,200) + const {buildApp}=await import('/app/backend/dist/index.js');app=await buildApp({logger:false,startScheduler:false}) + const id1=prefix+'-1',id2=prefix+'-2' + if(!resume){ + assert.equal(await enqueueTelegramOutbox({id:id1,dedupeKey:id1,payload:payload(1)}),true) + assert.equal(await enqueueTelegramOutbox({id:id1+'-duplicate',dedupeKey:id1,payload:payload(1)}),false) + const senders=await Promise.all([sender(),sender()]) + assert.equal(senders.reduce((n,s)=>n+s.result.sent,0),1);assert.equal(senders.reduce((n,s)=>n+s.calls,0),1) + report.providerSendCalls+=1;report.providerAcceptanceIds.push(...senders.flatMap(s=>s.ids)) + let overview=await getAlertsOutboxOverview();assert.equal(overview.counts.sent,1) + assert.equal(Number((await pool.query('SELECT count(*) AS n FROM alert_history WHERE id=$1 AND sent_ok=true',[prefix+'-history1'])).rows[0].n),1) + cases.push({name:'dedupe and independent senders',senders:2,queuedRows:1,providerSends:1,sentHistoryRows:1}) + } + globalThis.fetch=async(...args)=>{ + const sending=new URL(String(args[0])).pathname.endsWith('/sendMessage') + if(sending){assert(report.providerSendCalls<(resume?1:3),'Live send budget exhausted');report.providerSendCalls++} + const response=await originalFetch(...args) + if(sending){ + const accepted=await response.clone().json() + if(accepted.ok!==true){report.providerRejectionCodes??=[];report.providerRejectionCodes.push(accepted.error_code??null);return response} + report.providerAcceptanceIds.push(accepted.result.message_id) + if(suppressReceipt){suppressReceipt=false;throw Error('Own TEST197 receipt suppressed after confirmed provider acceptance')} + } + return response + } + assert.equal(await enqueueTelegramOutbox({id:id2,dedupeKey:id2,payload:payload(2)}),true) + let outcome;let overview; + if(!resume){ + suppressReceipt=true;outcome=await dispatchPendingOutbox(1);assert.equal(outcome.sent,0);assert.equal(outcome.held,1) + overview=await getAlertsOutboxOverview();assert.equal(overview.counts.unknown,1);assert.equal(overview.items[0].id,id2) + const before=report.providerSendCalls;await dispatchPendingOutbox(1);assert.equal(report.providerSendCalls,before) + cases.push({name:'controlled lost receipt',providerAccepted:true,status:'unknown',automaticResend:false,physicalDisconnect:false}) + }else{await pool.query("UPDATE alert_outbox SET status='unknown',last_error='Own resume fixture: controlled unknown, no additional provider send' WHERE id=$1",[id2]);cases.push({name:'resume fixture',status:'unknown',providerSend:false,priorLiveEvidence:'telegram197-partial.json'})} + const retry='/api/alerts/outbox/'+id2+'/retry',ack={expectedVersion:0,acknowledgedDuplicateRisk:true} + const reader=await app.inject({method:'POST',url:retry,headers:{authorization:'Bearer '+readerLogin.data.access_token},payload:ack});assert.equal(reader.statusCode,403) + const missing=await app.inject({method:'POST',url:retry,headers:{authorization:'Bearer '+adminToken},payload:{expectedVersion:0}});assert.equal(missing.statusCode,400) + const approved=await app.inject({method:'POST',url:retry,headers:{authorization:'Bearer '+adminToken},payload:ack});assert.equal(approved.statusCode,200);assert.equal(approved.json().resolutionVersion,1) + const stale=await app.inject({method:'POST',url:retry,headers:{authorization:'Bearer '+adminToken},payload:ack});assert.equal(stale.statusCode,409) + outcome=await dispatchPendingOutbox(1);report.retryDiagnostic={outcome,rows:(await pool.query("SELECT status,retry_count,resolution_version,next_attempt_at,last_error FROM alert_outbox WHERE id=$1",[id2])).rows};assert.equal(outcome.sent,1) + overview=await getAlertsOutboxOverview();assert.equal(overview.counts.sent,resume?1:2);assert.equal(overview.counts.unknown,0) + assert.equal(Number((await pool.query('SELECT count(*) AS n FROM alert_history WHERE sent_ok=true')).rows[0].n),resume?1:2) + cases.push({name:'explicit retry with real Portal JWT',reader:403,missingAck:400,admin:200,staleVersion:409,resolutionVersion:1,intentionalDuplicate:true,sentHistoryRows:resume?1:2}) + assert.equal(report.providerSendCalls,resume?1:3);assert.equal(report.providerAcceptanceIds.length,resume?1:3) + report.passed=true +}catch(e){ + fs.writeFileSync(root+'/private-failure.log',String(e.stack??e),{mode:0o600});report.errorName=e.name +}finally{ + globalThis.fetch=originalFetch + if(app)await app.close() + for(const id of ownedUsers){const deleted=await portalCall('/api/v1/admin/users/'+id,'DELETE',undefined,adminToken);assert.equal(deleted.status,204)} + report.ownPortalUsersRemoved=true + await closePool() + fs.writeFileSync(root+'/result.json',JSON.stringify(report,null,2));console.log(JSON.stringify({passed:report.passed,providerSendCalls:report.providerSendCalls,errorName:report.errorName,ownPortalUsersRemoved:report.ownPortalUsersRemoved})) +} +if(!report.passed)process.exitCode=1 diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index 56b724cd..af012aca 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -1,6 +1,6 @@ # UX/UI: протокол внешней приёмки 12.5 -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md). @@ -696,7 +696,7 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). @@ -2388,3 +2388,15 @@ Production backend/frontend ux-peak196 развёрнуты.466 backend+525 fron | [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Runtime issuer/Portal → меню приложений → тот же Portal; reader → masked DTO + blocked edit, writer → existing editor | Следующий197: реальная доставка из outbox через собственную временную БД, dedupe/two senders, controlled lost receipt после реального Telegram acceptance, no automatic repeat, explicit acknowledged retry/stale version/RBAC. Планируется3 помеченных test messages, включая намеренный повтор№2; не превращать controlled receipt suppression в физическую WAN/lost-ACK приёмку. Portal JWT revocation доexp, настоящее expiry/refresh/client OS и crash/lock-loss остаются отдельными границами.12.5 открыта. + +## 12.5.197 — доставка Telegram и управляемый повтор (2026-10-13) + +Production compiled outbox проверен в собственной временной PostgreSQL БД и ограниченной роли, с реальными JWT Portal и тестовым Telegram bot/chat. Первый live прогон: enqueue с одинаковым dedupeKey сохранил одну запись; два независимых Node sender процесса выполнили одну отправку, одна запись sent и одна history. Telegram принял№2, затем драйвер намеренно подавил ответ: статус unknown, следующая автоматическая диспетчеризация не отправила сообщение повторно. Это контролируемая имитация потерянного ответа, не физический обрыв WAN. + +Reader retry403, отсутствие acknowledgedDuplicateRisk400, admin expectedVersion0→1 с подтверждением риска200, повтор старой версии409. Однако завершающий assert первого полного live прогона sent=1 не прошёл; outcome тогда не был записан. Причина не установлена. Исходный failed протокол сохранён, цельный непрерывный live сценарий не объявляется пройденным. Для локализации полный сценарий с реальной БД/Portal JWT и симулированным Telegram ответом прошёл без сетевых отправок. Далее только оставшаяся ручная отправка проверена на новой собственной unknown fixture: Telegram accepted, status sent, resolutionVersion1, history одна. Это отдельный успешный live тест, не продолжение прежней БД. + +Всего реально приняты3 сообщения: одно TEST197№1 и два одинаковых TEST197№2, последние являются намеренным повтором. Пользователь подтвердил именно это количество. Три own DB/role/container и собственные Portal reader users удалены; временный private bot file на сервере удалён. Рабочие настройки Telegram приложения сохранены для следующих пользовательских проверок. Пароли/конфигурация CHR не менялись, runtime остаётся ux-peak196. Драйвер не входит вtest:all, требует own DB, явный чат и подтверждение риска, имеет отдельный resume режим. Диагностика завершающей отправки теперь сохраняет outcome/статус; отрицательный provider response не превращается assert в искусственный unknown, счётчик учитывает начало request. + +Протоколы: [первый partial/failed live](ux-ui/acceptance/telegram197-partial-2026-10-13.json), [полный SQL с simulated provider](ux-ui/acceptance/telegram197-dry-result-2026-10-13.json), [отдельный live retry](ux-ui/acceptance/telegram197-resume-result-2026-10-13.json), [итог и ограничения](ux-ui/acceptance/telegram197-summary-2026-10-13.json). + +Следующий198: настоящий expiry/logout/reissue Portal и безопасный return_to. Первый непрерывный Telegram live сценарий остаётся диагностической границей; повторять его только при достаточной диагностике и основании, а не отправлять дополнительные дубли ради зелёного счётчика.12.5 открыта. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 3a87773e..916eb4f0 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-13. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-13 -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. Этапы0–11 завершены в локальных границах журнала. История выполненных внешних блоков и доказательства сохранены в [журнале](ux-ui-stage-12.md) и [протоколе](ux-ui-external-acceptance.md). Реальная Telegram доставка, Portal SSO, multi-instance и оставшиеся профильные сетевые ограничения открыты. @@ -371,6 +371,6 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index c7f2340d..ac1c8571 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -38,6 +38,18 @@ | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–196 и ограничения ниже. Runtime backend/frontend ux-peak196. | +## 12.5.197 — доставка Telegram и управляемый повтор (2026-10-13) + +Production compiled outbox проверен в собственной временной PostgreSQL БД и ограниченной роли, с реальными JWT Portal и тестовым Telegram bot/chat. Первый live прогон: enqueue с одинаковым dedupeKey сохранил одну запись; два независимых Node sender процесса выполнили одну отправку, одна запись sent и одна history. Telegram принял№2, затем драйвер намеренно подавил ответ: статус unknown, следующая автоматическая диспетчеризация не отправила сообщение повторно. Это контролируемая имитация потерянного ответа, не физический обрыв WAN. + +Reader retry403, отсутствие acknowledgedDuplicateRisk400, admin expectedVersion0→1 с подтверждением риска200, повтор старой версии409. Однако завершающий assert первого полного live прогона sent=1 не прошёл; outcome тогда не был записан. Причина не установлена. Исходный failed протокол сохранён, цельный непрерывный live сценарий не объявляется пройденным. Для локализации полный сценарий с реальной БД/Portal JWT и симулированным Telegram ответом прошёл без сетевых отправок. Далее только оставшаяся ручная отправка проверена на новой собственной unknown fixture: Telegram accepted, status sent, resolutionVersion1, history одна. Это отдельный успешный live тест, не продолжение прежней БД. + +Всего реально приняты3 сообщения: одно TEST197№1 и два одинаковых TEST197№2, последние являются намеренным повтором. Пользователь подтвердил именно это количество. Три own DB/role/container и собственные Portal reader users удалены; временный private bot file на сервере удалён. Рабочие настройки Telegram приложения сохранены для следующих пользовательских проверок. Пароли/конфигурация CHR не менялись, runtime остаётся ux-peak196. Драйвер не входит вtest:all, требует own DB, явный чат и подтверждение риска, имеет отдельный resume режим. Диагностика завершающей отправки теперь сохраняет outcome/статус; отрицательный provider response не превращается assert в искусственный unknown, счётчик учитывает начало request. + +Протоколы: [первый partial/failed live](ux-ui/acceptance/telegram197-partial-2026-10-13.json), [полный SQL с simulated provider](ux-ui/acceptance/telegram197-dry-result-2026-10-13.json), [отдельный live retry](ux-ui/acceptance/telegram197-resume-result-2026-10-13.json), [итог и ограничения](ux-ui/acceptance/telegram197-summary-2026-10-13.json). + +Следующий198: настоящий expiry/logout/reissue Portal и безопасный return_to. Первый непрерывный Telegram live сценарий остаётся диагностической границей; повторять его только при достаточной диагностике и основании, а не отправлять дополнительные дубли ради зелёного счётчика.12.5 открыта. + ## 12.5.196 — приватность серверов и согласованный runtime Portal (2026-10-13) Реальное reader JWT в195 подтверждённо получало plaintext password CHR. Теперь serverReadForUser на HTTP list/detail возвращает password="" для пользователя без mm:servers:write/admin. Writer/admin и прежний AUTH_REQUIRED=false сохраняют existing DTO для редактирования. is_admin сам по себе не заменяет permission. Проекция создаёт копию и не меняет repository rows, хранимые/native credentials или работу collectors. Изменены servers-mapper.ts и два GET handlers routes/servers.ts; внутренние get/listServersRead остаются пригодными для native операций. Это защита этих endpoints, не аудит всех экспортов/secret-bearing DTO проекта. diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index b66ee634..b618ceeb 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,8 +1,8 @@ # Оставшаяся внешняя приёмка — 2026-10-13 -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. -Это актуальная матрица после 12.5.196. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. +Это актуальная матрица после 12.5.197. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend/frontend `ux-peak196`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. @@ -26,7 +26,7 @@ ## Следующая последовательность — 2026-10-13 -1. **197 — реальный Telegram outbox:** dedupe/two senders/unknown hold/explicit retry на собственной БД и тестовом чате.195–196 базовый SSO/Telegram transport, masked server DTO и runtime links приняты. Затем Portal expiry/revoke boundary и crash/lock-loss. +1. **198 — Portal expiry/logout/reissue и return_to:** базовый SSO, reader privacy и Telegram доставки приняты с границами197. После — диагностика цельного Telegram сценария/crash/lock-loss. 2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания. 3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций. @@ -1304,3 +1304,15 @@ Production backend/frontend ux-peak196 развёрнуты.466 backend+525 fron | [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Runtime issuer/Portal → меню приложений → тот же Portal; reader → masked DTO + blocked edit, writer → existing editor | Следующий197: реальная доставка из outbox через собственную временную БД, dedupe/two senders, controlled lost receipt после реального Telegram acceptance, no automatic repeat, explicit acknowledged retry/stale version/RBAC. Планируется3 помеченных test messages, включая намеренный повтор№2; не превращать controlled receipt suppression в физическую WAN/lost-ACK приёмку. Portal JWT revocation доexp, настоящее expiry/refresh/client OS и crash/lock-loss остаются отдельными границами.12.5 открыта. + +## 12.5.197 — доставка Telegram и управляемый повтор (2026-10-13) + +Production compiled outbox проверен в собственной временной PostgreSQL БД и ограниченной роли, с реальными JWT Portal и тестовым Telegram bot/chat. Первый live прогон: enqueue с одинаковым dedupeKey сохранил одну запись; два независимых Node sender процесса выполнили одну отправку, одна запись sent и одна history. Telegram принял№2, затем драйвер намеренно подавил ответ: статус unknown, следующая автоматическая диспетчеризация не отправила сообщение повторно. Это контролируемая имитация потерянного ответа, не физический обрыв WAN. + +Reader retry403, отсутствие acknowledgedDuplicateRisk400, admin expectedVersion0→1 с подтверждением риска200, повтор старой версии409. Однако завершающий assert первого полного live прогона sent=1 не прошёл; outcome тогда не был записан. Причина не установлена. Исходный failed протокол сохранён, цельный непрерывный live сценарий не объявляется пройденным. Для локализации полный сценарий с реальной БД/Portal JWT и симулированным Telegram ответом прошёл без сетевых отправок. Далее только оставшаяся ручная отправка проверена на новой собственной unknown fixture: Telegram accepted, status sent, resolutionVersion1, history одна. Это отдельный успешный live тест, не продолжение прежней БД. + +Всего реально приняты3 сообщения: одно TEST197№1 и два одинаковых TEST197№2, последние являются намеренным повтором. Пользователь подтвердил именно это количество. Три own DB/role/container и собственные Portal reader users удалены; временный private bot file на сервере удалён. Рабочие настройки Telegram приложения сохранены для следующих пользовательских проверок. Пароли/конфигурация CHR не менялись, runtime остаётся ux-peak196. Драйвер не входит вtest:all, требует own DB, явный чат и подтверждение риска, имеет отдельный resume режим. Диагностика завершающей отправки теперь сохраняет outcome/статус; отрицательный provider response не превращается assert в искусственный unknown, счётчик учитывает начало request. + +Протоколы: [первый partial/failed live](ux-ui/acceptance/telegram197-partial-2026-10-13.json), [полный SQL с simulated provider](ux-ui/acceptance/telegram197-dry-result-2026-10-13.json), [отдельный live retry](ux-ui/acceptance/telegram197-resume-result-2026-10-13.json), [итог и ограничения](ux-ui/acceptance/telegram197-summary-2026-10-13.json). + +Следующий198: настоящий expiry/logout/reissue Portal и безопасный return_to. Первый непрерывный Telegram live сценарий остаётся диагностической границей; повторять его только при достаточной диагностике и основании, а не отправлять дополнительные дубли ради зелёного счётчика.12.5 открыта. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 17cbdb17..8f0bb600 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -3693,3 +3693,15 @@ Production backend/frontend ux-peak196 развёрнуты.466 backend+525 fron | [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Runtime issuer/Portal → меню приложений → тот же Portal; reader → masked DTO + blocked edit, writer → existing editor | Следующий197: реальная доставка из outbox через собственную временную БД, dedupe/two senders, controlled lost receipt после реального Telegram acceptance, no automatic repeat, explicit acknowledged retry/stale version/RBAC. Планируется3 помеченных test messages, включая намеренный повтор№2; не превращать controlled receipt suppression в физическую WAN/lost-ACK приёмку. Portal JWT revocation доexp, настоящее expiry/refresh/client OS и crash/lock-loss остаются отдельными границами.12.5 открыта. + +## 12.5.197 — доставка Telegram и управляемый повтор (2026-10-13) + +Production compiled outbox проверен в собственной временной PostgreSQL БД и ограниченной роли, с реальными JWT Portal и тестовым Telegram bot/chat. Первый live прогон: enqueue с одинаковым dedupeKey сохранил одну запись; два независимых Node sender процесса выполнили одну отправку, одна запись sent и одна history. Telegram принял№2, затем драйвер намеренно подавил ответ: статус unknown, следующая автоматическая диспетчеризация не отправила сообщение повторно. Это контролируемая имитация потерянного ответа, не физический обрыв WAN. + +Reader retry403, отсутствие acknowledgedDuplicateRisk400, admin expectedVersion0→1 с подтверждением риска200, повтор старой версии409. Однако завершающий assert первого полного live прогона sent=1 не прошёл; outcome тогда не был записан. Причина не установлена. Исходный failed протокол сохранён, цельный непрерывный live сценарий не объявляется пройденным. Для локализации полный сценарий с реальной БД/Portal JWT и симулированным Telegram ответом прошёл без сетевых отправок. Далее только оставшаяся ручная отправка проверена на новой собственной unknown fixture: Telegram accepted, status sent, resolutionVersion1, history одна. Это отдельный успешный live тест, не продолжение прежней БД. + +Всего реально приняты3 сообщения: одно TEST197№1 и два одинаковых TEST197№2, последние являются намеренным повтором. Пользователь подтвердил именно это количество. Три own DB/role/container и собственные Portal reader users удалены; временный private bot file на сервере удалён. Рабочие настройки Telegram приложения сохранены для следующих пользовательских проверок. Пароли/конфигурация CHR не менялись, runtime остаётся ux-peak196. Драйвер не входит вtest:all, требует own DB, явный чат и подтверждение риска, имеет отдельный resume режим. Диагностика завершающей отправки теперь сохраняет outcome/статус; отрицательный provider response не превращается assert в искусственный unknown, счётчик учитывает начало request. + +Протоколы: [первый partial/failed live](ux-ui/acceptance/telegram197-partial-2026-10-13.json), [полный SQL с simulated provider](ux-ui/acceptance/telegram197-dry-result-2026-10-13.json), [отдельный live retry](ux-ui/acceptance/telegram197-resume-result-2026-10-13.json), [итог и ограничения](ux-ui/acceptance/telegram197-summary-2026-10-13.json). + +Следующий198: настоящий expiry/logout/reissue Portal и безопасный return_to. Первый непрерывный Telegram live сценарий остаётся диагностической границей; повторять его только при достаточной диагностике и основании, а не отправлять дополнительные дубли ради зелёного счётчика.12.5 открыта. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 055018d8..d1abd978 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -1,6 +1,6 @@ # Тестовый сервер UX/UI — 2026-10-10 -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. | Параметр | Проверенное состояние | | --- | --- | @@ -708,7 +708,7 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-13: завершены191–196. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true; reader password redacted вlist/detail, writer/admin сохранены, runtime Portal links исправлены. SQL roles3×2 endpoints/10996ms, E2E41/1.4m, live reader/admin UI4 passed. Telegram базовая доставка подтверждена пользователем. Следующий197 — real Telegram outbox/dedupe/multiple senders/unknown hold/manual retry в собственной временной БД.12.5 открыта. +Актуальное продолжение 2026-10-13: блок197 — Telegram live dedupe/two senders/unknown hold и отдельный explicit retry приняты, пользователь подтвердил одно№1/два№2. Первый полный live прогон не прошёл immediate retry; причина не установлена, цельный live сценарий остаётся открытым. Runtime backend/frontend ux-peak196, Portal1.3.1 healthy, AUTH_REQUIRED=true. Следующий198 — Portal expiry/logout/reissue и return_to;12.5 открыта. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). @@ -2119,3 +2119,15 @@ Production backend/frontend ux-peak196 развёрнуты.466 backend+525 fron | [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Runtime issuer/Portal → меню приложений → тот же Portal; reader → masked DTO + blocked edit, writer → existing editor | Следующий197: реальная доставка из outbox через собственную временную БД, dedupe/two senders, controlled lost receipt после реального Telegram acceptance, no automatic repeat, explicit acknowledged retry/stale version/RBAC. Планируется3 помеченных test messages, включая намеренный повтор№2; не превращать controlled receipt suppression в физическую WAN/lost-ACK приёмку. Portal JWT revocation доexp, настоящее expiry/refresh/client OS и crash/lock-loss остаются отдельными границами.12.5 открыта. + +## 12.5.197 — доставка Telegram и управляемый повтор (2026-10-13) + +Production compiled outbox проверен в собственной временной PostgreSQL БД и ограниченной роли, с реальными JWT Portal и тестовым Telegram bot/chat. Первый live прогон: enqueue с одинаковым dedupeKey сохранил одну запись; два независимых Node sender процесса выполнили одну отправку, одна запись sent и одна history. Telegram принял№2, затем драйвер намеренно подавил ответ: статус unknown, следующая автоматическая диспетчеризация не отправила сообщение повторно. Это контролируемая имитация потерянного ответа, не физический обрыв WAN. + +Reader retry403, отсутствие acknowledgedDuplicateRisk400, admin expectedVersion0→1 с подтверждением риска200, повтор старой версии409. Однако завершающий assert первого полного live прогона sent=1 не прошёл; outcome тогда не был записан. Причина не установлена. Исходный failed протокол сохранён, цельный непрерывный live сценарий не объявляется пройденным. Для локализации полный сценарий с реальной БД/Portal JWT и симулированным Telegram ответом прошёл без сетевых отправок. Далее только оставшаяся ручная отправка проверена на новой собственной unknown fixture: Telegram accepted, status sent, resolutionVersion1, history одна. Это отдельный успешный live тест, не продолжение прежней БД. + +Всего реально приняты3 сообщения: одно TEST197№1 и два одинаковых TEST197№2, последние являются намеренным повтором. Пользователь подтвердил именно это количество. Три own DB/role/container и собственные Portal reader users удалены; временный private bot file на сервере удалён. Рабочие настройки Telegram приложения сохранены для следующих пользовательских проверок. Пароли/конфигурация CHR не менялись, runtime остаётся ux-peak196. Драйвер не входит вtest:all, требует own DB, явный чат и подтверждение риска, имеет отдельный resume режим. Диагностика завершающей отправки теперь сохраняет outcome/статус; отрицательный provider response не превращается assert в искусственный unknown, счётчик учитывает начало request. + +Протоколы: [первый partial/failed live](ux-ui/acceptance/telegram197-partial-2026-10-13.json), [полный SQL с simulated provider](ux-ui/acceptance/telegram197-dry-result-2026-10-13.json), [отдельный live retry](ux-ui/acceptance/telegram197-resume-result-2026-10-13.json), [итог и ограничения](ux-ui/acceptance/telegram197-summary-2026-10-13.json). + +Следующий198: настоящий expiry/logout/reissue Portal и безопасный return_to. Первый непрерывный Telegram live сценарий остаётся диагностической границей; повторять его только при достаточной диагностике и основании, а не отправлять дополнительные дубли ради зелёного счётчика.12.5 открыта. diff --git a/docs/ux-ui/acceptance/telegram197-dry-result-2026-10-13.json b/docs/ux-ui/acceptance/telegram197-dry-result-2026-10-13.json new file mode 100644 index 00000000..d1993888 --- /dev/null +++ b/docs/ux-ui/acceptance/telegram197-dry-result-2026-10-13.json @@ -0,0 +1,57 @@ +{ + "date": "2026-10-13", + "block": "12.5.197", + "database": "mm_accept_166_1791881369983", + "scope": "Production compiled outbox, owned PostgreSQL, actual Portal JWT and real Telegram provider", + "cases": [ + { + "name": "dedupe and independent senders", + "senders": 2, + "queuedRows": 1, + "providerSends": 1, + "sentHistoryRows": 1 + }, + { + "name": "controlled lost receipt", + "providerAccepted": true, + "status": "unknown", + "automaticResend": false, + "physicalDisconnect": false + }, + { + "name": "explicit retry with real Portal JWT", + "reader": 403, + "missingAck": 400, + "admin": 200, + "staleVersion": 409, + "resolutionVersion": 1, + "intentionalDuplicate": true, + "sentHistoryRows": 2 + } + ], + "providerSendCalls": 3, + "providerAcceptanceIds": [ + 100, + 1, + 2 + ], + "ownPortalUsersRemoved": true, + "passed": true, + "retryDiagnostic": { + "outcome": { + "sent": 1, + "failed": 0, + "held": 0, + "errors": [] + }, + "rows": [ + { + "status": "sent", + "retry_count": 0, + "resolution_version": 1, + "next_attempt_at": "2026-10-13T08:49:39.235Z", + "last_error": null + } + ] + } +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/telegram197-partial-2026-10-13.json b/docs/ux-ui/acceptance/telegram197-partial-2026-10-13.json new file mode 100644 index 00000000..9d849fd1 --- /dev/null +++ b/docs/ux-ui/acceptance/telegram197-partial-2026-10-13.json @@ -0,0 +1,30 @@ +{ + "date": "2026-10-13", + "block": "12.5.197", + "database": "mm_accept_166_1791880757291", + "scope": "Production compiled outbox, owned PostgreSQL, actual Portal JWT and real Telegram provider", + "cases": [ + { + "name": "dedupe and independent senders", + "senders": 2, + "queuedRows": 1, + "providerSends": 1, + "sentHistoryRows": 1 + }, + { + "name": "controlled lost receipt", + "providerAccepted": true, + "status": "unknown", + "automaticResend": false, + "physicalDisconnect": false + } + ], + "providerSendCalls": 2, + "providerAcceptanceIds": [ + 3, + 4 + ], + "ownPortalUsersRemoved": true, + "passed": false, + "errorName": "AssertionError" +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/telegram197-resume-result-2026-10-13.json b/docs/ux-ui/acceptance/telegram197-resume-result-2026-10-13.json new file mode 100644 index 00000000..2a3f0dbb --- /dev/null +++ b/docs/ux-ui/acceptance/telegram197-resume-result-2026-10-13.json @@ -0,0 +1,48 @@ +{ + "date": "2026-10-13", + "block": "12.5.197", + "database": "mm_accept_166_1791881442739", + "resumeOnly": true, + "scope": "Production compiled outbox, owned PostgreSQL, actual Portal JWT and real Telegram provider", + "cases": [ + { + "name": "resume fixture", + "status": "unknown", + "providerSend": false, + "priorLiveEvidence": "telegram197-partial.json" + }, + { + "name": "explicit retry with real Portal JWT", + "reader": 403, + "missingAck": 400, + "admin": 200, + "staleVersion": 409, + "resolutionVersion": 1, + "intentionalDuplicate": true, + "sentHistoryRows": 1 + } + ], + "providerSendCalls": 1, + "providerAcceptanceIds": [ + 5 + ], + "ownPortalUsersRemoved": true, + "passed": true, + "retryDiagnostic": { + "outcome": { + "sent": 1, + "failed": 0, + "held": 0, + "errors": [] + }, + "rows": [ + { + "status": "sent", + "retry_count": 0, + "resolution_version": 1, + "next_attempt_at": "2026-10-13T08:50:49.443Z", + "last_error": null + } + ] + } +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/telegram197-summary-2026-10-13.json b/docs/ux-ui/acceptance/telegram197-summary-2026-10-13.json new file mode 100644 index 00000000..ff7fa7c8 --- /dev/null +++ b/docs/ux-ui/acceptance/telegram197-summary-2026-10-13.json @@ -0,0 +1,42 @@ +{ + "date": "2026-10-13", + "block": "12.5.197", + "humanReceipt": { + "confirmed": true, + "message1": 1, + "message2": 2 + }, + "providerAcceptedMessages": 3, + "livePartialCases": [ + "dedupe", + "two independent sender processes", + "controlled receipt suppression after real provider acceptance", + "unknown not automatically resent" + ], + "liveResumeCases": [ + "reader 403", + "missing duplicate ack 400", + "admin CAS 200", + "stale version 409", + "provider accepted explicit resend", + "sent state and history committed" + ], + "dryProvider": { + "fullScenarioPassed": true, + "realOwnedPostgreSQL": true, + "realPortalJWT": true, + "telegramNetwork": false + }, + "cleanup": { + "threeOwnedDatabasesAndRolesRemoved": true, + "ownPortalUsersRemoved": true, + "temporaryBotPrivateFileRemoved": true + }, + "limitations": [ + "First complete live run failed asserting immediate resend sent=1; outcome was not captured. Cause remains unresolved.", + "Successful live retry used a new owned unknown-row fixture; it was not continuation of the same database transaction chain.", + "Lost receipt was injected after provider acceptance, not a physical WAN disconnect.", + "No single uninterrupted full live pass claimed." + ], + "runtimeChanged": false +} \ No newline at end of file