# QA 测试结果 - 预约纪要独立真实HTTP契约 - 2026-10-07 环境:独立PG16 tmpfs端口56488,ndb_qa/mp_conference_test;真实Backend18000+BFF13000,mockNotification13001。合成JWT/AK,没有真实微信或邮件。不读.env、不接现有库。候选与源码摘要见http-contract-defect.md。QA仅修改outputs辅助程序,产品业务源码未改。 当前第三轮:33计划,实际6,5Pass/1Fail/27Blocked。第1轮实际3,2Pass/1测试脚本Fail(error.code读取错误,已修正);第2轮实际6,5Pass/1真实契约Fail;第3轮相同缺陷附原始NDBGET及PG快照。重跑不累计成独立用例数。真实缺陷 [NDB #4](https://redmine.mindsetech.com/issues/4)。第1轮脚本问题不是产品缺陷。 ## 第1轮 (实际执行) | ID | 名称/层级 | 前置/操作 | 预期 | 实际 | 状态 | 证据/缺陷/时间 | | --- | --- | --- | --- | --- | --- | --- | | R1-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-round1-results.json;2026-10-06T16:24:32.920Z | | R1-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-round1-results.json;2026-10-06T16:24:32.921Z | | R1-HTTP-003 | Anonymous minutes write denied / HTTP+PG | No JWT;PUT A minutes | 401 UNAUTHENTICATED, no mutation | Expected values to be strictly equal: + actual - expected + undefined - 'UNAUTHENTICATED' | Fail | http-round1-results.json;2026-10-06T16:24:33.711Z;QA脚本读取错误已修正(非产品缺陷) | ## 第2轮 (实际执行) | ID | 名称/层级 | 前置/操作 | 预期 | 实际 | 状态 | 证据/缺陷/时间 | | --- | --- | --- | --- | --- | --- | --- | | R2-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-round2-results.json;2026-10-06T16:25:16.992Z | | R2-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-round2-results.json;2026-10-06T16:25:16.992Z | | R2-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":"727c6e9f-eec0-4059-ae09-bd8e3a6ffd4b"}} | Pass | http-round2-results.json;2026-10-06T16:25:17.811Z | | R2-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":"1b04e380-2638-4bde-bbf8-562e538f5652"}} | Pass | http-round2-results.json;2026-10-06T16:25:17.814Z | | R2-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-round2-results.json;2026-10-06T16:25:17.824Z | | R2-HTTP-006 | A started free minutes-only created / HTTP+PG | A started,0h,no contract;PUT A minutes | reserved+unified Registration/Task | {"status":502,"data":{"error":{"code":"NDB_CONTRACT_ERROR","message":"上游响应格式异常"},"requestId":"779c8c45-ea09-4ef1-86e0-beb00e029ebd"}} | Fail | http-round2-results.json;2026-10-06T16:25:18.628Z;缺陷#4 | ## 第3轮 (最终33项计划含依赖阻塞) | ID | 名称/层级 | 前置/操作 | 预期 | 实际 | 状态 | 证据/缺陷/时间 | | --- | --- | --- | --- | --- | --- | --- | | R3-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:26:07.205Z | | R3-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:26:07.205Z | | R3-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":"5b0eba33-be90-453c-94e7-8cd54ae9f0a9"}} | Pass | http-integration-results.json;2026-10-06T16:26:07.988Z | | R3-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":"d6fc51dc-c9be-4257-8bed-1865ca970fbe"}} | Pass | http-integration-results.json;2026-10-06T16:26:07.990Z | | R3-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:26:08.000Z | | R3-HTTP-006 | A started free minutes-only created / HTTP+PG | A started,0h,no contract;PUT A minutes | reserved+unified Registration/Task | {"status":502,"data":{"error":{"code":"NDB_CONTRACT_ERROR","message":"上游响应格式异常"},"requestId":"c7586089-567e-4a07-8c1c-63832cead135"}} | Fail | http-integration-results.json;2026-10-06T16:26:08.827Z;缺陷#4 | | R3-HTTP-007 | A same-key retry reuses ids / HTTP+PG | A reserved;Repeat PUT same key | Same registration/task ids | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-008 | 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 | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-009 | A minutes-only has no attendance projection / HTTP+PG | A minutes requested only;GET A registration | JSON null | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-010 | A absent myMeetings and present myMinutes / HTTP+PG | A minutes-only;GET both lists | Attendance empty; minutes contains A | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-011 | A minutes-only cannot obtain join link / HTTP+PG | A already started;GET A join-link | visible=false,joinUrl=null | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-012 | A cannot add attendance after start / HTTP+PG | A started,minutes-only;POST A registration | MEETING_NOT_OPEN without new Task | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-013 | B1 minutes first while not started / HTTP+PG | B1 future,0h;PUT B1 minutes | reserved | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-014 | B1 then attendance shares Registration/Task / HTTP+PG | B1 minutes first;POST B1 registration + isolated snapshot | same id/task, both flags | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-015 | B1 future join link withheld / HTTP+PG | B1 both intents before start;GET join-link | visible=false | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-016 | B2 attendance first while not started / HTTP+PG | B2 future,0h;POST B2 registration | confirmed | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-017 | B2 then minutes shares Registration/Task / HTTP+PG | B2 attend first;PUT B2 minutes + snapshot | same id,task, both flags | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-018 | Both intentions appear in separate lists / HTTP+PG | A minutes-only,B1/B2 both;GET both my lists | myMeetings=2,myMinutes=3 | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-019 | Future B1 cancel keeps minutes and Task / HTTP+PG | B1 future,both;DELETE registration | cancelled;same reserved minutes and ongoing Task | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-020 | Future B1 reattend reuses id/Task / HTTP+PG | B1 cancelled but future;POST registration fresh key | confirmed,same ids,3 Tasks total | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-021 | Advance only isolated B fixtures to started / HTTP+PG | B1/B2 future registration complete;Guarded synthetic ORM time update | Only B1/B2 updated | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-022 | Started attendee B1 obtains link / HTTP+PG | B1 advanced,confirmed;GET join-link | visible=true synthetic invalid-domain link | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-023 | Started attendee B2 obtains link / HTTP+PG | B2 advanced,confirmed;GET join-link | visible=true | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-024 | Started B1 cancel preserves minutes Task / HTTP+PG | B1 started,both;DELETE registration + snapshot | cancelled and minutes same ids/ongoing Task | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-025 | Cancelled started B1 loses link / HTTP+PG | B1 cancelled,minutes retained;GET join-link | visible=false,no link | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-026 | Started B1 cannot restore attendance / HTTP+PG | B1 cancelled after start;POST attend fresh key | MEETING_NOT_OPEN,no extra Task | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-027 | Started B1 repeated minutes retained / HTTP+PG | B1 cancelled attendee,minutes active;PUT minutes fresh key | same reserved id/task | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-028 | Started B2 cancel preserves same minutes Task / HTTP+PG | B2 opposite order;DELETE registration | cancelled,same minutes id/task | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-029 | 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 | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-030 | Synthetic paid no contract rejects without mutation / HTTP+PG | D synthetic1h,no contracts;PUT D minutes | NO_ACTIVE_CONTRACT,still3 Tasks | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-031 | Real PG refusal outbox durable and deduplicated / HTTP+PG | D denied;Repeat rejection+PG SELECT | one pending row,not reservation | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-032 | 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 | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | | R3-HTTP-033 | Accepted refusal never becomes successful reservation / HTTP+PG | D notice accepted by mock;GET D minutes;GET myMinutes;snapshot | null,D absent,3 Tasks | 未执行:依赖HTTP-006成功;NDB已写入但BFF502,等待#4修复后继续 | Blocked | http-integration-results.json | ## 最短根因与资源收尾 第三轮原始NDBGET200:id/meeting_id/client_contact_id/task_id为number 1/1/2/1;attend_requested=false、minutes_requested=true均boolean;status='reserved' string;created_at='2026-10-07T00:26:08.883534' string无offset。BFF日期校验独立safeParse=false。真实NDB内部一条Registration与一条Task,contract=null、费用0、Task ongoing;客户端502不代表后端没写入。同幂等键PUT重试及GET前端权威状态尚未完成,修复后必须实测。 三轮专用Backend/BFF PID均已停止,containerStopped=true;明确容器ndb-qa-minutes-http-20261007-56488 Exited(0),lsof核对56488/18000/13000/13001无监听。tmpfs只清除本轮合成数据,日志保留;现有业务库、共享小程序产物、员工邮件均未碰。 ## 手册审核收口 minutes-reservation.md已改“无可用合同异常”和“分析师纪要显示未生成”,头部/尾部统一标UI与Mini复核通过,仅3图未登录入口→登录页→原会议返回。没有成功预约图或真实微信登录E2E,不能因HTTP进度扩张手册范围。源码修复由协调方路由BFF Agent,QA不实施;收到修复冻结和复验释放后复用既有独立验证权限。