Project

General

Profile

缺陷 #4 » http-round4-case-results.md

Redmine Admin, 10/06/2026 04:32 PM

 

QA 测试结果 - 独立真实HTTP第4轮 - BFF日期兼容修复复验 - 2026-10-07

环境/候选/门禁

2026-10-07 00:29 Asia/Shanghai,QA Agent。本机PG16 tmpfs 56488,独立ndb_qa/mp_conference_test;真实NDB18000、最新源独立编译BFF13000、mockNotification13001,均仅localhost。合成JWT/应用签名,无真实微信/手机号认证、现有业务库或真实邮件。

Backend HEAD444afbe26f529dd59c23b29ca4309e5dfabeb105,BFF HEADcb70aee75e7230ea6eb57a2203021c403f1dccfb及未提交候选。Backend serializer SHA256611bc92ed9d1c5d84abd8318a50c9ae41232275a454cea0c5588831c0b1de958;修复后BFF adapter SHA25615bf6cbd4389fa97d863899680b0419f9fc1b647356c70459e5ca7d7ad83b5d7,隔离编译JS SHA256a937103e1890283f8fcd508e869a3316d3e7b128ac83239873ce29c7b3d2bb4d。

操作:激活crm_backend后运行outputs/http_integration.cjs;脚本屏蔽Backend .env读取、迁移新库、seed合成0h会议、启动真实HTTP、仅推进B1/B2时间并自动停止专用资源。新增“权威GET保留naive微秒”用例,原33变34,编号按名称比对旧轮。

汇总:34计划,34Pass/0Fail/0Blocked。前3轮失败和阻塞保留于http-case-results.md、http-round1/2/3-results.json,不改成通过。本轮证明缺陷#4真实HTTP复验通过,不代表真实微信完整流程。

逐例

ID 用例/层级 前置与操作 预期 实际 状态 证据/时间/缺陷
R4-HTTP-001 Real NDB+BFF channel readiness / HTTP+PG Dedicated ports/databases;GET /health/ready NDB signed ping and PG both up {"status":"ok","channelDb":"up","ndb":"up"} Pass http-integration-results.json;2026-10-06T16:29:26.804Z;#4复验范围
R4-HTTP-002 Synthetic zero-contract empty baseline / HTTP+PG Fresh migration and seed;Read isolated ORM snapshot 0 Registration, 0 Tasks, 0 Contracts {"registrations":[],"tasks":[],"contract_count":0} Pass http-integration-results.json;2026-10-06T16:29:26.804Z;#4复验范围
R4-HTTP-003 Anonymous minutes write denied / HTTP+PG No JWT;PUT A minutes 401 UNAUTHENTICATED, no mutation {"status":401,"data":{"error":{"code":"UNAUTHENTICATED","message":"请先登录"},"requestId":"6def3d9e-6172-415e-863e-151132724f73"}} Pass http-integration-results.json;2026-10-06T16:29:27.556Z;#4复验范围
R4-HTTP-004 Unbound synthetic JWT denied / HTTP+PG User lacks phone/contact;PUT A minutes 403 CONTACT_NOT_BOUND {"status":403,"data":{"error":{"code":"CONTACT_NOT_BOUND","message":"请先绑定客户联系人"},"requestId":"682e586e-8537-4a7a-95e8-eafc68a29d72"}} Pass http-integration-results.json;2026-10-06T16:29:27.558Z;#4复验范围
R4-HTTP-005 Legacy subscription is not reservation / HTTP+PG Only old channel subscription seeded;GET A minutes JSON null, no NDB Task {"reservation":null,"taskCount":0} Pass http-integration-results.json;2026-10-06T16:29:27.567Z;#4复验范围
R4-HTTP-006 A started free minutes-only created / HTTP+PG A started,0h,no contract;PUT A minutes reserved+unified Registration/Task {"id":"1","meetingId":"1","clientContactId":"2","taskId":"1","status":"reserved","createdAt":"2026-10-07T00:29:28.409211"} Pass http-integration-results.json;2026-10-06T16:29:28.357Z;#4复验范围
R4-HTTP-007 A same-key retry reuses ids / HTTP+PG A reserved;Repeat PUT same key Same registration/task ids {"id":"1","meetingId":"1","clientContactId":"2","taskId":"1","status":"reserved","createdAt":"2026-10-07T00:29:28.409211"} Pass http-integration-results.json;2026-10-06T16:29:28.414Z;#4复验范围
R4-HTTP-008 A authoritative GET preserves server naive microseconds / HTTP+PG A reserved after replay;GET A minutes same ids and exact createdAt string {"id":"1","meetingId":"1","clientContactId":"2","taskId":"1","status":"reserved","createdAt":"2026-10-07T00:29:28.409211"} Pass http-integration-results.json;2026-10-06T16:29:28.452Z;#4复验范围
R4-HTTP-009 A concurrent natural retries on real PG / HTTP+PG A reserved; threaded real Backend;6 parallel PUT with distinct keys All same ids and only one Task {"responses":6,"registrationId":"1","taskId":"1","taskCount":1} Pass http-integration-results.json;2026-10-06T16:29:28.487Z;#4复验范围
R4-HTTP-010 A minutes-only has no attendance projection / HTTP+PG A minutes requested only;GET A registration JSON null null Pass http-integration-results.json;2026-10-06T16:29:29.352Z;#4复验范围
R4-HTTP-011 A absent myMeetings and present myMinutes / HTTP+PG A minutes-only;GET both lists Attendance empty; minutes contains A {"myMeetings":0,"myMinutes":1} Pass http-integration-results.json;2026-10-06T16:29:29.394Z;#4复验范围
R4-HTTP-012 A minutes-only cannot obtain join link / HTTP+PG A already started;GET A join-link visible=false,joinUrl=null {"visible":false,"joinUrl":null,"reason":"REGISTRATION_REQUIRED"} Pass http-integration-results.json;2026-10-06T16:29:29.483Z;#4复验范围
R4-HTTP-013 A cannot add attendance after start / HTTP+PG A started,minutes-only;POST A registration MEETING_NOT_OPEN without new Task {"status":409,"data":{"error":{"code":"MEETING_NOT_OPEN","message":"会议当前不可报名"},"requestId":"5f775969-8e2c-48fe-bd92-b16e7b15eb49"}} Pass http-integration-results.json;2026-10-06T16:29:29.527Z;#4复验范围
R4-HTTP-014 B1 minutes first while not started / HTTP+PG B1 future,0h;PUT B1 minutes reserved {"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"} Pass http-integration-results.json;2026-10-06T16:29:30.361Z;#4复验范围
R4-HTTP-015 B1 then attendance shares Registration/Task / HTTP+PG B1 minutes first;POST B1 registration + isolated snapshot same id/task, both flags {"projection":{"id":"2","meetingId":"2","status":"confirmed"},"record":{"id":2,"meeting_id":2,"client_contact_id":2,"task_id":2,"attend_requested":true,"minutes_requested":true,"status":"confirmed"}} Pass http-integration-results.json;2026-10-06T16:29:30.416Z;#4复验范围
R4-HTTP-016 B1 future join link withheld / HTTP+PG B1 both intents before start;GET join-link visible=false {"visible":false,"joinUrl":null,"reason":"MEETING_NOT_OPEN"} Pass http-integration-results.json;2026-10-06T16:29:31.223Z;#4复验范围
R4-HTTP-017 B2 attendance first while not started / HTTP+PG B2 future,0h;POST B2 registration confirmed {"id":"3","meetingId":"3","status":"confirmed"} Pass http-integration-results.json;2026-10-06T16:29:31.254Z;#4复验范围
R4-HTTP-018 B2 then minutes shares Registration/Task / HTTP+PG B2 attend first;PUT B2 minutes + snapshot same id,task, both flags {"reservation":{"id":"3","meetingId":"3","clientContactId":"2","taskId":"3","status":"reserved","createdAt":"2026-10-07T00:29:31.297439"},"record":{"id":3,"meeting_id":3,"client_contact_id":2,"task_id":3,"attend_requested":true,"minutes_requested":true,"status":"confirmed"}} Pass http-integration-results.json;2026-10-06T16:29:31.301Z;#4复验范围
R4-HTTP-019 Both intentions appear in separate lists / HTTP+PG A minutes-only,B1/B2 both;GET both my lists myMeetings=2,myMinutes=3 {"myMeetings":2,"myMinutes":3} Pass http-integration-results.json;2026-10-06T16:29:32.908Z;#4复验范围
R4-HTTP-020 Future B1 cancel keeps minutes and Task / HTTP+PG B1 future,both;DELETE registration cancelled;same reserved minutes and ongoing Task {"registration":{"id":"2","meetingId":"2","status":"cancelled"},"reservation":{"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"},"taskStatus":"ongoing"} Pass http-integration-results.json;2026-10-06T16:29:32.989Z;#4复验范围
R4-HTTP-021 Future B1 reattend reuses id/Task / HTTP+PG B1 cancelled but future;POST registration fresh key confirmed,same ids,3 Tasks total {"id":"2","meetingId":"2","status":"confirmed"} Pass http-integration-results.json;2026-10-06T16:29:33.910Z;#4复验范围
R4-HTTP-022 Advance only isolated B fixtures to started / HTTP+PG B1/B2 future registration complete;Guarded synthetic ORM time update Only B1/B2 updated {"advanced":[2,3]} Pass http-integration-results.json;2026-10-06T16:29:34.732Z;#4复验范围
R4-HTTP-023 Started attendee B1 obtains link / HTTP+PG B1 advanced,confirmed;GET join-link visible=true synthetic invalid-domain link {"visible":true,"joinUrl":"https://qa-meeting.example.invalid/join/B1_minutes_attend","reason":null} Pass http-integration-results.json;2026-10-06T16:29:35.508Z;#4复验范围
R4-HTTP-024 Started attendee B2 obtains link / HTTP+PG B2 advanced,confirmed;GET join-link visible=true {"visible":true,"joinUrl":"https://qa-meeting.example.invalid/join/B2_attend_minutes","reason":null} Pass http-integration-results.json;2026-10-06T16:29:35.550Z;#4复验范围
R4-HTTP-025 Started B1 cancel preserves minutes Task / HTTP+PG B1 started,both;DELETE registration + snapshot cancelled and minutes same ids/ongoing Task {"registration":{"id":"2","meetingId":"2","status":"cancelled"},"reservation":{"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"}} Pass http-integration-results.json;2026-10-06T16:29:35.586Z;#4复验范围
R4-HTTP-026 Cancelled started B1 loses link / HTTP+PG B1 cancelled,minutes retained;GET join-link visible=false,no link {"visible":false,"joinUrl":null,"reason":"REGISTRATION_REQUIRED"} Pass http-integration-results.json;2026-10-06T16:29:36.486Z;#4复验范围
R4-HTTP-027 Started B1 cannot restore attendance / HTTP+PG B1 cancelled after start;POST attend fresh key MEETING_NOT_OPEN,no extra Task {"status":409,"data":{"error":{"code":"MEETING_NOT_OPEN","message":"会议当前不可报名"},"requestId":"f261e04e-d31e-4dbc-ae31-145be5e9c02f"}} Pass http-integration-results.json;2026-10-06T16:29:36.520Z;#4复验范围
R4-HTTP-028 Started B1 repeated minutes retained / HTTP+PG B1 cancelled attendee,minutes active;PUT minutes fresh key same reserved id/task {"id":"2","meetingId":"2","clientContactId":"2","taskId":"2","status":"reserved","createdAt":"2026-10-07T00:29:30.412283"} Pass http-integration-results.json;2026-10-06T16:29:37.344Z;#4复验范围
R4-HTTP-029 Started B2 cancel preserves same minutes Task / HTTP+PG B2 opposite order;DELETE registration cancelled,same minutes id/task {"registration":{"id":"3","meetingId":"3","status":"cancelled"},"reservation":{"id":"3","meetingId":"3","clientContactId":"2","taskId":"3","status":"reserved","createdAt":"2026-10-07T00:29:31.297439"}} Pass http-integration-results.json;2026-10-06T16:29:37.390Z;#4复验范围
R4-HTTP-030 All free Tasks remain zero and unique / HTTP+PG A/B1/B2 complete;Read isolated snapshot 3 registrations,3 unique Tasks,0 contracts,all prices0 {"registrations":[{"id":1,"meeting_id":1,"client_contact_id":2,"task_id":1,"attend_requested":false,"minutes_requested":true,"status":"confirmed"},{"id":2,"meeting_id":2,"client_contact_id":2,"task_id":2,"attend_requested":true,"minutes_requested":true,"status":"cancelled"},{"id":3,"meeting_id":3,"client_contact_id":2,"task_id":3,"attend_requested":true,"minutes_requested":true,"status":"cancelled"}],"tasks":[{"id":1,"status":"ongoing","contract_id":null,"charge_total_hours":"0.0000","actual_price":"0.00","total_price":"0.00"},{"id":2,"status":"ongoing","contract_id":null,"charge_total_hours":"0.0000","actual_price":"0.00","total_price":"0.00"},{"id":3,"status":"ongoing","contract_id":null,"charge_total_hours":"0.0000","actual_price":"0.00","total_price":"0.00"}],"contract_count":0} Pass http-integration-results.json;2026-10-06T16:29:37.464Z;#4复验范围
R4-HTTP-031 Synthetic paid no contract rejects without mutation / HTTP+PG D synthetic1h,no contracts;PUT D minutes NO_ACTIVE_CONTRACT,still3 Tasks {"status":409,"data":{"error":{"code":"NO_ACTIVE_CONTRACT","message":"当前客户暂无有效合同,请联系客户经理开通后再报名"},"requestId":"e5e32c49-8b3e-48f0-ad21-a43a50da7cde"}} Pass http-integration-results.json;2026-10-06T16:29:38.248Z;#4复验范围
R4-HTTP-032 Real PG refusal outbox durable and deduplicated / HTTP+PG D denied;Repeat rejection+PG SELECT one pending row,not reservation [{"meeting_id":"4","state":"pending","attempts":0,"accepted_at":null}] Pass http-integration-results.json;2026-10-06T16:29:39.079Z;#4复验范围
R4-HTTP-033 Refusal persists across real BFF restart and mock acceptance / HTTP+PG Outbox stored in real PG;Stop/restart BFF; bootstrap dispatch to mock13001 same row accepted once;no real email {"outbox":{"state":"accepted","attempts":1,"accepted_at":"2026-10-06T16:29:39.777Z"},"mockRequests":1,"realEmails":0} Pass http-integration-results.json;2026-10-06T16:29:39.132Z;#4复验范围
R4-HTTP-034 Accepted refusal never becomes successful reservation / HTTP+PG D notice accepted by mock;GET D minutes;GET myMinutes;snapshot null,D absent,3 Tasks {"reservation":null,"myMinutes":3,"taskCount":3} Pass http-integration-results.json;2026-10-06T16:29:39.930Z;#4复验范围

独立断言结论及边界

A:minutes-only,attend=false,registration GET null,myMeetings无A,myMinutes有A,已开始无join。相同键重放及6个并行新键请求仍1记录/Task,权威GET返回同id/task和原始naive微秒,不补Z。

B1 minutes→attend:Registration.id=2/Task.id=2;B2 attend→minutes:id=3/task=3。尚未开始时先完成两意图,然后只推进这两条合成会议时间,两者获得synthetic example.invalid入会链接。取消参会后minutes保留同id/task,B1无入会权且不能在开始后恢复参会。三个免费Task全部ongoing、contract=null、actual/total_price=0,数目3,无重复计费。

D为合成1h/no-contract,业务拒绝NO_ACTIVE_CONTRACT,仍只有3Task。PG outbox只有1条;BFF真实重启后同条outbox accepted/attempts=1,mock13001接收1次,实际员工邮件0。accepted只表示本地mock HTTP接受,不表示投递;拒绝不能变成成功预约,D不在myMinutes。

资源与手册

Backend PID53599、BFF PID53601/53625均SIGTERM停止;明确QA容器ndb-qa-minutes-http-20261007-56488停止,四端口lsof无监听。tmpfs丢失仅本轮合成数据,无现有数据删除;保留日志。未改业务源码/共享Mini产物,未commit/push/deploy。

UI+Mini已复核手册3图只读范围。HTTP成功不新增“成功预约”UI截图;原生暂不登录、真实微信/手机号认证和完整成功手册仍未覆盖。此前单元/模拟322项属于旧BFF候选;本轮BFF全量独立127/127,最新跨端单元/模拟汇总331项330Pass/1旧Mini样式Fail;HTTP34单列不混算。

(3-3/4)