{
  "run": "2026-10-07 isolated real HTTP",
  "ports": {
    "postgres": 56488,
    "backend": 18000,
    "bff": 13000,
    "notificationMock": 13001
  },
  "fixture": {
    "meetings": {
      "A_started": 1,
      "B1_minutes_attend": 2,
      "B2_attend_minutes": 3,
      "D_paid_no_contract": 4
    },
    "contact_id": 2,
    "contract_count": 0
  },
  "checks": [
    {
      "id": "HTTP-001",
      "name": "Real NDB+BFF channel readiness",
      "precondition": "Dedicated ports/databases",
      "action": "GET /health/ready",
      "expected": "NDB signed ping and PG both up",
      "at": "2026-10-06T16:29:26.804Z",
      "actual": {
        "status": "ok",
        "channelDb": "up",
        "ndb": "up"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-002",
      "name": "Synthetic zero-contract empty baseline",
      "precondition": "Fresh migration and seed",
      "action": "Read isolated ORM snapshot",
      "expected": "0 Registration, 0 Tasks, 0 Contracts",
      "at": "2026-10-06T16:29:26.804Z",
      "actual": {
        "registrations": [],
        "tasks": [],
        "contract_count": 0
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-003",
      "name": "Anonymous minutes write denied",
      "precondition": "No JWT",
      "action": "PUT A minutes",
      "expected": "401 UNAUTHENTICATED, no mutation",
      "at": "2026-10-06T16:29:27.556Z",
      "actual": {
        "status": 401,
        "data": {
          "error": {
            "code": "UNAUTHENTICATED",
            "message": "请先登录"
          },
          "requestId": "6def3d9e-6172-415e-863e-151132724f73"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-004",
      "name": "Unbound synthetic JWT denied",
      "precondition": "User lacks phone/contact",
      "action": "PUT A minutes",
      "expected": "403 CONTACT_NOT_BOUND",
      "at": "2026-10-06T16:29:27.558Z",
      "actual": {
        "status": 403,
        "data": {
          "error": {
            "code": "CONTACT_NOT_BOUND",
            "message": "请先绑定客户联系人"
          },
          "requestId": "682e586e-8537-4a7a-95e8-eafc68a29d72"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-005",
      "name": "Legacy subscription is not reservation",
      "precondition": "Only old channel subscription seeded",
      "action": "GET A minutes",
      "expected": "JSON null, no NDB Task",
      "at": "2026-10-06T16:29:27.567Z",
      "actual": {
        "reservation": null,
        "taskCount": 0
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-006",
      "name": "A started free minutes-only created",
      "precondition": "A started,0h,no contract",
      "action": "PUT A minutes",
      "expected": "reserved+unified Registration/Task",
      "at": "2026-10-06T16:29:28.357Z",
      "actual": {
        "id": "1",
        "meetingId": "1",
        "clientContactId": "2",
        "taskId": "1",
        "status": "reserved",
        "createdAt": "2026-10-07T00:29:28.409211"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-007",
      "name": "A same-key retry reuses ids",
      "precondition": "A reserved",
      "action": "Repeat PUT same key",
      "expected": "Same registration/task ids",
      "at": "2026-10-06T16:29:28.414Z",
      "actual": {
        "id": "1",
        "meetingId": "1",
        "clientContactId": "2",
        "taskId": "1",
        "status": "reserved",
        "createdAt": "2026-10-07T00:29:28.409211"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-008",
      "name": "A authoritative GET preserves server naive microseconds",
      "precondition": "A reserved after replay",
      "action": "GET A minutes",
      "expected": "same ids and exact createdAt string",
      "at": "2026-10-06T16:29:28.452Z",
      "actual": {
        "id": "1",
        "meetingId": "1",
        "clientContactId": "2",
        "taskId": "1",
        "status": "reserved",
        "createdAt": "2026-10-07T00:29:28.409211"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-009",
      "name": "A concurrent natural retries on real PG",
      "precondition": "A reserved; threaded real Backend",
      "action": "6 parallel PUT with distinct keys",
      "expected": "All same ids and only one Task",
      "at": "2026-10-06T16:29:28.487Z",
      "actual": {
        "responses": 6,
        "registrationId": "1",
        "taskId": "1",
        "taskCount": 1
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-010",
      "name": "A minutes-only has no attendance projection",
      "precondition": "A minutes requested only",
      "action": "GET A registration",
      "expected": "JSON null",
      "at": "2026-10-06T16:29:29.352Z",
      "actual": null,
      "status": "Pass"
    },
    {
      "id": "HTTP-011",
      "name": "A absent myMeetings and present myMinutes",
      "precondition": "A minutes-only",
      "action": "GET both lists",
      "expected": "Attendance empty; minutes contains A",
      "at": "2026-10-06T16:29:29.394Z",
      "actual": {
        "myMeetings": 0,
        "myMinutes": 1
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-012",
      "name": "A minutes-only cannot obtain join link",
      "precondition": "A already started",
      "action": "GET A join-link",
      "expected": "visible=false,joinUrl=null",
      "at": "2026-10-06T16:29:29.483Z",
      "actual": {
        "visible": false,
        "joinUrl": null,
        "reason": "REGISTRATION_REQUIRED"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-013",
      "name": "A cannot add attendance after start",
      "precondition": "A started,minutes-only",
      "action": "POST A registration",
      "expected": "MEETING_NOT_OPEN without new Task",
      "at": "2026-10-06T16:29:29.527Z",
      "actual": {
        "status": 409,
        "data": {
          "error": {
            "code": "MEETING_NOT_OPEN",
            "message": "会议当前不可报名"
          },
          "requestId": "5f775969-8e2c-48fe-bd92-b16e7b15eb49"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-014",
      "name": "B1 minutes first while not started",
      "precondition": "B1 future,0h",
      "action": "PUT B1 minutes",
      "expected": "reserved",
      "at": "2026-10-06T16:29:30.361Z",
      "actual": {
        "id": "2",
        "meetingId": "2",
        "clientContactId": "2",
        "taskId": "2",
        "status": "reserved",
        "createdAt": "2026-10-07T00:29:30.412283"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-015",
      "name": "B1 then attendance shares Registration/Task",
      "precondition": "B1 minutes first",
      "action": "POST B1 registration + isolated snapshot",
      "expected": "same id/task, both flags",
      "at": "2026-10-06T16:29:30.416Z",
      "actual": {
        "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"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-016",
      "name": "B1 future join link withheld",
      "precondition": "B1 both intents before start",
      "action": "GET join-link",
      "expected": "visible=false",
      "at": "2026-10-06T16:29:31.223Z",
      "actual": {
        "visible": false,
        "joinUrl": null,
        "reason": "MEETING_NOT_OPEN"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-017",
      "name": "B2 attendance first while not started",
      "precondition": "B2 future,0h",
      "action": "POST B2 registration",
      "expected": "confirmed",
      "at": "2026-10-06T16:29:31.254Z",
      "actual": {
        "id": "3",
        "meetingId": "3",
        "status": "confirmed"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-018",
      "name": "B2 then minutes shares Registration/Task",
      "precondition": "B2 attend first",
      "action": "PUT B2 minutes + snapshot",
      "expected": "same id,task, both flags",
      "at": "2026-10-06T16:29:31.301Z",
      "actual": {
        "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"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-019",
      "name": "Both intentions appear in separate lists",
      "precondition": "A minutes-only,B1/B2 both",
      "action": "GET both my lists",
      "expected": "myMeetings=2,myMinutes=3",
      "at": "2026-10-06T16:29:32.908Z",
      "actual": {
        "myMeetings": 2,
        "myMinutes": 3
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-020",
      "name": "Future B1 cancel keeps minutes and Task",
      "precondition": "B1 future,both",
      "action": "DELETE registration",
      "expected": "cancelled;same reserved minutes and ongoing Task",
      "at": "2026-10-06T16:29:32.989Z",
      "actual": {
        "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"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-021",
      "name": "Future B1 reattend reuses id/Task",
      "precondition": "B1 cancelled but future",
      "action": "POST registration fresh key",
      "expected": "confirmed,same ids,3 Tasks total",
      "at": "2026-10-06T16:29:33.910Z",
      "actual": {
        "id": "2",
        "meetingId": "2",
        "status": "confirmed"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-022",
      "name": "Advance only isolated B fixtures to started",
      "precondition": "B1/B2 future registration complete",
      "action": "Guarded synthetic ORM time update",
      "expected": "Only B1/B2 updated",
      "at": "2026-10-06T16:29:34.732Z",
      "actual": {
        "advanced": [
          2,
          3
        ]
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-023",
      "name": "Started attendee B1 obtains link",
      "precondition": "B1 advanced,confirmed",
      "action": "GET join-link",
      "expected": "visible=true synthetic invalid-domain link",
      "at": "2026-10-06T16:29:35.508Z",
      "actual": {
        "visible": true,
        "joinUrl": "https://qa-meeting.example.invalid/join/B1_minutes_attend",
        "reason": null
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-024",
      "name": "Started attendee B2 obtains link",
      "precondition": "B2 advanced,confirmed",
      "action": "GET join-link",
      "expected": "visible=true",
      "at": "2026-10-06T16:29:35.550Z",
      "actual": {
        "visible": true,
        "joinUrl": "https://qa-meeting.example.invalid/join/B2_attend_minutes",
        "reason": null
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-025",
      "name": "Started B1 cancel preserves minutes Task",
      "precondition": "B1 started,both",
      "action": "DELETE registration + snapshot",
      "expected": "cancelled and minutes same ids/ongoing Task",
      "at": "2026-10-06T16:29:35.586Z",
      "actual": {
        "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"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-026",
      "name": "Cancelled started B1 loses link",
      "precondition": "B1 cancelled,minutes retained",
      "action": "GET join-link",
      "expected": "visible=false,no link",
      "at": "2026-10-06T16:29:36.486Z",
      "actual": {
        "visible": false,
        "joinUrl": null,
        "reason": "REGISTRATION_REQUIRED"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-027",
      "name": "Started B1 cannot restore attendance",
      "precondition": "B1 cancelled after start",
      "action": "POST attend fresh key",
      "expected": "MEETING_NOT_OPEN,no extra Task",
      "at": "2026-10-06T16:29:36.520Z",
      "actual": {
        "status": 409,
        "data": {
          "error": {
            "code": "MEETING_NOT_OPEN",
            "message": "会议当前不可报名"
          },
          "requestId": "f261e04e-d31e-4dbc-ae31-145be5e9c02f"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-028",
      "name": "Started B1 repeated minutes retained",
      "precondition": "B1 cancelled attendee,minutes active",
      "action": "PUT minutes fresh key",
      "expected": "same reserved id/task",
      "at": "2026-10-06T16:29:37.344Z",
      "actual": {
        "id": "2",
        "meetingId": "2",
        "clientContactId": "2",
        "taskId": "2",
        "status": "reserved",
        "createdAt": "2026-10-07T00:29:30.412283"
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-029",
      "name": "Started B2 cancel preserves same minutes Task",
      "precondition": "B2 opposite order",
      "action": "DELETE registration",
      "expected": "cancelled,same minutes id/task",
      "at": "2026-10-06T16:29:37.390Z",
      "actual": {
        "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"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-030",
      "name": "All free Tasks remain zero and unique",
      "precondition": "A/B1/B2 complete",
      "action": "Read isolated snapshot",
      "expected": "3 registrations,3 unique Tasks,0 contracts,all prices0",
      "at": "2026-10-06T16:29:37.464Z",
      "actual": {
        "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
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-031",
      "name": "Synthetic paid no contract rejects without mutation",
      "precondition": "D synthetic1h,no contracts",
      "action": "PUT D minutes",
      "expected": "NO_ACTIVE_CONTRACT,still3 Tasks",
      "at": "2026-10-06T16:29:38.248Z",
      "actual": {
        "status": 409,
        "data": {
          "error": {
            "code": "NO_ACTIVE_CONTRACT",
            "message": "当前客户暂无有效合同，请联系客户经理开通后再报名"
          },
          "requestId": "e5e32c49-8b3e-48f0-ad21-a43a50da7cde"
        }
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-032",
      "name": "Real PG refusal outbox durable and deduplicated",
      "precondition": "D denied",
      "action": "Repeat rejection+PG SELECT",
      "expected": "one pending row,not reservation",
      "at": "2026-10-06T16:29:39.079Z",
      "actual": [
        {
          "meeting_id": "4",
          "state": "pending",
          "attempts": 0,
          "accepted_at": null
        }
      ],
      "status": "Pass"
    },
    {
      "id": "HTTP-033",
      "name": "Refusal persists across real BFF restart and mock acceptance",
      "precondition": "Outbox stored in real PG",
      "action": "Stop/restart BFF; bootstrap dispatch to mock13001",
      "expected": "same row accepted once;no real email",
      "at": "2026-10-06T16:29:39.132Z",
      "actual": {
        "outbox": {
          "state": "accepted",
          "attempts": 1,
          "accepted_at": "2026-10-06T16:29:39.777Z"
        },
        "mockRequests": 1,
        "realEmails": 0
      },
      "status": "Pass"
    },
    {
      "id": "HTTP-034",
      "name": "Accepted refusal never becomes successful reservation",
      "precondition": "D notice accepted by mock",
      "action": "GET D minutes;GET myMinutes;snapshot",
      "expected": "null,D absent,3 Tasks",
      "at": "2026-10-06T16:29:39.930Z",
      "actual": {
        "reservation": null,
        "myMinutes": 3,
        "taskCount": 3
      },
      "status": "Pass"
    }
  ],
  "summary": {
    "executed": 34,
    "pass": 34,
    "fail": 0
  },
  "cleanup": {
    "services": [
      {
        "role": "Backend",
        "pid": 53599,
        "exitCode": null,
        "signal": "SIGTERM"
      },
      {
        "role": "BFF",
        "pid": 53601,
        "exitCode": null,
        "signal": "SIGTERM"
      },
      {
        "role": "BFF",
        "pid": 53625,
        "exitCode": null,
        "signal": "SIGTERM"
      }
    ],
    "container": "ndb-qa-minutes-http-20261007-56488",
    "containerStopped": true
  },
  "boundaries": {
    "realWechatLogin": false,
    "miniUI": false,
    "realEmails": 0,
    "sharedBusinessDbWrites": 0
  },
  "mockNotifications": [
    {
      "path": "/v1/notifications",
      "key": "minutes-no-contract-e0cdd570c83130ab69bfbdce67ee9d375a6b100c05156ebbc74abe0630fb5929",
      "body": {
        "metadata": {
          "source": "mp-conference-minutes-no-contract"
        },
        "deliveries": [
          {
            "channel": "email",
            "to": {
              "emails": [
                "qa-staff@example.invalid"
              ]
            },
            "subject": "纪要预约因无有效合同被拒绝",
            "content": {
              "kind": "normal",
              "contentType": "text",
              "body": "会议ID：4\n客户联系人ID：2\n渠道用户ID：qa-http-bound-user\n拒绝原因：NO_ACTIVE_CONTRACT\n预约未成功，请工作人员核实合同。"
            }
          }
        ]
      }
    }
  ]
}
