{"numFailedTestSuites":10,"numFailedTests":36,"numPassedTestSuites":262,"numPassedTests":3451,"numPendingTestSuites":5,"numPendingTests":37,"numRuntimeErrorTestSuites":3,"numTodoTests":0,"numTotalTestSuites":277,"numTotalTests":3524,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1793868578467,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":1212,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) reserve 하드캡 — maxFlows 초과 차단","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"reserve 하드캡 — maxFlows 초과 차단"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":4405,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) reserve 동시 경쟁 — 정확히 maxFlows개만 성공 (race)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"reserve 동시 경쟁 — 정확히 maxFlows개만 성공 (race)"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":7404,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) refresh — 살아있는 멤버 TTL 연장 (ZADD XX CH)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"refresh — 살아있는 멤버 TTL 연장 (ZADD XX CH)"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":8003,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) ★ purge된 멤버는 refresh가 되살리지 않음 (동시성 안전)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"★ purge된 멤버는 refresh가 되살리지 않음 (동시성 안전)"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":8007,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) OTP 미입력 이탈 — TTL 만료 자동 회수","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"OTP 미입력 이탈 — TTL 만료 자동 회수"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":8005,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) ★ slotStat score-window — 대기 hold와 확정자 구분","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"★ slotStat score-window — 대기 hold와 확정자 구분"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) admit 입장권 — 1회만 소비 (중복 입장 차단)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"admit 입장권 — 1회만 소비 (중복 입장 차단)"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":8004,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) settle — 슬롯 즉시 반납","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"settle — 슬롯 즉시 반납"},{"ancestorTitles":["TreatReservationService 슬롯 로직 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatReservationService 슬롯 로직 (실 redis) 세션 결속 예약은 API 인스턴스가 바뀌어도 정확히 한 번만 반납한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"세션 결속 예약은 API 인스턴스가 바뀌어도 정확히 한 번만 반납한다"}],"endTime":1793868640133,"message":"  ● TreatReservationService 슬롯 로직 (실 redis) › reserve 하드캡 — maxFlows 초과 차단\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › reserve 동시 경쟁 — 정확히 maxFlows개만 성공 (race)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › refresh — 살아있는 멤버 TTL 연장 (ZADD XX CH)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › ★ purge된 멤버는 refresh가 되살리지 않음 (동시성 안전)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › OTP 미입력 이탈 — TTL 만료 자동 회수\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › ★ slotStat score-window — 대기 hold와 확정자 구분\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › admit 입장권 — 1회만 소비 (중복 입장 차단)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › settle — 슬롯 즉시 반납\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatReservationService 슬롯 로직 (실 redis) › 세션 결속 예약은 API 인스턴스가 바뀌어도 정확히 한 번만 반납한다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/dispatch/treat-reservation.service.spec.ts","startTime":1793868578784,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatDispatcher 단계별 TTL 통합 (실 redis)"],"duration":1203,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatDispatcher 단계별 TTL 통합 (실 redis) 1차 CF-03002 → 슬롯 TTL이 OTP(180s)로 설정된다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"1차 CF-03002 → 슬롯 TTL이 OTP(180s)로 설정된다"},{"ancestorTitles":["TreatDispatcher 단계별 TTL 통합 (실 redis)"],"duration":4403,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatDispatcher 단계별 TTL 통합 (실 redis) 2차 treatCompare → TTL이 COLLECT(420s)로 갱신되고, 완료 후 settle된다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"2차 treatCompare → TTL이 COLLECT(420s)로 갱신되고, 완료 후 settle된다"},{"ancestorTitles":["TreatDispatcher 단계별 TTL 통합 (실 redis)"],"duration":7408,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatDispatcher 단계별 TTL 통합 (실 redis) 1차 인증 실패 → 즉시 settle (슬롯 점유 안 남김)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"1차 인증 실패 → 즉시 settle (슬롯 점유 안 남김)"},{"ancestorTitles":["TreatDispatcher 단계별 TTL 통합 (실 redis)"],"duration":8008,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatDispatcher 단계별 TTL 통합 (실 redis) 만석(20슬롯) → 큐 진입(CF-QUEUE), 슬롯 초과 점유 없음","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"만석(20슬롯) → 큐 진입(CF-QUEUE), 슬롯 초과 점유 없음"}],"endTime":1793868661500,"message":"  ● TreatDispatcher 단계별 TTL 통합 (실 redis) › 1차 CF-03002 → 슬롯 TTL이 OTP(180s)로 설정된다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatDispatcher 단계별 TTL 통합 (실 redis) › 2차 treatCompare → TTL이 COLLECT(420s)로 갱신되고, 완료 후 settle된다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatDispatcher 단계별 TTL 통합 (실 redis) › 1차 인증 실패 → 즉시 settle (슬롯 점유 안 남김)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatDispatcher 단계별 TTL 통합 (실 redis) › 만석(20슬롯) → 큐 진입(CF-QUEUE), 슬롯 초과 점유 없음\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.spec.ts","startTime":1793868640138,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["인사이트 정회원 라우트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 insight-route-is-registered-on-the-member-axis","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"insight-route-is-registered-on-the-member-axis"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 admin-view-insight-route-is-enforce-gated","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"admin-view-insight-route-is-enforce-gated"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 insight-route-keeps-its-guard","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"insight-route-keeps-its-guard"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 insight-route-rejects-non-canonical-odd-id","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"insight-route-rejects-non-canonical-odd-id"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 insight-path-writes-no-row","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"insight-path-writes-no-row"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 legacy-flag-parse-is-strict","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"legacy-flag-parse-is-strict"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 legacy-flag-restores-m2-bytes","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"legacy-flag-restores-m2-bytes"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 extended-path-fetches-inputs-before-request","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"extended-path-fetches-inputs-before-request"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 visit-ids-reach-the-request-body — 저장소 힌트 visits 가 본문 visit_ids 로 실린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"visit-ids-reach-the-request-body — 저장소 힌트 visits 가 본문 visit_ids 로 실린다"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 disclosure-screen-reaches-the-request-body — 탭 결과가 본문 disclosure_screen 으로 실린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"disclosure-screen-reaches-the-request-body — 탭 결과가 본문 disclosure_screen 으로 실린다"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 legacy-flag-sends-no-disclosure-screen","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"legacy-flag-sends-no-disclosure-screen"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"인사이트 정회원 라우트 extended-path-propagates-query-failure","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"extended-path-propagates-query-failure"},{"ancestorTitles":["인사이트 정회원 라우트"],"duration":0,"failureDetails":[{"errno":-2,"code":"ENOENT","syscall":"open","path":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json"}],"failureMessages":["Error: ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json'\n    at Object.readFileSync (node:fs:440:20)\n    at Object.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-insight-route.spec.ts:623:12)\n    at Promise.then.completed (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:298:28)\n    at new Promise (<anonymous>)\n    at callAsyncCircusFn (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:231:10)\n    at _callCircusTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:316:40)\n    at processTicksAndRejections (node:internal/process/task_queues:103:5)\n    at _runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:252:3)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:126:9)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:121:9)\n    at run (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:71:3)\n    at runAndTransformResultsToJestFormat (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n    at jestAdapter (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n    at runTestInternal (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:367:16)\n    at runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:444:34)\n    at Object.worker (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/testWorker.js:106:12)"],"fullName":"인사이트 정회원 라우트 getInsight — 합성 실측 응답이 세일즈 좌석 행과 reportV2 로 나간다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"getInsight — 합성 실측 응답이 세일즈 좌석 행과 reportV2 로 나간다"}],"endTime":1793868662254,"message":"  ● 인사이트 정회원 라우트 › getInsight — 합성 실측 응답이 세일즈 좌석 행과 reportV2 로 나간다\n\n    ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json'\n\n      621 |     try {\n      622 |       const { rich } = JSON.parse(\n    > 623 |         fs.readFileSync(\n          |            ^\n      624 |           path.join(\n      625 |             REPO_ROOT,\n      626 |             '.claude',\n\n      at Object.<anonymous> (apps/api/src/modules/analyze/analyze-insight-route.spec.ts:623:12)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-insight-route.spec.ts","startTime":1793868661504,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다 -dev 로 끝나면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"-dev 로 끝나면 통과한다"},{"ancestorTitles":["assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다 접미사 없는 이름은 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"접미사 없는 이름은 거부한다"},{"ancestorTitles":["assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다 빈 이름은 거부한다 (대상을 확인할 수 없다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 이름은 거부한다 (대상을 확인할 수 없다)"},{"ancestorTitles":["assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertWritableDatabase — 잘못된 DB 에 실패 결제 행을 넣지 않는다 ALERT_INJECT_ALLOW_DB 가 정확히 일치할 때만 연다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ALERT_INJECT_ALLOW_DB 가 정확히 일치할 때만 연다"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 라벨 접두를 벗기고 critical 을 잡는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"라벨 접두를 벗기고 critical 을 잡는다"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 라벨 접두를 벗기고 warn 을 잡는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"라벨 접두를 벗기고 warn 을 잡는다"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 복구가 critical 본문을 품어도 복구로 분류한다 (first-match-wins, 복구 우선)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"복구가 critical 본문을 품어도 복구로 분류한다 (first-match-wins, 복구 우선)"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 다이제스트 머리말을 잡는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"다이제스트 머리말을 잡는다"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 라벨 없는 POST /test 기본 메시지를 test 로 잡는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"라벨 없는 POST /test 기본 메시지를 test 로 잡는다"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 스누즈 해제 요약을 잡는다 (M3 신설 어휘)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스누즈 해제 요약을 잡는다 (M3 신설 어휘)"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 세 가지 🟠 어휘가 서로 오분류되지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"세 가지 🟠 어휘가 서로 오분류되지 않는다"},{"ancestorTitles":["classifySeverity — 실제 발송 문자열 고정 케이스"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifySeverity — 실제 발송 문자열 고정 케이스 어휘에 없는 본문은 미분류로 남긴다 (조용히 아무 통에나 넣지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"어휘에 없는 본문은 미분류로 남긴다 (조용히 아무 통에나 넣지 않는다)"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 poll 회차와 --advance 를 읽는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"poll 회차와 --advance 를 읽는다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 알 수 없는 플래그는 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"알 수 없는 플래그는 던진다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 --expect-db-down 은 poll 전용이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"--expect-db-down 은 poll 전용이다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 --advance 는 --sim-heartbeat 를 함의한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"--advance 는 --sim-heartbeat 를 함의한다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 --sim-heartbeat 는 단독으로도 쓸 수 있다 (9-a 실시간 경과 방어)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"--sim-heartbeat 는 단독으로도 쓸 수 있다 (9-a 실시간 경과 방어)"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 inject/clear 는 신호 축을 강제한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"inject/clear 는 신호 축을 강제한다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 inject a4 는 --base 나 --redis 없이는 파싱 단계에서 막힌다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"inject a4 는 --base 나 --redis 없이는 파싱 단계에서 막힌다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 --sample 은 over|under 만 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"--sample 은 over|under 만 받는다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 값이 빠진 플래그를 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"값이 빠진 플래그를 던진다"},{"ancestorTitles":["parseArgs — 조용한 강등을 만들지 않는다"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — 조용한 강등을 만들지 않는다 --ok/--bad 는 0 이상의 정수만 받는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"--ok/--bad 는 0 이상의 정수만 받는다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 오버라이드가 없으면 기본 목록이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"오버라이드가 없으면 기본 목록이다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 오버라이드된 기대 주기를 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"오버라이드된 기대 주기를 쓴다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 오버라이드에만 있는 이름도 감시 목록이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"오버라이드에만 있는 이름도 감시 목록이다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 숫자 문자열 항목은 버린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"숫자 문자열 항목은 버린다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 불리언 항목은 버린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"불리언 항목은 버린다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 0 이하 항목은 버린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"0 이하 항목은 버린다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 대문자 이름 항목은 버린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대문자 이름 항목은 버린다"},{"ancestorTitles":["resolveScheduleExpect — 규칙과 같은 감시 목록을 본다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveScheduleExpect — 규칙과 같은 감시 목록을 본다 유효 항목이 하나라도 있으면 그것만 쓴다 (기본 목록과 병합하지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"유효 항목이 하나라도 있으면 그것만 쓴다 (기본 목록과 병합하지 않는다)"},{"ancestorTitles":["parseDurationMs"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseDurationMs 단위를 읽는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"단위를 읽는다"},{"ancestorTitles":["parseDurationMs"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseDurationMs 형식 오류를 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"형식 오류를 던진다"},{"ancestorTitles":["parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다 빈 값·깨진 JSON 은 빈 대장이다 (§D3 4: 대장 없으면 아무것도 지우지 않는다)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"빈 값·깨진 JSON 은 빈 대장이다 (§D3 4: 대장 없으면 아무것도 지우지 않는다)"},{"ancestorTitles":["parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다 id 배열과 kv 원복 대장을 보존한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"id 배열과 kv 원복 대장을 보존한다"},{"ancestorTitles":["parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다 추적 중인 KV 가 있어도 주입 축이 비면 \"주입 중\"이 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"추적 중인 KV 가 있어도 주입 축이 비면 \"주입 중\"이 아니다"},{"ancestorTitles":["parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — 손상된 대장이 추측 삭제를 유발하지 않는다 숫자가 아닌 id 는 버린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"숫자가 아닌 id 는 버린다"},{"ancestorTitles":["DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합 원본이 실제로 db-down skip 을 낸다 (정규식이 조용히 0건을 세지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"원본이 실제로 db-down skip 을 낸다 (정규식이 조용히 0건을 세지 않는다)"},{"ancestorTitles":["DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합"],"duration":2,"failureDetails":[{"matcherResult":{"actual":["db-down-disabled","db-down-fallback","db-down-lease-not-acquired","db-down-no-destination","db-down-no-snapshot","db-down-snoozed","db-down-streak","db-down-suppressed"],"expected":["db-down-disabled","db-down-lease-not-acquired","db-down-no-destination","db-down-no-snapshot","db-down-snoozed","db-down-streak","db-down-suppressed"],"message":"expect(received).toEqual(expected) // deep equality\n\n- Expected  - 0\n+ Received  + 1\n\n@@ -1,7 +1,8 @@\n  Array [\n    \"db-down-disabled\",\n+   \"db-down-fallback\",\n    \"db-down-lease-not-acquired\",\n    \"db-down-no-destination\",\n    \"db-down-no-snapshot\",\n    \"db-down-snoozed\",\n    \"db-down-streak\",","name":"toEqual","pass":false}}],"failureMessages":["Error: expect(received).toEqual(expected) // deep equality\n\n- Expected  - 0\n+ Received  + 1\n\n@@ -1,7 +1,8 @@\n  Array [\n    \"db-down-disabled\",\n+   \"db-down-fallback\",\n    \"db-down-lease-not-acquired\",\n    \"db-down-no-destination\",\n    \"db-down-no-snapshot\",\n    \"db-down-snoozed\",\n    \"db-down-streak\",\n    at Object.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/scripts/alert-inject.spec.ts:304:39)\n    at Promise.then.completed (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:298:28)\n    at new Promise (<anonymous>)\n    at callAsyncCircusFn (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:231:10)\n    at _callCircusTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:316:40)\n    at processTicksAndRejections (node:internal/process/task_queues:103:5)\n    at _runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:252:3)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:126:9)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:121:9)\n    at run (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:71:3)\n    at runAndTransformResultsToJestFormat (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n    at jestAdapter (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n    at runTestInternal (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:367:16)\n    at runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:444:34)\n    at Object.worker (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/testWorker.js:106:12)"],"fullName":"DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합 상수와 원본 집합이 정확히 일치한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"상수와 원본 집합이 정확히 일치한다"},{"ancestorTitles":["DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합 정상 회차 결과는 인정하지 않는다 (DB 가 살아났다는 뜻이다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정상 회차 결과는 인정하지 않는다 (DB 가 살아났다는 뜻이다)"},{"ancestorTitles":["parseArgs — a5·scenario 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — a5·scenario 축 a5 를 신호 축으로 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a5 를 신호 축으로 받는다"},{"ancestorTitles":["parseArgs — a5·scenario 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — a5·scenario 축 --vendor 를 읽고, 없으면 null 이다 (활성 벤더 중 첫 번째를 고르라는 뜻)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"--vendor 를 읽고, 없으면 null 이다 (활성 벤더 중 첫 번째를 고르라는 뜻)"},{"ancestorTitles":["parseArgs — a5·scenario 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — a5·scenario 축 --vendor 에 값이 없으면 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"--vendor 에 값이 없으면 던진다"},{"ancestorTitles":["parseArgs — a5·scenario 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — a5·scenario 축 알 수 없는 신호 축은 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"알 수 없는 신호 축은 거부한다"},{"ancestorTitles":["parseArgs — a5·scenario 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseArgs — a5·scenario 축 scenario 는 id 를 요구하고, 카탈로그에 없는 id 를 부팅 전에 거부한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"scenario 는 id 를 요구하고, 카탈로그에 없는 id 를 부팅 전에 거부한다"},{"ancestorTitles":["parseLedger — orderDetailIds (a5 회수 대상)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — orderDetailIds (a5 회수 대상) 보존한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"보존한다"},{"ancestorTitles":["parseLedger — orderDetailIds (a5 회수 대상)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — orderDetailIds (a5 회수 대상) 옛 대장에는 필드가 없다 — 빈 배열로 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"옛 대장에는 필드가 없다 — 빈 배열로 읽는다"},{"ancestorTitles":["parseLedger — orderDetailIds (a5 회수 대상)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseLedger — orderDetailIds (a5 회수 대상) id 정의역(양의 정수)을 벗어난 값은 버린다 — 0 이 DELETE 대상으로 흘러들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"id 정의역(양의 정수)을 벗어난 값은 버린다 — 0 이 DELETE 대상으로 흘러들지 않는다"},{"ancestorTitles":["ledgerIsEmpty — detail 행만 남은 대장을 \"비었다\"로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ledgerIsEmpty — detail 행만 남은 대장을 \"비었다\"로 읽지 않는다 orderDetailIds 만 남아 있어도 비어 있지 않다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"orderDetailIds 만 남아 있어도 비어 있지 않다"},{"ancestorTitles":["ledgerIsEmpty — detail 행만 남은 대장을 \"비었다\"로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ledgerIsEmpty — detail 행만 남은 대장을 \"비었다\"로 읽지 않는다 셋 다 비고 kv 도 비면 비어 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"셋 다 비고 kv 도 비면 비어 있다"},{"ancestorTitles":["시나리오 카탈로그 — 구조 불변식"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 카탈로그 — 구조 불변식 id 가 중복되지 않는다 (중복이면 find 가 앞의 것만 돌려 뒤가 영영 안 돈다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"id 가 중복되지 않는다 (중복이면 find 가 앞의 것만 돌려 뒤가 영영 안 돈다)"},{"ancestorTitles":["시나리오 카탈로그 — 구조 불변식"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 카탈로그 — 구조 불변식 비어 있지 않다 (정규식·필터 실수로 목록이 0건이 되면 전 검사가 공회전한다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비어 있지 않다 (정규식·필터 실수로 목록이 0건이 되면 전 검사가 공회전한다)"},{"ancestorTitles":["시나리오 카탈로그 — 구조 불변식"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 카탈로그 — 구조 불변식 clear 하는 축은 앞선 단계에서 주입된 축이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"clear 하는 축은 앞선 단계에서 주입된 축이다"},{"ancestorTitles":["시나리오 카탈로그 — 구조 불변식"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 카탈로그 — 구조 불변식 관측을 만드는 단계(poll·test)가 최소 1개다 — 판정식이 볼 것이 있어야 한다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"관측을 만드는 단계(poll·test)가 최소 1개다 — 판정식이 볼 것이 있어야 한다"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 payment-fire: critical 이 있어야 PASS","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"payment-fire: critical 이 있어야 PASS"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 payment-under: 한 건이라도 나가면 FAIL","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"payment-under: 한 건이라도 나가면 FAIL"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 payment-suppress: 3회차에 critical 이 정확히 1건이어야 PASS","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"payment-suppress: 3회차에 critical 이 정확히 1건이어야 PASS"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 payment-recover: 복구 2건은 실패이고, 발화하지 않은 회차는 복구를 잴 수 없다고 말한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"payment-recover: 복구 2건은 실패이고, 발화하지 않은 회차는 복구를 잴 수 없다고 말한다"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 multi-channel: 목적지 수가 활성 채널 수와 같아야 PASS, 채널 1개면 SKIP","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"multi-channel: 목적지 수가 활성 채널 수와 같아야 PASS, 채널 1개면 SKIP"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 quiet: 무장애 구간에 한 건이라도 나가면 FAIL","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"quiet: 무장애 구간에 한 건이라도 나가면 FAIL"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 channel-test: 채널 수만큼 받아야 PASS (일부만 도달하면 FAIL)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"channel-test: 채널 수만큼 받아야 PASS (일부만 도달하면 FAIL)"},{"ancestorTitles":["시나리오 판정식 — 침묵을 통과로 읽지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"시나리오 판정식 — 침묵을 통과로 읽지 않는다 vendor-fire 는 풀 축(critical)만 성공으로 친다 — warn 은 다이제스트라 그 회차에 안 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"vendor-fire 는 풀 축(critical)만 성공으로 친다 — warn 은 다이제스트라 그 회차에 안 나간다"}],"endTime":1793868662327,"message":"  ● DB_DOWN_SKIPS — run() 의 실제 db-down 반환값 집합 › 상수와 원본 집합이 정확히 일치한다\n\n    expect(received).toEqual(expected) // deep equality\n\n    - Expected  - 0\n    + Received  + 1\n\n    @@ -1,7 +1,8 @@\n      Array [\n        \"db-down-disabled\",\n    +   \"db-down-fallback\",\n        \"db-down-lease-not-acquired\",\n        \"db-down-no-destination\",\n        \"db-down-no-snapshot\",\n        \"db-down-snoozed\",\n        \"db-down-streak\",\n\n      302 |\n      303 |   it('상수와 원본 집합이 정확히 일치한다', () => {\n    > 304 |     expect([...DB_DOWN_SKIPS].sort()).toEqual([...fromSource].sort());\n          |                                       ^\n      305 |   });\n      306 |\n      307 |   it('정상 회차 결과는 인정하지 않는다 (DB 가 살아났다는 뜻이다)', () => {\n\n      at Object.<anonymous> (scripts/alert-inject.spec.ts:304:39)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/scripts/alert-inject.spec.ts","startTime":1793868662256,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-drops-person-name-and-identifiers","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"view-drops-person-name-and-identifiers"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-seats-four-angles-and-lists-the-rest","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"view-seats-four-angles-and-lists-the-rest"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-expands-aggregate-by-code-and-window","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-expands-aggregate-by-code-and-window"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-keeps-aggregate-overmatch-visible","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-keeps-aggregate-overmatch-visible"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-counts-aggregate-without-count-as-matched","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-counts-aggregate-without-count-as-matched"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-attaches-examination-and-operation","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"view-attaches-examination-and-operation"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-survives-missing-procedures","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-survives-missing-procedures"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-does-not-attach-health-procedures-to-car-rows","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"view-does-not-attach-health-procedures-to-car-rows"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-leaves-insurance-ambiguous-evidence-unresolved","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-leaves-insurance-ambiguous-evidence-unresolved"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-derives-state-from-inputs","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"view-derives-state-from-inputs"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-separates-expired-from-unavailable","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-separates-expired-from-unavailable"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-separates-no-treatments-from-expired","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-separates-no-treatments-from-expired"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-rejoins-evidence-to-sent-treatments","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"view-rejoins-evidence-to-sent-treatments"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view notices-reflect-what-was-sent","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"notices-reflect-what-was-sent"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view notices-follow-state-not-treatments","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"notices-follow-state-not-treatments"},{"ancestorTitles":["insight-view"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"insight-view view-fixture-is-what-the-server-produces","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"view-fixture-is-what-the-server-produces"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[{"errno":-2,"code":"ENOENT","syscall":"open","path":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json"}],"failureMessages":["Error: ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json'\n    at Object.readFileSync (node:fs:440:20)\n    at readJson (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-view.spec.ts:29:47)\n    at Object.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-view.spec.ts:749:22)\n    at Promise.then.completed (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:298:28)\n    at new Promise (<anonymous>)\n    at callAsyncCircusFn (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:231:10)\n    at _callCircusTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:316:40)\n    at processTicksAndRejections (node:internal/process/task_queues:103:5)\n    at _runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:252:3)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:126:9)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:121:9)\n    at run (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:71:3)\n    at runAndTransformResultsToJestFormat (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n    at jestAdapter (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n    at runTestInternal (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:367:16)\n    at runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:444:34)\n    at Object.worker (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/testWorker.js:106:12)"],"fullName":"insight-view tip.sales 행 형상 근거를 다시 펼치지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"tip.sales 행 형상 근거를 다시 펼치지 않는다"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view tip.sales 집계 형상 근거는 상병으로 펼친다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"tip.sales 집계 형상 근거는 상병으로 펼친다"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view tip.sales 혼합·모호 근거를 항목마다 제 경로로 처리한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"tip.sales 혼합·모호 근거를 항목마다 제 경로로 처리한다"},{"ancestorTitles":["insight-view"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"insight-view tip.sales 병·의원만 남은 행 항목을 상병 전체로 펼치지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"tip.sales 병·의원만 남은 행 항목을 상병 전체로 펼치지 않는다"},{"ancestorTitles":["insight-view"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"insight-view reportV2 는 ready 에서만 선다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"reportV2 는 ready 에서만 선다"}],"endTime":1793868662362,"message":"  ● insight-view › tip.sales 행 형상 근거를 다시 펼치지 않는다\n\n    ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json'\n\n      27 | const FROZEN_AS_OF = '2026-09-02';\n      28 |\n    > 29 | const readJson = (p: string) => JSON.parse(fs.readFileSync(p, 'utf8'));\n         |                                               ^\n      30 |\n      31 | const treatment = (\n      32 |   over: Partial<InsightTreatmentOut> = {},\n\n      at readJson (apps/api/src/modules/ddx/insight-view.spec.ts:29:47)\n      at Object.<anonymous> (apps/api/src/modules/ddx/insight-view.spec.ts:749:22)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-view.spec.ts","startTime":1793868662330,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["mysqlErrorWrapper"],"duration":1,"failureDetails":[{"matcherResult":{"message":"expect(received).not.toContain(expected) // indexOf\n\nExpected substring: not \"ER_LOCK_WAIT_TIMEOUT\"\nReceived string:        \"{\\\"code\\\":\\\"ER_LOCK_WAIT_TIMEOUT\\\"}\"","pass":true}}],"failureMessages":["Error: expect(received).not.toContain(expected) // indexOf\n\nExpected substring: not \"ER_LOCK_WAIT_TIMEOUT\"\nReceived string:        \"{\\\"code\\\":\\\"ER_LOCK_WAIT_TIMEOUT\\\"}\"\n    at Object.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/drizzle/src/drizzle.utill.spec.ts:30:22)\n    at Promise.then.completed (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:298:28)\n    at new Promise (<anonymous>)\n    at callAsyncCircusFn (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/utils.js:231:10)\n    at _callCircusTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:316:40)\n    at processTicksAndRejections (node:internal/process/task_queues:103:5)\n    at _runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:252:3)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:126:9)\n    at _runTestsForDescribeBlock (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:121:9)\n    at run (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/run.js:71:3)\n    at runAndTransformResultsToJestFormat (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n    at jestAdapter (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n    at runTestInternal (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:367:16)\n    at runTest (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/runTest.js:444:34)\n    at Object.worker (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/jest-runner/build/testWorker.js:106:12)"],"fullName":"mysqlErrorWrapper 처리하지 않는 mysql 오류는 원본을 500 응답 본문에 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"failed","title":"처리하지 않는 mysql 오류는 원본을 500 응답 본문에 싣지 않는다"}],"endTime":1793868662390,"message":"  ● mysqlErrorWrapper › 처리하지 않는 mysql 오류는 원본을 500 응답 본문에 싣지 않는다\n\n    expect(received).not.toContain(expected) // indexOf\n\n    Expected substring: not \"ER_LOCK_WAIT_TIMEOUT\"\n    Received string:        \"{\\\"code\\\":\\\"ER_LOCK_WAIT_TIMEOUT\\\"}\"\n\n      28 |     expect(body).not.toContain('tn_agency_policy');\n      29 |     expect(body).not.toContain('sqlMessage');\n    > 30 |     expect(body).not.toContain('ER_LOCK_WAIT_TIMEOUT');\n         |                      ^\n      31 |   });\n      32 | });\n      33 |\n\n      at Object.<anonymous> (libs/drizzle/src/drizzle.utill.spec.ts:30:22)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/drizzle/src/drizzle.utill.spec.ts","startTime":1793868662365,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 두 번 실행해도 칸·유일 인덱스·값 제약이 한 벌이고 지정은 대상 한 행이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 두 번 실행해도 칸·유일 인덱스·값 제약이 한 벌이고 지정은 대상 한 행이다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 두 기동이 동시에 돌아도 둘 다 멈추지 않고 지정은 대상 한 행이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 두 기동이 동시에 돌아도 둘 다 멈추지 않고 지정은 대상 한 행이다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 유일 인덱스가 두 번째 1 을 막고 NULL 은 여럿 허용한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 유일 인덱스가 두 번째 1 을 막고 NULL 은 여럿 허용한다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 복합 유일 인덱스뿐이면 \"최대 1개\" 전제가 없어 지정하지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 복합 유일 인덱스뿐이면 \"최대 1개\" 전제가 없어 지정하지 않는다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 값 제약이 0 과 2 를 막는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 값 제약이 0 과 2 를 막는다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 지워진 뒤 같은 로그인 아이디로 다시 만든 계정은 지정되지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 지워진 뒤 같은 로그인 아이디로 다시 만든 계정은 지정되지 않는다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 칸 추가 뒤에도 기존 관리자 생성 경로로 두 명을 만들 수 있다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 칸 추가 뒤에도 기존 관리자 생성 경로로 두 명을 만들 수 있다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 표를 쥔 트랜잭션이 있으면 DDL 은 잠금 대기 상한 안에 실패하고 seed 는 던지지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 표를 쥔 트랜잭션이 있으면 DDL 은 잠금 대기 상한 안에 실패하고 seed 는 던지지 않는다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 판정은 칸이 없으면 거짓이고 지정 뒤 그 번호만 참이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 판정은 칸이 없으면 거짓이고 지정 뒤 그 번호만 참이다"},{"ancestorTitles":["최고관리자 seed — 실 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 seed — 실 MySQL mysql: 칸이 없는 표에서도 관리자 로그인 조회가 선다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"mysql: 칸이 없는 표에서도 관리자 로그인 조회가 선다"}],"coverage":{},"endTime":1793868745936,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/seeds/super-admin.seed.mysql.spec.ts","startTime":1793868745936,"status":"skipped","summary":""},{"assertionResults":[{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 동시 정산은 정확히 한 번 차감하고 정상 0건 결과를 저장한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"동시 정산은 정확히 한 번 차감하고 정상 0건 결과를 저장한다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 동시 취소는 예약을 한 번만 반환하고 차감하지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"동시 취소는 예약을 한 번만 반환하고 차감하지 않는다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 settle가 먼저 잠근 정산·취소 경합은 먼저 확정한 상태를 보존한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"settle가 먼저 잠근 정산·취소 경합은 먼저 확정한 상태를 보존한다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 refund가 먼저 잠근 정산·취소 경합은 먼저 확정한 상태를 보존한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"refund가 먼저 잠근 정산·취소 경합은 먼저 확정한 상태를 보존한다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 같은 인증의 동시 시작은 한 번만 예약한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"같은 인증의 동시 시작은 한 번만 예약한다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 마지막 한 자리를 다른 인증 두 건이 요청하면 패배 건의 상태까지 롤백한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"마지막 한 자리를 다른 인증 두 건이 요청하면 패배 건의 상태까지 롤백한다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 settle의 주문 UPDATE가 실패하면 분석과 수량 전체가 롤백된다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"settle의 주문 UPDATE가 실패하면 분석과 수량 전체가 롤백된다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 refund의 주문 UPDATE가 실패하면 분석과 수량 전체가 롤백된다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"refund의 주문 UPDATE가 실패하면 분석과 수량 전체가 롤백된다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 reserve의 주문 UPDATE가 실패하면 분석과 수량 전체가 롤백된다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"reserve의 주문 UPDATE가 실패하면 분석과 수량 전체가 롤백된다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 부분 수집 뒤 최종 실패 응답은 결과와 사용량을 남기지 않고 예약을 반환한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"부분 수집 뒤 최종 실패 응답은 결과와 사용량을 남기지 않고 예약을 반환한다"},{"ancestorTitles":["LossAnalysis 실제 MySQL 경합과 롤백"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 실제 MySQL 경합과 롤백 수집 중 취소 후 늦게 도착한 성공 응답은 결과를 저장하거나 차감하지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"수집 중 취소 후 늦게 도착한 성공 응답은 결과를 저장하거나 차감하지 않는다"}],"coverage":{},"endTime":1793868745936,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/loss-analysis/loss-analysis.mysql-cases.spec.ts","startTime":1793868745936,"status":"skipped","summary":""},{"assertionResults":[{"ancestorTitles":["settlement corporate live — 운영 리더"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"settlement corporate live — 운영 리더 읽기 전용 리더에서 저장소 SQL 로 2026 H1 기업 축 대리점·채널 분포와 스냅샷 불일치 회차를 센다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"읽기 전용 리더에서 저장소 SQL 로 2026 H1 기업 축 대리점·채널 분포와 스냅샷 불일치 회차를 센다"}],"coverage":{},"endTime":1793868745936,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/settlement.corporate.live.spec.ts","startTime":1793868745936,"status":"skipped","summary":""},{"assertionResults":[{"ancestorTitles":["settlement live — 운영 리더"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"settlement live — 운영 리더 읽기 전용 리더에서 저장소 SQL 로 엑셀 창 손해사정사 채널과 2026 H1 대리점·채널 분포를 센다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"읽기 전용 리더에서 저장소 SQL 로 엑셀 창 손해사정사 채널과 2026 H1 대리점·채널 분포를 센다"}],"coverage":{},"endTime":1793868745936,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/settlement.live.spec.ts","startTime":1793868745936,"status":"skipped","summary":""},{"assertionResults":[{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 진입 파일을 찾는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"진입 파일을 찾는다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":1196,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 alimtalk-status.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"alimtalk-status.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":642,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 analysis-stall.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"analysis-stall.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":743,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 analysis-status.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"analysis-status.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":870,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 ddx-verdict.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ddx-verdict.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":1066,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 delete-analysis.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"delete-analysis.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":1380,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 delete-fc.schdule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"delete-fc.schdule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":1485,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 delete-invoice-files.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"delete-invoice-files.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":1762,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 delete-treat.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"delete-treat.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":2665,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 disable-subscription.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"disable-subscription.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":2863,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 expired-money.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"expired-money.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":3101,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 fax-status.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"fax-status.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":3523,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 regular-agency-subscription.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"regular-agency-subscription.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":3821,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 regular-subscription.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"regular-subscription.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":4193,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 sales-statistics.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"sales-statistics.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":4317,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 samsung-s2-report.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"samsung-s2-report.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":4667,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 settlement-agency.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"settlement-agency.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"},{"ancestorTitles":["스케줄 진입의 모듈 그래프"],"duration":4772,"failureDetails":[],"failureMessages":[],"fullName":"스케줄 진입의 모듈 그래프 settlement-client.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"settlement-client.schedule.ts: 정적 import 순서대로 읽어도 AppModule 그래프에 undefined 가 없다"}],"endTime":1793868705945,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/schedule-entry-graph.spec.ts","startTime":1793868662865,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 1. 정책 표: 신원 × 행 전 칸이 판정 함수와 실제 가드 연쇄에서 표대로다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"1. 정책 표: 신원 × 행 전 칸이 판정 함수와 실제 가드 연쇄에서 표대로다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 1.2 B2C · 고객사 분석은 내부 관리자만 본다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"1.2 B2C · 고객사 분석은 내부 관리자만 본다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 1.3 분석의 어느 부분까지: 자동차 · 원본 엑셀 · PDF","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"1.3 분석의 어느 부분까지: 자동차 · 원본 엑셀 · PDF"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 2. 경로 불변식: 목록 · 판정 · 모든 읽기 경로 · 보조 조회가 같은 답을 낸다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"2. 경로 불변식: 목록 · 판정 · 모든 읽기 경로 · 보조 조회가 같은 답을 낸다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","3. 상태 변화"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 3. 상태 변화 회원을 형제 조직으로 옮기면 다음 요청이 403 이고 목록에서 빠진다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"회원을 형제 조직으로 옮기면 다음 요청이 403 이고 목록에서 빠진다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","3. 상태 변화"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 3. 상태 변화 조직관리자 자격을 풀면 401 이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"조직관리자 자격을 풀면 401 이다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","3. 상태 변화"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 3. 상태 변화 수준 1 로 내리면 상세는 403 E0607 · 목록은 보이고, 수준 0 이면 목록도 403 이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"수준 1 로 내리면 상세는 403 E0607 · 목록은 보이고, 수준 0 이면 목록도 403 이다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","3. 상태 변화"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 3. 상태 변화 삭제 표시하면 403 E0607 이고 목록에서 빠진다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"삭제 표시하면 403 E0607 이고 목록에서 빠진다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","3. 상태 변화"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 3. 상태 변화 내부 관리자 계정을 지우고 권한 버전을 올리면 401 이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"내부 관리자 계정을 지우고 권한 버전을 올리면 401 이다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 4. 가림: 영업 응답 전체에 합성 고객 값이 없고, 기업 응답에는 있다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"4. 가림: 영업 응답 전체에 합성 고객 값이 없고, 기업 응답에는 있다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","5. 자격은 세션 쿠키 하나다"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 5. 자격은 세션 쿠키 하나다 옛 토큰 발급 경로는 없다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"옛 토큰 발급 경로는 없다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","5. 자격은 세션 쿠키 하나다"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 5. 자격은 세션 쿠키 하나다 쿠키가 없으면 옛 경로 전부 401 이다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"쿠키가 없으면 옛 경로 전부 401 이다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","5. 자격은 세션 쿠키 하나다"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 5. 자격은 세션 쿠키 하나다 옛 토큰만 있으면 헤더든 주소든 거부한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"옛 토큰만 있으면 헤더든 주소든 거부한다"},{"ancestorTitles":["분석 열람 정책 표 — 실제 AppModule · 실제 MySQL","5. 자격은 세션 쿠키 하나다"],"duration":null,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정책 표 — 실제 AppModule · 실제 MySQL 5. 자격은 세션 쿠키 하나다 범위 밖 쿠키에 남의 토큰을 얹어도 쿠키 판정대로 거부한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"pending","title":"범위 밖 쿠키에 남의 토큰을 얹어도 쿠키 판정대로 거부한다"}],"coverage":{},"endTime":1793868745936,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analysis-access.mysql.spec.ts","startTime":1793868745936,"status":"skipped","summary":""},{"assertionResults":[{"ancestorTitles":["applyHttpServerTimeouts (ALB 앞 keep-alive)"],"duration":6011,"failureDetails":[],"failureMessages":[],"fullName":"applyHttpServerTimeouts (ALB 앞 keep-alive) 반사실: Node 기본 설정이면 8초 쉰 연결을 서버가 먼저 닫는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"반사실: Node 기본 설정이면 8초 쉰 연결을 서버가 먼저 닫는다"},{"ancestorTitles":["applyHttpServerTimeouts (ALB 앞 keep-alive)"],"duration":8008,"failureDetails":[],"failureMessages":[],"fullName":"applyHttpServerTimeouts (ALB 앞 keep-alive) 적용하면 8초 쉰 같은 연결로 두 번째 요청이 200","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"적용하면 8초 쉰 같은 연결로 두 번째 요청이 200"},{"ancestorTitles":["applyHttpServerTimeouts (ALB 앞 keep-alive)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"applyHttpServerTimeouts (ALB 앞 keep-alive) keep-alive 는 ALB 기본 유휴(60초)보다 길고, 헤더 대기는 그보다 길고, 요청 시간은 30분","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"keep-alive 는 ALB 기본 유휴(60초)보다 길고, 헤더 대기는 그보다 길고, 요청 시간은 30분"}],"endTime":1793868720046,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/http-server.helper.spec.ts","startTime":1793868706014,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":1213,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) enqueue → FIFO 순번 (만석이라 대기, position/ahead)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"enqueue → FIFO 순번 (만석이라 대기, position/ahead)"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":4405,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 맨앞 + 슬롯 여유 → READY, 그 자리를 admit hold로 선점(새치기 차단)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"맨앞 + 슬롯 여유 → READY, 그 자리를 admit hold로 선점(새치기 차단)"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":7407,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 만석(20슬롯)이면 맨앞이어도 READY 보류(WAITING)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"만석(20슬롯)이면 맨앞이어도 READY 보류(WAITING)"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 본인 하트비트 끊김 → status EXPIRED + 큐에서 제거","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"본인 하트비트 끊김 → status EXPIRED + 큐에서 제거"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 맨앞 이탈 → pruneFront로 정리, 뒷사람이 올라오고 dropped 집계","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"맨앞 이탈 → pruneFront로 정리, 뒷사람이 올라오고 dropped 집계"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) isStillQueued — 살아있으면 true(alive 갱신), 떠났으면 false","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"isStillQueued — 살아있으면 true(alive 갱신), 떠났으면 false"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8008,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 혼합 배포 중 scope 키가 없는 기존 queueId는 진료 큐로 유지한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"혼합 배포 중 scope 키가 없는 기존 queueId는 진료 큐로 유지한다"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8005,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) aliveCount — 유령(하트비트 만료) 제외","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"aliveCount — 유령(하트비트 만료) 제외"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8007,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 중간 이탈자 — pruneFront는 못 잡고(맨앞 생존), full prune이 잡는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"중간 이탈자 — pruneFront는 못 잡고(맨앞 생존), full prune이 잡는다"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8008,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 중간 좀비가 맨앞 도달 → pruneFront 즉시 제거, READY는 산 사람에게만","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"중간 좀비가 맨앞 도달 → pruneFront 즉시 제거, READY는 산 사람에게만"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8005,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) metrics — size/alive/ghost/capacity 집계","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"metrics — size/alive/ghost/capacity 집계"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) ★ 맨앞 백그라운드(active 만료) → 뒷사람이 슬롯 받음(건너뜀), 맨앞 순번 보존","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"★ 맨앞 백그라운드(active 만료) → 뒷사람이 슬롯 받음(건너뜀), 맨앞 순번 보존"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) ★ 슬롯 1자리뿐이면 맨앞만 READY, 뒷사람 WAITING (새치기 차단 유지)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"★ 슬롯 1자리뿐이면 맨앞만 READY, 뒷사람 WAITING (새치기 차단 유지)"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8005,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) ★ 빈 슬롯 N개 → 앞 N명 병렬 READY (1명씩 직렬 아님)","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"★ 빈 슬롯 N개 → 앞 N명 병렬 READY (1명씩 직렬 아님)"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8007,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) 맨앞 복귀(다시 폴링)하면 active 살아나 슬롯 받음","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"맨앞 복귀(다시 폴링)하면 active 살아나 슬롯 받음"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) inhouse 큐는 외부 벤더 자리가 남아도 공용 inhouse 슬롯만 사용한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"inhouse 큐는 외부 벤더 자리가 남아도 공용 inhouse 슬롯만 사용한다"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) inhouse 큐는 슬롯은 공유하지만 HIRA 공급자 rate 카운터는 공유하지 않는다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"inhouse 큐는 슬롯은 공유하지만 HIRA 공급자 rate 카운터는 공유하지 않는다"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8005,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) inhouse 공급자 설정이 없으면 무한 대기열 대신 즉시 중단한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"inhouse 공급자 설정이 없으면 무한 대기열 대신 즉시 중단한다"},{"ancestorTitles":["TreatQueueService 대기열 (실 redis)"],"duration":8006,"failureDetails":[{}],"failureMessages":["MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n    at Socket.<anonymous> (/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/node_modules/ioredis/built/redis/event_handler.js:207:37)\n    at Object.onceWrapper (node:events:634:26)\n    at Socket.emit (node:events:519:28)\n    at TCP.<anonymous> (node:net:347:12)"],"fullName":"TreatQueueService 대기열 (실 redis) READY 폴링이 마지막 슬롯을 hold한 뒤에도 같은 queueId로 입장한다","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"READY 폴링이 마지막 슬롯을 hold한 뒤에도 같은 queueId로 입장한다"}],"endTime":1793868720312,"message":"  ● TreatQueueService 대기열 (실 redis) › enqueue → FIFO 순번 (만석이라 대기, position/ahead)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 맨앞 + 슬롯 여유 → READY, 그 자리를 admit hold로 선점(새치기 차단)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 만석(20슬롯)이면 맨앞이어도 READY 보류(WAITING)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 본인 하트비트 끊김 → status EXPIRED + 큐에서 제거\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 맨앞 이탈 → pruneFront로 정리, 뒷사람이 올라오고 dropped 집계\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › isStillQueued — 살아있으면 true(alive 갱신), 떠났으면 false\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 혼합 배포 중 scope 키가 없는 기존 queueId는 진료 큐로 유지한다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › aliveCount — 유령(하트비트 만료) 제외\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 중간 이탈자 — pruneFront는 못 잡고(맨앞 생존), full prune이 잡는다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 중간 좀비가 맨앞 도달 → pruneFront 즉시 제거, READY는 산 사람에게만\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › metrics — size/alive/ghost/capacity 집계\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › ★ 맨앞 백그라운드(active 만료) → 뒷사람이 슬롯 받음(건너뜀), 맨앞 순번 보존\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › ★ 슬롯 1자리뿐이면 맨앞만 READY, 뒷사람 WAITING (새치기 차단 유지)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › ★ 빈 슬롯 N개 → 앞 N명 병렬 READY (1명씩 직렬 아님)\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › 맨앞 복귀(다시 폴링)하면 active 살아나 슬롯 받음\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › inhouse 큐는 외부 벤더 자리가 남아도 공용 inhouse 슬롯만 사용한다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › inhouse 큐는 슬롯은 공유하지만 HIRA 공급자 rate 카운터는 공유하지 않는다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › inhouse 공급자 설정이 없으면 무한 대기열 대신 즉시 중단한다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n\n  ● TreatQueueService 대기열 (실 redis) › READY 폴링이 마지막 슬롯을 hold한 뒤에도 같은 queueId로 입장한다\n\n    MaxRetriesPerRequestError: Reached the max retries per request limit (which is 3). Refer to \"maxRetriesPerRequest\" option for details.\n\n      at Socket.<anonymous> (node_modules/ioredis/built/redis/event_handler.js:207:37)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/dispatch/treat-queue.service.spec.ts","startTime":1793868578778,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["접근 계약 부팅 단언 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 부팅 단언 판정 레지스트리와 런타임 집합이 같으면 위반이 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"레지스트리와 런타임 집합이 같으면 위반이 없다"},{"ancestorTitles":["접근 계약 부팅 단언 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 부팅 단언 판정 음성: 행 하나를 뺀 레지스트리면 선언 없음 위반이 1이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"음성: 행 하나를 뺀 레지스트리면 선언 없음 위반이 1이다"},{"ancestorTitles":["접근 계약 부팅 단언 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 부팅 단언 판정 음성: 레지스트리에 없는 경로가 런타임에 있으면 미지 경로 위반이 1이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 레지스트리에 없는 경로가 런타임에 있으면 미지 경로 위반이 1이다"},{"ancestorTitles":["접근 계약 부팅 단언 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 부팅 단언 판정 레지스트리에만 있는 행은 런타임 부재 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"레지스트리에만 있는 행은 런타임 부재 위반이다"},{"ancestorTitles":["접근 계약 부팅 단언 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 부팅 단언 판정 음성: 예외 경로가 런타임 집합에 없어도 위반이 0이다 (예외가 누락 검사를 덮는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음성: 예외 경로가 런타임 집합에 없어도 위반이 0이다 (예외가 누락 검사를 덮는다)"},{"ancestorTitles":["접근 계약 예외표 · 접두 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 예외표 · 접두 경계 예외 경로 7개와 접두 /swagger/ 아래 경로는 위반이 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"예외 경로 7개와 접두 /swagger/ 아래 경로는 위반이 아니다"},{"ancestorTitles":["접근 계약 예외표 · 접두 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 예외표 · 접두 경계 음성: /swagger-admin 과 /swagger-admin/x 는 예외가 아니라 미지 경로 위반이다 (접두 경계)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: /swagger-admin 과 /swagger-admin/x 는 예외가 아니라 미지 경로 위반이다 (접두 경계)"},{"ancestorTitles":["접근 계약 예외표 · 접두 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 예외표 · 접두 경계 음성: 예외 경로의 다른 메서드(DELETE /health · POST /live)는 예외가 아니라 미지 경로 위반이다 (메서드 경계)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 예외 경로의 다른 메서드(DELETE /health · POST /live)는 예외가 아니라 미지 경로 위반이다 (메서드 경계)"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 warn 은 던지지 않고 Logger.warn 을 한 번 부른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"warn 은 던지지 않고 Logger.warn 을 한 번 부른다"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 음성(리뷰 R1): warn 에서 위반 0건이면 Logger.log 한 줄로 모드와 대조 행 수를 남기고 warn 은 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"음성(리뷰 R1): warn 에서 위반 0건이면 Logger.log 한 줄로 모드와 대조 행 수를 남기고 warn 은 부르지 않는다"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 fail 은 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"fail 은 던진다"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 음성: 라우터 스택 없음 입력과 수집 0건 입력은 단언 불능 위반 1건이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음성: 라우터 스택 없음 입력과 수집 0건 입력은 단언 불능 위반 1건이다"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 음성: 단언 불능은 warn 에서 던지지 않고 fail 에서 던진다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"음성: 단언 불능은 warn 에서 던지지 않고 fail 에서 던진다"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 음성: 라우터 스택이 없는 Express 앱은 단언 불능으로 세고 부팅을 멈추지 않는다 (warn)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음성: 라우터 스택이 없는 Express 앱은 단언 불능으로 세고 부팅을 멈추지 않는다 (warn)"},{"ancestorTitles":["접근 계약 모드 · 단언 불능"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 모드 · 단언 불능 음성: fail 모드에서 라우터 스택이 없는 앱은 단언 불능으로 던진다 (fail-open 금지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: fail 모드에서 라우터 스택이 없는 앱은 단언 불능으로 던진다 (fail-open 금지)"},{"ancestorTitles":["접근 계약 실제 라우터 수집"],"duration":81,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 실제 라우터 수집 실제 라우터: 최소 Nest 모듈의 GET /zz-probe 를 수집하고 빈 레지스트리에서 미지 경로 1건이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"실제 라우터: 최소 Nest 모듈의 GET /zz-probe 를 수집하고 빈 레지스트리에서 미지 경로 1건이다"},{"ancestorTitles":["접근 계약 실제 라우터 수집"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 실제 라우터 수집 음성: 목록 밖 와일드카드 핸들러(/zz-export/*)는 수집에서 빠지지 않고 미지 경로 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 목록 밖 와일드카드 핸들러(/zz-export/*)는 수집에서 빠지지 않고 미지 경로 위반이다"},{"ancestorTitles":["접근 계약 실제 라우터 수집"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 실제 라우터 수집 실제 Swagger 경로: setupSwagger 가 만든 문서 경로(-json · -yaml · 접두)는 예외표로 덮여 위반이 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"실제 Swagger 경로: setupSwagger 가 만든 문서 경로(-json · -yaml · 접두)는 예외표로 덮여 위반이 없다"},{"ancestorTitles":["접근 계약 와일드카드 등록 (미들웨어 층 대 핸들러)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 와일드카드 등록 (미들웨어 층 대 핸들러) 미들웨어 2층 + @Get(*) 핸들러 = 핸들러 GET /* 1건만 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미들웨어 2층 + @Get(*) 핸들러 = 핸들러 GET /* 1건만 위반이다"},{"ancestorTitles":["접근 계약 와일드카드 등록 (미들웨어 층 대 핸들러)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 와일드카드 등록 (미들웨어 층 대 핸들러) 음성: 미들웨어 층 없이 @Get(*) 핸들러만 있으면 GET /* 가 위반이다 (기준 개수로 가리지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 미들웨어 층 없이 @Get(*) 핸들러만 있으면 GET /* 가 위반이다 (기준 개수로 가리지 않는다)"},{"ancestorTitles":["접근 계약 와일드카드 등록 (미들웨어 층 대 핸들러)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 와일드카드 등록 (미들웨어 층 대 핸들러) 음성: 미들웨어 층이 1개로 줄고 핸들러가 남으면 위반이 숨지 않는다 (슬롯 빌림 금지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 미들웨어 층이 1개로 줄고 핸들러가 남으면 위반이 숨지 않는다 (슬롯 빌림 금지)"},{"ancestorTitles":["접근 계약 와일드카드 등록 (M4 · 1509 반례)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 와일드카드 등록 (M4 · 1509 반례) 미선언 와일드카드 핸들러는 위반으로 잡힌다 (미들웨어 2층은 빼고 핸들러 층은 남긴다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미선언 와일드카드 핸들러는 위반으로 잡힌다 (미들웨어 2층은 빼고 핸들러 층은 남긴다)"},{"ancestorTitles":["접근 계약 와일드카드 등록 (@All 핸들러의 모양은 미들웨어와 같다)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 와일드카드 등록 (@All 핸들러의 모양은 미들웨어와 같다) 음성(리뷰 R1 codex): 미들웨어 1층 + 미선언 @All(*) 면 핸들러 층 ACL 이 위반으로 남는다 (층 수 2 로 가리지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성(리뷰 R1 codex): 미들웨어 1층 + 미선언 @All(*) 면 핸들러 층 ACL 이 위반으로 남는다 (층 수 2 로 가리지 않는다)"},{"ancestorTitles":["접근 계약 와일드카드 등록 (@All 핸들러의 모양은 미들웨어와 같다)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 와일드카드 등록 (@All 핸들러의 모양은 미들웨어와 같다) 미들웨어 2층 + 미선언 @All(*): 미들웨어 두 층은 빠지고 핸들러 층의 GET /* 가 1건 위반으로 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"미들웨어 2층 + 미선언 @All(*): 미들웨어 두 층은 빠지고 핸들러 층의 GET /* 가 1건 위반으로 남는다"},{"ancestorTitles":["접근 계약 main.ts 배선"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 main.ts 배선 main.ts 는 listen 앞에서 비주석 부팅 단언 호출을 정확히 한 번 한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"main.ts 는 listen 앞에서 비주석 부팅 단언 호출을 정확히 한 번 한다"},{"ancestorTitles":["접근 계약 main.ts 배선"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 main.ts 배선 음성: 호출을 주석 처리하면 호출 0건이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 호출을 주석 처리하면 호출 0건이다"},{"ancestorTitles":["접근 계약 main.ts 배선"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 main.ts 배선 음성: 호출을 listen 뒤로 옮기면 before 가 거짓이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 호출을 listen 뒤로 옮기면 before 가 거짓이다"},{"ancestorTitles":["접근 계약 실제 AppModule 대조"],"duration":1283,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 실제 AppModule 대조 실제 AppModule: setupSwagger 를 붙인 앱이 fail 단언을 통과하고 미선언 핸들러가 없다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"실제 AppModule: setupSwagger 를 붙인 앱이 fail 단언을 통과하고 미선언 핸들러가 없다"},{"ancestorTitles":["접근 계약 범위 선언 (M6b Task 5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 범위 선언 (M6b Task 5) 현재 레지스트리는 범위 선언 누락 위반이 0건이다 (골든 목록 대조)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"현재 레지스트리는 범위 선언 누락 위반이 0건이다 (골든 목록 대조)"},{"ancestorTitles":["접근 계약 범위 선언 (M6b Task 5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 범위 선언 (M6b Task 5) 범위 선언 누락 1건: 신규 영업 자동 칸 행 하나를 더한 사본은 위반이 1이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"범위 선언 누락 1건: 신규 영업 자동 칸 행 하나를 더한 사본은 위반이 1이다"},{"ancestorTitles":["접근 계약 범위 선언 (M6b Task 5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 범위 선언 (M6b Task 5) 범위 선언 누락 1건: 저자 선언(author) 이면 신규 행도 위반이 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"범위 선언 누락 1건: 저자 선언(author) 이면 신규 행도 위반이 아니다"},{"ancestorTitles":["접근 계약 범위 선언 (M6b Task 5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 범위 선언 (M6b Task 5) 범위 필드가 없는 행은 조용히 통과하지 않고 단언 불능으로 센다 (fail-closed)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 필드가 없는 행은 조용히 통과하지 않고 단언 불능으로 센다 (fail-closed)"},{"ancestorTitles":["접근 계약 범위 선언 (M6b Task 5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"접근 계약 범위 선언 (M6b Task 5) fail 모드는 던진다: 범위 선언 누락 위반이 있으면 부팅 단언이 멈춘다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"fail 모드는 던진다: 범위 선언 누락 위반이 있으면 부팅 단언이 멈춘다"},{"ancestorTitles":["관리자 경로 대조 (D5-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 경로 대조 (D5-2) 맵 행이 없는 관리자 런타임 경로는 맵 누락 위반이다 (맵 한 행을 뺀 음성)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"맵 행이 없는 관리자 런타임 경로는 맵 누락 위반이다 (맵 한 행을 뺀 음성)"},{"ancestorTitles":["관리자 경로 대조 (D5-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 경로 대조 (D5-2) 맵 행이 런타임에 없으면 맵 고아 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"맵 행이 런타임에 없으면 맵 고아 위반이다"},{"ancestorTitles":["관리자 경로 대조 (D5-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 경로 대조 (D5-2) 맵 코드가 카탈로그에 없으면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"맵 코드가 카탈로그에 없으면 위반이다"},{"ancestorTitles":["관리자 경로 대조 (D5-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 경로 대조 (D5-2) 인증 가드 없는 /admin 핸들러는 위반이고, 예외 원장에 있으면 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"인증 가드 없는 /admin 핸들러는 위반이고, 예외 원장에 있으면 통과한다"},{"ancestorTitles":["관리자 경로 대조 (D5-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 경로 대조 (D5-2) 예외 사유가 빈칸이면 위반이다 (사유 빈칸 음성)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"예외 사유가 빈칸이면 위반이다 (사유 빈칸 음성)"},{"ancestorTitles":["집행 메타 대조 (관리자 화면 통합 단계 1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"집행 메타 대조 (관리자 화면 통합 단계 1) 정상 핸들러는 위반 0이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"정상 핸들러는 위반 0이다"},{"ancestorTitles":["집행 메타 대조 (관리자 화면 통합 단계 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"집행 메타 대조 (관리자 화면 통합 단계 1) 역할 칸 불일치: 핸들러 @Roles 를 바꾸고 레지스트리를 안 고친 사본 (순서는 보지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"역할 칸 불일치: 핸들러 @Roles 를 바꾸고 레지스트리를 안 고친 사본 (순서는 보지 않는다)"},{"ancestorTitles":["집행 메타 대조 (관리자 화면 통합 단계 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"집행 메타 대조 (관리자 화면 통합 단계 1) 역할 없는 인증 핸들러: 인증 가드만 단 새 핸들러 · 빈 @Roles 는 위반, 최고관리자 가드와 예외 셋은 통과","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"역할 없는 인증 핸들러: 인증 가드만 단 새 핸들러 · 빈 @Roles 는 위반, 최고관리자 가드와 예외 셋은 통과"},{"ancestorTitles":["집행 메타 대조 (관리자 화면 통합 단계 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"집행 메타 대조 (관리자 화면 통합 단계 1) 인증 핸들러 공개 표지: isPublic 이 있으면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"인증 핸들러 공개 표지: isPublic 이 있으면 위반이다"},{"ancestorTitles":["집행 메타 대조 (관리자 화면 통합 단계 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"집행 메타 대조 (관리자 화면 통합 단계 1) 조직관리자 쓰기 차단 없음: @Roles('admin','corp') 또는 org-manager 에 CorpReadonlyGuard 가 없으면 위반, corp-super 는 대상 밖","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"조직관리자 쓰기 차단 없음: @Roles('admin','corp') 또는 org-manager 에 CorpReadonlyGuard 가 없으면 위반, corp-super 는 대상 밖"},{"ancestorTitles":["집행 메타 대조 (관리자 화면 통합 단계 1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"집행 메타 대조 (관리자 화면 통합 단계 1) 분석 수준: 표지 있는 컨트롤러의 기업 핸들러가 수준을 빼면 위반, 표지에 가드가 없으면 위반","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"분석 수준: 표지 있는 컨트롤러의 기업 핸들러가 수준을 빼면 위반, 표지에 가드가 없으면 위반"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 정상 목록은 위반이 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"정상 목록은 위반이 없다"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 행 가드를 뺀 핸들러는 붉다 (역할이 admin 하나가 아니면)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행 가드를 뺀 핸들러는 붉다 (역할이 admin 하나가 아니면)"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 보조 조회에 대상 가드가 없거나 경로가 사라지면 붉다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"보조 조회에 대상 가드가 없거나 경로가 사라지면 붉다"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 옛 경로가 관리자 경로와 갈리면 붉다 (상속을 끊은 경우)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"옛 경로가 관리자 경로와 갈리면 붉다 (상속을 끊은 경우)"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 옛 경로에 세션 가드나 맵 행이 없으면 붉다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"옛 경로에 세션 가드나 맵 행이 없으면 붉다"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 옛 토큰 발급 경로가 되살아나면 붉다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"옛 토큰 발급 경로가 되살아나면 붉다"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":24,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 비시험 소스가 옛 토큰 헤더를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비시험 소스가 옛 토큰 헤더를 읽지 않는다"},{"ancestorTitles":["분석 열람 정적 규칙 음성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 열람 정적 규칙 음성 분석 서비스를 받는 새 컨트롤러는 목록에 드러난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"분석 서비스를 받는 새 컨트롤러는 목록에 드러난다"},{"ancestorTitles":["메뉴 권한 표 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 (E5) 카탈로그 코드는 칸 표 또는 메뉴 밖 목록에 있고, 칸 표 코드는 카탈로그 안이고, 메뉴 밖 사유가 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"카탈로그 코드는 칸 표 또는 메뉴 밖 목록에 있고, 칸 표 코드는 카탈로그 안이고, 메뉴 밖 사유가 있다"}],"endTime":1793868722607,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-contract/access-contract.spec.ts","startTime":1793868720315,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 plan: 선택 목록이 JSON 배열이 아니거나 항목 형태가 어긋나거나 행 번호가 겹치면 거부한다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"plan: 선택 목록이 JSON 배열이 아니거나 항목 형태가 어긋나거나 행 번호가 겹치면 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 plan: 반영 예정 밖 판정을 고르면 거부한다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"plan: 반영 예정 밖 판정을 고르면 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 plan: 재판정이 미리보기 판정과 로그인아이디가 같으면 반영하고 다르면 상태 변경이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"plan: 재판정이 미리보기 판정과 로그인아이디가 같으면 반영하고 다르면 상태 변경이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 plan: 파일에 없는 행 번호를 고르면 상태 변경이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"plan: 파일에 없는 행 번호를 고르면 상태 변경이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 plan: 고르지 않은 반영 예정 행을 미선택으로 센다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"plan: 고르지 않은 반영 예정 행을 미선택으로 센다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 outcome: 행 결과를 반영·실패·상태 변경으로 세고 미선택 계수를 함께 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"outcome: 행 결과를 반영·실패·상태 변경으로 세고 미선택 계수를 함께 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 outcome: 실패 사유에 그 행의 비밀번호 값이 있으면 가린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"outcome: 실패 사유에 그 행의 비밀번호 값이 있으면 가린다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":52,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 xlsx: 실패분 엑셀은 실패와 상태 변경 행만 싣고 비밀번호 열이 없다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"xlsx: 실패분 엑셀은 실패와 상태 변경 행만 싣고 비밀번호 열이 없다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 순수 모듈"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 순수 모듈 alarm: 알림 문구는 계수와 의심 확인·하한 강행·화면 수정 여부만 싣고 로그인아이디를 싣지 않으며 255자 안이다","invocations":1,"location":null,"numPassingAsserts":29,"retryReasons":[],"status":"passed","title":"alarm: 알림 문구는 계수와 의심 확인·하한 강행·화면 수정 여부만 싣고 로그인아이디를 싣지 않으며 255자 안이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 파일이 없으면 파일 누락으로 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"confirm: 파일이 없으면 파일 누락으로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 선택 목록 필드가 없으면 검증에서 거부한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"confirm: 선택 목록 필드가 없으면 검증에서 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":320,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 재판정에서 기업 선택 의심이면 확인 없이 쓰기 없이 거부한다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"confirm: 재판정에서 기업 선택 의심이면 확인 없이 쓰기 없이 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":296,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 신규 생성은 기존 업로드 검증·등록·최초 구독을 그 행으로 부른다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"confirm: 신규 생성은 기존 업로드 검증·등록·최초 구독을 그 행으로 부른다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":213,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 되살리기는 비밀번호 갱신·사용 복원·구독 복원 순이고 구독중이면 구독을 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"confirm: 되살리기는 비밀번호 갱신·사용 복원·구독 복원 순이고 구독중이면 구독을 건드리지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":152,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 되살리기에서 파일 비밀번호가 없거나 형식 밖이면 비밀번호를 갱신하지 않고 그 사실을 행에 싣는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"confirm: 되살리기에서 파일 비밀번호가 없거나 형식 밖이면 비밀번호를 갱신하지 않고 그 사실을 행에 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":131,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 구독 복원은 기존 구독처리 경로를 신규 구독 아님으로 부른다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"confirm: 구독 복원은 기존 구독처리 경로를 신규 구독 아님으로 부른다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":156,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 중지와 해지는 하한을 한 번 판정하고 행마다 강행 사용중지를 부른다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"confirm: 중지와 해지는 하한을 한 번 판정하고 행마다 강행 사용중지를 부른다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":282,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 하한 경고면 쓰기 없이 수치를 실어 거부한다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"confirm: 하한 경고면 쓰기 없이 수치를 실어 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":277,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 계약 없는 기업에 생성·복원 행이 있으면 쓰기 없이 거부한다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"confirm: 계약 없는 기업에 생성·복원 행이 있으면 쓰기 없이 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":280,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 한 행의 실패가 다음 행을 막지 않고 사유를 그 행에 싣는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"confirm: 한 행의 실패가 다음 행을 막지 않고 사유를 그 행에 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":126,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 상태 변경 행에는 쓰기를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"confirm: 상태 변경 행에는 쓰기를 부르지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":292,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 같은 기업의 확정이 진행 중이면 두 번째 요청을 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"confirm: 같은 기업의 확정이 진행 중이면 두 번째 요청을 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":284,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 요약 알림을 한 번 남기고 응답과 알림에 비밀번호 값이 없다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"confirm: 요약 알림을 한 번 남기고 응답과 알림에 비밀번호 값이 없다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":143,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 confirm: 쓰기 뒤 알림·실패분 엑셀이 실패해도 결과가 돌아오고 행 실패 로그에 행·기업·판정이 남는다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"confirm: 쓰기 뒤 알림·실패분 엑셀이 실패해도 결과가 돌아오고 행 실패 로그에 행·기업·판정이 남는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 확정 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 확정 엔드포인트 wiring: 반영이 부르는 기존 메서드가 서비스와 리포지터리에 실재한다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"wiring: 반영이 부르는 기존 메서드가 서비스와 리포지터리에 실재한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 양식 의심"],"duration":279,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 양식 의심 confirm: 양식 의심을 확인하지 않으면 어떤 쓰기도 없이 거부한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"confirm: 양식 의심을 확인하지 않으면 어떤 쓰기도 없이 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 양식 의심"],"duration":132,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 양식 의심 confirm: 확인 표지가 알림 문구에 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"confirm: 확인 표지가 알림 문구에 남는다"}],"endTime":1793868723704,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-confirm.spec.ts","startTime":1793868720048,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) map 행에 그 회원의 한 달 사용(전 주문)을 붙이고 반영 · 결제완료만 청구한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"map 행에 그 회원의 한 달 사용(전 주문)을 붙이고 반영 · 결제완료만 청구한다"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 합계는 청구 행만, 뺀 FC 는 월말 상태 · 이월 · 결제 미완료로 묶는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"합계는 청구 행만, 뺀 FC 는 월말 상태 · 이월 · 결제 미완료로 묶는다"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 반영 주문을 바꿔 고른 회원은 청구 행 한 줄만 남기고 막지 않는다(리뷰 M2)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"반영 주문을 바꿔 고른 회원은 청구 행 한 줄만 남기고 막지 않는다(리뷰 M2)"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":50,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 남긴 줄의 리포트 판정은 회원의 월말 상태다 — 「중복 주문」 표시가 아니다(리뷰 F3)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"남긴 줄의 리포트 판정은 회원의 월말 상태다 — 「중복 주문」 표시가 아니다(리뷰 F3)"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 한 회원의 청구 행이 둘이거나 회원 없는 청구 행이면 막고, 단가가 섞인 것은 막지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"한 회원의 청구 행이 둘이거나 회원 없는 청구 행이면 막고, 단가가 섞인 것은 막지 않는다"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 거래명세서는 틀 자리를 모두 채우고, 값은 이스케이프한다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"거래명세서는 틀 자리를 모두 채우고, 값은 이스케이프한다"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 단가가 섞이면 품목을 단가별 행으로 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"단가가 섞이면 품목을 단가별 행으로 낸다"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 파일 이름은 수기 규칙, 확정 전 표시, 위험 글자 치환 · RFC 5987 인코딩","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"파일 이름은 수기 규칙, 확정 전 표시, 위험 글자 치환 · RFC 5987 인코딩"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 원장 xlsx 는 FC원장 · 사용내역 · 요약이 같은 수를 낸다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"원장 xlsx 는 FC원장 · 사용내역 · 요약이 같은 수를 낸다"},{"ancestorTitles":["사용 FC 회차 원장 · 거래명세서 (D1)"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 회차 원장 · 거래명세서 (D1) 공급가액은 행에 나눠도 합이 명세서와 같다(리뷰 M1)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"공급가액은 행에 나눠도 합이 명세서와 같다(리뷰 M1)"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 기간은 양끝 포함 1~12달, 뒤집힘 · 상한 · 미래 달은 400","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"기간은 양끝 포함 1~12달, 뒤집힘 · 상한 · 미래 달은 400"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 기간 표기 · 파일 이름은 수기 규칙(해를 넘기면 두 해를 다 쓴다)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"기간 표기 · 파일 이름은 수기 규칙(해를 넘기면 두 해를 다 쓴다)"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 달마다 품목 한 행 · 공급가액은 합계에서 · 발급번호 · 주문번호 · 서명일은 마지막 달 말일","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"달마다 품목 한 행 · 공급가액은 합계에서 · 발급번호 · 주문번호 · 서명일은 마지막 달 말일"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 세 달부터 발급번호 · 주문번호는 처음~끝으로 줄인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"세 달부터 발급번호 · 주문번호는 처음~끝으로 줄인다"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":59,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 공급가액은 달마다 배분해 그 달 단독 명세와 같고, 기간 반올림 차는 요약 한 줄에 적는다(리뷰 F2)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"공급가액은 달마다 배분해 그 달 단독 명세와 같고, 기간 반올림 차는 요약 한 줄에 적는다(리뷰 F2)"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 해를 넘긴 발급번호 · 진행 중인 달은 오늘 날짜와 한 줄","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"해를 넘긴 발급번호 · 진행 중인 달은 오늘 날짜와 한 줄"},{"ancestorTitles":["기간 사용 FC 거래명세서 (D2)"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"기간 사용 FC 거래명세서 (D2) 기간 원장은 회차 칸 없이 달을 쌓고 요약에 합계 · 고유 FC 를 낸다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"기간 원장은 회차 칸 없이 달을 쌓고 요약에 합계 · 고유 FC 를 낸다"},{"ancestorTitles":["AdminAgencySettlementService 사용 FC 원장 가드 (D1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAgencySettlementService 사용 FC 원장 가드 (D1) 스냅샷 안에서 이름 없이 사건을 읽고, 확정액과 같으면 낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"스냅샷 안에서 이름 없이 사건을 읽고, 확정액과 같으면 낸다"},{"ancestorTitles":["AdminAgencySettlementService 사용 FC 원장 가드 (D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAgencySettlementService 사용 FC 원장 가드 (D1) 주문 기준 회차 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문 기준 회차 이면 400"},{"ancestorTitles":["AdminAgencySettlementService 사용 FC 원장 가드 (D1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAgencySettlementService 사용 FC 원장 가드 (D1) 확정액과 다름 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"확정액과 다름 이면 400"},{"ancestorTitles":["AdminAgencySettlementService 사용 FC 원장 가드 (D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAgencySettlementService 사용 FC 원장 가드 (D1) 확정액 없음 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"확정액 없음 이면 400"},{"ancestorTitles":["AdminAgencySettlementService 사용 FC 원장 가드 (D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAgencySettlementService 사용 FC 원장 가드 (D1) 같은 회원 청구 두 행 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 회원 청구 두 행 이면 400"},{"ancestorTitles":["AdminAgencySettlementService 사용 FC 원장 가드 (D1)"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"AdminAgencySettlementService 사용 FC 원장 가드 (D1) 확정 전이면 금액 대조 없이 미리보기로 낸다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"확정 전이면 금액 대조 없이 미리보기로 낸다"},{"ancestorTitles":["AgencyUsageStatementService (D2)"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"AgencyUsageStatementService (D2) 사건에서 바로 세어 원장을 낸다 — 회차를 읽지 않고, 이름 없이","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사건에서 바로 세어 원장을 낸다 — 회차를 읽지 않고, 이름 없이"},{"ancestorTitles":["AgencyUsageStatementService (D2)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AgencyUsageStatementService (D2) 공급받는자는 넘긴 값이 등록값을 이긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"공급받는자는 넘긴 값이 등록값을 이긴다"},{"ancestorTitles":["AgencyUsageStatementService (D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyUsageStatementService (D2) 기업이 없으면 404, 계약 단가를 못 쓰는 달이 있으면 그 달 이름으로 400","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기업이 없으면 404, 계약 단가를 못 쓰는 달이 있으면 그 달 이름으로 400"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) TrueType 머리만 받는다 — OTF · woff · woff2 · HTML 은 거른다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"TrueType 머리만 받는다 — OTF · woff · woff2 · HTML 은 거른다"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 주소는 설정이 아니라 상수다 — 운영 관리자 먼저, stg 관리자 다음","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"주소는 설정이 아니라 상수다 — 운영 관리자 먼저, stg 관리자 다음"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 운영 관리자에 글꼴이 아직 없으면(SPA HTML) stg 관리자에서 받고, 세 파일을 한 주소에서만 받는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"운영 관리자에 글꼴이 아직 없으면(SPA HTML) stg 관리자에서 받고, 세 파일을 한 주소에서만 받는다"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 해시가 다르거나 연결이 안 되면 다음 주소, 다 실패하면 503 이고 실패는 기억하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"해시가 다르거나 연결이 안 되면 다음 주소, 다 실패하면 503 이고 실패는 기억하지 않는다"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 길이 머리가 없어도 크기 상한을 받는 동안 건다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"길이 머리가 없어도 크기 상한을 받는 동안 건다"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":1501,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 모든 주소를 합친 시간 상한이 있고, 한 파일이 실패하면 같은 주소의 나머지 받기를 끊는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"모든 주소를 합친 시간 상한이 있고, 한 파일이 실패하면 같은 주소의 나머지 받기를 끊는다"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 성공한 글꼴은 다시 읽지 않고, 동시 요청은 한 번만 읽는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"성공한 글꼴은 다시 읽지 않고, 동시 요청은 한 번만 읽는다"},{"ancestorTitles":["StatementFontLoader (D6 — 관리자 주소 상수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"StatementFontLoader (D6 — 관리자 주소 상수) 배포본 해시는 Pretendard 1.3.9 TTF 세 개다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"배포본 해시는 Pretendard 1.3.9 TTF 세 개다"}],"endTime":1793868724561,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/active-member-ledger.spec.ts","startTime":1793868722617,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 판독"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 판독 edits: 행 수정이 JSON 배열이 아니거나 항목 형태가 어긋나거나 행 번호가 겹치거나 모르는 키가 있으면 행 수정 오류로 거부한다","invocations":1,"location":null,"numPassingAsserts":18,"retryReasons":[],"status":"passed","title":"edits: 행 수정이 JSON 배열이 아니거나 항목 형태가 어긋나거나 행 번호가 겹치거나 모르는 키가 있으면 행 수정 오류로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 판독"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 판독 edits: 파일에 없는 행 번호를 고치면 행 수정 오류로 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"edits: 파일에 없는 행 번호를 고치면 행 수정 오류로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 판독"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 판독 edits: 뺀 행에 값 수정이 함께 와도 제외로만 센다 — 한 행이 두 계수에 걸치지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"edits: 뺀 행에 값 수정이 함께 와도 제외로만 센다 — 한 행이 두 계수에 걸치지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 판독"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 판독 edits: 고친 값은 파일 판독과 같게 앞뒤 공백만 지우고 빈 값은 없음으로 둔다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"edits: 고친 값은 파일 판독과 같게 앞뒤 공백만 지우고 빈 값은 없음으로 둔다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 고친 값 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 고친 값 판정 judge: 고친 로그인아이디·비밀번호·연락처로 판정한다 — 형식 밖 행이 고친 뒤 반영 예정이 된다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"judge: 고친 로그인아이디·비밀번호·연락처로 판정한다 — 형식 밖 행이 고친 뒤 반영 예정이 된다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 고친 값 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 고친 값 판정 judge: 뺀 행은 제외 판정이고 파일 안 중복 계수와 조회에서 빠진다 — 남은 한 행은 중복이 풀린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"judge: 뺀 행은 제외 판정이고 파일 안 중복 계수와 조회에서 빠진다 — 남은 한 행은 중복이 풀린다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 고친 값 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 고친 값 판정 judge: 신규 생성 행의 연락처가 선택 기업에 이미 있거나 파일 안 신규 생성 행끼리 겹치면 연락처 중복이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"judge: 신규 생성 행의 연락처가 선택 기업에 이미 있거나 파일 안 신규 생성 행끼리 겹치면 연락처 중복이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 고친 값 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 고친 값 판정 judge: 판정 행은 고친 칸 이름과 연락처를 싣고 비밀번호 값은 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"judge: 판정 행은 고친 칸 이름과 연락처를 싣고 비밀번호 값은 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 엔드포인트"],"duration":423,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 엔드포인트 endpoint: preview 와 confirm 은 같은 행 수정으로 재판정해 고친 행을 반영하고 고친 비밀번호로 계정을 만든다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"endpoint: preview 와 confirm 은 같은 행 수정으로 재판정해 고친 행을 반영하고 고친 비밀번호로 계정을 만든다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 엔드포인트"],"duration":430,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 엔드포인트 endpoint: 연락처 중복 조회는 신규 생성 후보가 있을 때만 선택 기업으로 한 번 부르고 확정 검증과 같은 값을 넘긴다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"endpoint: 연락처 중복 조회는 신규 생성 후보가 있을 때만 선택 기업으로 한 번 부르고 확정 검증과 같은 값을 넘긴다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 엔드포인트"],"duration":147,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 엔드포인트 endpoint: 확정 알림과 로그에 화면 수정·제외 행 수가 실리고 고친 값은 실리지 않는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"endpoint: 확정 알림과 로그에 화면 수정·제외 행 수가 실리고 고친 값은 실리지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 행 수정 엔드포인트"],"duration":283,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 행 수정 엔드포인트 endpoint: 행을 빼도 기업 오선택 의심은 그대로다 — 뺀 행이 조회 키에 남는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"endpoint: 행을 빼도 기업 오선택 의심은 그대로다 — 뺀 행이 조회 키에 남는다"}],"endTime":1793868725237,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-edits.spec.ts","startTime":1793868723706,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 등록 — 선택 기업에 없고 비밀번호가 형식에 맞으면 신규 생성이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 등록 — 선택 기업에 없고 비밀번호가 형식에 맞으면 신규 생성이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 등록 — 선택 기업에 없고 비밀번호가 없거나 형식 밖이면 검토 항목이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 등록 — 선택 기업에 없고 비밀번호가 없거나 형식 밖이면 검토 항목이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 등록 — 선택 기업에서 중지된 계정은 되살리기이고 구독 상태를 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"judge: 등록 — 선택 기업에서 중지된 계정은 되살리기이고 구독 상태를 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 등록 — 선택 기업에서 사용중이면 구독중은 변경 없음, 아니면 구독 복원이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 등록 — 선택 기업에서 사용중이면 구독중은 변경 없음, 아니면 구독 복원이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 삭제 — 선택 기업에 없으면 미매칭 검토 항목이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 삭제 — 선택 기업에 없으면 미매칭 검토 항목이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 삭제 — 사용중은 중지, 중지인데 구독중은 해지, 중지·해지는 변경 없음이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 삭제 — 사용중은 중지, 중지인데 구독중은 해지, 중지·해지는 변경 없음이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 로그인아이디가 없거나 형식 밖이면 검토 항목이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 로그인아이디가 없거나 형식 밖이면 검토 항목이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 파일 안에서 겹치는 로그인아이디는 모든 출현을 검토 항목으로 둔다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 파일 안에서 겹치는 로그인아이디는 모든 출현을 검토 항목으로 둔다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: s 접두가 없는 숫자 코드는 s 를 붙여 대조하고 그 사실을 행에 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: s 접두가 없는 숫자 코드는 s 를 붙여 대조하고 그 사실을 행에 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: DB 로그인아이디가 대소문자·뒤 공백만 달라도 같은 아이디로 대조한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"judge: DB 로그인아이디가 대소문자·뒤 공백만 달라도 같은 아이디로 대조한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 구독 상태가 구독·해지·이력 없음 밖이면 검토 항목이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 구독 상태가 구독·해지·이력 없음 밖이면 검토 항목이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 기업별 매칭 건수를 선택 기업과 다른 기업으로 나누고 사용중 계수를 함께 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"judge: 기업별 매칭 건수를 선택 기업과 다른 기업으로 나누고 사용중 계수를 함께 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 다른 기업의 매칭이 선택 기업보다 많으면 기업 선택 의심을 켠다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"judge: 다른 기업의 매칭이 선택 기업보다 많으면 기업 선택 의심을 켠다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판정 judge: 행에 비밀번호 값을 싣지 않고 있음과 없음만 싣는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"judge: 행에 비밀번호 값을 싣지 않고 있음과 없음만 싣는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 preview: 기업 코드가 없거나 운영 기업 3곳 밖이면 검증에서 거부한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"preview: 기업 코드가 없거나 운영 기업 3곳 밖이면 검증에서 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 preview: 파일이 없으면 파일 누락으로 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"preview: 파일이 없으면 파일 누락으로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 preview: 기업 코드가 DB 에 없으면 이름 붙은 오류로 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"preview: 기업 코드가 DB 에 없으면 이름 붙은 오류로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":148,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 preview: 판독한 로그인아이디로 한 번 조회하고 판정을 돌려준다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"preview: 판독한 로그인아이디로 한 번 조회하고 판정을 돌려준다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":264,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 preview: 응답에 비밀번호 값이 없다 — 대조군으로 같은 파일의 판독 결과에는 있다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"preview: 응답에 비밀번호 값이 없다 — 대조군으로 같은 파일의 판독 결과에는 있다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":117,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 preview: 조회가 실패하면 로그인아이디 없이 코드와 건수만 로그에 남긴다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"preview: 조회가 실패하면 로그인아이디 없이 코드와 건수만 로그에 남긴다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 agencies: 운영 기업 코드 3곳만 조회하고 sf 는 묻지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"agencies: 운영 기업 코드 3곳만 조회하고 sf 는 묻지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 repository: 매칭 조회는 로그인아이디로만 거르고 기업으로 거르지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"repository: 매칭 조회는 로그인아이디로만 거르고 기업으로 거르지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 프리뷰 엔드포인트"],"duration":255,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 프리뷰 엔드포인트 wiring: 판정의 형식 검사는 기존 계정 업로드와 같은 규칙을 쓴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"wiring: 판정의 형식 검사는 기존 계정 업로드와 같은 규칙을 쓴다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 등록 — 연락처 01012345678 는 create 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 등록 — 연락처 01012345678 는 create 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 등록 — 연락처 010-1234-5678 는 create 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 등록 — 연락처 010-1234-5678 는 create 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 등록 — 연락처 null 는 create 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 등록 — 연락처 null 는 create 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 등록 — 연락처 01112345678 는 create-phone-invalid 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 등록 — 연락처 01112345678 는 create-phone-invalid 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 등록 — 연락처 +82 10 1234 5678 는 create-phone-invalid 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 등록 — 연락처 +82 10 1234 5678 는 create-phone-invalid 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 등록 — 연락처 010123 는 create-phone-invalid 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 등록 — 연락처 010123 는 create-phone-invalid 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 로그인아이디 true 는 s + 숫자가 아니라 형식 밖이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 로그인아이디 true 는 s + 숫자가 아니라 형식 밖이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 로그인아이디 null 는 s + 숫자가 아니라 형식 밖이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 로그인아이디 null 는 s + 숫자가 아니라 형식 밖이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 로그인아이디 test 는 s + 숫자가 아니라 형식 밖이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 로그인아이디 test 는 s + 숫자가 아니라 형식 밖이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 로그인아이디 abcd 는 s + 숫자가 아니라 형식 밖이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 로그인아이디 abcd 는 s + 숫자가 아니라 형식 밖이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: s + 숫자는 그대로 쓰고 숫자만 있으면 s 를 붙인다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: s + 숫자는 그대로 쓰고 숫자만 있으면 s 를 붙인다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 중간에 공백이 든 로그인아이디는 실존 계정을 가리키지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 중간에 공백이 든 로그인아이디는 실존 계정을 가리키지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 중간에 공백이 든 비밀번호는 형식 밖이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 중간에 공백이 든 비밀번호는 형식 밖이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 시트 계정삭제요청 를 true 의도로 올리면 어긋남은 register 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 시트 계정삭제요청 를 true 의도로 올리면 어긋남은 register 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 시트 계정등록요청 를 false 의도로 올리면 어긋남은 register 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 시트 계정등록요청 를 false 의도로 올리면 어긋남은 register 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 시트 계정등록요청 를 true 의도로 올리면 어긋남은 delete 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 시트 계정등록요청 를 true 의도로 올리면 어긋남은 delete 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 시트 Sheet1 를 false 의도로 올리면 어긋남은 register 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 시트 Sheet1 를 false 의도로 올리면 어긋남은 register 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 시트 계정등록 및 삭제 를 false 의도로 올리면 어긋남은 delete 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 시트 계정등록 및 삭제 를 false 의도로 올리면 어긋남은 delete 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 헤더가 정본과 다르면 양식 의심이고 행 판정은 그대로다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 헤더가 정본과 다르면 양식 의심이고 행 판정은 그대로다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 비정상 입력 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 비정상 입력 판정 judge: 시트·헤더가 모두 정본이면 양식 의심이 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"judge: 시트·헤더가 모두 정본이면 양식 의심이 없다"}],"endTime":1793868725626,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-preview.spec.ts","startTime":1793868724563,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) 시한 안에 끝나면 결과를 돌려주고 연결을 되돌린다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"시한 안에 끝나면 결과를 돌려주고 연결을 되돌린다"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":51,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) 시한을 넘으면 ETIMEDOUT 으로 거절하고 서버 질의에 KILL QUERY 를 보낸다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"시한을 넘으면 ETIMEDOUT 으로 거절하고 서버 질의에 KILL QUERY 를 보낸다"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":51,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 은 풀을 거치지 않는 전용 연결로 나간다 (풀 연결은 판정용 한 개뿐)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"KILL 은 풀을 거치지 않는 전용 연결로 나간다 (풀 연결은 판정용 한 개뿐)"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":31,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 번호는 정수만 쓴다 — 정수가 아니면 KILL 을 보내지 않고 연결을 파기한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"KILL 번호는 정수만 쓴다 — 정수가 아니면 KILL 을 보내지 않고 연결을 파기한다"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":82,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) 시한 뒤 도착한 연결은 즉시 되돌린다 (뒤 도착 연결 반환)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"시한 뒤 도착한 연결은 즉시 되돌린다 (뒤 도착 연결 반환)"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":31,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 연결을 열지 못하면 연결을 파기하고 거절은 그대로 낸다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"KILL 연결을 열지 못하면 연결을 파기하고 거절은 그대로 낸다"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":584,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 응답이 멈추면 전용 연결을 파기하고 다음 취소는 새 연결로 나간다 (1906)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"KILL 응답이 멈추면 전용 연결을 파기하고 다음 취소는 새 연결로 나간다 (1906)"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":52,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 연결이 끊겨 있으면 새 연결로 한 번 더 보낸다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"KILL 연결이 끊겨 있으면 새 연결로 한 번 더 보낸다"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":81,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 대상 스레드가 이미 끝났으면 (1094) 취소는 된 것으로 보고 연결을 파기하지도 다시 보내지도 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"KILL 대상 스레드가 이미 끝났으면 (1094) 취소는 된 것으로 보고 연결을 파기하지도 다시 보내지도 않는다"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) 늦은 KILL 실패는 뒤에 만든 새 연결을 지우지 않는다 (ABA)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"늦은 KILL 실패는 뒤에 만든 새 연결을 지우지 않는다 (ABA)"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":30,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) 시한을 넘으면 KILL 응답을 기다리지 않고 판정 연결을 즉시 파기해 풀 슬롯을 돌려준다 (슬롯)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"시한을 넘으면 KILL 응답을 기다리지 않고 판정 연결을 즉시 파기해 풀 슬롯을 돌려준다 (슬롯)"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":123,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) KILL 연결이 서버에서 끊겨 error 가 나도 프로세스를 죽이지 않고 다음 취소는 새 연결로 나간다 (유휴 끊김)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"KILL 연결이 서버에서 끊겨 error 가 나도 프로세스를 죽이지 않고 다음 취소는 새 연결로 나간다 (유휴 끊김)"},{"ancestorTitles":["판정 시한 취소 (judge-cancel)"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"판정 시한 취소 (judge-cancel) 작업이 동기로 던져도 판정 연결을 풀로 되돌리고 그 오류를 낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"작업이 동기로 던져도 판정 연결을 풀로 되돌리고 그 오류를 낸다"}],"endTime":1793868726388,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/judge-cancel.spec.ts","startTime":1793868725238,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 규칙 (i): 스위치가 꺼져 있으면 판정 결과와 무관하게 통과한다 (OFF)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"규칙 (i): 스위치가 꺼져 있으면 판정 결과와 무관하게 통과한다 (OFF)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 규칙 (ii): DB 오류와 최고관리자 조회 오류는 중단이다 (중단)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"규칙 (ii): DB 오류와 최고관리자 조회 오류는 중단이다 (중단)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 규칙 (iii): 최고관리자 전용 코드는 allow 만 통과하고, 표 부재 판정 불가도 거부한다 (최고관리자 전용 · 판정 불가)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"규칙 (iii): 최고관리자 전용 코드는 allow 만 통과하고, 표 부재 판정 불가도 거부한다 (최고관리자 전용 · 판정 불가)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 규칙 (ii-b): 관리자 행이 없으면 (삭제된 계정) 최고관리자 전용 코드도 미인증이다 (행 없음 · E0601)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"규칙 (ii-b): 관리자 행이 없으면 (삭제된 계정) 최고관리자 전용 코드도 미인증이다 (행 없음 · E0601)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 규칙 (iv)~(vi): 허용은 통과, 권한 없음은 permission 거부, 관리자 대상 밖은 통과한다 (E0607 사유)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"규칙 (iv)~(vi): 허용은 통과, 권한 없음은 permission 거부, 관리자 대상 밖은 통과한다 (E0607 사유)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 규칙 (vii): 판정 불가 중 표 부재 · 칸 부재도 거부하고 미지 코드도 거부한다 (판정 불가 · 미지 코드)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"규칙 (vii): 판정 불가 중 표 부재 · 칸 부재도 거부하고 미지 코드도 거부한다 (판정 불가 · 미지 코드)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 판정 불가 사유 표는 사유 12개 전부에 통과 · 거부 · 중단 중 하나를 준다 (판정 불가)","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"판정 불가 사유 표는 사유 12개 전부에 통과 · 거부 · 중단 중 하나를 준다 (판정 불가)"},{"ancestorTitles":["판정 규칙 (순수 함수)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"판정 규칙 (순수 함수) 자기 판정 경로는 강제 예외다 (자기 판정) — HEAD 는 GET 으로 접고 POST · 다른 rbac 행은 예외가 아니다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"자기 판정 경로는 강제 예외다 (자기 판정) — HEAD 는 GET 으로 접고 POST · 다른 rbac 행은 예외가 아니다"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 OFF 영역 요청은 동기로 통과하고 평가기와 공용 풀을 열지 않는다 (OFF)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"OFF 영역 요청은 동기로 통과하고 평가기와 공용 풀을 열지 않는다 (OFF)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 권한 행이 있는 관리자는 스위치가 켜진 영역에서 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"권한 행이 있는 관리자는 스위치가 켜진 영역에서 통과한다"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 권한 행이 없으면 (삭제된 계정) 미인증 401 E0601 로 닫는다 (행 없음 · E0601)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"권한 행이 없으면 (삭제된 계정) 미인증 401 E0601 로 닫는다 (행 없음 · E0601)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 NULL 신원 (athId 없음) 은 권한 집합을 읽지 않고 E0607 권한 거부다 (NULL 신원 · E0607)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"NULL 신원 (athId 없음) 은 권한 집합을 읽지 않고 E0607 권한 거부다 (NULL 신원 · E0607)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 권한 집합에 코드가 없으면 E0607 권한 거부를 낸다 (E0607 · 권한 없음)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"권한 집합에 코드가 없으면 E0607 권한 거부를 낸다 (E0607 · 권한 없음)"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 최고관리자 전용 코드는 최고관리자만 통과하고 나머지는 super-only 거부다 (최고관리자 전용 · isSuper)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자 전용 코드는 최고관리자만 통과하고 나머지는 super-only 거부다 (최고관리자 전용 · isSuper)"},{"ancestorTitles":["가드 강제 경로"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 판정 불가 중 표 부재 · 칸 부재는 스위치가 켜지면 E0607 거부이고 꺼지면 판정하지 않는다 (판정 불가 · E0607 · OFF)","invocations":1,"location":null,"numPassingAsserts":20,"retryReasons":[],"status":"passed","title":"판정 불가 중 표 부재 · 칸 부재는 스위치가 켜지면 E0607 거부이고 꺼지면 판정하지 않는다 (판정 불가 · E0607 · OFF)"},{"ancestorTitles":["가드 강제 경로"],"duration":1001,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 중단: 판정이 시한을 넘으면 503 이다 (중단 · 시한)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"중단: 판정이 시한을 넘으면 503 이다 (중단 · 시한)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 판정 불가 중 최고관리자 전용 코드의 표 부재는 거부한다 (판정 불가 · 최고관리자 전용)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"판정 불가 중 최고관리자 전용 코드의 표 부재는 거부한다 (판정 불가 · 최고관리자 전용)"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 중단: 권한 행 조회의 일반 DB 오류는 503 이다 (중단)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"중단: 권한 행 조회의 일반 DB 오류는 503 이다 (중단)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 중단: 권한 집합이 비었고 최고관리자 조회가 실패하면 일반 코드도 503 이다 (중단 · isSuper)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"중단: 권한 집합이 비었고 최고관리자 조회가 실패하면 일반 코드도 503 이다 (중단 · isSuper)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 중단 사유는 판정 사유 코드만 경고로 남기고 오류 메시지는 남기지 않는다 (중단 · 로그)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"중단 사유는 판정 사유 코드만 경고로 남기고 오류 메시지는 남기지 않는다 (중단 · 로그)"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 중단: 판정 준비 예외는 예외 코드를 경고로 남기고 503 이다 (중단 · 로그 · 준비)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"중단: 판정 준비 예외는 예외 코드를 경고로 남기고 503 이다 (중단 · 로그 · 준비)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 중단: 최고관리자 조회 오류는 최고관리자 전용 코드도 503 이다 (중단 · 최고관리자 전용)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"중단: 최고관리자 조회 오류는 최고관리자 전용 코드도 503 이다 (중단 · 최고관리자 전용)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 미지 코드는 실제 평가기에서 unknown-code 가 나와 거부된다 (미지 코드)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"미지 코드는 실제 평가기에서 unknown-code 가 나와 거부된다 (미지 코드)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 관리자 라벨인데 번호가 없으면 미인증 401 E0601 로 닫는다 (관리자 라벨)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 라벨인데 번호가 없으면 미인증 401 E0601 로 닫는다 (관리자 라벨)"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 관리자 계열 다른 종류 (영업) 는 강제 경로에서 통과한다 — controller 가드 몫 (관리자 라벨)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 계열 다른 종류 (영업) 는 강제 경로에서 통과한다 — controller 가드 몫 (관리자 라벨)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 옛 열람 토큰 헤더는 신원이 아니라 판정 없이 컨트롤러 가드로 넘긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"옛 열람 토큰 헤더는 신원이 아니라 판정 없이 컨트롤러 가드로 넘긴다"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 준비 실패: 라우트 읽기가 던지면 스위치가 켜진 상태에서 동기로 503 이다 (준비 실패)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"준비 실패: 라우트 읽기가 던지면 스위치가 켜진 상태에서 동기로 503 이다 (준비 실패)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 준비 실패: 스위치가 모두 꺼져 있으면 칸만 남기고 통과한다 (준비 실패 · OFF)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"준비 실패: 스위치가 모두 꺼져 있으면 칸만 남기고 통과한다 (준비 실패 · OFF)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 자기 판정 경로는 스위치가 켜져도 평가하지 않고 통과한다 (자기 판정)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자기 판정 경로는 스위치가 켜져도 평가하지 않고 통과한다 (자기 판정)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 영역 2 스위치가 켜지고 권한 집합에 코드가 없으면 E0607 권한 거부다 (영역 2 · 거부)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영역 2 스위치가 켜지고 권한 집합에 코드가 없으면 E0607 권한 거부다 (영역 2 · 거부)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 영역 2 스위치가 켜지고 권한이 있으면 통과한다 (영역 2 · 허용)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영역 2 스위치가 켜지고 권한이 있으면 통과한다 (영역 2 · 허용)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 영역 2 권한 행 조회의 일반 DB 오류는 503 이다 (영역 2 · 중단)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영역 2 권한 행 조회의 일반 DB 오류는 503 이다 (영역 2 · 중단)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 영역 3 스위치가 켜지고 권한 집합에 코드가 없으면 E0607 권한 거부다 (영역 3 · 거부)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영역 3 스위치가 켜지고 권한 집합에 코드가 없으면 E0607 권한 거부다 (영역 3 · 거부)"},{"ancestorTitles":["가드 강제 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 영역 3 스위치가 켜지고 권한이 있으면 통과한다 (영역 3 · 허용)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영역 3 스위치가 켜지고 권한이 있으면 통과한다 (영역 3 · 허용)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 영역 3 권한 행 조회의 일반 DB 오류는 503 이다 (영역 3 · 중단)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영역 3 권한 행 조회의 일반 DB 오류는 503 이다 (영역 3 · 중단)"},{"ancestorTitles":["가드 강제 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 다른 영역의 스위치만 켜진 요청은 판정하지 않고 통과한다 (영역 2 · 3 · OFF 짝)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"다른 영역의 스위치만 켜진 요청은 판정하지 않고 통과한다 (영역 2 · 3 · OFF 짝)"},{"ancestorTitles":["가드 강제 경로"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"가드 강제 경로 권한 집합 조회의 표 부재는 판정 불가라 E0607 거부이고 DB 오류는 503 이다 (판정 불가 · 중단 · 권한 집합)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"권한 집합 조회의 표 부재는 판정 불가라 E0607 거부이고 DB 오류는 503 이다 (판정 불가 · 중단 · 권한 집합)"}],"endTime":1793868726809,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/enforce.spec.ts","startTime":1793868725628,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["관리자 감시 인터셉터"],"duration":23,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 판정 예외는 unknown 으로 접힌다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정 예외는 unknown 으로 접힌다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":350,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 풀 포화 때 업무 요청이 시간 상한 안에 끝난다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"풀 포화 때 업무 요청이 시간 상한 안에 끝난다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 정지한 DB 작업이 있어도 동시 실행은 상한을 넘지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정지한 DB 작업이 있어도 동시 실행은 상한을 넘지 않는다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":357,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 시간 상한이 지나면 멈춘 판정의 슬롯을 돌려준다 (풀 연결은 여전히 쥐어 있다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"시간 상한이 지나면 멈춘 판정의 슬롯을 돌려준다 (풀 연결은 여전히 쥐어 있다)"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 감시 풀은 연결 2 · 대기 없음 · 큐 0 이다 (DB 쪽 동시 상한은 이 값이다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"감시 풀은 연결 2 · 대기 없음 · 큐 0 이다 (DB 쪽 동시 상한은 이 값이다)"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 최고관리자 판정 조회는 감시 연결로 간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자 판정 조회는 감시 연결로 간다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 판정 결과 unmapped 는 허용으로 세지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정 결과 unmapped 는 허용으로 세지 않는다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 요청 처리 중 감시 코드가 던져도 업무 요청은 끊기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"요청 처리 중 감시 코드가 던져도 업무 요청은 끊기지 않는다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":31,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 기록 단계가 던져도 처리되지 않은 거부가 생기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기록 단계가 던져도 처리되지 않은 거부가 생기지 않는다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 감시 연결마다 질의 시간 상한을 건다 (정지한 질의를 서버가 끊는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"감시 연결마다 질의 시간 상한을 건다 (정지한 질의를 서버가 끊는다)"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 SET 이 실패한 감시 연결은 버리고 경고를 남긴다 (R2)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"SET 이 실패한 감시 연결은 버리고 경고를 남긴다 (R2)"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 미배정 관리자 요청은 판정하지 않고 집계한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"미배정 관리자 요청은 판정하지 않고 집계한다"},{"ancestorTitles":["관리자 감시 인터셉터"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 인터셉터 판정 입력이 없으면 아무것도 세지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"판정 입력이 없으면 아무것도 세지 않는다"},{"ancestorTitles":["범위 강제 상수 커밋 값"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 강제 상수 커밋 값 SCOPE_ENFORCE_SALES_CORP 는 켜져 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SCOPE_ENFORCE_SALES_CORP 는 켜져 있다"}],"endTime":1793868727260,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/access-control.spec.ts","startTime":1793868726390,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":119,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 독립 도구로 암호화한 파일을 맞는 암호로 열어 행을 읽는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 독립 도구로 암호화한 파일을 맞는 암호로 열어 행을 읽는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":127,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 틀린 암호는 암호 불일치로 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 틀린 암호는 암호 불일치로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 암호 파일에 암호가 없으면 암호 필요로 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"xlsx: 암호 파일에 암호가 없으면 암호 필요로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":29,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 암호 없는 xlsx 는 암호 입력과 무관하게 그대로 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"xlsx: 암호 없는 xlsx 는 암호 입력과 무관하게 그대로 읽는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: xlsx 도 암호 파일도 아니면 읽기 불가로 거부한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"xlsx: xlsx 도 암호 파일도 아니면 읽기 불가로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 관측한 방식 밖의 암호화는 지원 불가로 거부한다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"xlsx: 관측한 방식 밖의 암호화는 지원 불가로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":118,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: FAT 목록이 DIFAT 섹터로 넘어간 파일도 연다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"xlsx: FAT 목록이 DIFAT 섹터로 넘어간 파일도 연다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":148,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 비밀번호 칸이 빈 행을 throw 없이 없음으로 센다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"xlsx: 비밀번호 칸이 빈 행을 throw 없이 없음으로 센다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":127,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 헤더와 ※ 안내 행은 행으로 세지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"xlsx: 헤더와 ※ 안내 행은 행으로 세지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 시트가 둘 이상이면 읽기 불가로 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 시트가 둘 이상이면 읽기 불가로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — xlsx 판독"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — xlsx 판독 xlsx: 손상된 CFB(순환 체인 · 범위 밖 섹터 · 잘린 스트림)는 멈추지 않고 읽기 불가로 거부한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"xlsx: 손상된 CFB(순환 체인 · 범위 밖 섹터 · 잘린 스트림)는 멈추지 않고 읽기 불가로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 칸 안 공백은 앞뒤만 지운다 — 중간은 남겨 형식 검사에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 칸 안 공백은 앞뒤만 지운다 — 중간은 남겨 형식 검사에 넘긴다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ '로그인아이디', '성명', '비밀번호', '연락처' ] 의 정본 일치는 true 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ '로그인아이디', '성명', '비밀번호', '연락처' ] 의 정본 일치는 true 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ '로그인아이디', '성명', '비밀번호', '연락처', null ] 의 정본 일치는 true 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ '로그인아이디', '성명', '비밀번호', '연락처', null ] 의 정본 일치는 true 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ '로그인 아이디', '성명', '비밀번호', '연락처' ] 의 정본 일치는 true 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ '로그인 아이디', '성명', '비밀번호', '연락처' ] 의 정본 일치는 true 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ 'ID', 'NAME', 'PASSWORD', 'TEL' ] 의 정본 일치는 false 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ 'ID', 'NAME', 'PASSWORD', 'TEL' ] 의 정본 일치는 false 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ '순번', '로그인아이디', '성명', '비밀번호', '연락처' ] 의 정본 일치는 false 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ '순번', '로그인아이디', '성명', '비밀번호', '연락처' ] 의 정본 일치는 false 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ '로그인아이디', '성명', '연락처' ] 의 정본 일치는 false 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ '로그인아이디', '성명', '연락처' ] 의 정본 일치는 false 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 [ '성명', '로그인아이디', '비밀번호', '연락처' ] 의 정본 일치는 false 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 [ '성명', '로그인아이디', '비밀번호', '연락처' ] 의 정본 일치는 false 다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 판독 정규화와 양식 대조"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 판독 정규화와 양식 대조 xlsx: 헤더 없이 데이터로 시작해도 판독 결과에 1행 값이 실리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"xlsx: 헤더 없이 데이터로 시작해도 판독 결과에 1행 값이 실리지 않는다"}],"endTime":1793868727623,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-xlsx.spec.ts","startTime":1793868726811,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 parse: 의도가 없거나 허용값 밖이면 검증에서 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"parse: 의도가 없거나 허용값 밖이면 검증에서 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 parse: 파일이 없으면 파일 누락으로 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"parse: 파일이 없으면 파일 누락으로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트"],"duration":302,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 parse: 응답은 집계만 싣고 비밀번호 값을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"parse: 응답은 집계만 싣고 비밀번호 값을 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트"],"duration":127,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 parse: 대조군 — 같은 파일의 파싱 결과에는 비밀번호 값이 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"parse: 대조군 — 같은 파일의 파싱 결과에는 비밀번호 값이 있다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트","요청 로그"],"duration":26,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 요청 로그 log: 대조군 — 누출 배선이면 JSON 본문 값이 로그에 실린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"log: 대조군 — 누출 배선이면 JSON 본문 값이 로그에 실린다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트","요청 로그"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 요청 로그 log: multipart 로 받은 파일 암호는 요청 시작 직렬화에 실리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"log: multipart 로 받은 파일 암호는 요청 시작 직렬화에 실리지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트","요청 로그"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 요청 로그 log: multipart 파일 부분으로 받은 붙여 넣은 표는 요청 로그에 실리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"log: multipart 파일 부분으로 받은 붙여 넣은 표는 요청 로그에 실리지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트","요청 로그"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 요청 로그 log: 실제 req 직렬화는 redact 가 없어도 본문을 아예 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"log: 실제 req 직렬화는 redact 가 없어도 본문을 아예 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트","요청 로그"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 요청 로그 log: 직렬화가 본문을 실어도 redact 가 파일 암호를 가린다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"log: 직렬화가 본문을 실어도 redact 가 파일 암호를 가린다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 파싱 엔드포인트","요청 로그"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 파싱 엔드포인트 요청 로그 log: 직렬화가 본문을 실어도 redact 가 행 수정의 평문 비밀번호를 가린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"log: 직렬화가 본문을 실어도 redact 가 행 수정의 평문 비밀번호를 가린다"}],"endTime":1793868728034,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-parse.spec.ts","startTime":1793868727262,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatService certify claim"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim blocks duplicate certify claims","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"blocks duplicate certify claims"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim sets and releases only its own claim token","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"sets and releases only its own claim token"},{"ancestorTitles":["TreatService certify claim"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim refreshes only its own long-running certify claim","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"refreshes only its own long-running certify claim"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim fails open when Redis is unavailable","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"fails open when Redis is unavailable"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim stores and restores a completed certify response for a reopened invite","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"stores and restores a completed certify response for a reopened invite"},{"ancestorTitles":["TreatService certify claim"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim reports pending while the original certify claim is still running","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reports pending while the original certify claim is still running"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim expires an old SMS response and releases its order and engine reservation","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"expires an old SMS response and releases its order and engine reservation"},{"ancestorTitles":["TreatService certify claim"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim does not create a new attempt when an uncached active order remains","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"does not create a new attempt when an uncached active order remains"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim expires an uncached active order after the SMS deadline","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"expires an uncached active order after the SMS deadline"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim keeps an expired resume active when collection won the DB race","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"keeps an expired resume active when collection won the DB race"},{"ancestorTitles":["TreatService certify claim"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim keeps the DB expiry result when engine cancellation fails","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"keeps the DB expiry result when engine cancellation fails"},{"ancestorTitles":["TreatService certify claim"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim claims a regular collection before emitting the background job","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"claims a regular collection before emitting the background job"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim does not emit collection when expiry already won the DB race","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not emit collection when expiry already won the DB race"},{"ancestorTitles":["TreatService certify claim"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatService certify claim keeps the B2C background flow outside the order-detail claim","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"keeps the B2C background flow outside the order-detail claim"},{"ancestorTitles":["TreatDispatcher certify cancellation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatDispatcher certify cancellation releases the reservation and cancels an inhouse engine session","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"releases the reservation and cancels an inhouse engine session"}],"endTime":1793868728042,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/treat-certify-claim.spec.ts","startTime":1793868727627,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":32,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 1행이 정본 열 이름이고 시트가 하나면 정본 배치로 확정돼 사람 확인이 필요 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"layout: 1행이 정본 열 이름이고 시트가 하나면 정본 배치로 확정돼 사람 확인이 필요 없다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 열 이름 별칭으로 쓰임을 제안한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"layout: 열 이름 별칭으로 쓰임을 제안한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 열 이름이 없으면 값 모양으로 로그인아이디·연락처·비밀번호 열을 제안하고 순번 열은 고르지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"layout: 열 이름이 없으면 값 모양으로 로그인아이디·연락처·비밀번호 열을 제안하고 순번 열은 고르지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 비밀번호로 보이는 칸과 비밀번호 열은 예시와 열 이름을 응답에 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"layout: 비밀번호로 보이는 칸과 비밀번호 열은 예시와 열 이름을 응답에 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 대조군 — 가린 열의 값은 같은 파일의 판독 결과에 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"layout: 대조군 — 가린 열의 값은 같은 파일의 판독 결과에 있다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 마지막 데이터 행을 열 이름 행으로 골라도 비밀번호 모양 값을 열 이름에 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"layout: 마지막 데이터 행을 열 이름 행으로 골라도 비밀번호 모양 값을 열 이름에 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 시트가 둘 이상이면 시트 목록을 싣고 고른 시트를 읽는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"layout: 시트가 둘 이상이면 시트 목록을 싣고 고른 시트를 읽는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 열 이름 행을 고르면 그 아래부터 읽고 없음이면 1행부터 읽는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"layout: 열 이름 행을 고르면 그 아래부터 읽고 없음이면 1행부터 읽는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 배치를 받으면 위치가 아니라 배치의 열로 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"layout: 배치를 받으면 위치가 아니라 배치의 열로 읽는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 배치가 JSON 이 아니거나 로그인아이디 열이 없거나 열이 겹치거나 범위 밖이면 열 배치 오류로 거부한다","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"layout: 배치가 JSON 이 아니거나 로그인아이디 열이 없거나 열이 겹치거나 범위 밖이면 열 배치 오류로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":29,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 열 이름이 비밀번호인 열을 다른 쓰임으로 받으면 열 배치 오류로 거부하고 제안은 그 열을 다른 쓰임에 두지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"layout: 열 이름이 비밀번호인 열을 다른 쓰임으로 받으면 열 배치 오류로 거부하고 제안은 그 열을 다른 쓰임에 두지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 layout: 배치를 받은 판정은 1행이 정본과 달라도 양식 의심을 켜지 않고 시트 이름 의도 대조는 그대로 켠다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"layout: 배치를 받은 판정은 1행이 정본과 달라도 양식 의심을 켜지 않고 시트 이름 의도 대조는 그대로 켠다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치 엔드포인트"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 엔드포인트 endpoint: parse 는 배치 없이도 제안 배치와 그 배치로 센 계수를 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"endpoint: parse 는 배치 없이도 제안 배치와 그 배치로 센 계수를 돌려준다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치 엔드포인트"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 엔드포인트 endpoint: parse 는 시트·열 이름 행만 받으면 그 조건으로 쓰임을 다시 제안한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"endpoint: parse 는 시트·열 이름 행만 받으면 그 조건으로 쓰임을 다시 제안한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치 엔드포인트"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 엔드포인트 endpoint: parse 는 쓰임까지 받으면 헤더 의심을 끄고 그 배치로 센 계수를 돌려준다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"endpoint: parse 는 쓰임까지 받으면 헤더 의심을 끄고 그 배치로 센 계수를 돌려준다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치 엔드포인트"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 엔드포인트 endpoint: preview 와 confirm 은 받은 배치로 판독한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"endpoint: preview 와 confirm 은 받은 배치로 판독한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 열 배치 엔드포인트"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 열 배치 엔드포인트 endpoint: 배치 없는 preview 는 지금처럼 정본 위치로 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"endpoint: 배치 없는 preview 는 지금처럼 정본 위치로 읽는다"}],"endTime":1793868728449,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-layout.spec.ts","startTime":1793868728044,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":43,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.issue — createIssue","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.issue — createIssue"},{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":41,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.corp.charge — createCorpMoney","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.corp.charge — createCorpMoney"},{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":41,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.grant — createGrant","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.grant — createGrant"},{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":41,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.grant.single — createGrantSingle","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.grant.single — createGrantSingle"},{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":67,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.issue.upload — uploadIssue","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.issue.upload — uploadIssue"},{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":49,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.grant.upload — uploadGrant","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.grant.upload — uploadGrant"},{"ancestorTitles":["txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다"],"duration":42,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 여섯 트랜잭션 경로가 커밋 대기를 담은 상한을 낸다 money.charge-request.approve — processChargeRequest","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"money.charge-request.approve — processChargeRequest"},{"ancestorTitles":["txDurationMs — 커밋 대기가 길어지면 값도 커진다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 커밋 대기가 길어지면 값도 커진다 대기를 3배로 늘리면 방출값도 정확히 3배다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"대기를 3배로 늘리면 방출값도 정확히 3배다"},{"ancestorTitles":["txDurationMs — 트랜잭션이 없는 계층은 null 이다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"txDurationMs — 트랜잭션이 없는 계층은 null 이다 T4 만료 처리는 null 을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"T4 만료 처리는 null 을 싣는다"}],"endTime":1793868728534,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-duration.spec.ts","startTime":1793868728036,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["expired-money 스케줄"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"expired-money 스케줄 [MS12-sched-1] 전건 성공이면 0 을 돌려주고 하트비트를 실패 0 · 성공 표시로 한 번 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-sched-1] 전건 성공이면 0 을 돌려주고 하트비트를 실패 0 · 성공 표시로 한 번 남긴다"},{"ancestorTitles":["expired-money 스케줄"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expired-money 스케줄 [MS12-sched-2] 실패 회원이 1 이면 1 을 돌려주고 하트비트 없이 실패 수만 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS12-sched-2] 실패 회원이 1 이면 1 을 돌려주고 하트비트 없이 실패 수만 남긴다"},{"ancestorTitles":["expired-money 스케줄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expired-money 스케줄 [MS12-sched-3] 기록 쓰기가 실패하면 그 reject 를 삼키지 않고 호출부로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[MS12-sched-3] 기록 쓰기가 실패하면 그 reject 를 삼키지 않고 호출부로 돌려준다"},{"ancestorTitles":["expired-money 스케줄"],"duration":211,"failureDetails":[],"failureMessages":[],"fullName":"expired-money 스케줄 [MS12-sched-4] 모듈을 읽는 것만으로는 프로세스를 끝내거나 앱 컨텍스트를 열지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS12-sched-4] 모듈을 읽는 것만으로는 프로세스를 끝내거나 앱 컨텍스트를 열지 않는다"},{"ancestorTitles":["expired-money 스케줄"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"expired-money 스케줄 [MS12-sched-5] 종료 코드: 0 만 0, 그 밖의 값과 던짐은 1 이고 던질 때 메시지 본문을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"[MS12-sched-5] 종료 코드: 0 만 0, 그 밖의 값과 던짐은 1 이고 던질 때 메시지 본문을 싣지 않는다"}],"endTime":1793868728876,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/expired-money.schedule.spec.ts","startTime":1793868728451,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyFcService account update Excel"],"duration":37,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService account update Excel parses editable fields and rejects an invalid use status","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"parses editable fields and rejects an invalid use status"},{"ancestorTitles":["AgencyFcService account update Excel"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService account update Excel stores per-row detail after an account update upload","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"stores per-row detail after an account update upload"},{"ancestorTitles":["AgencyFcService account update Excel"],"duration":215,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService account update Excel hashes each row separately even when passwords are equal","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"hashes each row separately even when passwords are equal"}],"endTime":1793868729025,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/fc-agency-account-update.spec.ts","startTime":1793868728536,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["회차 주문 목록 — corp 에는 사유를 열지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회차 주문 목록 — corp 에는 사유를 열지 않는다 corp 응답은 사유 칸 · 이중 청구 후보 회차가 비어 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"corp 응답은 사유 칸 · 이중 청구 후보 회차가 비어 있다"},{"ancestorTitles":["회차 주문 목록 — corp 에는 사유를 열지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회차 주문 목록 — corp 에는 사유를 열지 않는다 corp 는 이중 청구 후보로 거를 수 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"corp 는 이중 청구 후보로 거를 수 없다"},{"ancestorTitles":["회차 주문 목록 — corp 에는 사유를 열지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회차 주문 목록 — corp 에는 사유를 열지 않는다 corp 상세에는 운영자 알림 칸(다시 담기 · 이중 청구 후보)이 없다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"corp 상세에는 운영자 알림 칸(다시 담기 · 이중 청구 후보)이 없다"},{"ancestorTitles":["회차 주문 목록 — corp 에는 사유를 열지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회차 주문 목록 — corp 에는 사유를 열지 않는다 corp 는 사유로 거를 수 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"corp 는 사유로 거를 수 없다"},{"ancestorTitles":["회차 주문 목록 — corp 에는 사유를 열지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회차 주문 목록 — corp 에는 사유를 열지 않는다 관리자는 사유를 그대로 본다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자는 사유를 그대로 본다"}],"endTime":1793868729284,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/settlement-corp-reason.spec.ts","startTime":1793868729030,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["비밀번호 재설정 — 조회 단계의 티켓 발급"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 조회 단계의 티켓 발급 조회: 서명 비밀이 없거나 회원 JWT 비밀과 같으면 본인인증·DB 조회 전에 503 으로 닫힌다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"조회: 서명 비밀이 없거나 회원 JWT 비밀과 같으면 본인인증·DB 조회 전에 503 으로 닫힌다"},{"ancestorTitles":["비밀번호 재설정 — 조회 단계의 티켓 발급"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 조회 단계의 티켓 발급 조회: 본인인증한 회원의 memId 와 비밀번호 지문을 담은 10분 티켓을 발급한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"조회: 본인인증한 회원의 memId 와 비밀번호 지문을 담은 10분 티켓을 발급한다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 티켓이 없으면 401(E0606)이고 DB 를 읽지도 쓰지도 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"재설정: 티켓이 없으면 401(E0606)이고 DB 를 읽지도 쓰지도 않는다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 다른 회원의 티켓이면 조회 조건이 티켓 memId 와 본문 loginId 를 함께 걸어 401 이고 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"재설정: 다른 회원의 티켓이면 조회 조건이 티켓 memId 와 본문 loginId 를 함께 걸어 401 이고 쓰지 않는다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 만료된 티켓이면 401 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재설정: 만료된 티켓이면 401 이다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 회원 access 토큰과 같은 비밀의 송장 토큰은 티켓 자리를 지나지 못한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"재설정: 회원 access 토큰과 같은 비밀의 송장 토큰은 티켓 자리를 지나지 못한다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 서명이 다른 티켓이면 401 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재설정: 서명이 다른 티켓이면 401 이다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 지문이 없거나 비밀번호가 이미 바뀐 티켓이면 비밀번호 대조 전에 401 이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"재설정: 지문이 없거나 비밀번호가 이미 바뀐 티켓이면 비밀번호 대조 전에 401 이다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":78,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 갱신 조건이 티켓 회원 한 행과 발급 당시 비밀번호 해시뿐이고 refresh 토큰을 비운다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"재설정: 갱신 조건이 티켓 회원 한 행과 발급 당시 비밀번호 해시뿐이고 refresh 토큰을 비운다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":40,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 같은 티켓의 동시 제출 중 늦은 쪽은 갱신 0행이라 401 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재설정: 같은 티켓의 동시 제출 중 늦은 쪽은 갱신 0행이라 401 이다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 서명 비밀이 없거나 회원 JWT 비밀과 같으면 401 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"재설정: 서명 비밀이 없거나 회원 JWT 비밀과 같으면 401 이다"},{"ancestorTitles":["비밀번호 재설정 — 티켓 검증과 한 행 갱신"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 티켓 검증과 한 행 갱신 재설정: 새 비밀번호가 기존과 같으면 400 이고 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재설정: 새 비밀번호가 기존과 같으면 400 이고 쓰지 않는다"},{"ancestorTitles":["비밀번호 재설정 — 컨트롤러의 티켓 전달"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 컨트롤러의 티켓 전달 컨트롤러: 조회 응답이 티켓을 본문과 httpOnly 쿠키(10분)로 싣고 저장 금지 헤더를 단다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"컨트롤러: 조회 응답이 티켓을 본문과 httpOnly 쿠키(10분)로 싣고 저장 금지 헤더를 단다"},{"ancestorTitles":["비밀번호 재설정 — 컨트롤러의 티켓 전달"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 컨트롤러의 티켓 전달 컨트롤러: 재설정은 헤더 티켓을 쿠키보다 먼저 쓰고 성공하면 쿠키를 지운다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"컨트롤러: 재설정은 헤더 티켓을 쿠키보다 먼저 쓰고 성공하면 쿠키를 지운다"},{"ancestorTitles":["비밀번호 재설정 — 컨트롤러의 티켓 전달"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 컨트롤러의 티켓 전달 컨트롤러: 재설정은 헤더가 없으면 쿠키 티켓을 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"컨트롤러: 재설정은 헤더가 없으면 쿠키 티켓을 쓴다"},{"ancestorTitles":["비밀번호 재설정 — 컨트롤러의 티켓 전달"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 재설정 — 컨트롤러의 티켓 전달 로그인: 응답의 access·refresh 토큰을 콘솔에 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"로그인: 응답의 access·refresh 토큰을 콘솔에 남기지 않는다"},{"ancestorTitles":["재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set 갱신: refresh 를 읽은 뒤 비밀번호가 바뀌어 갱신이 0행이면 새 토큰 없이 401 이고, 갱신 조건은 memId · 읽은 해시 · 받은 토큰이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"갱신: refresh 를 읽은 뒤 비밀번호가 바뀌어 갱신이 0행이면 새 토큰 없이 401 이고, 갱신 조건은 memId · 읽은 해시 · 받은 토큰이다"},{"ancestorTitles":["재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set 갱신: 비밀번호 · 토큰이 그대로면 새 토큰을 발급하고 갱신 조건에 받은 토큰을 건다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"갱신: 비밀번호 · 토큰이 그대로면 새 토큰을 발급하고 갱신 조건에 받은 토큰을 건다"},{"ancestorTitles":["재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set 로그인: 앱 로그인 중 비밀번호가 바뀌어 refresh 기록이 0행이면 토큰 없이 실패하고, 기록 조건은 memId 와 읽은 해시다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"로그인: 앱 로그인 중 비밀번호가 바뀌어 refresh 기록이 0행이면 토큰 없이 실패하고, 기록 조건은 memId 와 읽은 해시다"},{"ancestorTitles":["재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set 로그인: 비밀번호가 그대로면 앱 refresh 토큰을 기록해 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"로그인: 비밀번호가 그대로면 앱 refresh 토큰을 기록해 돌려준다"},{"ancestorTitles":["재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"재설정과 경합한 refresh 기록 — 읽은 해시 compare-and-set 로그인: 같은 초에 두 번 발급한 refresh 토큰이 서로 다르다(발급마다 jti)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"로그인: 같은 초에 두 번 발급한 refresh 토큰이 서로 다르다(발급마다 jti)"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 후계 jti"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 후계 jti 갱신: 같은 토큰으로 같은 초에 온 갱신은 같은 새 토큰을 받고, 토큰이 다르면 새 토큰도 다르다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"갱신: 같은 토큰으로 같은 초에 온 갱신은 같은 새 토큰을 받고, 토큰이 다르면 새 토큰도 다르다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 후계 jti"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 후계 jti 갱신: JSON 으로 감싼 토큰도 감싸지 않은 토큰과 같은 후계를 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신: JSON 으로 감싼 토큰도 감싸지 않은 토큰과 같은 후계를 낸다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 후계 jti"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 후계 jti 갱신: 옛 형식(jti 없음) 토큰도 jti 있는 새 토큰을 내고 받은 토큰과 값이 다르다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"갱신: 옛 형식(jti 없음) 토큰도 jti 있는 새 토큰을 내고 받은 토큰과 값이 다르다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 진 쪽의 후계 채택"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 진 쪽의 후계 채택 갱신: 토큰 조건이 0행이고 저장값이 받은 토큰의 후계면 그 토큰을 돌려주고 다시 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"갱신: 토큰 조건이 0행이고 저장값이 받은 토큰의 후계면 그 토큰을 돌려주고 다시 쓰지 않는다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 진 쪽의 후계 채택"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 진 쪽의 후계 채택 갱신: 토큰 조건이 0행이고 저장값이 한 번 더 회전한 다음 세대 이면 401 이고 다시 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신: 토큰 조건이 0행이고 저장값이 한 번 더 회전한 다음 세대 이면 401 이고 다시 쓰지 않는다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 진 쪽의 후계 채택"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 진 쪽의 후계 채택 갱신: 토큰 조건이 0행이고 저장값이 signout 이 비운 자리 이면 401 이고 다시 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신: 토큰 조건이 0행이고 저장값이 signout 이 비운 자리 이면 401 이고 다시 쓰지 않는다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 진 쪽의 후계 채택"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 진 쪽의 후계 채택 갱신: 토큰 조건이 0행이고 저장값이 재설정이 비운 자리 이면 401 이고 다시 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신: 토큰 조건이 0행이고 저장값이 재설정이 비운 자리 이면 401 이고 다시 쓰지 않는다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 진 쪽의 후계 채택"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 진 쪽의 후계 채택 갱신: 토큰 조건이 0행이고 저장값이 다른 기기 로그인의 무작위 jti 이면 401 이고 다시 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신: 토큰 조건이 0행이고 저장값이 다른 기기 로그인의 무작위 jti 이면 401 이고 다시 쓰지 않는다"},{"ancestorTitles":["같은 토큰의 동시 갱신 — 진 쪽의 후계 채택"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 토큰의 동시 갱신 — 진 쪽의 후계 채택 갱신: 토큰 조건이 0행이고 저장값이 후계지만 해시가 바뀐 자리 이면 401 이고 다시 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신: 토큰 조건이 0행이고 저장값이 후계지만 해시가 바뀐 자리 이면 401 이고 다시 쓰지 않는다"},{"ancestorTitles":["회원 access 발급 실물 — principalKind 클레임"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 access 발급 실물 — principalKind 클레임 발급 실물 · 회원 로그인 · access 토큰이 principalKind member 를 싣고 회원 형상 판정과 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발급 실물 · 회원 로그인 · access 토큰이 principalKind member 를 싣고 회원 형상 판정과 같다"},{"ancestorTitles":["회원 access 발급 실물 — principalKind 클레임"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 access 발급 실물 — principalKind 클레임 발급 실물 · 회원 갱신 · 새 access 토큰도 principalKind member 를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"발급 실물 · 회원 갱신 · 새 access 토큰도 principalKind member 를 싣는다"}],"endTime":1793868729296,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/user/password-reset.spec.ts","startTime":1793868728879,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["stair"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"stair 구정책 재현 — 상품원가 정률 50% 설정으로 2026H1 인별 실지급 3건과 운영비 합계를 재현한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"구정책 재현 — 상품원가 정률 50% 설정으로 2026H1 인별 실지급 3건과 운영비 합계를 재현한다"},{"ancestorTitles":["stair"],"duration":26,"failureDetails":[],"failureMessages":[],"fullName":"stair 건 분할 불변 — 채널 합 1건과 12,900원 단위 분할이 같은 정확값을 낸다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"건 분할 불변 — 채널 합 1건과 12,900원 단위 분할이 같은 정확값을 낸다"},{"ancestorTitles":["stair"],"duration":66,"failureDetails":[],"failureMessages":[],"fullName":"stair 계단 불변식 — 고정 시드 무작위 설정 500건에서 독립 재계산한 차감 합이 공급가액과 같다","invocations":1,"location":null,"numPassingAsserts":2001,"retryReasons":[],"status":"passed","title":"계단 불변식 — 고정 시드 무작위 설정 500건에서 독립 재계산한 차감 합이 공급가액과 같다"},{"ancestorTitles":["stair"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"stair 음수 잔여 — 원가와 보상 합이 공급가액을 넘으면 NEGATIVE_RESIDUAL 로 드러난다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음수 잔여 — 원가와 보상 합이 공급가액을 넘으면 NEGATIVE_RESIDUAL 로 드러난다"},{"ancestorTitles":["stair"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"stair 누락 — 원가 없는 상품·보상 없는 채널·채널 없는 건이 각각 플래그로 드러난다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"누락 — 원가 없는 상품·보상 없는 채널·채널 없는 건이 각각 플래그로 드러난다"},{"ancestorTitles":["stair"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"stair 적용범위 — 채널 A 의 보상 계약이 채널 B 의 건에 적용되지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"적용범위 — 채널 A 의 보상 계약이 채널 B 의 건에 적용되지 않는다"},{"ancestorTitles":["stair"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"stair 설정 오류 — 잔여 0개·같은 수취인 둘·알 수 없는 수취인·산정방식·범위 값이면 ok false","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"설정 오류 — 잔여 0개·같은 수취인 둘·알 수 없는 수취인·산정방식·범위 값이면 ok false"},{"ancestorTitles":["stair"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"stair 원가 변경 반응 — 원가만 바꾼 두 산출의 보험유니버스 몫 차가 건수 × 원가차다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"원가 변경 반응 — 원가만 바꾼 두 산출의 보험유니버스 몫 차가 건수 × 원가차다"},{"ancestorTitles":["stair"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"stair 과거 재현 — 대체 시작일 이전 건의 산출은 대체 전후가 같다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"과거 재현 — 대체 시작일 이전 건의 산출은 대체 전후가 같다"},{"ancestorTitles":["stair"],"duration":200,"failureDetails":[],"failureMessages":[],"fullName":"stair 과거 불변 — 고정 시드 무작위 변경 200회 중 수락 50회 이상이고 수락 뒤에도 오늘까지 날짜 건의 산출이 같다","invocations":1,"location":null,"numPassingAsserts":58,"retryReasons":[],"status":"passed","title":"과거 불변 — 고정 시드 무작위 변경 200회 중 수락 50회 이상이고 수락 뒤에도 오늘까지 날짜 건의 산출이 같다"},{"ancestorTitles":["stair"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"stair 기업 범위 원가 — 같은 날 기업 범위와 상품 범위가 둘 다 유효하면 기업 범위가 적용된다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기업 범위 원가 — 같은 날 기업 범위와 상품 범위가 둘 다 유효하면 기업 범위가 적용된다"},{"ancestorTitles":["stair"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"stair 기업 범위 원가 — 기업 코드가 없는 건은 상품 범위를 타고 산출이 기업 범위 행이 없을 때와 같다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"기업 범위 원가 — 기업 코드가 없는 건은 상품 범위를 타고 산출이 기업 범위 행이 없을 때와 같다"},{"ancestorTitles":["stair"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"stair 기업 범위 원가 — 기업 코드와 상품 코드가 같은 문자열이어도 범위 종류가 다르면 매칭하지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"기업 범위 원가 — 기업 코드와 상품 코드가 같은 문자열이어도 범위 종류가 다르면 매칭하지 않는다"},{"ancestorTitles":["stair"],"duration":65,"failureDetails":[],"failureMessages":[],"fullName":"stair 기업 범위 원가 — 고정 시드 무작위 설정 500건에 기업 범위 행을 섞어도 차감 합이 공급가액과 같다","invocations":1,"location":null,"numPassingAsserts":2003,"retryReasons":[],"status":"passed","title":"기업 범위 원가 — 고정 시드 무작위 설정 500건에 기업 범위 행을 섞어도 차감 합이 공급가액과 같다"}],"endTime":1793868729681,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/stair.spec.ts","startTime":1793868729298,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 대조 scope: 기존 계정의 조직이 관할 조직 부분트리 안이면 관할 안이고 밖이거나 경로가 없으면 관할 밖이며 조직이 없으면 미배정이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"scope: 기존 계정의 조직이 관할 조직 부분트리 안이면 관할 안이고 밖이거나 경로가 없으면 관할 밖이며 조직이 없으면 미배정이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 대조"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 대조 scope: 관할 조직을 받지 않으면 대조하지 않고 행과 요약의 관할 칸이 빈다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"scope: 관할 조직을 받지 않으면 대조하지 않고 행과 요약의 관할 칸이 빈다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 대조 scope: 관할 대조는 행 판정과 기업·양식 의심을 바꾸지 않는다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"scope: 관할 대조는 행 판정과 기업·양식 의심을 바꾸지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 대조 scope: 신규 생성 행 · 다른 기업에만 있는 행 · 뺀 행은 관할 대조에 들지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"scope: 신규 생성 행 · 다른 기업에만 있는 행 · 뺀 행은 관할 대조에 들지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 엔드포인트"],"duration":136,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 엔드포인트 endpoint: preview 는 선택 기업의 조직 목록에서 관할 조직을 찾아 대조한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"endpoint: preview 는 선택 기업의 조직 목록에서 관할 조직을 찾아 대조한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 엔드포인트 endpoint: 관할 조직이 선택 기업의 조직 목록 밖이면 이름 붙은 오류로 거부한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"endpoint: 관할 조직이 선택 기업의 조직 목록 밖이면 이름 붙은 오류로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 엔드포인트 endpoint: preview DTO 는 26자 이하 관할 조직 칸을 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"endpoint: preview DTO 는 26자 이하 관할 조직 칸을 받는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 엔드포인트 agencies: 기업마다 사용 중인 조직을 싣고 조직이 없는 기업은 빈 목록이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"agencies: 기업마다 사용 중인 조직을 싣고 조직이 없는 기업은 빈 목록이다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 질의"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 질의 repository: 관할 조직 목록은 기업 번호로 거르고 사용 중이며 경로가 있는 조직만 고른다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"repository: 관할 조직 목록은 기업 번호로 거르고 사용 중이며 경로가 있는 조직만 고른다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 관할 조직 질의"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 관할 조직 질의 repository: 회원 조회는 조직 표를 결합해 소속 조직 번호·이름·경로를 고른다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"repository: 회원 조회는 조직 표를 결합해 소속 조직 번호·이름·경로를 고른다"}],"endTime":1793868729690,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-scope.spec.ts","startTime":1793868729286,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["인증 요청별 리마인드"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"인증 요청별 리마인드 ainvite 이전 리마인드는 새 인증을 사용할 수 없다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"ainvite 이전 리마인드는 새 인증을 사용할 수 없다"},{"ancestorTitles":["인증 요청별 리마인드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"인증 요청별 리마인드 loss-invite 이전 리마인드는 새 인증을 사용할 수 없다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"loss-invite 이전 리마인드는 새 인증을 사용할 수 없다"},{"ancestorTitles":["인증 요청별 리마인드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"인증 요청별 리마인드 다른 초대와 종료된 세션은 사용할 수 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"다른 초대와 종료된 세션은 사용할 수 없다"},{"ancestorTitles":["완료 요청 서버 차단"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"완료 요청 서버 차단 간편인증은 구 식별값·누락·다른 주문을 차단하고 문자는 유지한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"간편인증은 구 식별값·누락·다른 주문을 차단하고 문자는 유지한다"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이전 의료비 리마인드 완료는 현재 세션을 선점하거나 기관을 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"이전 의료비 리마인드 완료는 현재 세션을 선점하거나 기관을 호출하지 않는다"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"backgroundTreat 이전 진료 리마인드 완료는 분석 이벤트와 예약 선점을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"backgroundTreat 이전 진료 리마인드 완료는 분석 이벤트와 예약 선점을 만들지 않는다"},{"ancestorTitles":[],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"treat 이전 진료 리마인드 완료는 분석 이벤트와 예약 선점을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"treat 이전 진료 리마인드 완료는 분석 이벤트와 예약 선점을 만들지 않는다"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이전 취소 응답이 늦게 도착해도 새 세션과 예약은 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이전 취소 응답이 늦게 도착해도 새 세션과 예약은 유지한다"}],"endTime":1793868730060,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alimtalk/alimtalk-reminder-attempt.spec.ts","startTime":1793868729683,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["알림 설정 메타 카탈로그"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알림 설정 메타 카탈로그 레지스트리 전수 전제: 규칙과 설정이 0건이 아니다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"레지스트리 전수 전제: 규칙과 설정이 0건이 아니다"},{"ancestorTitles":["알림 설정 메타 카탈로그"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"알림 설정 메타 카탈로그 설정 메타 계약: 시간 키는 unit ms 를 갖는다","invocations":1,"location":null,"numPassingAsserts":47,"retryReasons":[],"status":"passed","title":"설정 메타 계약: 시간 키는 unit ms 를 갖는다"},{"ancestorTitles":["알림 설정 메타 카탈로그"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 설정 메타 카탈로그 설정 메타 계약: 비율 키는 unit ratio 를 갖는다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"설정 메타 계약: 비율 키는 unit ratio 를 갖는다"},{"ancestorTitles":["알림 설정 메타 카탈로그"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"알림 설정 메타 카탈로그 설정 메타 계약: JSON 키 3종이 keyOptions·keySet·필드별 shape 를 갖는다","invocations":1,"location":null,"numPassingAsserts":105,"retryReasons":[],"status":"passed","title":"설정 메타 계약: JSON 키 3종이 keyOptions·keySet·필드별 shape 를 갖는다"},{"ancestorTitles":["알림 설정 메타 카탈로그"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알림 설정 메타 카탈로그 테스트 문구 계약: 전 규칙이 sampleText 와 테스트 배너를 갖는다","invocations":1,"location":null,"numPassingAsserts":39,"retryReasons":[],"status":"passed","title":"테스트 문구 계약: 전 규칙이 sampleText 와 테스트 배너를 갖는다"},{"ancestorTitles":["알림 억제창 메타 계약 (MS2 D4 · MS3 D12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알림 억제창 메타 계약 (MS2 D4 · MS3 D12) MS6-C1 억제창을 선언한 규칙은 하트비트와 진료 모니터링 24시간, 정기결제 36시간이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS6-C1 억제창을 선언한 규칙은 하트비트와 진료 모니터링 24시간, 정기결제 36시간이다"},{"ancestorTitles":["알림 억제창 메타 계약 (MS2 D4 · MS3 D12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 억제창 메타 계약 (MS2 D4 · MS3 D12) MS2-7: 억제창 값은 양의 유한수이고, 부재는 관리자 설정 alert_dedupe_ms 로 읽힌다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-7: 억제창 값은 양의 유한수이고, 부재는 관리자 설정 alert_dedupe_ms 로 읽힌다"},{"ancestorTitles":["MS6 감시 목록 계약 (배포 분기 · 일 1회 집합)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MS6 감시 목록 계약 (배포 분기 · 일 1회 집합) [MS8-C1] ddx-verdict 는 2분 기대와 설명으로 감시 목록에 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS8-C1] ddx-verdict 는 2분 기대와 설명으로 감시 목록에 있다"},{"ancestorTitles":["MS6 감시 목록 계약 (배포 분기 · 일 1회 집합)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MS6 감시 목록 계약 (배포 분기 · 일 1회 집합) MS6-C2 감시 목록 키 집합과 dockerfile case 집합의 차이는 명시 예외 목록과 같다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS6-C2 감시 목록 키 집합과 dockerfile case 집합의 차이는 명시 예외 목록과 같다"},{"ancestorTitles":["MS6 감시 목록 계약 (배포 분기 · 일 1회 집합)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"MS6 감시 목록 계약 (배포 분기 · 일 1회 집합) MS6-C3 일 1회 집합은 감시 목록의 부분집합이고 하루 기대이며 전역 유예 기본값은 2 다","invocations":1,"location":null,"numPassingAsserts":19,"retryReasons":[],"status":"passed","title":"MS6-C3 일 1회 집합은 감시 목록의 부분집합이고 하루 기대이며 전역 유예 기본값은 2 다"}],"endTime":1793868730082,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-settings-catalog.spec.ts","startTime":1793868729705,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["rolesAllow — 역할 또는 신원 종류"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rolesAllow — 역할 또는 신원 종류 @Roles('corp-super') 는 기업 최고만 통과한다 (조직관리자 · 영업 · 관리자 거부)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"@Roles('corp-super') 는 기업 최고만 통과한다 (조직관리자 · 영업 · 관리자 거부)"},{"ancestorTitles":["rolesAllow — 역할 또는 신원 종류"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"rolesAllow — 역할 또는 신원 종류 @Roles('corp') 는 기업 최고와 조직관리자를 둘 다 통과시킨다 (회귀)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"@Roles('corp') 는 기업 최고와 조직관리자를 둘 다 통과시킨다 (회귀)"},{"ancestorTitles":["rolesAllow — 역할 또는 신원 종류"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"rolesAllow — 역할 또는 신원 종류 메타가 없으면 통과하고, corpScope 없는 corp 신원은 종류 낱말을 통과하지 못한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"메타가 없으면 통과하고, corpScope 없는 corp 신원은 종류 낱말을 통과하지 못한다"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminOrderController].getOrderList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminOrderController].getOrderList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminOrderController].downloadOrderList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminOrderController].downloadOrderList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminOrderController].getDetail 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminOrderController].getDetail 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminOrderController].cancelOrder 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminOrderController].cancelOrder 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencyFcAdminController].assignOrg 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencyFcAdminController].assignOrg 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencyFcAdminController].setOrgManager 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencyFcAdminController].setOrgManager 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencyFcAdminController].orgPermissionUpload 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencyFcAdminController].orgPermissionUpload 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencyFcAdminController].downloadOrgPermissionUploadForm 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencyFcAdminController].downloadOrgPermissionUploadForm 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAnalyzeController].downloadOriginalList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAnalyzeController].downloadOriginalList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencySettlementAdminController].getAgencySettlementList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencySettlementAdminController].getAgencySettlementList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencySettlementAdminController].getAgencySettlement 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencySettlementAdminController].getAgencySettlement 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencySettlementAdminController].getAgencySettlementOrderList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencySettlementAdminController].getAgencySettlementOrderList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencySettlementAdminController].downloadAgencySettlementOrderExcel 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencySettlementAdminController].downloadAgencySettlementOrderExcel 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AgencySettlementAdminController].downloadAgencySettlementStatement 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AgencySettlementAdminController].downloadAgencySettlementStatement 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].getIssueList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].getIssueList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].getIssueDetail 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].getIssueDetail 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].createCorpMoney 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].createCorpMoney 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].createGrant 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].createGrant 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].createGrantSingle 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].createGrantSingle 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].cancelPayment 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].cancelPayment 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].processRefund 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].processRefund 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].getChargeRequestList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].getChargeRequestList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].createChargeRequest 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].createChargeRequest 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function MoneyAdminController].cancelChargeRequest 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function MoneyAdminController].cancelChargeRequest 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function CorpMyController].getMyAgency 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function CorpMyController].getMyAgency 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function CorpMyController].updateMyAgency 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function CorpMyController].updateMyAgency 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function CorpMyController].getMyInfo 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function CorpMyController].getMyInfo 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function CorpMyController].updateMyInfo 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function CorpMyController].updateMyInfo 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAgencyOrganizationController].getList 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAgencyOrganizationController].getList 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAgencyOrganizationController].create 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAgencyOrganizationController].create 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAgencyOrganizationController].getDetail 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAgencyOrganizationController].getDetail 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAgencyOrganizationController].update 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAgencyOrganizationController].update 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAgencyOrganizationController].move 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAgencyOrganizationController].move 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAgencyOrganizationController].delete 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAgencyOrganizationController].delete 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAlarmController].updateAlarmChecked 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAlarmController].updateAlarmChecked 를 통과하는 신원 종류"},{"ancestorTitles":["RolesGuard — 손 검사를 옮긴 핸들러"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"RolesGuard — 손 검사를 옮긴 핸들러 [Function AdminAlarmController].deleteAlarm 를 통과하는 신원 종류","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[Function AdminAlarmController].deleteAlarm 를 통과하는 신원 종류"},{"ancestorTitles":["CorpReadonlyGuard — 조직관리자 마이페이지 쓰기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CorpReadonlyGuard — 조직관리자 마이페이지 쓰기 조직관리자의 POST verify-password · my-info 는 @AllowOrgWrite 로 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"조직관리자의 POST verify-password · my-info 는 @AllowOrgWrite 로 통과한다"},{"ancestorTitles":["CorpReadonlyGuard — 조직관리자 마이페이지 쓰기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CorpReadonlyGuard — 조직관리자 마이페이지 쓰기 조직관리자의 POST my-agency 는 쓰기 차단 가드에서도 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조직관리자의 POST my-agency 는 쓰기 차단 가드에서도 거부된다"},{"ancestorTitles":["CorpAnalysisViewGuard — 분석 노출 토글"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CorpAnalysisViewGuard — 분석 노출 토글 수준 0 기업은 403, 수준 1 기업은 통과, 관리자는 수준과 무관하게 통과","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"수준 0 기업은 403, 수준 1 기업은 통과, 관리자는 수준과 무관하게 통과"}],"endTime":1793868730411,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/roles.guard.spec.ts","startTime":1793868730062,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 FaxAdminController · admin → 통과","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"FaxAdminController · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 FaxAdminController · sales → 403","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"FaxAdminController · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 FaxAdminController · corp → 403","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"FaxAdminController · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 FaxAdminController · none → 403","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"FaxAdminController · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatTestController · admin → 통과","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"TreatTestController · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatTestController · sales → 403","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"TreatTestController · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":37,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatTestController · corp → 403","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"TreatTestController · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatTestController · none → 403","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"TreatTestController · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 ClinicalResultController · admin → 통과","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"ClinicalResultController · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 ClinicalResultController · sales → 403","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"ClinicalResultController · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 ClinicalResultController · corp → 403","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"ClinicalResultController · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 ClinicalResultController · none → 403","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"ClinicalResultController · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesController · admin → 통과","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"AdminCoursesController · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesController · sales → 403","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"AdminCoursesController · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesController · corp → 403","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"AdminCoursesController · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesController · none → 403","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"AdminCoursesController · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesReviewsController · admin → 통과","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"AdminCoursesReviewsController · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesReviewsController · sales → 403","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"AdminCoursesReviewsController · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesReviewsController · corp → 403","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"AdminCoursesReviewsController · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesReviewsController · none → 403","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"AdminCoursesReviewsController · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatMonitorController · admin → 통과","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"TreatMonitorController · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatMonitorController · sales → 403","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"TreatMonitorController · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatMonitorController · corp → 403","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"TreatMonitorController · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatMonitorController · none → 403","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"TreatMonitorController · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getAllList · admin → 통과","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MenuController · getAllList · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getAllList · sales → 403","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MenuController · getAllList · sales → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getAllList · corp → 403","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MenuController · getAllList · corp → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getAllList · none → 403","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MenuController · getAllList · none → 403"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getMyMenus · admin → 통과","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MenuController · getMyMenus · admin → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getMyMenus · sales → 통과","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MenuController · getMyMenus · sales → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getMyMenus · corp → 통과","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MenuController · getMyMenus · corp → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · getMyMenus · none → 통과","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MenuController · getMyMenus · none → 통과"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 FaxAdminController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"FaxAdminController · isPublic 우회가 없다"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatTestController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"TreatTestController · isPublic 우회가 없다"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 ClinicalResultController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"ClinicalResultController · isPublic 우회가 없다"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"AdminCoursesController · isPublic 우회가 없다"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 AdminCoursesReviewsController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"AdminCoursesReviewsController · isPublic 우회가 없다"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 TreatMonitorController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"TreatMonitorController · isPublic 우회가 없다"},{"ancestorTitles":["관리자 컨트롤러 역할 경계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 컨트롤러 역할 경계 MenuController · isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MenuController · isPublic 우회가 없다"}],"endTime":1793868730584,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/admin-roles-access.spec.ts","startTime":1793868730084,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["createIssue — 사유 유형 판정"],"duration":31,"failureDetails":[],"failureMessages":[],"fullName":"createIssue — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createIssue — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createIssue — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["createIssue — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createIssue — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createIssue — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createIssue — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["createIssue — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createIssue — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["createCorpMoney — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createCorpMoney — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["createCorpMoney — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createCorpMoney — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["createCorpMoney — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["processChargeRequest — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["processChargeRequest — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["processChargeRequest — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["processChargeRequest — 사유 유형 판정"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["processChargeRequest — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["createGrant — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createGrant — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createGrant — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createGrant — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["createGrant — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createGrant — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createGrant — 사유 유형 판정"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"createGrant — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["createGrant — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createGrant — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["createGrantSingle — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createGrantSingle — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createGrantSingle — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createGrantSingle — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["createGrantSingle — 사유 유형 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createGrantSingle — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["createGrantSingle — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createGrantSingle — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["createGrantSingle — 사유 유형 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createGrantSingle — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["uploadIssue — 사유 유형 판정"],"duration":26,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["uploadIssue — 사유 유형 판정"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["uploadIssue — 사유 유형 판정"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["uploadIssue — 사유 유형 판정"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["uploadIssue — 사유 유형 판정"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["uploadGrant — 사유 유형 판정"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 사유 유형 판정 사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 유형이 없으면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["uploadGrant — 사유 유형 판정"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 사유 유형 판정 모르는 사유 유형도 트랜잭션 전에 거절한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 사유 유형도 트랜잭션 전에 거절한다"},{"ancestorTitles":["uploadGrant — 사유 유형 판정"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 사유 유형 판정 기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세 사유가 비면 트랜잭션 전에 거절하고 행이 없다"},{"ancestorTitles":["uploadGrant — 사유 유형 판정"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 사유 유형 판정 기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 에 상세 사유가 있으면 저장되고 행에 그 코드가 실린다"},{"ancestorTitles":["uploadGrant — 사유 유형 판정"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 사유 유형 판정 사유 유형이 있으면 감사 행에 그 코드가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유 유형이 있으면 감사 행에 그 코드가 실린다"},{"ancestorTitles":["엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4)"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4) 엑셀 발행 미리보기도 사유 유형이 없으면 거절한다 — 확인 모달 전에 보인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"엑셀 발행 미리보기도 사유 유형이 없으면 거절한다 — 확인 모달 전에 보인다"},{"ancestorTitles":["엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4)"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4) 엑셀 발행 미리보기는 사유가 맞으면 통과하고 적용하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"엑셀 발행 미리보기는 사유가 맞으면 통과하고 적용하지 않는다"},{"ancestorTitles":["엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4)"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4) uploadIssue 는 기타일 때 사유가 빈 행 번호를 거절 문장에 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uploadIssue 는 기타일 때 사유가 빈 행 번호를 거절 문장에 싣는다"},{"ancestorTitles":["엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4)"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"엑셀 일괄 — 업로드당 유형 하나 · 거절 문장이 빈 행을 말한다(D4) uploadGrant 는 기타일 때 사유가 빈 행 번호를 거절 문장에 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uploadGrant 는 기타일 때 사유가 빈 행 번호를 거절 문장에 싣는다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 일괄 GRANT 는 사유 유형 없이 저장되고 감사 행에 CORP_DISTRIBUTE 가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"일괄 GRANT 는 사유 유형 없이 저장되고 감사 행에 CORP_DISTRIBUTE 가 실린다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 일괄 GRANT_RECOVERY 는 사유 유형 없이 저장되고 감사 행에 CORP_RECOVER 가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"일괄 GRANT_RECOVERY 는 사유 유형 없이 저장되고 감사 행에 CORP_RECOVER 가 실린다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 기업이 사유 유형을 보내도 서버가 정한 값으로 덮는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업이 사유 유형을 보내도 서버가 정한 값으로 덮는다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 단건 금액 1000 는 CORP_DISTRIBUTE 로 저장된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단건 금액 1000 는 CORP_DISTRIBUTE 로 저장된다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 단건 금액 -1000 는 CORP_RECOVER 로 저장된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단건 금액 -1000 는 CORP_RECOVER 로 저장된다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 엑셀 행 금액 [1000,500] 는 사유 유형 없이 CORP_DISTRIBUTE 로 저장된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"엑셀 행 금액 [1000,500] 는 사유 유형 없이 CORP_DISTRIBUTE 로 저장된다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 엑셀 행 금액 [-1000,-500] 는 사유 유형 없이 CORP_RECOVER 로 저장된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"엑셀 행 금액 [-1000,-500] 는 사유 유형 없이 CORP_RECOVER 로 저장된다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 엑셀 행 금액 [1000,-500] 는 사유 유형 없이 CORP_DISTRIBUTE_RECOVER 로 저장된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"엑셀 행 금액 [1000,-500] 는 사유 유형 없이 CORP_DISTRIBUTE_RECOVER 로 저장된다"},{"ancestorTitles":["기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업 콘솔(scope) 지급·회수 — 사유 유형 없이 배분/회수로 저장 관리자 선택지(AUDIT_REASON)에는 기업 콘솔 사유가 섞이지 않고, 감사 로그는 라벨로 읽는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"관리자 선택지(AUDIT_REASON)에는 기업 콘솔 사유가 섞이지 않고, 감사 로그는 라벨로 읽는다"}],"endTime":1793868730903,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-reason.spec.ts","startTime":1793868730419,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) 리스를 못 얻으면 규칙을 평가하지 않고 lastRunAt 도 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"리스를 못 얻으면 규칙을 평가하지 않고 lastRunAt 도 바뀌지 않는다"},{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) 만료된 리스는 다시 획득한다 (크래시 복구 경로)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"만료된 리스는 다시 획득한다 (크래시 복구 경로)"},{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) 정상 종료 직후 재실행이 즉시 획득한다 — 조기 반납이 다음 회차를 막지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정상 종료 직후 재실행이 즉시 획득한다 — 조기 반납이 다음 회차를 막지 않는다"},{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) 리스 행이 없어도 자가 생성 후 획득한다 — 시딩 누락이 영구 무음을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"리스 행이 없어도 자가 생성 후 획득한다 — 시딩 누락이 영구 무음을 만들지 않는다"},{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) als_value 가 비숫자면 획득하되 leaseHealthy:false 로 노출한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"als_value 가 비숫자면 획득하되 leaseHealthy:false 로 노출한다"},{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) 토큰 불일치면 미획득 — affectedRows 가 아니라 토큰 비교로 판정한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"토큰 불일치면 미획득 — affectedRows 가 아니라 토큰 비교로 판정한다"},{"ancestorTitles":["AlertService.run — 리스 (D1-b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 리스 (D1-b) 반납은 소유권 조건부다 — 타 실행이 보유 중이면 값이 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"반납은 소유권 조건부다 — 타 실행이 보유 중이면 값이 바뀌지 않는다"},{"ancestorTitles":["AlertService.run — 소유권 재확인 2회"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 소유권 재확인 2회 발송 직전 리스를 빼앗기면 발송도 상태 쓰기도 하지 않는다 (7-b)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"발송 직전 리스를 빼앗기면 발송도 상태 쓰기도 하지 않는다 (7-b)"},{"ancestorTitles":["AlertService.run — 소유권 재확인 2회"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 소유권 재확인 2회 발송 중 리스를 빼앗기면 상태 변경을 폐기하고 새 소유자의 값을 보존한다 (9-b)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발송 중 리스를 빼앗기면 상태 변경을 폐기하고 새 소유자의 값을 보존한다 (9-b)"},{"ancestorTitles":["AlertService.run — 소유권 재확인 2회"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 소유권 재확인 2회 상태는 전부 리스 조건부 write 로만 나간다 — setSetting 을 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"상태는 전부 리스 조건부 write 로만 나간다 — setSetting 을 쓰지 않는다"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 채널 1개가 실패해도 나머지는 발송되고 run() 은 throw 하지 않는다 (M5 · M10)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"채널 1개가 실패해도 나머지는 발송되고 run() 은 throw 하지 않는다 (M5 · M10)"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 1개 채널만 성공하면 그 목적지 키만 ok:true 이고 실패분은 다음 주기에 재시도된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"1개 채널만 성공하면 그 목적지 키만 ok:true 이고 실패분은 다음 주기에 재시도된다"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 억제창 안에서 재실행하면 발송이 0이다 (M4)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"억제창 안에서 재실행하면 발송이 0이다 (M4)"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 전 채널 실패 시 키는 ok:false 로 남고 1주기 경과 후 재발송된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전 채널 실패 시 키는 ok:false 로 남고 1주기 경과 후 재발송된다"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 ok:false 기록 직후 크래시를 모사해도 1주기 뒤 재발송된다 — 영구 무음이 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ok:false 기록 직후 크래시를 모사해도 1주기 뒤 재발송된다 — 영구 무음이 없다"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 복구 억제를 선언한 규칙은 복구를 보내지 않고 상태만 지운다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"복구 억제를 선언한 규칙은 복구를 보내지 않고 상태만 지운다"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 선언이 없는 규칙의 복구는 그대로 나간다 — 억제가 다른 규칙에 번지지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"선언이 없는 규칙의 복구는 그대로 나간다 — 억제가 다른 규칙에 번지지 않는다"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 경고가 사라지면 복구를 정확히 1회 보내고 재실행 시 0회다 (M3)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"경고가 사라지면 복구를 정확히 1회 보내고 재실행 시 0회다 (M3)"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 ok:false 목적지에는 복구를 보내지 않고 키만 조용히 삭제한다 (Santa R7)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ok:false 목적지에는 복구를 보내지 않고 키만 조용히 삭제한다 (Santa R7)"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 경고 지속 중 채널을 추가하면 신규 채널로만 발송된다 (D7 키 단위 · M13)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경고 지속 중 채널을 추가하면 신규 채널로만 발송된다 (D7 키 단위 · M13)"},{"ancestorTitles":["AlertService.run — 다중 채널 격리 · 억제 · 복구"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 다중 채널 격리 · 억제 · 복구 MS2-2: 채널을 제거하면 그 목적지 키는 발송 0건이고 상태를 지우며 해소 문구가 없다 (D7 · M13)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-2: 채널을 제거하면 그 목적지 키는 발송 0건이고 상태를 지우며 해소 문구가 없다 (D7 · M13)"},{"ancestorTitles":["AlertService.run — 단계별 격리 (D8)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 단계별 격리 (D8) 규칙 A 가 throw 해도 규칙 B 의 finding 은 발송된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"규칙 A 가 throw 해도 규칙 B 의 finding 은 발송된다"},{"ancestorTitles":["AlertService.run — 단계별 격리 (D8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 단계별 격리 (D8) alc_types JSON 이 깨진 채널만 건너뛰고 나머지로 발송한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"alc_types JSON 이 깨진 채널만 건너뛰고 나머지로 발송한다"},{"ancestorTitles":["AlertService.run — 단계별 격리 (D8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 단계별 격리 (D8) run() 은 어떤 경로로도 throw 하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"run() 은 어떤 경로로도 throw 하지 않는다"},{"ancestorTitles":["AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지) 규칙이 throw 하면 살아 있는 경고에 복구를 보내지 않고 상태를 보존한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"규칙이 throw 하면 살아 있는 경고에 복구를 보내지 않고 상태를 보존한다"},{"ancestorTitles":["AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지) 규칙을 OFF 로 내려도 복구가 나가지 않는다 — 다시 켤 때까지 상태를 보존한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"규칙을 OFF 로 내려도 복구가 나가지 않는다 — 다시 켤 때까지 상태를 보존한다"},{"ancestorTitles":["AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지) 채널 조회 실패는 \"채널 0개\"와 다르다 — 복구를 보내지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"채널 조회 실패는 \"채널 0개\"와 다르다 — 복구를 보내지 않는다"},{"ancestorTitles":["AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지) 미평가 규칙의 연속 카운트는 리셋되지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미평가 규칙의 연속 카운트는 리셋되지 않는다"},{"ancestorTitles":["AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 미평가 규칙은 \"해소\"가 아니다 (허위 복구 방지) 평가에 성공한 규칙의 복구는 그대로 나간다 — 격리가 복구를 통째로 막지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"평가에 성공한 규칙의 복구는 그대로 나간다 — 격리가 복구를 통째로 막지 않는다"},{"ancestorTitles":["AlertService.run — 전체 OFF · 메시지 접두"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 전체 OFF · 메시지 접두 alert_enabled 가 0 이면 즉시 반환한다 (R8)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"alert_enabled 가 0 이면 즉시 반환한다 (R8)"},{"ancestorTitles":["AlertService.run — 전체 OFF · 메시지 접두"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 전체 OFF · 메시지 접두 메시지 본문에 환경 접두가 붙지 않는다 (§D9 라벨 제거)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"메시지 본문에 환경 접두가 붙지 않는다 (§D9 라벨 제거)"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) channelHint 매칭 채널이 있으면 일반 채널로는 가지 않는다 — 합집합이 아니라 우선순위","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"channelHint 매칭 채널이 있으면 일반 채널로는 가지 않는다 — 합집합이 아니라 우선순위"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) 힌트 매칭이 없으면 일반 채널로 폴백한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"힌트 매칭이 없으면 일반 채널로 폴백한다"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) alc_types 가 이 규칙 id 를 포함할 때만 대상이 된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"alc_types 가 이 규칙 id 를 포함할 때만 대상이 된다"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) 검증 탈락 URL 은 발송 0이고 droppedUrlCount 로 드러난다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"검증 탈락 URL 은 발송 0이고 droppedUrlCount 로 드러난다"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) 허용 호스트에서 빠진 활성 채널 URL 도 발송 열화 집계에 든다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"허용 호스트에서 빠진 활성 채널 URL 도 발송 열화 집계에 든다"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) 서비스의 미이관 수는 남은 옛 목적지 수와 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서비스의 미이관 수는 남은 옛 목적지 수와 같다"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) 서비스의 미이관 수는 옛 읽기가 실패하면 unknown 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서비스의 미이관 수는 옛 읽기가 실패하면 unknown 이다"},{"ancestorTitles":["AlertService — 목적지 전개 (D7 · D9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 목적지 전개 (D7 · D9) 이관된 레거시 목적지는 손계산한 발화별 URL 집합과 같다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이관된 레거시 목적지는 손계산한 발화별 URL 집합과 같다"},{"ancestorTitles":["AlertService.send — 유일한 발송 지점"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.send — 유일한 발송 지점 어떤 실패에도 throw 하지 않고 ok:false 를 반환한다 (3xx · 타임아웃 · 검증 탈락)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"어떤 실패에도 throw 하지 않고 ok:false 를 반환한다 (3xx · 타임아웃 · 검증 탈락)"},{"ancestorTitles":["AlertService.send — 유일한 발송 지점"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.send — 유일한 발송 지점 외부로 나가는 본문과 이력 본문의 개인정보 꼴을 가린다 (SD-5)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"외부로 나가는 본문과 이력 본문의 개인정보 꼴을 가린다 (SD-5)"},{"ancestorTitles":["AlertService.send — 유일한 발송 지점"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.send — 유일한 발송 지점 빈 URL 로는 axios 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 URL 로는 axios 를 부르지 않는다"},{"ancestorTitles":["AlertService.send — 유일한 발송 지점"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.send — 유일한 발송 지점 모든 발송에 maxRedirects:0 과 8초 타임아웃이 걸린다 (D9 · Santa R5)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모든 발송에 maxRedirects:0 과 8초 타임아웃이 걸린다 (D9 · Santa R5)"},{"ancestorTitles":["AlertService.send — 유일한 발송 지점"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.send — 유일한 발송 지점 허용 호스트가 사설 대역으로 해석되면 발송하지 않는다 (주소 축)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"허용 호스트가 사설 대역으로 해석되면 발송하지 않는다 (주소 축)"},{"ancestorTitles":["AlertService.send — 유일한 발송 지점"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.send — 유일한 발송 지점 복구 발송도 같은 send() 를 경유한다 — send 를 막으면 복구도 0건","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"복구 발송도 같은 send() 를 경유한다 — send 를 막으면 복구도 0건"},{"ancestorTitles":["AlertService — 손상된 억제 상태 정규화"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 손상된 억제 상태 정규화 엔트리가 숫자여도 ok:false 로 읽고 복구를 보내지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"엔트리가 숫자여도 ok:false 로 읽고 복구를 보내지 않는다"},{"ancestorTitles":["AlertService — 손상된 억제 상태 정규화"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 손상된 억제 상태 정규화 키에 `::` 가 여러 번 섞여 있어도 파싱하지 않으므로 그대로 다뤄진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"키에 `::` 가 여러 번 섞여 있어도 파싱하지 않으므로 그대로 다뤄진다"},{"ancestorTitles":["AlertService — 지속성 적용 (M8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService — 지속성 적용 (M8) 연속 임계가 2면 1회만 잡힌 경고는 발송하지 않고 2회째에 발송한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"연속 임계가 2면 1회만 잡힌 경고는 발송하지 않고 2회째에 발송한다"},{"ancestorTitles":["AlertService.status — 8필드 (D4-2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.status — 8필드 (D4-2) 활성 채널 수와 관측 카운터를 기계 판독 가능하게 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"활성 채널 수와 관측 카운터를 기계 판독 가능하게 낸다"},{"ancestorTitles":["AlertService.run — warn 다이제스트 (§D5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — warn 다이제스트 (§D5) 간격 미달이면 큐에 쌓기만 하고 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"간격 미달이면 큐에 쌓기만 하고 발송하지 않는다"},{"ancestorTitles":["AlertService.run — warn 다이제스트 (§D5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — warn 다이제스트 (§D5) 간격에 도달하면 목적지당 1건으로 묶어 보내고 큐를 비운다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"간격에 도달하면 목적지당 1건으로 묶어 보내고 큐를 비운다"},{"ancestorTitles":["AlertService.run — warn 다이제스트 (§D5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — warn 다이제스트 (§D5) 같은 키는 접어서 횟수로 센다 — 상시 재발 warn 이 본문 30줄을 독차지하면 안 된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"같은 키는 접어서 횟수로 센다 — 상시 재발 warn 이 본문 30줄을 독차지하면 안 된다"},{"ancestorTitles":["AlertService.run — warn 다이제스트 (§D5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — warn 다이제스트 (§D5) 접힌 횟수는 회차를 넘어 누적된다 — 매번 1로 리셋되면 접기의 절반이 무의미하다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"접힌 횟수는 회차를 넘어 누적된다 — 매번 1로 리셋되면 접기의 절반이 무의미하다"},{"ancestorTitles":["AlertService.run — warn 다이제스트 (§D5)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — warn 다이제스트 (§D5) 전 목적지 실패면 큐를 비우지 않고 다음 회차에 재시도한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전 목적지 실패면 큐를 비우지 않고 다음 회차에 재시도한다"},{"ancestorTitles":["AlertService.run — warn 다이제스트 (§D5)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — warn 다이제스트 (§D5) ruleId 없는 구 항목(M1 이 넣은 것)은 전 채널로 폴백 발송한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ruleId 없는 구 항목(M1 이 넣은 것)은 전 채널로 폴백 발송한다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) DB 가 정상이면 폴백을 타지 않고 last-known-good 스냅샷을 남긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"DB 가 정상이면 폴백을 타지 않고 last-known-good 스냅샷을 남긴다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 스냅샷 streak 은 폴백 전용 노브에서 온다 — persistenceStreak(기본 1) 을 쓰면 게이트가 no-op 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스냅샷 streak 은 폴백 전용 노브에서 온다 — persistenceStreak(기본 1) 을 쓰면 게이트가 no-op 이다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 스냅샷 urls 는 검증을 통과한 활성 채널만 담는다 (D9 경계 유지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스냅샷 urls 는 검증을 통과한 활성 채널만 담는다 (D9 경계 유지)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 프로브 1회 실패로는 발송하지 않는다 — 순단이 곧바로 오탐이 되면 안 된다(R2-F2)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"프로브 1회 실패로는 발송하지 않는다 — 순단이 곧바로 오탐이 되면 안 된다(R2-F2)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 연속 실패가 snapshot.streak 에 도달하면 발송한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"연속 실패가 snapshot.streak 에 도달하면 발송한다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 발송 후 억제창 안에서는 재발송하지 않는다 (M4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발송 후 억제창 안에서는 재발송하지 않는다 (M4)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 복구는 실제로 발송한 목적지에만 1회 나간다 (UI10)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"복구는 실제로 발송한 목적지에만 1회 나간다 (UI10)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 복구도 kill switch 를 지킨다 — 장애 중 알림을 끄면 복구가 되살아나지 않는다 (UI16)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"복구도 kill switch 를 지킨다 — 장애 중 알림을 끄면 복구가 되살아나지 않는다 (UI16)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 복구는 현재 채널 목록으로 좁혀진다 — 삭제된 채널로는 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"복구는 현재 채널 목록으로 좁혀진다 — 삭제된 채널로는 나가지 않는다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 미발송 상태에서는 복구도 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미발송 상태에서는 복구도 나가지 않는다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 스냅샷이 없으면 무발송이다 — 보낼 목적지를 알 수 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스냅샷이 없으면 무발송이다 — 보낼 목적지를 알 수 없다"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 알림 OFF 스냅샷이면 fail-closed 다 (UI16 · R2-F3)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"알림 OFF 스냅샷이면 fail-closed 다 (UI16 · R2-F3)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 채널이 지워진 스냅샷은 보낼 곳이 없어 무발송이다 (R2-F3)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"채널이 지워진 스냅샷은 보낼 곳이 없어 무발송이다 (R2-F3)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 전체 OFF 조기 반환 직전에 스냅샷 툼스톤을 남긴다 (보조 그물, §D7 2)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전체 OFF 조기 반환 직전에 스냅샷 툼스톤을 남긴다 (보조 그물, §D7 2)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) 폴백 리스를 못 잡은 회차는 상태를 읽지도 쓰지도 않는다 (R3-F4)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"폴백 리스를 못 잡은 회차는 상태를 읽지도 쓰지도 않는다 (R3-F4)"},{"ancestorTitles":["AlertService.run — DB 폴백 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — DB 폴백 (§D7) DB 복구 시 연속카운트가 0 으로 리셋된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"DB 복구 시 연속카운트가 0 으로 리셋된다"},{"ancestorTitles":["AlertService.run — 런너 틱 (M3 §D2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 런너 틱 (M3 §D2) 전체 OFF 회차에도 틱을 찍는다 — 끈 상태에서 런너가 죽으면 차이가 0 이 되면 안 된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"전체 OFF 회차에도 틱을 찍는다 — 끈 상태에서 런너가 죽으면 차이가 0 이 되면 안 된다"},{"ancestorTitles":["AlertService.run — 런너 틱 (M3 §D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 런너 틱 (M3 §D2) 리스 미획득 회차는 틱을 찍지 않는다 — 죽은 런너가 살아 있는 것처럼 보이면 안 된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"리스 미획득 회차는 틱을 찍지 않는다 — 죽은 런너가 살아 있는 것처럼 보이면 안 된다"},{"ancestorTitles":["AlertService.run — 런너 틱 (M3 §D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 런너 틱 (M3 §D2) 간격 링을 통째로 보관하고 상한 5개를 넘지 않는다 (R3-F1)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"간격 링을 통째로 보관하고 상한 5개를 넘지 않는다 (R3-F1)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 스누즈 회차는 발송 0 이지만 평가는 계속되어 경과가 snoozeLog 에 남는다 (R1-F3)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"스누즈 회차는 발송 0 이지만 평가는 계속되어 경과가 snoozeLog 에 남는다 (R1-F3)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 스누즈가 허위 복구를 만들지 않는다 — 억제 상태를 보존한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"스누즈가 허위 복구를 만들지 않는다 — 억제 상태를 보존한다"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 스누즈 중에도 streak 이 진행돼 해제 첫 회차에 지속분이 발송된다 (R2-F3)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"스누즈 중에도 streak 이 진행돼 해제 첫 회차에 지속분이 발송된다 (R2-F3)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 해제 회차에 해소분은 요약 1건, 지속분은 정상 발송으로 소유권이 넘어간다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"해제 회차에 해소분은 요약 1건, 지속분은 정상 발송으로 소유권이 넘어간다"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 요약 발송이 실패하면 snoozeLog 항목이 유지돼 다음 회차에 재시도된다 (R3-F3)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"요약 발송이 실패하면 snoozeLog 항목이 유지돼 다음 회차에 재시도된다 (R3-F3)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 평가 실패 회차는 거짓 해소를 만들지 않는다 (R4-F3)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"평가 실패 회차는 거짓 해소를 만들지 않는다 (R4-F3)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 해제 회차에 규칙이 throw 하면 항목을 지우지도 보내지도 않는다 (R5-F4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"해제 회차에 규칙이 throw 하면 항목을 지우지도 보내지도 않는다 (R5-F4)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 전역 스누즈 회차는 대기 다이제스트도 막고 스냅샷에 snoozeUntil 을 싣는다 (R8-F4 · R8-F5)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"전역 스누즈 회차는 대기 다이제스트도 막고 스냅샷에 snoozeUntil 을 싣는다 (R8-F4 · R8-F5)"},{"ancestorTitles":["AlertService.run — 스누즈 (M3 §D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 스누즈 (M3 §D7) 전역 스누즈가 DB 폴백 발송도 막는다 (R8-F4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전역 스누즈가 DB 폴백 발송도 막는다 (R8-F4)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 규칙 throw 회차에 checkedAt 이 밀리지 않고 error 가 채워진다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"규칙 throw 회차에 checkedAt 이 밀리지 않고 error 가 채워진다"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 발송 성공이 그 규칙의 sentAt·firedAt 에 귀속된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발송 성공이 그 규칙의 sentAt·firedAt 에 귀속된다"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 다이제스트 발송이 타입별 시각을 갱신하고 이력은 물리 발송 1행만 남긴다 (R7-F2 · R8-F3)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"다이제스트 발송이 타입별 시각을 갱신하고 이력은 물리 발송 1행만 남긴다 (R7-F2 · R8-F3)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 이력 기록 실패가 발송 결과를 바꾸지 않고 구멍 표지를 남긴다 (R5-F2)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이력 기록 실패가 발송 결과를 바꾸지 않고 구멍 표지를 남긴다 (R5-F2)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 보존기간 정리가 회차마다 돌고, 실패해도 발송 결과를 바꾸지 않는다 (§D1)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"보존기간 정리가 회차마다 돌고, 실패해도 발송 결과를 바꾸지 않는다 (§D1)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 이력에 원문 URL 이 없고 채널이 귀속된다 (R5-F1 · R4-F4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이력에 원문 URL 이 없고 채널이 귀속된다 (R5-F1 · R4-F4)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 본문에 섞인 원문 웹훅 URL 도 이력에 남지 않는다 (R5-F1 우회 차단)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"본문에 섞인 원문 웹훅 URL 도 이력에 남지 않는다 (R5-F1 우회 차단)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 스킴 대소문자·허용목록 축소로 마스킹을 빗나가지 않는다 (santa R2)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스킴 대소문자·허용목록 축소로 마스킹을 빗나가지 않는다 (santa R2)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 비밀이 아닌 URL 은 이력 본문에 그대로 남는다 — 조사에 쓸모를 남긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비밀이 아닌 URL 은 이력 본문에 그대로 남는다 — 조사에 쓸모를 남긴다"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 같은 URL 을 가진 채널 둘은 오귀속 대신 미귀속이다 (R6-F5)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 URL 을 가진 채널 둘은 오귀속 대신 미귀속이다 (R6-F5)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) 복구 발송도 채널에 귀속된다 (R4-F4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"복구 발송도 채널에 귀속된다 (R4-F4)"},{"ancestorTitles":["AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 규칙 기록 · 발송 이력 (M3 §D3 · §D4) DB 폴백 진입 자체가 이력 구멍 표지를 남긴다 — 전 목적지 실패여도 (R6-F4)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"DB 폴백 진입 자체가 이력 구멍 표지를 남긴다 — 전 목적지 실패여도 (R6-F4)"},{"ancestorTitles":["AlertService.run — 해소 문면 (상태가 심각도를 대체한다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 해소 문면 (상태가 심각도를 대체한다) 발화 원문의 심각도 마커를 걷어내고 지속 시간을 붙인다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"발화 원문의 심각도 마커를 걷어내고 지속 시간을 붙인다"},{"ancestorTitles":["AlertService.run — 해소 문면 (상태가 심각도를 대체한다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 해소 문면 (상태가 심각도를 대체한다) 재발송으로 t 가 갱신돼도 지속 시간은 최초 발화부터 잰다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"재발송으로 t 가 갱신돼도 지속 시간은 최초 발화부터 잰다"},{"ancestorTitles":["AlertService.run — 해소 문면 (상태가 심각도를 대체한다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 해소 문면 (상태가 심각도를 대체한다) 한 목적지의 해소 여러 건은 한 통으로 묶인다 — 발송이 묶였으면 해소도 묶인다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"한 목적지의 해소 여러 건은 한 통으로 묶인다 — 발송이 묶였으면 해소도 묶인다"},{"ancestorTitles":["AlertService.run — 해소 문면 (상태가 심각도를 대체한다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 해소 문면 (상태가 심각도를 대체한다) 묶음을 끈 규칙의 해소는 1건 1통이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"묶음을 끈 규칙의 해소는 1건 1통이다"},{"ancestorTitles":["AlertService.sendTest — 안전 계약"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 안전 계약 sendTest 계약: channelId 교집합 — 한 채널을 찍은 요청이 전 채널로 퍼지지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: channelId 교집합 — 한 채널을 찍은 요청이 전 채널로 퍼지지 않는다"},{"ancestorTitles":["AlertService.sendTest — 안전 계약"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 안전 계약 sendTest 계약: 첫 줄이 테스트 배너이고 그 아래가 규칙의 실제 문면이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 첫 줄이 테스트 배너이고 그 아래가 규칙의 실제 문면이다"},{"ancestorTitles":["AlertService.sendTest — 안전 계약"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 안전 계약 sendTest 계약: sampleText 가 없는 규칙은 연결 확인 문면으로 떨어지고 배너는 그대로다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: sampleText 가 없는 규칙은 연결 확인 문면으로 떨어지고 배너는 그대로다"},{"ancestorTitles":["AlertService.sendTest — 안전 계약"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 안전 계약 sendTest 계약: 제외 사유 코드 8종 — 여덟 지점이 각각 자기 이름으로 드러난다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 제외 사유 코드 8종 — 여덟 지점이 각각 자기 이름으로 드러난다"},{"ancestorTitles":["AlertService.sendTest — 안전 계약"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 안전 계약 sendTest 계약: 미등록 ruleId 거부 — 카탈로그에 없는 종류는 400 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 미등록 ruleId 거부 — 카탈로그에 없는 종류는 400 이다"},{"ancestorTitles":["AlertService.sendTest — 안전 계약"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 안전 계약 sendTest 계약: unknown-hint 사전 차단 — destinationsFor 에 넘기기 전에 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: unknown-hint 사전 차단 — destinationsFor 에 넘기기 전에 막는다"},{"ancestorTitles":["suppressesRecovery — 선언 판정(M9 D8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"suppressesRecovery — 선언 판정(M9 D8) 선언한 규칙만 억제한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"선언한 규칙만 억제한다"},{"ancestorTitles":["suppressesRecovery — 선언 판정(M9 D8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"suppressesRecovery — 선언 판정(M9 D8) 선언이 없으면 억제하지 않는다 — 부재는 지금 동작이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"선언이 없으면 억제하지 않는다 — 부재는 지금 동작이다"},{"ancestorTitles":["suppressesRecovery — 선언 판정(M9 D8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"suppressesRecovery — 선언 판정(M9 D8) 규칙 미상이면 억제하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"규칙 미상이면 억제하지 않는다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 목록에서 뺀 스케줄의 상태 키는 발송 0건이고 상태가 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-1: 목록에서 뺀 스케줄의 상태 키는 발송 0건이고 상태가 남는다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 같은 규칙의 목록 안 키는 같은 회차에 발화하고, 정상화 뒤 복구 1회가 나간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS2-1: 같은 규칙의 목록 안 키는 같은 회차에 발화하고, 정상화 뒤 복구 1회가 나간다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 제외 판정과 finding 생성은 같은 목록 스냅샷을 쓴다 — 두 번째 읽기가 달라도 발송 0","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-1: 제외 판정과 finding 생성은 같은 목록 스냅샷을 쓴다 — 두 번째 읽기가 달라도 발송 0"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: keyExclusion() 이 던지면 그 규칙은 회차 전체가 미평가다 — 발송 0 · 상태 보존, 다른 규칙은 발송된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-1: keyExclusion() 이 던지면 그 규칙은 회차 전체가 미평가다 — 발송 0 · 상태 보존, 다른 규칙은 발송된다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 제외된 키의 스트릭은 리셋되지 않고 이월된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS2-1: 제외된 키의 스트릭은 리셋되지 않고 이월된다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 상태 키의 URL 에 :: 가 있어도 접두가 맞는 키만 제외 판정에 걸린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS2-1: 상태 키의 URL 에 :: 가 있어도 접두가 맞는 키만 제외 판정에 걸린다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 설정 일괄 조회가 던지면 하트비트 회차 전체가 발송 0 · 상태 보존이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-1: 설정 일괄 조회가 던지면 하트비트 회차 전체가 발송 0 · 상태 보존이다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 저장된 목록이 유효 항목 0개이면 회차 전체가 발송 0 · 상태 보존이고 기본 목록으로 판정하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-1: 저장된 목록이 유효 항목 0개이면 회차 전체가 발송 0 · 상태 보존이고 기본 목록으로 판정하지 않는다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 저장된 목록이 판독 불가(JSON 파손)이면 회차 전체가 발송 0 · 상태 보존이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-1: 저장된 목록이 판독 불가(JSON 파손)이면 회차 전체가 발송 0 · 상태 보존이다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 목록의 일부만 탈락하면 탈락 이름만 발송 0 · 보존이고 나머지 목록 안 키는 정상 판정된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS2-1: 목록의 일부만 탈락하면 탈락 이름만 발송 0 · 보존이고 나머지 목록 안 키는 정상 판정된다"},{"ancestorTitles":["AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목록 제외 · 평가 보존 (D4 · L3 HIGH-1) MS2-1: 하트비트 판정용 설정의 개별 조회가 던지면 공용 조회가 성공해도 회차 전체가 보존이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-1: 하트비트 판정용 설정의 개별 조회가 던지면 공용 조회가 성공해도 회차 전체가 보존이다"},{"ancestorTitles":["AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2) MS2-2: 채널이 비활성이 되면 그 목적지 키는 발송 0건이고 상태를 지우며 해소 문구가 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-2: 채널이 비활성이 되면 그 목적지 키는 발송 0건이고 상태를 지우며 해소 문구가 없다"},{"ancestorTitles":["AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2) MS2-2: 채널을 삭제하면 그 목적지 키는 발송 0건이고 상태를 지운다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-2: 채널을 삭제하면 그 목적지 키는 발송 0건이고 상태를 지운다"},{"ancestorTitles":["AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2) MS2-2: 대상 종류에서 이 규칙이 빠지면 그 목적지 키는 발송 0건이고 상태를 지운다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-2: 대상 종류에서 이 규칙이 빠지면 그 목적지 키는 발송 0건이고 상태를 지운다"},{"ancestorTitles":["AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2) MS2-2: 구 엔트리(hint · legacy · kind 없음)는 기존대로 복구 1회가 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-2: 구 엔트리(hint · legacy · kind 없음)는 기존대로 복구 1회가 나간다"},{"ancestorTitles":["AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2) MS2-2: 목적지 확인이 불완전했던 회차에는 채널 발화는 나가고 그 회차 복구는 0 · 보존이며 스트릭은 이월로 덮이지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS2-2: 목적지 확인이 불완전했던 회차에는 채널 발화는 나가고 그 회차 복구는 0 · 보존이며 스트릭은 이월로 덮이지 않는다"},{"ancestorTitles":["AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 목적지 소실 · 레거시 재확인 (D7 · R3 HIGH-1 · HIGH-2) MS4: 진료 임계 설정 읽기가 실패하면 규칙은 미평가로 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS4: 진료 임계 설정 읽기가 실패하면 규칙은 미평가로 남는다"},{"ancestorTitles":["AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9) MS2-3: 복구 발송이 한 번 실패하면 다음 회차에 같은 복구가 1회 재시도되고, 성공하면 상태가 지워진다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-3: 복구 발송이 한 번 실패하면 다음 회차에 같은 복구가 1회 재시도되고, 성공하면 상태가 지워진다"},{"ancestorTitles":["AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9) MS2-3: 복구 발송이 세 번 실패하면 상태를 지우고 포기 로그를 한 번 남기며, 네 번째 회차에는 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-3: 복구 발송이 세 번 실패하면 상태를 지우고 포기 로그를 한 번 남기며, 네 번째 회차에는 발송하지 않는다"},{"ancestorTitles":["AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9) MS2-3: 복구 대기 중 같은 키가 다시 잡히면 억제창 안이어도 새 발화가 나간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS2-3: 복구 대기 중 같은 키가 다시 잡히면 억제창 안이어도 새 발화가 나간다"},{"ancestorTitles":["AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9) MS2-3: 지속성 2 환경에서 복구 실패 뒤 같은 키가 재발하면 옛 복구를 보내지 않고 새 발화를 낸다 (재검증 codex high)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-3: 지속성 2 환경에서 복구 실패 뒤 같은 키가 재발하면 옛 복구를 보내지 않고 새 발화를 낸다 (재검증 codex high)"},{"ancestorTitles":["AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9) MS2-3: 열린 장애의 재발 발송이 실패해도 정상화 뒤 복구가 나간다 — 복구 의무는 재발 실패로 사라지지 않는다 (재검증 codex high)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-3: 열린 장애의 재발 발송이 실패해도 정상화 뒤 복구가 나간다 — 복구 의무는 재발 실패로 사라지지 않는다 (재검증 codex high)"},{"ancestorTitles":["AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 복구 재시도 · 상태 정규화 (B11 · MS2-9) MS2-9: 새 칸 (hint · kind · legacy · recovering) 은 상태 정규화를 지난다 (round trip)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-9: 새 칸 (hint · kind · legacy · recovering) 은 상태 정규화를 지난다 (round trip)"},{"ancestorTitles":["AlertService.run — MS2 하트비트 억제창 · 억제창 계약 (D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 하트비트 억제창 · 억제창 계약 (D4) MS2-4: 하트비트 발화 뒤 24시간 안의 재발송은 0건이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS2-4: 하트비트 발화 뒤 24시간 안의 재발송은 0건이다"},{"ancestorTitles":["AlertService.run — MS2 하트비트 억제창 · 억제창 계약 (D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 하트비트 억제창 · 억제창 계약 (D4) MS2-4: 24시간 뒤에는 리마인더가 1건 나간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS2-4: 24시간 뒤에는 리마인더가 1건 나간다"},{"ancestorTitles":["AlertService.run — MS2 하트비트 억제창 · 억제창 계약 (D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 하트비트 억제창 · 억제창 계약 (D4) MS2-7: 억제창을 선언하지 않은 규칙은 관리자 설정 dedupeMs 를 그대로 쓴다 (부재 = 현행)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-7: 억제창을 선언하지 않은 규칙은 관리자 설정 dedupeMs 를 그대로 쓴다 (부재 = 현행)"},{"ancestorTitles":["AlertService.run — MS2 스누즈 해제 재확인 (R3-F3 · R3 HIGH-2 · L2 architect)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 스누즈 해제 재확인 (R3-F3 · R3 HIGH-2 · L2 architect) MS2-8: 스누즈 중 목록에서 뺀 키는 스누즈 로그에 resolvedAt 이 찍히지 않고 해제 요약에 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS2-8: 스누즈 중 목록에서 뺀 키는 스누즈 로그에 resolvedAt 이 찍히지 않고 해제 요약에 나가지 않는다"},{"ancestorTitles":["AlertService.run — MS2 스누즈 해제 재확인 (R3-F3 · R3 HIGH-2 · L2 architect)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS2 스누즈 해제 재확인 (R3-F3 · R3 HIGH-2 · L2 architect) 레거시 필드가 남아 있어도 발화 목적지는 채널 행만 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"레거시 필드가 남아 있어도 발화 목적지는 채널 행만 쓴다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 값만 바뀌는 진료 입력은 발화 1회 · 복구 0회다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 값만 바뀌는 진료 입력은 발화 1회 · 복구 0회다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 진료 지속성 임계 2 는 1회차 발화 0 · 2회차 발화 1 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 진료 지속성 임계 2 는 1회차 발화 0 · 2회차 발화 1 이다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 복구는 연속 정상 2회 뒤에만 나간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS3: 복구는 연속 정상 2회 뒤에만 나간다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 스누즈 중 재발은 연속 정상 카운터를 되돌린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: 스누즈 중 재발은 연속 정상 카운터를 되돌린다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 복구 발송 실패는 다음 부재 회차에 한 번 재시도한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS3: 복구 발송 실패는 다음 부재 회차에 한 번 재시도한다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 벤더 비활성 전환은 활성 사건의 해소 0건이고 상태를 유지한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS3: 벤더 비활성 전환은 활성 사건의 해소 0건이고 상태를 유지한다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 벤더 설정 읽기가 던지면 회차는 발송도 해소도 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS3: 벤더 설정 읽기가 던지면 회차는 발송도 해소도 없다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 진료 억제창 24시간이면 진입 1회 · 해소 1회다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS3: 진료 억제창 24시간이면 진입 1회 · 해소 1회다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 연속 정상 카운터는 상태 정규화를 지난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: 연속 정상 카운터는 상태 정규화를 지난다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 스누즈 중 정상 뒤 재발은 해제 때 해소 요약을 보내지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 스누즈 중 정상 뒤 재발은 해제 때 해소 요약을 보내지 않는다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 스누즈 중 감지 뒤 정상, 해제와 함께 재발 1회면 발화 없이 해소 요약 1건이 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 스누즈 중 감지 뒤 정상, 해제와 함께 재발 1회면 발화 없이 해소 요약 1건이 나간다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 스누즈 중 감지 뒤 정상, 스누즈 중 1회 재발, 해제 회차 정상이면 해소 요약 1건이 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 스누즈 중 감지 뒤 정상, 스누즈 중 1회 재발, 해제 회차 정상이면 해소 요약 1건이 나간다"},{"ancestorTitles":["AlertService.run — 진료 모니터링 발화 안정화 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 진료 모니터링 발화 안정화 (MS3) MS3: 해제 회차 발송이 한 목적지만 실패하면 그 목적지에만 해소 요약 1건이 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: 해제 회차 발송이 한 목적지만 실패하면 그 목적지에만 해소 요약 1건이 남는다"},{"ancestorTitles":["AlertService.run — MS6 정기결제 회차 판정 (엔진 경유)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS6 정기결제 회차 판정 (엔진 경유) MS6-N1-5 지속 사건은 배치 네 개 동안 발송 1회이고 해소 문구는 발화 시각 기준이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS6-N1-5 지속 사건은 배치 네 개 동안 발송 1회이고 해소 문구는 발화 시각 기준이다"},{"ancestorTitles":["AlertService.run — MS6 정기결제 회차 판정 (엔진 경유)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS6 정기결제 회차 판정 (엔진 경유) MS6-N1-7 후속 배치 없이 36시간이 지나면 같은 문면의 리마인더 1회가 나가고 해소는 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS6-N1-7 후속 배치 없이 36시간이 지나면 같은 문면의 리마인더 1회가 나가고 해소는 나가지 않는다"},{"ancestorTitles":["AlertService.run — MS6 정기결제 회차 판정 (엔진 경유)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS6 정기결제 회차 판정 (엔진 경유) MS6-N1-15 배포 전 열린 사건과 판정 상태 없음은 복구를 막고 다음 완료 회차 판정 뒤에만 해소된다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS6-N1-15 배포 전 열린 사건과 판정 상태 없음은 복구를 막고 다음 완료 회차 판정 뒤에만 해소된다"},{"ancestorTitles":["AlertService.run — MS6 정기결제 회차 판정 (엔진 경유)"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS6 정기결제 회차 판정 (엔진 경유) MS6-N1-20 두 완료 회차를 한 번에 읽어도 실패 발화는 한 건이고 해소는 다음 평가에서 난다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS6-N1-20 두 완료 회차를 한 번에 읽어도 실패 발화는 한 건이고 해소는 다음 평가에서 난다"},{"ancestorTitles":["AlertService.run — MS6 정기결제 회차 판정 (엔진 경유)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS6 정기결제 회차 판정 (엔진 경유) MS6-N1-18 보강 — 앞 사건의 억제 칸이 살아 있으면 새 실패는 칸이 복구된 뒤 발송되고 해소는 그 발송이 확인된 뒤에만 난다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"MS6-N1-18 보강 — 앞 사건의 억제 칸이 살아 있으면 새 실패는 칸이 복구된 뒤 발송되고 해소는 그 발송이 확인된 뒤에만 난다"},{"ancestorTitles":["AlertService.run — MS6 정기결제 회차 판정 (엔진 경유)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS6 정기결제 회차 판정 (엔진 경유) MS6-N1-21 발송이 실패한 실패 발화는 다음 평가에서 다시 나가고 해소는 발송이 확인된 뒤에만 난다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MS6-N1-21 발송이 실패한 실패 발화는 다음 평가에서 다시 나가고 해소는 발송이 확인된 뒤에만 난다"},{"ancestorTitles":["AlertService.run — MS7 알림톡 체류 규칙 (엔진 경유)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — MS7 알림톡 체류 규칙 (엔진 경유) [MS7-A4] 체류 규칙 1개를 등록해 한 회차를 돌리면 발송 1건이 나간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS7-A4] 체류 규칙 1개를 등록해 한 회차를 돌리면 발송 1건이 나간다"},{"ancestorTitles":["AlertService.run — 엔진 판정 (MS8 편차 11 · 16)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 엔진 판정 (MS8 편차 11 · 16) [MS8-E6] 발송 목적지가 모두 실패한 회차는 send-failed 이고 ok 가 0, 한 건이라도 성공하면 null 이고 ok 가 1","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS8-E6] 발송 목적지가 모두 실패한 회차는 send-failed 이고 ok 가 0, 한 건이라도 성공하면 null 이고 ok 가 1"},{"ancestorTitles":["AlertService.run — 엔진 판정 (MS8 편차 11 · 16)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 엔진 판정 (MS8 편차 11 · 16) [MS8-E7] DB 폴백 발송이 모두 실패하면 db-down-send-failed 이고 ok 가 0 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS8-E7] DB 폴백 발송이 모두 실패하면 db-down-send-failed 이고 ok 가 0 이다"},{"ancestorTitles":["AlertService.run — 엔진 판정 (MS8 편차 11 · 16)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 엔진 판정 (MS8 편차 11 · 16) [MS8-E8] 복구 발송이 모두 실패한 회차는 send-failed 이고 ok 가 0, 복구 한 건이라도 성공하면 null 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS8-E8] 복구 발송이 모두 실패한 회차는 send-failed 이고 ok 가 0, 복구 한 건이라도 성공하면 null 이다"},{"ancestorTitles":["AlertService.run — 엔진 판정 (MS8 편차 11 · 16)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 엔진 판정 (MS8 편차 11 · 16) [MS8-E9] 채널 조회가 던지면 channel-lookup-failed 이고 ok 가 0 이다, 전체 규칙 OFF 는 null 이고 ok 가 1 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS8-E9] 채널 조회가 던지면 channel-lookup-failed 이고 ok 가 0 이다, 전체 규칙 OFF 는 null 이고 ok 가 1 이다"},{"ancestorTitles":["AlertService.run — 엔진 판정 (MS8 편차 11 · 16)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.run — 엔진 판정 (MS8 편차 11 · 16) [MS8-E10] 활성 규칙이 모두 평가에 실패하면 rule-eval-all-failed 이고 ok 가 0 이다, 하나만 실패하면 null 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS8-E10] 활성 규칙이 모두 평가에 실패하면 rule-eval-all-failed 이고 ok 가 0 이다, 하나만 실패하면 null 이다"}],"endTime":1793868731005,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert.service.spec.ts","startTime":1793868730586,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["영업대리점 상세 · 수정 (19j 위험 1 · 2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 상세 · 수정 (19j 위험 1 · 2) 영업 A 가 영업 B 상세 · 수정 → 403, 서비스를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"영업 A 가 영업 B 상세 · 수정 → 403, 서비스를 부르지 않는다"},{"ancestorTitles":["영업대리점 상세 · 수정 (19j 위험 1 · 2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 상세 · 수정 (19j 위험 1 · 2) 담당 번호 없는 영업 신원은 어느 대리점도 못 본다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"담당 번호 없는 영업 신원은 어느 대리점도 못 본다"},{"ancestorTitles":["영업대리점 상세 · 수정 (19j 위험 1 · 2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 상세 · 수정 (19j 위험 1 · 2) 영업 A 가 본인 대리점명 · 로그인 아이디 · 총판 여부를 바꾸면 403","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"영업 A 가 본인 대리점명 · 로그인 아이디 · 총판 여부를 바꾸면 403"},{"ancestorTitles":["영업대리점 상세 · 수정 (19j 위험 1 · 2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 상세 · 수정 (19j 위험 1 · 2) 영업 A 의 본인 비밀번호 · 연락처 변경(금지 필드는 같은 값 재전송)은 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 A 의 본인 비밀번호 · 연락처 변경(금지 필드는 같은 값 재전송)은 통과"},{"ancestorTitles":["영업대리점 상세 · 수정 (19j 위험 1 · 2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 상세 · 수정 (19j 위험 1 · 2) 관리자는 아무 대리점의 대리점명도 바꾼다 (현행)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자는 아무 대리점의 대리점명도 바꾼다 (현행)"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 영업 A 가 sagId 없이 전체 목록 → A 채널만 (쿼리를 신원 값으로 덮는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 A 가 sagId 없이 전체 목록 → A 채널만 (쿼리를 신원 값으로 덮는다)"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 관리자 전체 목록은 쿼리 그대로 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 전체 목록은 쿼리 그대로 (현행)"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 영업 A 가 B 채널 상세 · 수정 → 403, 수정을 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"영업 A 가 B 채널 상세 · 수정 → 403, 수정을 부르지 않는다"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 영업 A 가 수정 · 생성 본문에 sagId=B → A 로 저장","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 A 가 수정 · 생성 본문에 sagId=B → A 로 저장"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 관리자 수정은 본문 sagId 그대로 · 소유 번호를 넘기지 않는다 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 수정은 본문 sagId 그대로 · 소유 번호를 넘기지 않는다 (현행)"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 관리자 생성은 본문 sagId 그대로 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 생성은 본문 sagId 그대로 (현행)"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 삭제: 컨트롤러는 영업이면 신원 sagId, 관리자면 undefined 를 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"삭제: 컨트롤러는 영업이면 신원 sagId, 관리자면 undefined 를 넘긴다"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 섞인 삭제 (A 채널 + B 채널) → 전체 거부, 아무것도 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"섞인 삭제 (A 채널 + B 채널) → 전체 거부, 아무것도 지우지 않는다"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 담당 번호 없는 영업(null)은 자기 채널도 못 지운다 · 본인 채널만이면 지운다 · 관리자는 현행","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"담당 번호 없는 영업(null)은 자기 채널도 못 지운다 · 본인 채널만이면 지운다 · 관리자는 현행"},{"ancestorTitles":["영업대리점 채널 (19j 위험 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업대리점 채널 (19j 위험 3) 영업 수정 · 삭제는 저장소에 자기 sagId 를 넘긴다 · 관리자는 넘기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 수정 · 삭제는 저장소에 자기 sagId 를 넘긴다 · 관리자는 넘기지 않는다"},{"ancestorTitles":["영업 채널 일괄 삭제 원자성 (19v MAJOR 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업 채널 일괄 삭제 원자성 (19v MAJOR 1) 영업: 지운 행 수가 요청 id 수보다 적으면 트랜잭션 안에서 403 을 던져 되돌린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업: 지운 행 수가 요청 id 수보다 적으면 트랜잭션 안에서 403 을 던져 되돌린다"},{"ancestorTitles":["영업 채널 일괄 삭제 원자성 (19v MAJOR 1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업 채널 일괄 삭제 원자성 (19v MAJOR 1) 영업: 전부 지우면 통과 · 같은 id 중복은 한 행으로 센다 · 관리자는 행 수를 보지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업: 전부 지우면 통과 · 같은 id 중복은 한 행으로 센다 · 관리자는 행 수를 보지 않는다"},{"ancestorTitles":["주문 상세 · 구독 상세 (19j 위험 4 · 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"주문 상세 · 구독 상세 (19j 위험 4 · 6) 영업 A 가 담당 밖 주문 상세 → 403, 상세를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"영업 A 가 담당 밖 주문 상세 → 403, 상세를 읽지 않는다"},{"ancestorTitles":["주문 상세 · 구독 상세 (19j 위험 4 · 6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"주문 상세 · 구독 상세 (19j 위험 4 · 6) 담당 주문은 통과 · 담당 번호 없는 영업은 질의 없이 403","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"담당 주문은 통과 · 담당 번호 없는 영업은 질의 없이 403"},{"ancestorTitles":["주문 상세 · 구독 상세 (19j 위험 4 · 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"주문 상세 · 구독 상세 (19j 위험 4 · 6) 관리자 주문 상세는 영업 판정을 타지 않는다 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 주문 상세는 영업 판정을 타지 않는다 (현행)"},{"ancestorTitles":["주문 상세 · 구독 상세 (19j 위험 4 · 6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"주문 상세 · 구독 상세 (19j 위험 4 · 6) 영업 A 가 담당 밖 구독 상세 → 403, 상세를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"영업 A 가 담당 밖 구독 상세 → 403, 상세를 읽지 않는다"},{"ancestorTitles":["주문 상세 · 구독 상세 (19j 위험 4 · 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"주문 상세 · 구독 상세 (19j 위험 4 · 6) 담당 구독은 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"담당 구독은 통과"},{"ancestorTitles":["기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7) 영업 A 가 담당 밖 기업 회원 · 일반 회원 상세 → 403","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 A 가 담당 밖 기업 회원 · 일반 회원 상세 → 403"},{"ancestorTitles":["기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7) 없는 번호 · 담당 없는 회원도 같은 403 (존재 여부를 가르지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"없는 번호 · 담당 없는 회원도 같은 403 (존재 여부를 가르지 않는다)"},{"ancestorTitles":["기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7) 담당 회원은 통과하고 이름 · 전화 · 이메일은 가린다 (현행)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"담당 회원은 통과하고 이름 · 전화 · 이메일은 가린다 (현행)"},{"ancestorTitles":["기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 상세 · 일반 FC 상세 (19j 위험 5 · 7) 관리자는 담당과 무관하게 본다 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자는 담당과 무관하게 본다 (현행)"},{"ancestorTitles":["머니 적립 상세 (19j 거짓 1 · 위험 14 의 실제 주어)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"머니 적립 상세 (19j 거짓 1 · 위험 14 의 실제 주어) 상수 OFF 에서도 영업 A 가 담당 밖 기업 지급건 → 403, 상세를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 OFF 에서도 영업 A 가 담당 밖 기업 지급건 → 403, 상세를 읽지 않는다"},{"ancestorTitles":["머니 적립 상세 (19j 거짓 1 · 위험 14 의 실제 주어)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"머니 적립 상세 (19j 거짓 1 · 위험 14 의 실제 주어) 상수 OFF 에서 담당 기업 지급건은 통과 · 자기 기업 지급건을 보는 기업 신원도 단건 판정을 거쳐 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 OFF 에서 담당 기업 지급건은 통과 · 자기 기업 지급건을 보는 기업 신원도 단건 판정을 거쳐 통과한다"},{"ancestorTitles":["관리자 알림 읽음 · 삭제 (19j 위험 13)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 알림 읽음 · 삭제 (19j 위험 13) 관리자 A 가 관리자 B 알림 읽음 · 삭제 → 404, 바꾸지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"관리자 A 가 관리자 B 알림 읽음 · 삭제 → 404, 바꾸지 않는다"},{"ancestorTitles":["관리자 알림 읽음 · 삭제 (19j 위험 13)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 알림 읽음 · 삭제 (19j 위험 13) 본인 알림은 읽음 · 삭제된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"본인 알림은 읽음 · 삭제된다"}],"endTime":1793868731222,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/scope-immediate.spec.ts","startTime":1793868730906,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다 커밋되면 T1 줄이 한 건 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 T1 줄이 한 건 나간다"},{"ancestorTitles":["금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다 콜백이 던지면 줄이 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"콜백이 던지면 줄이 나가지 않는다"},{"ancestorTitles":["금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다 콜백은 완주했으나 커밋이 거부되면 줄이 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"콜백은 완주했으나 커밋이 거부되면 줄이 나가지 않는다"},{"ancestorTitles":["금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"금전 감사 줄 — 트랜잭션이 정상 반환한 뒤에만 나간다 커밋 단계 거부는 부분 기록도 남기지 않는다 — 어떤 층의 줄도 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋 단계 거부는 부분 기록도 남기지 않는다 — 어떤 층의 줄도 없다"},{"ancestorTitles":["동시 요청 — 감사 줄이 서로 섞이지 않는다"],"duration":22,"failureDetails":[],"failureMessages":[],"fullName":"동시 요청 — 감사 줄이 서로 섞이지 않는다 두 요청의 targetId 와 requestId 가 각자 짝을 유지한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"두 요청의 targetId 와 requestId 가 각자 짝을 유지한다"}],"endTime":1793868731251,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-tx.spec.ts","startTime":1793868731008,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["자동차 분석결과 공개 시점"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"자동차 분석결과 공개 시점 고객사 인증은 유지하고 최고관리자 전용 가드는 자동차 API에서만 해제한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"고객사 인증은 유지하고 최고관리자 전용 가드는 자동차 API에서만 해제한다"},{"ancestorTitles":["자동차 분석결과 공개 시점"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"자동차 분석결과 공개 시점 공개 이전은 빈 결과, 공개 시점부터는 자동차 결과를 반환한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"공개 이전은 빈 결과, 공개 시점부터는 자동차 결과를 반환한다"}],"endTime":1793868731425,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/client/client/client.service.spec.ts","startTime":1793868731224,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["uploadGrant — 지급 배치 식별자가 감사 줄에 실린다"],"duration":22,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 지급 배치 식별자가 감사 줄에 실린다 행마다 만든 mngId 가 batch 키로 나간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행마다 만든 mngId 가 batch 키로 나간다"},{"ancestorTitles":["uploadGrant — 지급 배치 식별자가 감사 줄에 실린다"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 지급 배치 식별자가 감사 줄에 실린다 배치 식별자는 changes 안이 아니라 최상위 batch 키에 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"배치 식별자는 changes 안이 아니라 최상위 batch 키에 있다"},{"ancestorTitles":["uploadGrant — 지급 배치 식별자가 감사 줄에 실린다"],"duration":96,"failureDetails":[],"failureMessages":[],"fullName":"uploadGrant — 지급 배치 식별자가 감사 줄에 실린다 상한을 넘는 업로드는 잘린 사실을 값에 남긴다 — 부분 재구성임을 알 수 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상한을 넘는 업로드는 잘린 사실을 값에 남긴다 — 부분 재구성임을 알 수 있다"},{"ancestorTitles":["uploadIssue — 적립 배치 식별자가 감사 줄에 실린다"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 적립 배치 식별자가 감사 줄에 실린다 행마다 만든 mniId 가 batch 키로 나간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행마다 만든 mniId 가 batch 키로 나간다"},{"ancestorTitles":["uploadIssue — 적립 배치 식별자가 감사 줄에 실린다"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 적립 배치 식별자가 감사 줄에 실린다 배치 식별자는 changes 안이 아니라 최상위 batch 키에 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"배치 식별자는 changes 안이 아니라 최상위 batch 키에 있다"},{"ancestorTitles":["uploadIssue — 적립 배치 식별자가 감사 줄에 실린다"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 적립 배치 식별자가 감사 줄에 실린다 id 를 못 받은 행이 있으면 감사 줄이 그 사실을 말한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"id 를 못 받은 행이 있으면 감사 줄이 그 사실을 말한다"},{"ancestorTitles":["uploadIssue — 적립 배치 식별자가 감사 줄에 실린다"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 적립 배치 식별자가 감사 줄에 실린다 전 행이 id 를 돌려주면 유실 표시가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전 행이 id 를 돌려주면 유실 표시가 없다"},{"ancestorTitles":["uploadIssue — 적립 배치 식별자가 감사 줄에 실린다"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"uploadIssue — 적립 배치 식별자가 감사 줄에 실린다 dryRun 은 아무 줄도 내지 않는다 — 적용하지 않은 것을 기록으로 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dryRun 은 아무 줄도 내지 않는다 — 적용하지 않은 것을 기록으로 남기지 않는다"}],"endTime":1793868731581,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-batch.spec.ts","startTime":1793868731252,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 접근제어"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 접근제어 access: 컨트롤러에 인증 가드와 최고관리자 가드가 둘 다 걸려 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"access: 컨트롤러에 인증 가드와 최고관리자 가드가 둘 다 걸려 있다"},{"ancestorTitles":["삼성화재 계정 인테이크 접근제어"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 접근제어 access: 판정 전용 session 핸들러가 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"access: 판정 전용 session 핸들러가 없다"},{"ancestorTitles":["삼성화재 계정 인테이크 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 접근제어 access: 핸들러에 isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"access: 핸들러에 isPublic 우회가 없다"},{"ancestorTitles":["삼성화재 계정 인테이크 업로드 크기 상한"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 업로드 크기 상한 upload: 파일을 받는 핸들러는 전부 상한 걸린 인터셉터 하나를 쓴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"upload: 파일을 받는 핸들러는 전부 상한 걸린 인터셉터 하나를 쓴다"},{"ancestorTitles":["삼성화재 계정 인테이크 업로드 크기 상한"],"duration":93,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 업로드 크기 상한 upload: 상한을 넘는 파일은 핸들러에 닿기 전에 413 으로 막힌다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"upload: 상한을 넘는 파일은 핸들러에 닿기 전에 413 으로 막힌다"}],"endTime":1793868731769,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-access.spec.ts","startTime":1793868731426,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 1 타인 memId 목록은 403 이고 getList 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"1 타인 memId 목록은 403 이고 getList 를 부르지 않는다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 2 타인 손해사정 상세는 403 이다 — 컨트롤러 → 실 서비스 → 목 저장소, getDetail 인자는 (lsaId, true, 토큰 memId)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"2 타인 손해사정 상세는 403 이다 — 컨트롤러 → 실 서비스 → 목 저장소, getDetail 인자는 (lsaId, true, 토큰 memId)"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 3 상세 행이 없거나 회원 칸이 비면 같은 403 이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"3 상세 행이 없거나 회원 칸이 비면 같은 403 이다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 4 관리자 상세(isUser=false)는 소유 대조를 건너뛴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"4 관리자 상세(isUser=false)는 소유 대조를 건너뛴다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 5 생성 컨트롤러는 본문 memId 가 달라도 서비스에 토큰 memId 를 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"5 생성 컨트롤러는 본문 memId 가 달라도 서비스에 토큰 memId 를 넘긴다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 6 생성 서비스는 본문 memId 를 인자 값으로 덮어 저장소에 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"6 생성 서비스는 본문 memId 를 인자 값으로 덮어 저장소에 넘긴다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 7 타인 손해사정 수정은 403 이고 저장소 쓰기 · S3 업로드가 없다 — isOwner 인자는 (lsaId, 토큰 memId)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"7 타인 손해사정 수정은 403 이고 저장소 쓰기 · S3 업로드가 없다 — isOwner 인자는 (lsaId, 토큰 memId)"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 8 수정에 남의 첨부 id 가 섞이면 403 이다 — countMapped 인자 · 쓰기 미호출 · 중복 id 는 고유화","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"8 수정에 남의 첨부 id 가 섞이면 403 이다 — countMapped 인자 · 쓰기 미호출 · 중복 id 는 고유화"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 9 타인 손해사정 삭제는 403 이다 — deleteOwned 인자는 (고유 ids, 토큰 memId)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"9 타인 손해사정 삭제는 403 이다 — deleteOwned 인자는 (고유 ids, 토큰 memId)"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 10 삭제 저장소 — 잠금 행 수가 ids 보다 적으면(혼합 소유 포함) false 이고 DELETE 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"10 삭제 저장소 — 잠금 행 수가 ids 보다 적으면(혼합 소유 포함) false 이고 DELETE 를 부르지 않는다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 11 삭제 저장소 — 잠금 읽기와 DELETE 의 where 가 각각 memId 를 AND 로 싣고 for update 를 부른다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"11 삭제 저장소 — 잠금 읽기와 DELETE 의 where 가 각각 memId 를 AND 로 싣고 for update 를 부른다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 12 isOwner where 바인딩이 [lsaId, memId] 순서다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"12 isOwner where 바인딩이 [lsaId, memId] 순서다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 13 countMapped where 바인딩이 [lsaId, lafIds…] 순서다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"13 countMapped where 바인딩이 [lsaId, lafIds…] 순서다"},{"ancestorTitles":["손해사정 소유자 대조 (보안 핫픽스 M5 K9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"손해사정 소유자 대조 (보안 핫픽스 M5 K9) 14 본인 목록 · 상세 · 수정 · 삭제는 컨트롤러에서 통과한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"14 본인 목록 · 상세 · 수정 · 삭제는 컨트롤러에서 통과한다"}],"endTime":1793868731861,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/loss-adjustment/loss-adjustment/loss-ownership.spec.ts","startTime":1793868731582,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["원본 진료 다운로드 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"원본 진료 다운로드 접근제어 medical: 컨트롤러에 회원 인증 · 분석 소유자 가드가 이 순서로 걸려 있고 isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"medical: 컨트롤러에 회원 인증 · 분석 소유자 가드가 이 순서로 걸려 있고 isPublic 우회가 없다"},{"ancestorTitles":["원본 진료 다운로드 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"원본 진료 다운로드 접근제어 medical: 모듈이 OrderDetailModule 을 가져온다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"medical: 모듈이 OrderDetailModule 을 가져온다"},{"ancestorTitles":["원본 진료 다운로드 접근제어","HTTP"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"원본 진료 다운로드 접근제어 HTTP medical: 무토큰 401 · 타인 회원 403 · 소유자 200 이고 거부된 요청은 엑셀을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"medical: 무토큰 401 · 타인 회원 403 · 소유자 200 이고 거부된 요청은 엑셀을 만들지 않는다"}],"endTime":1793868732083,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/medical/medical-access.spec.ts","startTime":1793868731771,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyPolicyModule 배선"],"duration":19,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyModule 배선 AgencyPolicyModule 을 가져온 FcModule·SubscribeModule 이 순환 없이 컴파일된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"AgencyPolicyModule 을 가져온 FcModule·SubscribeModule 이 순환 없이 컴파일된다"}],"endTime":1793868732189,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/policy/policy.module.spec.ts","startTime":1793868731863,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AuthModule JwtService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuthModule JwtService providers 에 JwtService 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"providers 에 JwtService 가 없다"},{"ancestorTitles":["AuthModule JwtService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuthModule JwtService exports 에 JwtService 가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"exports 에 JwtService 가 없다"}],"endTime":1793868732410,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/auth-module-jwt.spec.ts","startTime":1793868732086,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독 paste: 붙여 넣은 표를 줄마다 탭으로 갈라 줄 번호 그대로 읽고 순번만 있는 끝 행은 건너뛴다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"paste: 붙여 넣은 표를 줄마다 탭으로 갈라 줄 번호 그대로 읽고 순번만 있는 끝 행은 건너뛴다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독 paste: 메일 표 열 이름으로 코드·성명·비번 열을 제안하고 비번 열의 값과 열 이름은 보기에 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"paste: 메일 표 열 이름으로 코드·성명·비번 열을 제안하고 비번 열의 값과 열 이름은 보기에 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독 paste: 대조군 — 가린 비번 열의 값은 같은 표의 판독 결과에 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"paste: 대조군 — 가린 비번 열의 값은 같은 표의 판독 결과에 있다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독"],"duration":26,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독 paste: 붙여 넣은 표가 상한 바이트를 넘으면 붙여넣기 크기 오류로 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"paste: 붙여 넣은 표가 상한 바이트를 넘으면 붙여넣기 크기 오류로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 메일 표 붙여넣기 판독 paste: source 가 없으면 같은 텍스트를 지금처럼 읽기 불가로 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"paste: source 가 없으면 같은 텍스트를 지금처럼 읽기 불가로 거부한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 의도 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 의도 대조 intent: 붙여넣기에서 등록인데 비밀번호가 0건이거나 삭제인데 비밀번호가 있으면 양식 의심이고 xlsx 입력에서는 켜지지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"intent: 붙여넣기에서 등록인데 비밀번호가 0건이거나 삭제인데 비밀번호가 있으면 양식 의심이고 xlsx 입력에서는 켜지지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 의도 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 의도 대조 intent: 뺀 행·고친 비밀번호·비번 열 쓰임 해제는 붙여넣기 의도 대조를 끄지 못한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"intent: 뺀 행·고친 비밀번호·비번 열 쓰임 해제는 붙여넣기 의도 대조를 끄지 못한다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 의도 대조"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 의도 대조 intent: 비밀번호가 아닌 열의 영문+숫자 값은 붙여넣기 의도 대조의 계수가 되지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"intent: 비밀번호가 아닌 열의 영문+숫자 값은 붙여넣기 의도 대조의 계수가 되지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 엔드포인트 endpoint: source 는 paste 만 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"endpoint: source 는 paste 만 받는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 엔드포인트 endpoint: parse 는 붙여 넣은 표로 제안 배치·계수·의도 대조를 돌려주고 비밀번호 값을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"endpoint: parse 는 붙여 넣은 표로 제안 배치·계수·의도 대조를 돌려주고 비밀번호 값을 싣지 않는다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 엔드포인트 endpoint: preview 와 confirm 은 같은 붙여 넣은 표를 다시 읽어 코드에 s 를 붙인 계정을 만든다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"endpoint: preview 와 confirm 은 같은 붙여 넣은 표를 다시 읽어 코드에 s 를 붙인 계정을 만든다"},{"ancestorTitles":["삼성화재 계정 인테이크 — 붙여넣기 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"삼성화재 계정 인테이크 — 붙여넣기 엔드포인트 endpoint: 붙여넣기 의도 대조가 켜진 확정은 양식 의심 확인 없이 막힌다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"endpoint: 붙여넣기 의도 대조가 켜진 확정은 양식 의심 확인 없이 막힌다"}],"endTime":1793868732551,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/samsung-intake-paste.spec.ts","startTime":1793868732190,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["invoice merged PDF routes"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 회원과 관리자 경로에 각각의 인증 가드가 적용된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"회원과 관리자 경로에 각각의 인증 가드가 적용된다"},{"ancestorTitles":["invoice merged PDF routes"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 회원 경로는 토큰 회원번호로 소유자를 검증한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"회원 경로는 토큰 회원번호로 소유자를 검증한다"},{"ancestorTitles":["invoice merged PDF routes"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 소유자 확인 후 1분짜리 PDF 조회 링크를 발급한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"소유자 확인 후 1분짜리 PDF 조회 링크를 발급한다"},{"ancestorTitles":["invoice merged PDF routes"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 단기 토큰을 검증해 기존 inline PDF 응답을 반환한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"단기 토큰을 검증해 기존 inline PDF 응답을 반환한다"},{"ancestorTitles":["invoice merged PDF routes"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 다른 청구서 ID에 발급된 토큰은 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"다른 청구서 ID에 발급된 토큰은 거부한다"},{"ancestorTitles":["invoice merged PDF routes"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 단기 링크는 회원 JWT로 사용할 수 없고 변조 시 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"단기 링크는 회원 JWT로 사용할 수 없고 변조 시 거부한다"},{"ancestorTitles":["invoice merged PDF routes"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"invoice merged PDF routes 관리자 경로는 관리자 가드 이후 소유자 제한 없이 조회한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 경로는 관리자 가드 이후 소유자 제한 없이 조회한다"}],"endTime":1793868732595,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/invoice/invoice-merged-pdf.controller.spec.ts","startTime":1793868732412,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["settlement"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"settlement 버킷 합 — 대리점 행과 미귀속 행의 잔여 합이 전체 잔여와 같다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"버킷 합 — 대리점 행과 미귀속 행의 잔여 합이 전체 잔여와 같다"},{"ancestorTitles":["settlement"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement 미귀속 — 채널·대리점이 없는 건은 버려지지 않고 unattributed 행으로 들어간다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"미귀속 — 채널·대리점이 없는 건은 버려지지 않고 unattributed 행으로 들어간다"},{"ancestorTitles":["settlement"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"settlement 커버리지 — 산출된 대리점 수가 입력에 매출이 있는 대리점 수와 같다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"커버리지 — 산출된 대리점 수가 입력에 매출이 있는 대리점 수와 같다"},{"ancestorTitles":["settlement"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement 음수 잔여 — 건수와 잔여 합이 대리점 행에 드러나고 금액은 음수 그대로다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"음수 잔여 — 건수와 잔여 합이 대리점 행에 드러나고 금액은 음수 그대로다"},{"ancestorTitles":["settlement"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"settlement 오류 — ok:false 건은 합계에서 빠지고 errors 에 사유별 건수·결제금액으로 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"오류 — ok:false 건은 합계에서 빠지고 errors 에 사유별 건수·결제금액으로 남는다"},{"ancestorTitles":["settlement"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement 반올림 — 행별 half-up 합이 정확값 합의 반올림과 다른 입력에서 roundingDiff 가 그 차와 같다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"반올림 — 행별 half-up 합이 정확값 합의 반올림과 다른 입력에서 roundingDiff 가 그 차와 같다"},{"ancestorTitles":["settlement"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"settlement 정확 합 — 무작위 500건에서 차감 합이 입력 결제금액에서 직접 계산한 공급가액 합과 같다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"정확 합 — 무작위 500건에서 차감 합이 입력 결제금액에서 직접 계산한 공급가액 합과 같다"},{"ancestorTitles":["settlement"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement 건의 날짜 — ord_created_at 의 날짜 부분으로 유효기간을 평가해 23:59:59 건이 그날 설정을 탄다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"건의 날짜 — ord_created_at 의 날짜 부분으로 유효기간을 평가해 23:59:59 건이 그날 설정을 탄다"},{"ancestorTitles":["settlement"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"settlement 설정 없음 — 잔여 행이 없는 구간의 건은 RESIDUAL_MISSING 으로 전건 errors 에 들어간다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"설정 없음 — 잔여 행이 없는 구간의 건은 RESIDUAL_MISSING 으로 전건 errors 에 들어간다"},{"ancestorTitles":["settlement"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement 세전 — 응답 객체의 재귀 키 어디에도 원천징수 항목이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"세전 — 응답 객체의 재귀 키 어디에도 원천징수 항목이 없다"},{"ancestorTitles":["settlement"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"settlement 구정책 재현 — 원가 정률 50%·보상 정률 30% 설정으로 2026H1 손해사정사 5채널을 산출해 재현 산출물을 쓴다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"구정책 재현 — 원가 정률 50%·보상 정률 30% 설정으로 2026H1 손해사정사 5채널을 산출해 재현 산출물을 쓴다"},{"ancestorTitles":["settlement"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"settlement 실측 분포 — 고정본의 대리점·미귀속 건수와 금액이 산출에서 한 건도 사라지지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"실측 분포 — 고정본의 대리점·미귀속 건수와 금액이 산출에서 한 건도 사라지지 않는다"},{"ancestorTitles":["settlement"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"settlement 실측 분포 — 미귀속 행의 결제금액이 고정본의 미귀속 합과 같다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"실측 분포 — 미귀속 행의 결제금액이 고정본의 미귀속 합과 같다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 확정 회차의 반영 주문 1건이 계단 1건이고 결제금액 자리에 정산단가가 들어간다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"기업 축 — 확정 회차의 반영 주문 1건이 계단 1건이고 결제금액 자리에 정산단가가 들어간다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 회차의 주문 합이 확정 스냅샷과 다르거나 스냅샷이 null 이면 그 회차 주문 전부가 합계에서 빠지고 두 금액이 snapshotMismatches 와 errors 에 남는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기업 축 — 회차의 주문 합이 확정 스냅샷과 다르거나 스냅샷이 null 이면 그 회차 주문 전부가 합계에서 빠지고 두 금액이 snapshotMismatches 와 errors 에 남는다"},{"ancestorTitles":["settlement — 기업 축"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 채널 미귀속 — 채널 없는 건은 대리점마다(대리점 미귀속 버킷 포함) 채널 미귀속 행 하나로 모이고 정확값에서 채널 행과 합이 대리점 행과 같다","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"채널 미귀속 — 채널 없는 건은 대리점마다(대리점 미귀속 버킷 포함) 채널 미귀속 행 하나로 모이고 정확값에서 채널 행과 합이 대리점 행과 같다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 채널 미귀속 — 공급가액에 소수가 생기는 100원 단가 입력에서 직렬화된 응답의 채널 행·채널 미귀속 행·channelRoundingDiff 합이 대리점 행과 같다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"채널 미귀속 — 공급가액에 소수가 생기는 100원 단가 입력에서 직렬화된 응답의 채널 행·채널 미귀속 행·channelRoundingDiff 합이 대리점 행과 같다"},{"ancestorTitles":["settlement — 기업 축"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 채널 행 — 대리점 id 순(대리점 미귀속 버킷 마지막) 다음 채널 코드 순으로 정렬돼 같은 입력의 순서를 바꿔도 응답이 같다","invocations":1,"location":null,"numPassingAsserts":21,"retryReasons":[],"status":"passed","title":"채널 행 — 대리점 id 순(대리점 미귀속 버킷 마지막) 다음 채널 코드 순으로 정렬돼 같은 입력의 순서를 바꿔도 응답이 같다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 같은 채널 코드가 대리점이 다른 두 기업에 걸리면 채널 행이 대리점별로 갈리고 불일치 건수·금액이 드러난다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기업 축 — 같은 채널 코드가 대리점이 다른 두 기업에 걸리면 채널 행이 대리점별로 갈리고 불일치 건수·금액이 드러난다"},{"ancestorTitles":["settlement — 기업 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 대기 회차는 계단에 들어가지 않고 회차 수와 배치 생성액으로 드러난다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"기업 축 — 대기 회차는 계단에 들어가지 않고 회차 수와 배치 생성액으로 드러난다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 건당 정액 보상은 반영 주문마다 붙어 한 회차 N건이면 N배다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"기업 축 — 건당 정액 보상은 반영 주문마다 붙어 한 회차 N건이면 N배다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 버킷 합이 대리점 행과 채널 미귀속 행을 더해 전체 잔여와 같다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기업 축 — 버킷 합이 대리점 행과 채널 미귀속 행을 더해 전체 잔여와 같다"},{"ancestorTitles":["settlement — 기업 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 축 — 응답이 콘솔 확정액을 입력으로 쓴다는 source 와 기업 채널 기준 basis 를 싣는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기업 축 — 응답이 콘솔 확정액을 입력으로 쓴다는 source 와 기업 채널 기준 basis 를 싣는다"},{"ancestorTitles":["settlement — 기업 축"],"duration":83,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 실측 분포 — 고정본의 대리점·채널 건수와 금액이 기업 축 산출에서 한 건도 사라지지 않는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"기업 실측 분포 — 고정본의 대리점·채널 건수와 금액이 기업 축 산출에서 한 건도 사라지지 않는다"},{"ancestorTitles":["settlement — 기업 축"],"duration":80,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 기업 축 기업 실측 분포 — 채널 미귀속 행의 금액 합이 고정본 대리점 표의 채널 미귀속 합과 같다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"기업 실측 분포 — 채널 미귀속 행의 금액 합이 고정본 대리점 표의 채널 미귀속 합과 같다"},{"ancestorTitles":["settlement — 채널 행 원가·잔여·플래그 (R11-A)"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 채널 행 원가·잔여·플래그 (R11-A) 채널 행·채널 없음 행의 원가·잔여·플래그가 외부 계산과 같고, 하위 행 합 + channelRoundingDiff 가 대리점 행 네 금액과 같다","invocations":1,"location":null,"numPassingAsserts":36,"retryReasons":[],"status":"passed","title":"채널 행·채널 없음 행의 원가·잔여·플래그가 외부 계산과 같고, 하위 행 합 + channelRoundingDiff 가 대리점 행 네 금액과 같다"},{"ancestorTitles":["settlement — 채널 행 원가·잔여·플래그 (R11-A)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 채널 행 원가·잔여·플래그 (R11-A) 채널 행에 없는 플래그 키는 싣지 않는다 — 보상이 정해진 채널 행의 flags 는 빈 객체다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"채널 행에 없는 플래그 키는 싣지 않는다 — 보상이 정해진 채널 행의 flags 는 빈 객체다"},{"ancestorTitles":["settlement — 월별 묶음 (R11-A)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 월별 묶음 (R11-A) 달 경계로 잘라 첫·끝 달은 구간에 맞추고, 각 달은 그 달 입력만으로 한 두 축 산출과 같다 — 기업 회차는 회차일 달에 통째로 들어간다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"달 경계로 잘라 첫·끝 달은 구간에 맞추고, 각 달은 그 달 입력만으로 한 두 축 산출과 같다 — 기업 회차는 회차일 달에 통째로 들어간다"},{"ancestorTitles":["settlement — 월별 묶음 (R11-A)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 월별 묶음 (R11-A) 건 없는 달도 0 으로 들어가고 연 경계·하루 구간을 자른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"건 없는 달도 0 으로 들어가고 연 경계·하루 구간을 자른다"},{"ancestorTitles":["settlement — 월별 묶음 (R11-A)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 월별 묶음 (R11-A) 9999년 12월에서 끝난다 — 다음 경계 10000-01-01 이 문자열로 거꾸로 서도 구간 끝에서 멈춘다(C 리뷰 B1)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"9999년 12월에서 끝난다 — 다음 경계 10000-01-01 이 문자열로 거꾸로 서도 구간 끝에서 멈춘다(C 리뷰 B1)"},{"ancestorTitles":["settlement — 첫 결제 건수 (R17-A)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 첫 결제 건수 (R17-A) 개인 축 — 합계 · 대리점 · 채널 · 채널 미귀속 행이 그 행 건 중 첫 결제 건수를 갖고, 채널 행 + 채널 미귀속 행 = 대리점 행이다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"개인 축 — 합계 · 대리점 · 채널 · 채널 미귀속 행이 그 행 건 중 첫 결제 건수를 갖고, 채널 행 + 채널 미귀속 행 = 대리점 행이다"},{"ancestorTitles":["settlement — 첫 결제 건수 (R17-A)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 첫 결제 건수 (R17-A) 기업 축 — 「건」 이 반영 주문 1건이라 첫 결제를 세지 않고 모든 칸이 null 이다(입력에 표시가 있어도)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"기업 축 — 「건」 이 반영 주문 1건이라 첫 결제를 세지 않고 모든 칸이 null 이다(입력에 표시가 있어도)"},{"ancestorTitles":["settlement — 잔여 음수 드러내기 (R17-A)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 잔여 음수 드러내기 (R17-A) 개인 축 — 채널 행 · 채널 미귀속 행이 대리점 행과 같은 음수 건수 · 금액을 갖고, 원인은 (상품, 결제금액) 묶음으로 음수가 큰 순이다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"개인 축 — 채널 행 · 채널 미귀속 행이 대리점 행과 같은 음수 건수 · 금액을 갖고, 원인은 (상품, 결제금액) 묶음으로 음수가 큰 순이다"},{"ancestorTitles":["settlement — 잔여 음수 드러내기 (R17-A)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"settlement — 잔여 음수 드러내기 (R17-A) 기업 축 — 원인 묶음에 기업 코드와 청구 단가가 들어가고 기업마다 갈린다 · 음수가 없으면 빈 배열이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기업 축 — 원인 묶음에 기업 코드와 청구 단가가 들어가고 기업마다 갈린다 · 음수가 없으면 빈 배열이다"}],"endTime":1793868732842,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/settlement.spec.ts","startTime":1793868732553,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["processPendingFaxStatuses — 머니 원복이 줄로 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processPendingFaxStatuses — 머니 원복이 줄로 남는다 원복이 반환하면 회원마다 moneyFaxRestore 커밋 줄이 나가고 원복 실패 수는 0 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"원복이 반환하면 회원마다 moneyFaxRestore 커밋 줄이 나가고 원복 실패 수는 0 이다"},{"ancestorTitles":["processPendingFaxStatuses — 머니 원복이 줄로 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processPendingFaxStatuses — 머니 원복이 줄로 남는다 원복이 던지면 FAX_RESTORE_FAILED 줄이 나가고 실패 수가 호출부에 도달한다 — 삼키지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"원복이 던지면 FAX_RESTORE_FAILED 줄이 나가고 실패 수가 호출부에 도달한다 — 삼키지 않는다"},{"ancestorTitles":["processPendingFaxStatuses — 머니 원복이 줄로 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processPendingFaxStatuses — 머니 원복이 줄로 남는다 원복이 실패해도 흐름이 그대로다 — 팩스는 FAILED 로 닫히고 배치 알림 확인과 다음 건이 돈다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"원복이 실패해도 흐름이 그대로다 — 팩스는 FAILED 로 닫히고 배치 알림 확인과 다음 건이 돈다"},{"ancestorTitles":["processPendingFaxStatuses — 머니 원복이 줄로 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processPendingFaxStatuses — 머니 원복이 줄로 남는다 대기 건이 없으면 원복 실패 수도 0 으로 돌아간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대기 건이 없으면 원복 실패 수도 0 으로 돌아간다"}],"endTime":1793868732927,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fax/fax-restore-audit.spec.ts","startTime":1793868732597,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["고객 인적사항 가림 — 공용 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 공용 함수 영업 신원이면 이름·연락처·생년월일을 목록과 같은 규칙으로 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 신원이면 이름·연락처·생년월일을 목록과 같은 규칙으로 가린다"},{"ancestorTitles":["고객 인적사항 가림 — 공용 함수"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 공용 함수 통합·기업·신원 없음은 원본 객체를 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"통합·기업·신원 없음은 원본 객체를 그대로 돌려준다"},{"ancestorTitles":["고객 인적사항 가림 — 공용 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 공용 함수 주문 정보가 없는 응답은 영업이어도 그대로다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문 정보가 없는 응답은 영업이어도 그대로다"},{"ancestorTitles":["고객 인적사항 가림 — 공용 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 공용 함수 고객 정보가 비어 있으면 빈 문자열로 접는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"고객 정보가 비어 있으면 빈 문자열로 접는다"},{"ancestorTitles":["고객 인적사항 가림 — 관리자 JWT 상세 라우트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 관리자 JWT 상세 라우트 영업 신원의 기본·집계 응답은 고객 인적사항이 가려진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 신원의 기본·집계 응답은 고객 인적사항이 가려진다"},{"ancestorTitles":["고객 인적사항 가림 — 관리자 JWT 상세 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 관리자 JWT 상세 라우트 통합관리자 신원은 원본을 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"통합관리자 신원은 원본을 받는다"},{"ancestorTitles":["고객 인적사항 가림 — 관리자 JWT 상세 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 관리자 JWT 상세 라우트 영업 신원의 원본 다운로드는 파일명 가림 플래그를 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 신원의 원본 다운로드는 파일명 가림 플래그를 서비스에 넘긴다"},{"ancestorTitles":["고객 인적사항 가림 — 옛 경로 상세 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 옛 경로 상세 라우트 영업 신원은 기본·집계 응답이 가려진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 신원은 기본·집계 응답이 가려진다"},{"ancestorTitles":["고객 인적사항 가림 — 옛 경로 상세 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 옛 경로 상세 라우트 통합 신원은 원본을 받는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"통합 신원은 원본을 받는다"},{"ancestorTitles":["고객 인적사항 가림 — 원본 다운로드 파일명"],"duration":18,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 원본 다운로드 파일명 가림 대상이면 실명 대신 oddId 로 파일명을 짓는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가림 대상이면 실명 대신 oddId 로 파일명을 짓는다"},{"ancestorTitles":["고객 인적사항 가림 — 원본 다운로드 파일명"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 원본 다운로드 파일명 통합·기업이면 기존처럼 고객 이름을 파일명에 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"통합·기업이면 기존처럼 고객 이름을 파일명에 쓴다"},{"ancestorTitles":["고객 인적사항 가림 — 분석관리 목록 (공용 함수 재사용 회귀)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 분석관리 목록 (공용 함수 재사용 회귀) 영업 신원의 목록 응답은 고객 인적사항이 가려진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 신원의 목록 응답은 고객 인적사항이 가려진다"},{"ancestorTitles":["고객 인적사항 가림 — 분석관리 목록 (공용 함수 재사용 회귀)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"고객 인적사항 가림 — 분석관리 목록 (공용 함수 재사용 회귀) 영업 신원의 목록 엑셀 행은 가려지고 통합 신원은 원본이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 신원의 목록 엑셀 행은 가려지고 통합 신원은 원본이다"}],"endTime":1793868733124,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-sales-mask.spec.ts","startTime":1793868732845,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SamsungS2ReportService"],"duration":82,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService S2 유료플랜 행을 엑셀로 만들어 설정된 수신자에게 보낸다","invocations":1,"location":null,"numPassingAsserts":24,"retryReasons":[],"status":"passed","title":"S2 유료플랜 행을 엑셀로 만들어 설정된 수신자에게 보낸다"},{"ancestorTitles":["SamsungS2ReportService"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService 허용되지 않은 수신자면 조회나 발송을 하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"허용되지 않은 수신자면 조회나 발송을 하지 않는다"},{"ancestorTitles":["SamsungS2ReportService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService 허용 수신자에 다른 주소가 더 붙어 있어도 조회나 발송을 하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"허용 수신자에 다른 주소가 더 붙어 있어도 조회나 발송을 하지 않는다"},{"ancestorTitles":["SamsungS2ReportService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService 07시 원본 파일이 없으면 재생성하거나 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"07시 원본 파일이 없으면 재생성하거나 발송하지 않는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 계약 단가를 쓸 수 없으면(NO_CONTRACT) 명세 없이 리포트만 보내고 본문에 까닭을 적는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"계약 단가를 쓸 수 없으면(NO_CONTRACT) 명세 없이 리포트만 보내고 본문에 까닭을 적는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 계약 단가를 쓸 수 없으면(MULTIPLE_PRICES) 명세 없이 리포트만 보내고 본문에 까닭을 적는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"계약 단가를 쓸 수 없으면(MULTIPLE_PRICES) 명세 없이 리포트만 보내고 본문에 까닭을 적는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 계약 단가를 쓸 수 없으면(ZERO_PRICE) 명세 없이 리포트만 보내고 본문에 까닭을 적는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"계약 단가를 쓸 수 없으면(ZERO_PRICE) 명세 없이 리포트만 보내고 본문에 까닭을 적는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 명세는 매월 1일 preview 에만 붙고 다른 날은 본문에 한 줄을 남긴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"명세는 매월 1일 preview 에만 붙고 다른 날은 본문에 한 줄을 남긴다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 섞인 달이면 본문에 월중 적용 시작일을 적는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"섞인 달이면 본문에 월중 적용 시작일을 적는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) final 은 명세를 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"final 은 명세를 만들지 않는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) preview 는 리포트와 명세 두 첨부를 보낸다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"preview 는 리포트와 명세 두 첨부를 보낸다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 정책이 주문 기준이면 첨부가 하나다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"정책이 주문 기준이면 첨부가 하나다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 명세 생성이 실패하면 preview 를 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"명세 생성이 실패하면 preview 를 발송하지 않는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 명세 S3 업로드가 실패하면 preview 를 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"명세 S3 업로드가 실패하면 preview 를 발송하지 않는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 명세(M3)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 명세(M3) 명세 이력 기록이 실패하면 preview 를 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"명세 이력 기록이 실패하면 preview 를 발송하지 않는다"}],"endTime":1793868733186,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-agency/samsung-s2-report.service.spec.ts","startTime":1793868732929,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["콘솔 거래명세서 — 기업 정보 채우기(결정 12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 기업 정보 채우기(결정 12) 등록값 · 회계팀 이메일(다듬어서)을 내고, 형식이 아니면 비운다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"등록값 · 회계팀 이메일(다듬어서)을 내고, 형식이 아니면 비운다"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":23,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) PDF · 원장을 한 번 읽어 붙이고, 본문은 이스케이프하고, 보낸 사람 · 받는 사람을 기록한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"PDF · 원장을 한 번 읽어 붙이고, 본문은 이스케이프하고, 보낸 사람 · 받는 사람을 기록한다"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 진행 중인 달 · 받는 사람 수 초과는 읽기 전에 400","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"진행 중인 달 · 받는 사람 수 초과는 읽기 전에 400"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 글꼴을 못 읽으면 보내지도 기록하지도 않는다(503)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"글꼴을 못 읽으면 보내지도 기록하지도 않는다(503)"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 메일 서버가 거절하면 502 이고 기록은 스탬프하지 않는다(확인 못 함)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"메일 서버가 거절하면 502 이고 기록은 스탬프하지 않는다(확인 못 함)"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 따옴표 지역부 주소는 읽기 전에 막는다 — 봉투에서 다른 수신자로 풀린다(리뷰 M1)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"따옴표 지역부 주소는 읽기 전에 막는다 — 봉투에서 다른 수신자로 풀린다(리뷰 M1)"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 일부 수신자가 거절되면 스탬프하지 않고 거절 주소를 돌려준다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"일부 수신자가 거절되면 스탬프하지 않고 거절 주소를 돌려준다"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 1분 안에 같은 기록이 있으면(다른 서버에서 보냄) 409","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"1분 안에 같은 기록이 있으면(다른 서버에서 보냄) 409"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 스탬프가 실패해도 메일은 나갔으니 성공으로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스탬프가 실패해도 메일은 나갔으니 성공으로 돌려준다"},{"ancestorTitles":["콘솔 거래명세서 — 바로 메일(결정 13)"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"콘솔 거래명세서 — 바로 메일(결정 13) 같은 메일이 보내지는 중이면 409, 끝나면 다시 보낼 수 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 메일이 보내지는 중이면 409, 끝나면 다시 보낼 수 있다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 acct@example.com 는 받고 봉투도 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"acct@example.com 는 받고 봉투도 같다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 first.last+billing@sub.example.co.kr 는 받고 봉투도 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"first.last+billing@sub.example.co.kr 는 받고 봉투도 같다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 a_b-c%d@ex-ample.io 는 받고 봉투도 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"a_b-c%d@ex-ample.io 는 받고 봉투도 같다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 \"billing@outside.test x\"@agency.test 는 받지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"\"billing@outside.test x\"@agency.test 는 받지 않는다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 \"first last\"@example.com 는 받지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"\"first last\"@example.com 는 받지 않는다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 a b@example.com 는 받지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a b@example.com 는 받지 않는다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 a@b@example.com 는 받지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a@b@example.com 는 받지 않는다"},{"ancestorTitles":["받는 사람 주소 = 실제 봉투 주소"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"받는 사람 주소 = 실제 봉투 주소 a,b@example.com 는 받지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"a,b@example.com 는 받지 않는다"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 정상 요청은 통과하고 agcId 는 숫자다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"정상 요청은 통과하고 agcId 는 숫자다"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 받는 사람 6명 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"받는 사람 6명 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 받는 사람 0명 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"받는 사람 0명 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 이메일 아님 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이메일 아님 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 따옴표 지역부 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"따옴표 지역부 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 제목 줄바꿈 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"제목 줄바꿈 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 빈 본문 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 본문 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 모르는 키 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 키 이면 400"},{"ancestorTitles":["메일 요청 검증(전역 ClassValidatorPipe)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메일 요청 검증(전역 ClassValidatorPipe) 월 형식 이면 400","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"월 형식 이면 400"}],"endTime":1793868733361,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/usage-statement-mail.spec.ts","startTime":1793868733126,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM) 상수 OFF: 영업 신원이어도 결제 행 잠금을 타지 않고 예약을 커밋한 뒤 PG 를 부른다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"상수 OFF: 영업 신원이어도 결제 행 잠금을 타지 않고 예약을 커밋한 뒤 PG 를 부른다"},{"ancestorTitles":["결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM) 상수 ON · 영업 신원: 결제 행을 잠그고 같은 트랜잭션 안에서 PG 취소와 DB 갱신을 한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원: 결제 행을 잠그고 같은 트랜잭션 안에서 PG 취소와 DB 갱신을 한다"},{"ancestorTitles":["결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM) 상수 ON · 영업 신원: PG 실패면 예약 해제 트랜잭션을 따로 열지 않고 바깥 되돌림에 맡긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원: PG 실패면 예약 해제 트랜잭션을 따로 열지 않고 바깥 되돌림에 맡긴다"},{"ancestorTitles":["결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"결제 취소 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 2차 MEDIUM) 이미 취소 처리 중이면 PG 를 부르지 않고 PG 호출 뒤 실패 로그도 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"이미 취소 처리 중이면 PG 를 부르지 않고 PG 호출 뒤 실패 로그도 남기지 않는다"},{"ancestorTitles":["결제 취소 실패 로그 키는 트랜잭션 여부를 따른다 (M6c R3 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제 취소 실패 로그 키는 트랜잭션 여부를 따른다 (M6c R3 MEDIUM) 상수 OFF: PG 호출 뒤 DB 실패는 롤백 키가 아니라 상태 불명 키로 남는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"상수 OFF: PG 호출 뒤 DB 실패는 롤백 키가 아니라 상태 불명 키로 남는다"},{"ancestorTitles":["결제 취소 실패 로그 키는 트랜잭션 여부를 따른다 (M6c R3 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"결제 취소 실패 로그 키는 트랜잭션 여부를 따른다 (M6c R3 MEDIUM) 상수 ON · 영업 신원: PG 호출 뒤 DB 실패는 트랜잭션 되돌림 키로 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원: PG 호출 뒤 DB 실패는 트랜잭션 되돌림 키로 남는다"}],"endTime":1793868733387,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money.service.cancel-scope.spec.ts","startTime":1793868733190,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 restore: 해지·미만료 구독을 되살린다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"restore: 해지·미만료 구독을 되살린다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 restore: 만료된 해지는 되살리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"restore: 만료된 해지는 되살리지 않는다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 restore: 구독 이력이 없으면 되살리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"restore: 구독 이력이 없으면 되살리지 않는다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 restore: 이미 구독중이면 되살리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"restore: 이미 구독중이면 되살리지 않는다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 default: useAt=1 은 구독을 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"default: useAt=1 은 구독을 건드리지 않는다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 skip: 회원 행이 없는 id 는 not-found 로 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"skip: 회원 행이 없는 id 는 not-found 로 남는다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 stop: useAt=0 은 전건 해지한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"stop: useAt=0 은 전건 해지한다"},{"ancestorTitles":["AgencyFcService.resign — 사용상태와 구독의 분기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.resign — 사용상태와 구독의 분기 stop: useAt=0 에서 subId null 은 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"stop: useAt=0 에서 subId null 은 호출하지 않는다"},{"ancestorTitles":["AgencyFcService.unsubscribe — 구독 이력이 없는 회원"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.unsubscribe — 구독 이력이 없는 회원 subId null 이 섞이면 쓰기 전에 전건 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"subId null 이 섞이면 쓰기 전에 전건 거부한다"},{"ancestorTitles":["AgencyFcService.unsubscribe — 구독 이력이 없는 회원"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.unsubscribe — 구독 이력이 없는 회원 쓰기 중 실패는 회원과 사유를 함께 알린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"쓰기 중 실패는 회원과 사유를 함께 알린다"},{"ancestorTitles":["AgencyFcService.unsubscribe — 구독 이력이 없는 회원"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.unsubscribe — 구독 이력이 없는 회원 쓰기 중 드라이버 오류는 원문을 응답에 싣지 않고 서버 로그로만 남긴다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"쓰기 중 드라이버 오류는 원문을 응답에 싣지 않고 서버 로그로만 남긴다"},{"ancestorTitles":["AgencyFcService.unsubscribe — 구독 이력이 없는 회원"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcService.unsubscribe — 구독 이력이 없는 회원 구독 이력이 전건 있으면 종전대로 전건 해지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독 이력이 전건 있으면 종전대로 전건 해지한다"}],"endTime":1793868733613,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/fc-agency-resign-subscribe.spec.ts","startTime":1793868733366,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 형상은 isSuper · menus · permissions · permissionsAvailable · superAvailable · menusAvailable 여섯 키다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"형상은 isSuper · menus · permissions · permissionsAvailable · superAvailable · menusAvailable 여섯 키다"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 최고관리자는 전 코드를 받고 바인딩을 묻지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"최고관리자는 전 코드를 받고 바인딩을 묻지 않는다"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 일반 관리자는 바인딩의 역할 코드를 받는다 (바인딩 · 코드 읽기 각 한 번)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"일반 관리자는 바인딩의 역할 코드를 받는다 (바인딩 · 코드 읽기 각 한 번)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 일반 관리자의 권한 집합은 최고관리자 전용 코드와 카탈로그 밖 코드를 뺀다 (evaluate 와 같다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"일반 관리자의 권한 집합은 최고관리자 전용 코드와 카탈로그 밖 코드를 뺀다 (evaluate 와 같다)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 바인딩 행이 없거나 athId 가 없으면 빈 집합이고 권한 조회는 성공이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"바인딩 행이 없거나 athId 가 없으면 빈 집합이고 권한 조회는 성공이다"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 비관리자 역할은 권한 집합을 주지 않는다 (영업 · 기업은 파생 메뉴다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"비관리자 역할은 권한 집합을 주지 않는다 (영업 · 기업은 파생 메뉴다)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 판정 조회가 던져도 메뉴와 권한 집합은 비최고관리자 값으로 이어진다 (M7c 정정)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"판정 조회가 던져도 메뉴와 권한 집합은 비최고관리자 값으로 이어진다 (M7c 정정)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 판정 조회 실패 시 superAvailable 은 false · isSuper 는 false · menusAvailable 은 true 다 (M7c 정정)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"판정 조회 실패 시 superAvailable 은 false · isSuper 는 false · menusAvailable 은 true 다 (M7c 정정)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 판정 조회가 던져도 일반 관리자는 자기 권한 집합을 읽는다 (M7c 정정)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"판정 조회가 던져도 일반 관리자는 자기 권한 집합을 읽는다 (M7c 정정)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 판정 조회가 던져도 최고관리자 전용 코드는 권한 집합에서 빠진다 (M7c 정정)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정 조회가 던져도 최고관리자 전용 코드는 권한 집합에서 빠진다 (M7c 정정)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 메뉴 조회가 던져도 isSuper 는 유지되고 menusAvailable 만 false 다 (음성)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"메뉴 조회가 던져도 isSuper 는 유지되고 menusAvailable 만 false 다 (음성)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 권한 조회가 던지면 집합만 알 수 없음으로 두고 isSuper · menus 는 유지한다 (부분 실패)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"권한 조회가 던지면 집합만 알 수 없음으로 두고 isSuper · menus 는 유지한다 (부분 실패)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 최고관리자는 권한 조회를 타지 않고 isSuper true 와 menus 를 준다 (정상 경로)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자는 권한 조회를 타지 않고 isSuper true 와 menus 를 준다 (정상 경로)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 메뉴 값은 MenuService.getMyMenuTree 의 값과 같다 (스위치 OFF = 현행)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"메뉴 값은 MenuService.getMyMenuTree 의 값과 같다 (스위치 OFF = 현행)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 관리자 역할의 응답 메뉴는 여전히 MenuService 참조 그대로다 (응답 불변 · 스위치 OFF)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 역할의 응답 메뉴는 여전히 MenuService 참조 그대로다 (응답 불변 · 스위치 OFF)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 영업 · 기업 /admin/me 는 파생 메뉴를 주고 menuSource 를 derived 로 단다 (M7c 배선)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"영업 · 기업 /admin/me 는 파생 메뉴를 주고 menuSource 를 derived 로 단다 (M7c 배선)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) agcAnalysisView 조회가 실패하면 기업 응답의 menusAvailable 은 false 다 (M7c 배선)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"agcAnalysisView 조회가 실패하면 기업 응답의 menusAvailable 은 false 다 (M7c 배선)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 기업 agcId 가 없거나 tn_agency 행이 없으면 분석 게이트를 0 으로 읽지 않고 menusAvailable 이 거짓이다 (M7c 배선)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"기업 agcId 가 없거나 tn_agency 행이 없으면 분석 게이트를 0 으로 읽지 않고 menusAvailable 이 거짓이다 (M7c 배선)"},{"ancestorTitles":["GET /admin/me 본문 (AdminMeService)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/me 본문 (AdminMeService) 주입 타입은 공용 핸들 · 최고관리자 서비스 · 메뉴 서비스 · 컨트롤러 탐색 넷뿐이다 (감시 핸들 미주입)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주입 타입은 공용 핸들 · 최고관리자 서비스 · 메뉴 서비스 · 컨트롤러 탐색 넷뿐이다 (감시 핸들 미주입)"},{"ancestorTitles":["메뉴 파생 ON 소비자 (격리 레지스트리)"],"duration":41,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 ON 소비자 (격리 레지스트리) ON 소비자: 일반 관리자는 권한 있는 URL 만 남고 매핑 없는 URL 은 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ON 소비자: 일반 관리자는 권한 있는 URL 만 남고 매핑 없는 URL 은 남는다"},{"ancestorTitles":["메뉴 파생 ON 소비자 (격리 레지스트리)"],"duration":37,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 ON 소비자 (격리 레지스트리) ON 소비자: 최고관리자는 매핑된 URL 전부가 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ON 소비자: 최고관리자는 매핑된 URL 전부가 남는다"},{"ancestorTitles":["메뉴 파생 ON 소비자 (격리 레지스트리)"],"duration":50,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 ON 소비자 (격리 레지스트리) ON 소비자: 영업 역할은 스위치와 무관하게 파생 메뉴이고 현행 트리를 참조하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ON 소비자: 영업 역할은 스위치와 무관하게 파생 메뉴이고 현행 트리를 참조하지 않는다"},{"ancestorTitles":["메뉴 파생 ON 소비자 (격리 레지스트리)"],"duration":37,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 ON 소비자 (격리 레지스트리) ON 소비자: 권한 집합을 모르면 매핑된 URL 은 숨는다 (음성)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"ON 소비자: 권한 집합을 모르면 매핑된 URL 은 숨는다 (음성)"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 관리자 역할: 맵 행을 영역과 함께 주고 내 코드 집합 · 스위치 상태를 준다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"관리자 역할: 맵 행을 영역과 함께 주고 내 코드 집합 · 스위치 상태를 준다"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 스위치 켜짐이 판정 지도에 그대로 실린다 (영역 3)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스위치 켜짐이 판정 지도에 그대로 실린다 (영역 3)"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 영업: applies 참 · 그 종류가 부를 수 있는 행만 · 스위치 전부 거짓 · 권한 바인딩을 묻지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"영업: applies 참 · 그 종류가 부를 수 있는 행만 · 스위치 전부 거짓 · 권한 바인딩을 묻지 않는다"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 기업 최고: 종류 낱말 · 쓰기 행이 들어가고 분석 수준 행은 기업 값으로 거른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기업 최고: 종류 낱말 · 쓰기 행이 들어가고 분석 수준 행은 기업 값으로 거른다"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 조직관리자: 쓰기는 @AllowOrgWrite 행만, 기업 최고 전용 행은 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조직관리자: 쓰기는 @AllowOrgWrite 행만, 기업 최고 전용 행은 없다"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 기업 분석 값을 못 읽으면(행 없음 · 조회 실패) 비관리자 판정 지도는 503 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기업 분석 값을 못 읽으면(행 없음 · 조회 실패) 비관리자 판정 지도는 503 이다"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 최고관리자는 전 코드를 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자는 전 코드를 받는다"},{"ancestorTitles":["GET /admin/permission-map 본문 (D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"GET /admin/permission-map 본문 (D7) 관리자 응답은 비관리자 표 이전(fd1a9ae0)의 식과 글자 단위로 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 응답은 비관리자 표 이전(fd1a9ae0)의 식과 글자 단위로 같다"}],"endTime":1793868733694,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/admin-me.service.spec.ts","startTime":1793868733388,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["tokenMemId"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"tokenMemId 토큰이 없으면 404, 주장한 memId 가 다르면 403, 같으면 그 값","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"토큰이 없으면 404, 주장한 memId 가 다르면 403, 같으면 그 값"},{"ancestorTitles":["구독 경로"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"구독 경로 구독 가입 · 즉시 변경은 body memId 가 토큰과 같아야 하고 카드 · 구독 주인을 본다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"구독 가입 · 즉시 변경은 body memId 가 토큰과 같아야 하고 카드 · 구독 주인을 본다"},{"ancestorTitles":["구독 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"구독 경로 구독현황은 남의 memId 를 못 본다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독현황은 남의 memId 를 못 본다"},{"ancestorTitles":["구독 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"구독 경로 unsubscribe 는 구독 주인을 본 뒤에 바꾼다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"unsubscribe 는 구독 주인을 본 뒤에 바꾼다"},{"ancestorTitles":["구독 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"구독 경로 reservation 는 구독 주인을 본 뒤에 바꾼다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"reservation 는 구독 주인을 본 뒤에 바꾼다"},{"ancestorTitles":["구독 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"구독 경로 promptPayment 는 구독 주인을 본 뒤에 바꾼다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"promptPayment 는 구독 주인을 본 뒤에 바꾼다"},{"ancestorTitles":["구독 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"구독 경로 assertOwner — 구독 · 카드 주인이 다르면 403","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"assertOwner — 구독 · 카드 주인이 다르면 403"},{"ancestorTitles":["카드 경로"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"카드 경로 목록 · 등록 · 대표 변경은 토큰과 같은 memId 만, 삭제는 토큰 회원으로 범위를 건다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"목록 · 등록 · 대표 변경은 토큰과 같은 memId 만, 삭제는 토큰 회원으로 범위를 건다"},{"ancestorTitles":["분석 경로"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"분석 경로 로그인 없는 상태 변경은 인증실패만 받고, 생긴 지 인증 제한 시간(170초) 지난 진행 중 인증만 조건부로 닫는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"로그인 없는 상태 변경은 인증실패만 받고, 생긴 지 인증 제한 시간(170초) 지난 진행 중 인증만 조건부로 닫는다"},{"ancestorTitles":["분석 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"분석 경로 닫지 못한 건(아직 이름 · 이미 끝남 · 진행 중 아님)과 없는 분석은 알림 없이 성공으로 답한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"닫지 못한 건(아직 이름 · 이미 끝남 · 진행 중 아님)과 없는 분석은 알림 없이 성공으로 답한다"},{"ancestorTitles":["분석 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"분석 경로 비노출은 그 회원의 분석만, 남의 것이 섞이면 아무것도 안 바꾼다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"비노출은 그 회원의 분석만, 남의 것이 섞이면 아무것도 안 바꾼다"},{"ancestorTitles":["분석 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"분석 경로 컨트롤러 — 비노출은 토큰 회원으로, 상태 변경은 좁힌 경로로","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"컨트롤러 — 비노출은 토큰 회원으로, 상태 변경은 좁힌 경로로"}],"endTime":1793868733869,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/user/member-ownership.spec.ts","startTime":1793868733620,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["강제 ON · 소속 쓰기 (기업 범위)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 소속 쓰기 (기업 범위) 정상 경로: 담당 범위 회원만이면 같은 트랜잭션 tx 로 잠그고 판정하고 바꾼다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"정상 경로: 담당 범위 회원만이면 같은 트랜잭션 tx 로 잠그고 판정하고 바꾼다"},{"ancestorTitles":["강제 ON · 소속 쓰기 (기업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 소속 쓰기 (기업 범위) 잠금 순서: 회원 → 담당 기업 → 회원 현재 소속 조직 → 목적지 조직 (판정 전에 끝난다)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"잠금 순서: 회원 → 담당 기업 → 회원 현재 소속 조직 → 목적지 조직 (판정 전에 끝난다)"},{"ancestorTitles":["강제 ON · 소속 쓰기 (기업 범위)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 소속 쓰기 (기업 범위) 연결 1개: 기업 배정의 현행 판정 (회원 기업 · 목적지 조직) 도 같은 tx 를 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"연결 1개: 기업 배정의 현행 판정 (회원 기업 · 목적지 조직) 도 같은 tx 를 받는다"},{"ancestorTitles":["강제 ON · 소속 쓰기 (기업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 소속 쓰기 (기업 범위) 사전 판정 (corp): 담당 기업 밖 회원이 섞이면 트랜잭션도 잠금도 열기 전에 거부한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"사전 판정 (corp): 담당 기업 밖 회원이 섞이면 트랜잭션도 잠금도 열기 전에 거부한다"},{"ancestorTitles":["강제 ON · 소속 쓰기 (기업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 소속 쓰기 (기업 범위) 신원 없음: 판정 신원이 없으면 판정 없이 통과하지 않고 거부한다 (쓰기 0회)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"신원 없음: 판정 신원이 없으면 판정 없이 통과하지 않고 거부한다 (쓰기 0회)"}],"endTime":1793868733923,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/scope-enforce.spec.ts","startTime":1793868733696,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["money.issue — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"money.issue — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.issue — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"money.issue — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"},{"ancestorTitles":["money.corp.charge — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"money.corp.charge — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.corp.charge — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"money.corp.charge — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"},{"ancestorTitles":["money.grant — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"money.grant — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.grant — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"money.grant — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"},{"ancestorTitles":["money.grant.single — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"money.grant.single — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.grant.single — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"money.grant.single — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"},{"ancestorTitles":["money.issue.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":27,"failureDetails":[],"failureMessages":[],"fullName":"money.issue.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.issue.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"money.issue.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"},{"ancestorTitles":["money.grant.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":17,"failureDetails":[],"failureMessages":[],"fullName":"money.grant.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.grant.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":52,"failureDetails":[],"failureMessages":[],"fullName":"money.grant.upload — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"},{"ancestorTitles":["money.charge-request.approve — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"money.charge-request.approve — 내구 행이 지급과 함께 커밋되고 함께 거부된다 커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"커밋되면 그 트랜잭션의 tx 에 감사 행이 정확히 한 건 쌓인다"},{"ancestorTitles":["money.charge-request.approve — 내구 행이 지급과 함께 커밋되고 함께 거부된다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"money.charge-request.approve — 내구 행이 지급과 함께 커밋되고 함께 거부된다 적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 지급이 거부되고 T1 줄이 없으며 실패 진단이 남는다"}],"endTime":1793868734231,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-store.spec.ts","startTime":1793868733925,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ddx 판정 admin-view 라우트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx 판정 admin-view 라우트 admin-view-route-is-registered","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"admin-view-route-is-registered"},{"ancestorTitles":["ddx 판정 admin-view 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 판정 admin-view 라우트 admin-view-route-keeps-row-guard","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin-view-route-keeps-row-guard"},{"ancestorTitles":["ddx 판정 admin-view 라우트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 판정 admin-view 라우트 member-route-keeps-owner-guard","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"member-route-keeps-owner-guard"},{"ancestorTitles":["ddx 판정 admin-view 라우트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx 판정 admin-view 라우트 both-routes-call-the-same-service-method","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"both-routes-call-the-same-service-method"}],"endTime":1793868734270,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-ddx-admin-view.spec.ts","startTime":1793868733871,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["컨트롤러 배선 — 요청자의 자격이 조립 지점까지 내려간다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"컨트롤러 배선 — 요청자의 자격이 조립 지점까지 내려간다 최고관리자 요청자의 자격이 여섯 목록·상세에 그대로 간다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"최고관리자 요청자의 자격이 여섯 목록·상세에 그대로 간다"},{"ancestorTitles":["컨트롤러 배선 — 요청자의 자격이 조립 지점까지 내려간다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"컨트롤러 배선 — 요청자의 자격이 조립 지점까지 내려간다 일반 admin 요청자의 자격이 여섯 목록·상세에 그대로 간다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"일반 admin 요청자의 자격이 여섯 목록·상세에 그대로 간다"},{"ancestorTitles":["processedByCell — 자격이 없으면 칸이 빈다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processedByCell — 자격이 없으면 칸이 빈다 자격이 있으면 처리 계정 칸이 원본 칸을 가리킨다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자격이 있으면 처리 계정 칸이 원본 칸을 가리킨다"},{"ancestorTitles":["processedByCell — 자격이 없으면 칸이 빈다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processedByCell — 자격이 없으면 칸이 빈다 자격이 없으면 세 칸 어디에도 원본 칸이 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자격이 없으면 세 칸 어디에도 원본 칸이 없다"},{"ancestorTitles":["processedByCell — 자격이 없으면 칸이 빈다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processedByCell — 자격이 없으면 칸이 빈다 세 칸의 이름은 자격과 무관하게 같다 — 화면 형상이 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"세 칸의 이름은 자격과 무관하게 같다 — 화면 형상이 바뀌지 않는다"},{"ancestorTitles":["processedByOnly — 형제 키도 자격에 걸린다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processedByOnly — 형제 키도 자격에 걸린다 자격이 있으면 원본 칸을 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자격이 있으면 원본 칸을 그대로 돌려준다"},{"ancestorTitles":["processedByOnly — 형제 키도 자격에 걸린다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processedByOnly — 형제 키도 자격에 걸린다 자격이 없으면 원본 칸이 값에 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자격이 없으면 원본 칸이 값에 없다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 적립 목록·상세 은 형제 키를 내리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"적립 목록·상세 은 형제 키를 내리지 않는다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 기업머니 이력 은 형제 키를 내리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"기업머니 이력 은 형제 키를 내리지 않는다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 환불 목록·상세 은 형제 키를 내리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"환불 목록·상세 은 형제 키를 내리지 않는다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 결제 취소 내역 은 형제 키를 내리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"결제 취소 내역 은 형제 키를 내리지 않는다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 충전요청 목록 은 형제 키를 내리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"충전요청 목록 은 형제 키를 내리지 않는다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 충전요청의 승인자 이름 칸은 남아 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"충전요청의 승인자 이름 칸은 남아 있다"},{"ancestorTitles":["응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"응답 계약 — 처리 계정을 다른 이름으로 싣는 형제 키가 없다 processedBy 덩어리는 그대로 내려간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"processedBy 덩어리는 그대로 내려간다"}],"endTime":1793868734482,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-processed-by.spec.ts","startTime":1793868734236,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["핸들러 범위 절 · 목록 (I1 · I4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 목록 (I1 · I4) ON: 영업 전 기업 목록(I1)은 담당 sagId 절을 저장소에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ON: 영업 전 기업 목록(I1)은 담당 sagId 절을 저장소에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 목록 (I1 · I4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 목록 (I1 · I4) OFF: 같은 요청도 저장소 인자는 현행과 같이 비어 있다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OFF: 같은 요청도 저장소 인자는 현행과 같이 비어 있다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 목록 (I1 · I4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 목록 (I1 · I4) OFF: 구독 실패 목록(I4)도 저장소 인자가 null 이다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OFF: 구독 실패 목록(I4)도 저장소 인자가 null 이다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 목록 (I1 · I4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 목록 (I1 · I4) ON: 담당 영업 키가 없는 영업 신원은 500 이 아니라 403 으로 거부된다 (목록 호출 0회)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"ON: 담당 영업 키가 없는 영업 신원은 500 이 아니라 403 으로 거부된다 (목록 호출 0회)"},{"ancestorTitles":["핸들러 범위 절 · 목록 (I1 · I4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 목록 (I1 · I4) ON: 구독 실패 목록(I4)은 절을 서비스에 넘기고, 목록과 count 는 같은 범위 조건을 쓴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ON: 구독 실패 목록(I4)은 절을 서비스에 넘기고, 목록과 count 는 같은 범위 조건을 쓴다"},{"ancestorTitles":["핸들러 범위 절 · 목록 (I1 · I4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 목록 (I1 · I4) 범위 절 생성기는 같은 입력에 같은 절 목록을 돌려준다 (집계·내보내기 경로는 이 시험이 보지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"범위 절 생성기는 같은 입력에 같은 절 목록을 돌려준다 (집계·내보내기 경로는 이 시험이 보지 않는다)"},{"ancestorTitles":["단건 3의미 (분리 함수)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"단건 3의미 (분리 함수) 3의미는 이름별 함수로 나뉘고 같은 입력에 서로 다른 의미를 합치지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"3의미는 이름별 함수로 나뉘고 같은 입력에 서로 다른 의미를 합치지 않는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀) ON: 영업 머니 내역 목록은 담당 sagId 절을 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ON: 영업 머니 내역 목록은 담당 sagId 절을 서비스에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀) 범위 인자 동일: 머니 내역 목록과 count 는 같은 범위 절 객체를 저장소에 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 인자 동일: 머니 내역 목록과 count 는 같은 범위 절 객체를 저장소에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀) 범위 인자 동일: 결제 목록과 count 도 같은 범위 절을 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 인자 동일: 결제 목록과 count 도 같은 범위 절을 받는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀) OFF: 머니 내역 목록의 저장소 인자는 null 이다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OFF: 머니 내역 목록의 저장소 인자는 null 이다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 목록 (I5 · I6 목록 · 엑셀) ON: 담당 영업 키가 없는 영업 신원은 머니 목록에서 403 이고 서비스를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"ON: 담당 영업 키가 없는 영업 신원은 머니 목록에서 403 이고 서비스를 부르지 않는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) 범위 인자 동일: 적립 목록과 count 는 같은 범위 절 객체를 저장소에 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 인자 동일: 적립 목록과 count 는 같은 범위 절 객체를 저장소에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) ON: 영업 적립 목록 컨트롤러는 담당 sagId 절을 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ON: 영업 적립 목록 컨트롤러는 담당 sagId 절을 서비스에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) OFF: 적립 목록의 범위 인자는 null 이다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OFF: 적립 목록의 범위 인자는 null 이다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) 타 기업 누출 0: 담당이 아닌 기업의 기업머니 내역은 403 이고 이력 · 요약을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"타 기업 누출 0: 담당이 아닌 기업의 기업머니 내역은 403 이고 이력 · 요약을 읽지 않는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) 범위 인자 동일: 담당 기업의 이력 목록과 count 는 같은 범위 절을 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 인자 동일: 담당 기업의 이력 목록과 count 는 같은 범위 절을 받는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) OFF: 기업머니 내역은 범위 검사 없이 저장소 인자 null 이다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"OFF: 기업머니 내역은 범위 검사 없이 저장소 인자 null 이다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 적립 · 기업 이력 (I7 · I5 목록) 타 기업 누출 0 (질의 형상): 영업 담당 조건은 그 영업의 sagId 만 인자로 갖는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"타 기업 누출 0 (질의 형상): 영업 담당 조건은 그 영업의 sagId 만 인자로 갖는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) 담당 기업의 다른 회원 허용: 회원 기업의 담당 영업이 요청 영업이면 회원 내역을 서비스가 준다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"담당 기업의 다른 회원 허용: 회원 기업의 담당 영업이 요청 영업이면 회원 내역을 서비스가 준다"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) 타 기업 거부: 회원 기업의 담당 영업이 다르면 403 이고 회원 내역을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"타 기업 거부: 회원 기업의 담당 영업이 다르면 403 이고 회원 내역을 읽지 않는다"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) 미선언 403: 담당 영업 키가 없는 영업 신원은 소유 기업이 맞아도 적립 단건에서 403 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미선언 403: 담당 영업 키가 없는 영업 신원은 소유 기업이 맞아도 적립 단건에서 403 이다"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) 타 기업 거부 (적립 단건): 담당이 아닌 기업의 지급건은 403 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"타 기업 거부 (적립 단건): 담당이 아닌 기업의 지급건은 403 이다"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) 타 기업 거부 (결제 단건): 결제 회원 기업의 담당 영업이 다르면 상세와 이용내역 모두 403 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"타 기업 거부 (결제 단건): 결제 회원 기업의 담당 영업이 다르면 상세와 이용내역 모두 403 이다"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) OFF: 회원 내역 단건은 소유 기업 조회 (getMemberAgcId · getSagIdOfAgc) 를 하지 않는다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"OFF: 회원 내역 단건은 소유 기업 조회 (getMemberAgcId · getSagIdOfAgc) 를 하지 않는다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 머니 단건 · 조직 단건 (I2 · I5 · I6 · I7) 범위 밖 조직 거부: 영업 신원이 담당이 아닌 기업의 조직 상세를 보면 403 이고 상세를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 밖 조직 거부: 영업 신원이 담당이 아닌 기업의 조직 상세를 보면 403 이고 상세를 읽지 않는다"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완) 타 기업 거부 (기업 지급 · 개별 지급): 대상 기업의 담당 영업이 다르면 403 이고 지급 서비스를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"타 기업 거부 (기업 지급 · 개별 지급): 대상 기업의 담당 영업이 다르면 403 이고 지급 서비스를 부르지 않는다"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완) 타 기업 거부 (기업 엑셀 지급 · 기업 충전): 대상 기업이 다르면 403 이고 서비스를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"타 기업 거부 (기업 엑셀 지급 · 기업 충전): 대상 기업이 다르면 403 이고 서비스를 부르지 않는다"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완) 타 기업 거부 (결제 취소): 결제 회원 기업의 담당 영업이 다르면 403 이고 취소를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"타 기업 거부 (결제 취소): 결제 회원 기업의 담당 영업이 다르면 403 이고 취소를 부르지 않는다"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완) 담당 기업의 지급은 허용되고 서비스가 받는다 (정상 경로)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"담당 기업의 지급은 허용되고 서비스가 받는다 (정상 경로)"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 (기업 지정 지급 · 충전 · 결제 취소, M6b 보완) OFF: 기업 지급은 대상 기업 소유 조회를 하지 않는다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"OFF: 기업 지급은 대상 기업 소유 조회를 하지 않는다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2) ON: 영업 환불 목록은 담당 sagId 절을 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ON: 영업 환불 목록은 담당 sagId 절을 서비스에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2) OFF: 환불 목록은 범위 인자가 null 이다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OFF: 환불 목록은 범위 인자가 null 이다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2) 범위 인자 동일: 환불 목록과 count 는 같은 범위 절 객체를 저장소에 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 인자 동일: 환불 목록과 count 는 같은 범위 절 객체를 저장소에 넘긴다"},{"ancestorTitles":["핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2) 타 기업 거부 (환불 단건): 환불 회원 기업의 담당 영업이 다르면 403 이고 환불을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"타 기업 거부 (환불 단건): 환불 회원 기업의 담당 영업이 다르면 403 이고 환불을 읽지 않는다"},{"ancestorTitles":["핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 절 · 환불 목록 · 단건 (M6b 보완 · R2) 담당 기업의 환불 단건은 허용되고 서비스가 준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"담당 기업의 환불 단건은 허용되고 서비스가 준다"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1) 잠금 뒤 판정 인자: 담당 영업의 쓰기 4종은 담당 번호를 서비스에 넘긴다 (충전 · 지급 · 개별 · 엑셀)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"잠금 뒤 판정 인자: 담당 영업의 쓰기 4종은 담당 번호를 서비스에 넘긴다 (충전 · 지급 · 개별 · 엑셀)"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1) 잠금 뒤 판정 인자: 상수 OFF 면 판정 인자가 undefined 다 (응답 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잠금 뒤 판정 인자: 상수 OFF 면 판정 인자가 undefined 다 (응답 불변)"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1) 잠금 뒤 판정: 잠근 기업의 담당이 신원과 다르면 (사전 판정 뒤 재배정 경합) 403 으로 되돌린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"잠금 뒤 판정: 잠근 기업의 담당이 신원과 다르면 (사전 판정 뒤 재배정 경합) 403 으로 되돌린다"},{"ancestorTitles":["핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · 머니 쓰기 잠금 뒤 판정 (M6b 보완 R1) 잠금 뒤 판정: 담당이 같으면 통과하고, 판정 인자가 없으면 저장소를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잠금 뒤 판정: 담당이 같으면 통과하고, 판정 인자가 없으면 저장소를 읽지 않는다"},{"ancestorTitles":["핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로) 호출처 의미 고정: 단건 읽기 호출처는 표의 의미 이름을 judgeSingleScope 에 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"호출처 의미 고정: 단건 읽기 호출처는 표의 의미 이름을 judgeSingleScope 에 넘긴다"},{"ancestorTitles":["핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로) 호출처 의미 고정: 조직 상세는 소유자 또는 관리자 열람 의미다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"호출처 의미 고정: 조직 상세는 소유자 또는 관리자 열람 의미다"},{"ancestorTitles":["핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로) 상수 OFF 단건 통과: 강제 상수가 꺼져 있으면 단건 키를 읽지도 판정하지도 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상수 OFF 단건 통과: 강제 상수가 꺼져 있으면 단건 키를 읽지도 판정하지도 않는다"},{"ancestorTitles":["핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로) 관리자 래퍼 통과: admin 역할은 단건 키를 읽지 않고 판정 없이 통과한다 (현행 가드와 같다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 래퍼 통과: admin 역할은 단건 키를 읽지 않고 판정 없이 통과한다 (현행 가드와 같다)"},{"ancestorTitles":["핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로) corpScope 미지값 래퍼 deny: 기업 신원의 알 수 없는 corpScope 는 단건 조직 상세에서 403 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"corpScope 미지값 래퍼 deny: 기업 신원의 알 수 없는 corpScope 는 단건 조직 상세에서 403 이다"},{"ancestorTitles":["핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"핸들러 범위 판정 · M6c 단건 래퍼 (신원별 키 · 의미 고정 · 통과 경로) 단건 기업 agcId 래퍼: 기업 최고는 자기 기업 회원 내역을 보고 다른 기업은 403 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"단건 기업 agcId 래퍼: 기업 최고는 자기 기업 회원 내역을 보고 다른 기업은 403 이다"}],"endTime":1793868734527,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/scope-handlers.spec.ts","startTime":1793868734275,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다 구독 일부 성공 뒤 던져도 성공한 회원은 적용, 실패한 회원은 실패로 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독 일부 성공 뒤 던져도 성공한 회원은 적용, 실패한 회원은 실패로 실린다"},{"ancestorTitles":["기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다 구독 1·해지 1 이 섞인 업로드에서 뒤 해지가 실패해 던져도 전이별로 갈린다(IMPL-0)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독 1·해지 1 이 섞인 업로드에서 뒤 해지가 실패해 던져도 전이별로 갈린다(IMPL-0)"},{"ancestorTitles":["기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다 사용중지는 계정 상태 전원을 먼저 싣고, 중간 해지가 던져도 뒤 건까지 시도한다(M9 D6)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사용중지는 계정 상태 전원을 먼저 싣고, 중간 해지가 던져도 뒤 건까지 시도한다(M9 D6)"},{"ancestorTitles":["기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다 사용처리는 resume 만 싣는다 — 구독은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사용처리는 resume 만 싣는다 — 구독은 건드리지 않는다"},{"ancestorTitles":["기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 FC 일괄 — 커밋된 회원이 컬렉터에 남는다 되살리기는 resubscribe 전이로 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"되살리기는 resubscribe 전이로 싣는다"}],"endTime":1793868734719,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/fc-agency-subscribe-audit.spec.ts","startTime":1793868734484,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyFcEventHandler"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcEventHandler 최종 활성수가 seat 미만이면 어떤 변경도 시작하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"최종 활성수가 seat 미만이면 어떤 변경도 시작하지 않는다"},{"ancestorTitles":["AgencyFcEventHandler"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcEventHandler 동일 상태와 구독 이력이 없는 해지는 성공 no-op이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"동일 상태와 구독 이력이 없는 해지는 성공 no-op이다"},{"ancestorTitles":["AgencyFcEventHandler"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcEventHandler 혼합 파일은 구독 변경 후 해지 변경을 처리한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"혼합 파일은 구독 변경 후 해지 변경을 처리한다"},{"ancestorTitles":["AgencyFcEventHandler"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcEventHandler 최초구독 일부 실패 시 실패 회원만 상세에 기록한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"최초구독 일부 실패 시 실패 회원만 상세에 기록한다"}],"endTime":1793868734777,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/agency-fc.event-handler.spec.ts","startTime":1793868734529,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["StartLossAnalysisDto"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"StartLossAnalysisDto 카카오·네이버·PASS만 허용한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"카카오·네이버·PASS만 허용한다"},{"ancestorTitles":["LossAnalysisService.createInvite"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.createInvite 로그인 회원 소유 주문만 발송 검증한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"로그인 회원 소유 주문만 발송 검증한다"},{"ancestorTitles":["LossAnalysisService.getPublic"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.getPublic 인증 요청 전에는 알림톡 초대만으로 진입한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"인증 요청 전에는 알림톡 초대만으로 진입한다"},{"ancestorTitles":["LossAnalysisService.getPublic"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.getPublic 승인 대기 링크에는 서버 기준 만료시각을 함께 준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"승인 대기 링크에는 서버 기준 만료시각을 함께 준다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 공용 inhouse 자리가 없으면 인증·분석행 생성 없이 같은 큐에서 기다린다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"공용 inhouse 자리가 없으면 인증·분석행 생성 없이 같은 큐에서 기다린다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start inhouse 공급자 설정이 없으면 인증·분석행 생성 전에 중단한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"inhouse 공급자 설정이 없으면 인증·분석행 생성 전에 중단한다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 공용 inhouse 입장권을 인증 세션에 결속하고 큐를 제거한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"공용 inhouse 입장권을 인증 세션에 결속하고 큐를 제거한다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 인증 요청이 실패하면 공용 입장권과 초대 예약을 모두 반납한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"인증 요청이 실패하면 공용 입장권과 초대 예약을 모두 반납한다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 인증 발송 뒤 세션 취소가 불명확하면 초대와 슬롯을 자동 재사용하지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"인증 발송 뒤 세션 취소가 불명확하면 초대와 슬롯을 자동 재사용하지 않는다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 같은 초대는 인증 요청을 한 번만 시작한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"같은 초대는 인증 요청을 한 번만 시작한다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 인증 요청 실패 시 공유 예약 건수를 환불한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"인증 요청 실패 시 공유 예약 건수를 환불한다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 새 초대의 인증 요청 실패 시 선행 생성한 분석행과 예약을 함께 되돌린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"새 초대의 인증 요청 실패 시 선행 생성한 분석행과 예약을 함께 되돌린다"},{"ancestorTitles":["LossAnalysisService.start"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.start 인증 발송 후 응답과 취소 확정을 모두 놓쳐도 같은 세션으로 승인을 계속한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"인증 발송 후 응답과 취소 확정을 모두 놓쳐도 같은 세션으로 승인을 계속한다"},{"ancestorTitles":["LossAnalysisService.collect"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.collect 홈택스가 제공한 전체 연도를 고객 선택 없이 수집한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"홈택스가 제공한 전체 연도를 고객 선택 없이 수집한다"},{"ancestorTitles":["LossAnalysisService.collect"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.collect 엔진 세션이 BUSY라 취소도 실패하면 공용 슬롯을 먼저 반납하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"엔진 세션이 BUSY라 취소도 실패하면 공용 슬롯을 먼저 반납하지 않는다"},{"ancestorTitles":["LossAnalysisService.collect"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.collect 사용자 취소가 엔진에서 확정되지 않으면 분석과 공용 슬롯을 유지한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사용자 취소가 엔진에서 확정되지 않으면 분석과 공용 슬롯을 유지한다"},{"ancestorTitles":["LossAnalysisService.restart"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.restart 만료된 승인 세션을 닫고 같은 초대를 새 인증 가능 상태로 되돌린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"만료된 승인 세션을 닫고 같은 초대를 새 인증 가능 상태로 되돌린다"},{"ancestorTitles":["LossAnalysisService.restart"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.restart 엔진 세션 종료가 불확실하면 승인 상태를 복구하고 슬롯을 유지한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"엔진 세션 종료가 불확실하면 승인 상태를 복구하고 슬롯을 유지한다"},{"ancestorTitles":["LossAnalysisService.restart"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService.restart 서버 기준 승인 시간이 남았으면 기존 세션을 종료하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"서버 기준 승인 시간이 남았으면 기존 세션을 종료하지 않는다"},{"ancestorTitles":["LossAnalysisService terminal session recovery"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService terminal session recovery 재사용 가능한 승인 확인 실패는 원래 만료시각을 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재사용 가능한 승인 확인 실패는 원래 만료시각을 유지한다"},{"ancestorTitles":["LossAnalysisService terminal session recovery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService terminal session recovery 승인 유효시간이 지나면 같은 초대를 재인증 가능 상태로 복구한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"승인 유효시간이 지나면 같은 초대를 재인증 가능 상태로 복구한다"},{"ancestorTitles":["LossAnalysisService terminal session recovery"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService terminal session recovery 의료비 수집 중 엔진 세션이 닫히면 죽은 READY 대신 재인증 상태로 복구한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"의료비 수집 중 엔진 세션이 닫히면 죽은 READY 대신 재인증 상태로 복구한다"},{"ancestorTitles":["LossAnalysisService terminal session recovery"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisService terminal session recovery 수집 성공 뒤 DB 완료 저장이 실패해도 닫힌 세션을 READY로 되돌리지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"수집 성공 뒤 DB 완료 저장이 실패해도 닫힌 세션을 READY로 되돌리지 않는다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 입력 번호 01098760000·응답 유실 false에서도 인증·고객·리마인드 번호를 일치시킨다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"입력 번호 01098760000·응답 유실 false에서도 인증·고객·리마인드 번호를 일치시킨다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 입력 번호 undefined·응답 유실 false에서도 인증·고객·리마인드 번호를 일치시킨다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"입력 번호 undefined·응답 유실 false에서도 인증·고객·리마인드 번호를 일치시킨다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 입력 번호 01098760000·응답 유실 true에서도 인증·고객·리마인드 번호를 일치시킨다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"입력 번호 01098760000·응답 유실 true에서도 인증·고객·리마인드 번호를 일치시킨다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 잘못된 전화번호 를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 전화번호 를 거절한다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 잘못된 전화번호 0212345678를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 전화번호 0212345678를 거절한다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 잘못된 전화번호 0101234를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 전화번호 0101234를 거절한다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 잘못된 전화번호 010123456789를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 전화번호 010123456789를 거절한다"},{"ancestorTitles":["실손 인증 전화번호 변경"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"실손 인증 전화번호 변경 잘못된 전화번호 010-1234-0000를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 전화번호 010-1234-0000를 거절한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 잘못된 이름 를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 이름 를 거절한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 잘못된 이름    를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 이름    를 거절한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 잘못된 이름 가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 이름 가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가를 거절한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 잘못된 이름 123를 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘못된 이름 123를 거절한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 이름 수정고객와 기존 클라이언트를 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이름 수정고객와 기존 클라이언트를 허용한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 이름 JANE DOE와 기존 클라이언트를 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이름 JANE DOE와 기존 클라이언트를 허용한다"},{"ancestorTitles":["실손 이름 입력 검증"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 이름 입력 검증 이름 undefined와 기존 클라이언트를 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이름 undefined와 기존 클라이언트를 허용한다"}],"endTime":1793868734965,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/loss-analysis/loss-analysis.service.spec.ts","startTime":1793868734720,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["FC 자동차 분석 공개"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 자동차 분석 공개 로그인은 유지하고 자동차 목록·상세의 최고관리자 가드만 해제한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"로그인은 유지하고 자동차 목록·상세의 최고관리자 가드만 해제한다"},{"ancestorTitles":["FC 자동차 분석 공개"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"FC 자동차 분석 공개 본인 주문만 16시부터 목록·상세를 반환한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"본인 주문만 16시부터 목록·상세를 반환한다"}],"endTime":1793868735028,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-car-visibility.spec.ts","startTime":1793868734782,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 내부 관리자","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"내부 관리자"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 영업 양수","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 양수"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 영업 번호 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 번호 없음"},{"ancestorTitles":["analysisScopeOf"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 영업 번호 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 번호 0"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 영업 번호 음수","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 번호 음수"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 기업 최고","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 최고"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 기업 최고 기업 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 최고 기업 없음"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 조직 정상","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조직 정상"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 조직 경로 빈 값","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조직 경로 빈 값"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 조직 경로 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조직 경로 없음"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 조직 경로 와일드카드","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조직 경로 와일드카드"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 기업 범위 모름","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 범위 모름"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 모르는 역할","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 역할"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 역할 없음 (개발 스웨거 우회 신원)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할 없음 (개발 스웨거 우회 신원)"},{"ancestorTitles":["analysisScopeOf"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"analysisScopeOf 신원 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"신원 없음"},{"ancestorTitles":["분석 목록 컨트롤러의 범위"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"분석 목록 컨트롤러의 범위 번호 없는 영업 쿠키는 서비스를 부르지 않고 E0607 이다 (옛 무필터 목록)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"번호 없는 영업 쿠키는 서비스를 부르지 않고 E0607 이다 (옛 무필터 목록)"},{"ancestorTitles":["분석 목록 컨트롤러의 범위"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"분석 목록 컨트롤러의 범위 범위는 쿼리 값을 덮어쓴다. 내부 관리자는 검색 칸이 그대로다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"범위는 쿼리 값을 덮어쓴다. 내부 관리자는 검색 칸이 그대로다"}],"endTime":1793868735188,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/analysis-scope.spec.ts","startTime":1793868734967,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":45,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 생성이 계정 ID 와 권한 그룹을 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"생성이 계정 ID 와 권한 그룹을 남긴다"},{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":41,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 수정이 비밀번호 값이 아니라 바뀌었다는 사실만 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수정이 비밀번호 값이 아니라 바뀌었다는 사실만 남긴다"},{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 수정이 권한 그룹의 전·후를 함께 남긴다 — 한 행으로 상승/하강이 읽힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"수정이 권한 그룹의 전·후를 함께 남긴다 — 한 행으로 상승/하강이 읽힌다"},{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 이전 값을 못 읽으면 쓰지 않는다 — 결측을 null 이나 현재 값으로 위장하지 않는다 (M10: 잠금 읽기 실패는 404)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이전 값을 못 읽으면 쓰지 않는다 — 결측을 null 이나 현재 값으로 위장하지 않는다 (M10: 잠금 읽기 실패는 404)"},{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 비밀번호를 안 바꾼 수정은 passwordChanged=false 로 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비밀번호를 안 바꾼 수정은 passwordChanged=false 로 남는다"},{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 삭제가 **계정마다 한 행**을 남기고 각 행이 로그인 ID 를 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"삭제가 **계정마다 한 행**을 남기고 각 행이 로그인 ID 를 싣는다"},{"ancestorTitles":["관리자 계정 변경 — 트랜잭션 안 적재"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — 트랜잭션 안 적재 삭제는 지우기 전에 읽는다 — 읽을 게 없으면 감사 행도 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"삭제는 지우기 전에 읽는다 — 읽을 게 없으면 감사 행도 없다"},{"ancestorTitles":["관리자 계정 변경 — fail-closed(D12)"],"duration":39,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — fail-closed(D12) 생성: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"생성: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다"},{"ancestorTitles":["관리자 계정 변경 — fail-closed(D12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — fail-closed(D12) 수정: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수정: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다"},{"ancestorTitles":["관리자 계정 변경 — fail-closed(D12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 계정 변경 — fail-closed(D12) 삭제: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"삭제: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다"}],"endTime":1793868735232,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/admin-audit.spec.ts","startTime":1793868735031,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["B2cAnalyzeController auth"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"B2cAnalyzeController auth blocks B2C result reads without the verified birth cookie","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"blocks B2C result reads without the verified birth cookie"},{"ancestorTitles":["B2cAnalyzeController auth"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"B2cAnalyzeController auth checks child detail ids against the owner bodId cookie","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"checks child detail ids against the owner bodId cookie"},{"ancestorTitles":["B2cAnalyzeController auth"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"B2cAnalyzeController auth does not expose legacy B2C PII lookup endpoints","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not expose legacy B2C PII lookup endpoints"},{"ancestorTitles":["B2cAnalyzeController auth"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"B2cAnalyzeController auth B2C 분석 추가 컨트롤러도 서명된 쿠키만 받는다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"B2C 분석 추가 컨트롤러도 서명된 쿠키만 받는다"},{"ancestorTitles":["B2cAnalyzeController auth"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"B2cAnalyzeController auth verify-birth 는 서명된 7일 쿠키를 낸다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"verify-birth 는 서명된 7일 쿠키를 낸다"},{"ancestorTitles":["B2cAnalyzeController auth"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"B2cAnalyzeController auth check-auth 는 서명 쿠키만 인증으로 본다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"check-auth 는 서명 쿠키만 인증으로 본다"}],"endTime":1793868735425,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/b2c-auth.spec.ts","startTime":1793868735190,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["지정 적립 배치 기업 번호는 회원 기업에서 정한다 (M6c 보완 HIGH)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 배치 기업 번호는 회원 기업에서 정한다 (M6c 보완 HIGH) 영업 신원: 호출자가 준 기업 번호가 회원 기업과 다르면 거부하고 적립 행을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 신원: 호출자가 준 기업 번호가 회원 기업과 다르면 거부하고 적립 행을 만들지 않는다"},{"ancestorTitles":["지정 적립 배치 기업 번호는 회원 기업에서 정한다 (M6c 보완 HIGH)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 배치 기업 번호는 회원 기업에서 정한다 (M6c 보완 HIGH) 영업 신원: 기업 번호를 주지 않고 회원이 여럿의 기업에 걸치면 배치 기업은 null 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 신원: 기업 번호를 주지 않고 회원이 여럿의 기업에 걸치면 배치 기업은 null 이다"},{"ancestorTitles":["지정 적립 배치 기업 번호는 회원 기업에서 정한다 (M6c 보완 HIGH)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 배치 기업 번호는 회원 기업에서 정한다 (M6c 보완 HIGH) 영업 신원: 회원이 한 기업이고 기업 번호가 같으면 그 기업으로 적립 행을 만든다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 신원: 회원이 한 기업이고 기업 번호가 같으면 그 기업으로 적립 행을 만든다"},{"ancestorTitles":["환불 처리 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 보완 LOW)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 처리 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 보완 LOW) 상수 OFF: 영업 판정 잠금 없이 승인 자체의 트랜잭션에서 처리 여부를 다시 보고 승인한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"상수 OFF: 영업 판정 잠금 없이 승인 자체의 트랜잭션에서 처리 여부를 다시 보고 승인한다"},{"ancestorTitles":["환불 처리 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 보완 LOW)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"환불 처리 · 바깥 트랜잭션은 영업 판정 경로에서만 (M6c 보완 LOW) 상수 ON · 영업 신원: 환불 행과 회원 행을 잠그고 같은 트랜잭션에서 승인한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원: 환불 행과 회원 행을 잠그고 같은 트랜잭션에서 승인한다"},{"ancestorTitles":["지정 적립 단건 키의 기업 번호는 대상 회원 전부와 같아야 한다 (M6c 보완 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 단건 키의 기업 번호는 대상 회원 전부와 같아야 한다 (M6c 보완 MEDIUM) 대상 회원이 다른 기업에 섞이면 기업 키를 null 로 둔다 (단건 판정은 deny)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상 회원이 다른 기업에 섞이면 기업 키를 null 로 둔다 (단건 판정은 deny)"},{"ancestorTitles":["지정 적립 단건 키의 기업 번호는 대상 회원 전부와 같아야 한다 (M6c 보완 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 단건 키의 기업 번호는 대상 회원 전부와 같아야 한다 (M6c 보완 MEDIUM) 대상 회원이 모두 같은 기업이면 기업 키를 그대로 둔다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상 회원이 모두 같은 기업이면 기업 키를 그대로 둔다"},{"ancestorTitles":["담당 밖 기업 번호는 대상 인원 수와 무관하게 403 이다 (M6c R3 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"담당 밖 기업 번호는 대상 인원 수와 무관하게 403 이다 (M6c R3 MEDIUM) 영업 신원 · 담당 밖 기업 번호 · 회원 0명: 400 이 아니라 403 이다 (인원 존재 여부 비노출)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 신원 · 담당 밖 기업 번호 · 회원 0명: 400 이 아니라 403 이다 (인원 존재 여부 비노출)"},{"ancestorTitles":["담당 밖 기업 번호는 대상 인원 수와 무관하게 403 이다 (M6c R3 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"담당 밖 기업 번호는 대상 인원 수와 무관하게 403 이다 (M6c R3 MEDIUM) 영업 신원 · 담당 밖 기업 번호 · 한도 초과 금액: 400 이 아니라 403 이다 (인원 수 비노출)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 신원 · 담당 밖 기업 번호 · 한도 초과 금액: 400 이 아니라 403 이다 (인원 수 비노출)"},{"ancestorTitles":["총 적용머니 한도는 회원 조회 앞에서 본다 (최종 리뷰 R1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"총 적용머니 한도는 회원 조회 앞에서 본다 (최종 리뷰 R1) 상수 OFF: 한도를 넘는 요청은 회원을 한 명도 조회하지 않고 400 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 OFF: 한도를 넘는 요청은 회원을 한 명도 조회하지 않고 400 이다"},{"ancestorTitles":["총 적용머니 한도는 회원 조회 앞에서 본다 (최종 리뷰 R1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"총 적용머니 한도는 회원 조회 앞에서 본다 (최종 리뷰 R1) 영업 판정 경로: 담당 밖 회원의 403 이 한도 400 보다 먼저다 (M6c R3 순서 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 판정 경로: 담당 밖 회원의 403 이 한도 400 보다 먼저다 (M6c R3 순서 불변)"}],"endTime":1793868735434,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money.service.write-scope.spec.ts","startTime":1793868735234,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["기업 구독이 정책 버전을 읽는다"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"기업 구독이 정책 버전을 읽는다 정기갱신에서 어느 버전에서든 구간 상품이었던 구독은 같은 구독으로 계약 상품에 복귀한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"정기갱신에서 어느 버전에서든 구간 상품이었던 구독은 같은 구독으로 계약 상품에 복귀한다"},{"ancestorTitles":["기업 구독이 정책 버전을 읽는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 구독이 정책 버전을 읽는다 정기갱신에서 적용된 정책의 구간 상품이 아니었던 구독은 해지 후 계약 상품으로 새로 구독하고 구간을 넘기지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"정기갱신에서 적용된 정책의 구간 상품이 아니었던 구독은 해지 후 계약 상품으로 새로 구독하고 구간을 넘기지 않는다"},{"ancestorTitles":["기업 구독이 정책 버전을 읽는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 구독이 정책 버전을 읽는다 신규 구독은 구독일에 유효한 버전의 구간으로 상품을 정한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"신규 구독은 구독일에 유효한 버전의 구간으로 상품을 정한다"}],"endTime":1793868735720,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/subscribe/subscribe/subscribe-agency-policy.spec.ts","startTime":1793868735429,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["runRegularSubscription — 일반 정기결제"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"runRegularSubscription — 일반 정기결제 정상 결제는 subscribeRenew · 포인트 적립 커밋 줄을 내고 실패 수는 0 이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"정상 결제는 subscribeRenew · 포인트 적립 커밋 줄을 내고 실패 수는 0 이다"},{"ancestorTitles":["runRegularSubscription — 일반 정기결제"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runRegularSubscription — 일반 정기결제 결제 커밋 뒤 알림이 던져도 커밋된 결제·적립 줄이 남고, 실패 줄 뒤 같은 예외를 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"결제 커밋 뒤 알림이 던져도 커밋된 결제·적립 줄이 남고, 실패 줄 뒤 같은 예외를 던진다"},{"ancestorTitles":["runRegularSubscription — 일반 정기결제"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"runRegularSubscription — 일반 정기결제 포인트 적립이 실패한 뒤 알림이 던져도 호출 단위 실패 수가 1 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"포인트 적립이 실패한 뒤 알림이 던져도 호출 단위 실패 수가 1 이다"},{"ancestorTitles":["runRegularSubscription — 일반 정기결제"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runRegularSubscription — 일반 정기결제 변경예정 전환(SUB003)이 커밋된 뒤 결제가 던져도 전환 줄이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"변경예정 전환(SUB003)이 커밋된 뒤 결제가 던져도 전환 줄이 남는다"},{"ancestorTitles":["runRegularSubscription — 일반 정기결제"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runRegularSubscription — 일반 정기결제 결제 실패(PAY003)는 주문 행이 커밋되므로 커밋 줄이 pmtState 로 결과를 말하고 적립 줄은 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"결제 실패(PAY003)는 주문 행이 커밋되므로 커밋 줄이 pmtState 로 결과를 말하고 적립 줄은 없다"},{"ancestorTitles":["runAgencySubscription — 기업 정기 처리"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"runAgencySubscription — 기업 정기 처리 계약이 해지됐으면 terminated 이고 결제액은 null 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"계약이 해지됐으면 terminated 이고 결제액은 null 이다"},{"ancestorTitles":["runAgencySubscription — 기업 정기 처리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runAgencySubscription — 기업 정기 처리 구독 상품이 계약의 초기 요금제 상품이면 initial-plan 이고 계약 상품 가격을 청구한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독 상품이 계약의 초기 요금제 상품이면 initial-plan 이고 계약 상품 가격을 청구한다"},{"ancestorTitles":["runAgencySubscription — 기업 정기 처리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runAgencySubscription — 기업 정기 처리 계약 상품이 바뀌었으면 product-changed 이고 새 구독 id 를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"계약 상품이 바뀌었으면 product-changed 이고 새 구독 id 를 싣는다"},{"ancestorTitles":["runAgencySubscription — 기업 정기 처리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runAgencySubscription — 기업 정기 처리 계약 상품이 그대로면 renewed 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"계약 상품이 그대로면 renewed 다"},{"ancestorTitles":["runAgencySubscription — 기업 정기 처리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runAgencySubscription — 기업 정기 처리 처리가 던지면 실패 줄을 낸 뒤 같은 예외를 던진다 — 실패 적재는 스케줄러가 진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"처리가 던지면 실패 줄을 낸 뒤 같은 예외를 던진다 — 실패 적재는 스케줄러가 진다"},{"ancestorTitles":["reservationForUnsubscribe — 해지완료 일괄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reservationForUnsubscribe — 해지완료 일괄 영향 행 수가 대상 수인 줄 한 건을 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영향 행 수가 대상 수인 줄 한 건을 낸다"},{"ancestorTitles":["reservationForUnsubscribe — 해지완료 일괄"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reservationForUnsubscribe — 해지완료 일괄 영향 0 이면 줄을 내지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영향 0 이면 줄을 내지 않는다"},{"ancestorTitles":["reservationForUnsubscribe — 해지완료 일괄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reservationForUnsubscribe — 해지완료 일괄 던지면 실패 줄을 낸 뒤 같은 예외를 던진다 — 삼키면 하트비트가 찍힌다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"던지면 실패 줄을 낸 뒤 같은 예외를 던진다 — 삼키면 하트비트가 찍힌다"},{"ancestorTitles":["changeNextPayment — 결제일 전·후 값"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"changeNextPayment — 결제일 전·후 값 갱신 전 값과 요청 값을 컬렉터에 싣고 대상은 구독 id 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"갱신 전 값과 요청 값을 컬렉터에 싣고 대상은 구독 id 다"}],"endTime":1793868735768,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/subscribe/subscribe/subscribe-schedule-audit.spec.ts","startTime":1793868735443,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["getDosing30DayDiagnosisGroups — 판정 행 상태"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getDosing30DayDiagnosisGroups — 판정 행 상태 empty 행은 ready · 0건이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"empty 행은 ready · 0건이다"},{"ancestorTitles":["getDosing30DayDiagnosisGroups — 판정 행 상태"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getDosing30DayDiagnosisGroups — 판정 행 상태 행이 없거나 아직 돌고 있으면 none 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"행이 없거나 아직 돌고 있으면 none 이다"}],"endTime":1793868735963,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-dosing30-diagnosis-empty.spec.ts","startTime":1793868735722,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["FCM 토큰 등록 — 토큰 회원에만 묶는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FCM 토큰 등록 — 토큰 회원에만 묶는다 공격자가 남의 loginId 를 실어도 토큰 memId 행에만 쓰고, loginId 로 행을 고르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"공격자가 남의 loginId 를 실어도 토큰 memId 행에만 쓰고, loginId 로 행을 고르지 않는다"},{"ancestorTitles":["FCM 토큰 등록 — 토큰 회원에만 묶는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FCM 토큰 등록 — 토큰 회원에만 묶는다 같은 기기 토큰을 쥔 다른 행은 지우되, 제외 기준도 토큰 memId 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 기기 토큰을 쥔 다른 행은 지우되, 제외 기준도 토큰 memId 다"}],"endTime":1793868736015,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/user/fcm-token-ownership.spec.ts","startTime":1793868735770,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 empty-indication-filled-from-store","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"empty-indication-filled-from-store"},{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 provider-indication-wins-over-store","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"provider-indication-wins-over-store"},{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 drug-name-matched-ignoring-spaces","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"drug-name-matched-ignoring-spaces"},{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 store-failure-keeps-the-verdict-view","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"store-failure-keeps-the-verdict-view"},{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 unmatched-drug-stays-null","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"unmatched-drug-stays-null"},{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 legacy-verdict-without-bydate-keeps-group-fallback","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"legacy-verdict-without-bydate-keeps-group-fallback"},{"ancestorTitles":["ddx 빈 indication 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx 빈 indication 폴백 bydate-indication-filled-from-store","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"bydate-indication-filled-from-store"}],"endTime":1793868736169,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-ddx-indication-fallback.spec.ts","startTime":1793868735964,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlimtalkService reminder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder 진료 인증 대기중일 때만 1회 발송한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"진료 인증 대기중일 때만 1회 발송한다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder 이미 인증을 제출했으면 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이미 인증을 제출했으면 발송하지 않는다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder 실손 인증 승인 대기가 아니면 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"실손 인증 승인 대기가 아니면 발송하지 않는다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder 인증 만료가 임박했으면 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"인증 만료가 임박했으면 발송하지 않는다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder loss 리마인드는 15초 뒤 예약된다 (ALIGO_LOSS_REMINDER_DELAY_MS, 설정 누락: false)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"loss 리마인드는 15초 뒤 예약된다 (ALIGO_LOSS_REMINDER_DELAY_MS, 설정 누락: false)"},{"ancestorTitles":["AlimtalkService reminder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder treat 리마인드는 15초 뒤 예약된다 (ALIGO_TREAT_REMINDER_DELAY_MS, 설정 누락: false)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"treat 리마인드는 15초 뒤 예약된다 (ALIGO_TREAT_REMINDER_DELAY_MS, 설정 누락: false)"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder loss 리마인드는 15초 뒤 예약된다 (ALIGO_LOSS_REMINDER_DELAY_MS, 설정 누락: true)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"loss 리마인드는 15초 뒤 예약된다 (ALIGO_LOSS_REMINDER_DELAY_MS, 설정 누락: true)"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder treat 리마인드는 15초 뒤 예약된다 (ALIGO_TREAT_REMINDER_DELAY_MS, 설정 누락: true)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"treat 리마인드는 15초 뒤 예약된다 (ALIGO_TREAT_REMINDER_DELAY_MS, 설정 누락: true)"},{"ancestorTitles":["AlimtalkService reminder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder 벤더의 명시적 거절만 제한 재시도 큐에 넣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"벤더의 명시적 거절만 제한 재시도 큐에 넣는다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder 응답 유실 가능성이 있는 예외는 중복 방지를 위해 재전송하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"응답 유실 가능성이 있는 예외는 중복 방지를 위해 재전송하지 않는다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder treat 리마인드는 승인 문구와 대체문자 복귀 링크를 기록한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"treat 리마인드는 승인 문구와 대체문자 복귀 링크를 기록한다"},{"ancestorTitles":["AlimtalkService reminder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService reminder loss 리마인드는 승인 문구와 대체문자 복귀 링크를 기록한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"loss 리마인드는 승인 문구와 대체문자 복귀 링크를 기록한다"}],"endTime":1793868736208,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alimtalk/alimtalk-reminder.spec.ts","startTime":1793868736017,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["예약수 환불 — 영향 1 만 줄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"예약수 환불 — 영향 1 만 줄 stall 정리: 영향 1 인 환불만 줄을 내고 최종상태는 분석실패다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"stall 정리: 영향 1 인 환불만 줄을 내고 최종상태는 분석실패다"},{"ancestorTitles":["예약수 환불 — 영향 1 만 줄"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"예약수 환불 — 영향 1 만 줄 인증 시한 초과 정리: 최종상태는 인증실패다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"인증 시한 초과 정리: 최종상태는 인증실패다"},{"ancestorTitles":["예약수 환불 — 영향 1 만 줄"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"예약수 환불 — 영향 1 만 줄 환불이 던지면 실패 줄을 낸 뒤 던진다 — 뒤 건은 돌지 않는다(흐름 무변경)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"환불이 던지면 실패 줄을 낸 뒤 던진다 — 뒤 건은 돌지 않는다(흐름 무변경)"},{"ancestorTitles":["예약수 보정 — 보정 건수가 대상 수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"예약수 보정 — 보정 건수가 대상 수 보정이 있으면 보정 주문 수를 대상 수로 한 줄을 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"보정이 있으면 보정 주문 수를 대상 수로 한 줄을 낸다"},{"ancestorTitles":["예약수 보정 — 보정 건수가 대상 수"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"예약수 보정 — 보정 건수가 대상 수 보정 0 건이면 줄을 내지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"보정 0 건이면 줄을 내지 않는다"},{"ancestorTitles":["예약수 보정 — 보정 건수가 대상 수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"예약수 보정 — 보정 건수가 대상 수 보정이 던지면 실패 줄을 낸 뒤 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"보정이 던지면 실패 줄을 낸 뒤 던진다"}],"endTime":1793868736374,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order-detail/order-reserve-audit.spec.ts","startTime":1793868736174,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["기업FC 해지 — 전건 시도 후 끝 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 해지 — 전건 시도 후 끝 판정 중간 건이 실패해도 뒤 건의 해지가 시도된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"중간 건이 실패해도 뒤 건의 해지가 시도된다"},{"ancestorTitles":["기업FC 해지 — 전건 시도 후 끝 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 해지 — 전건 시도 후 끝 판정 실패한 건만 sink.failed 로, 나머지는 applied 로 간다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"실패한 건만 sink.failed 로, 나머지는 applied 로 간다"},{"ancestorTitles":["기업FC 해지 — 전건 시도 후 끝 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 해지 — 전건 시도 후 끝 판정 실패가 하나라도 있으면 끝에서 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실패가 하나라도 있으면 끝에서 던진다"},{"ancestorTitles":["기업FC 해지 — 전건 시도 후 끝 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 해지 — 전건 시도 후 끝 판정 전건 성공이면 던지지 않고 반영 집계를 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"전건 성공이면 던지지 않고 반영 집계를 돌려준다"},{"ancestorTitles":["기업FC 해지 — 전건 시도 후 끝 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업FC 해지 — 전건 시도 후 끝 판정 전건 실패여도 전건을 시도한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"전건 실패여도 전건을 시도한다"}],"endTime":1793868736454,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/fc-agency-resign.spec.ts","startTime":1793868736210,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["사용 FC 기준 회차 map(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"사용 FC 기준 회차 map(A11) 사용 FC 마다 첫 완료 주문 1건만 INCLUDE, 나머지는 까닭과 함께 EXCLUDE","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"사용 FC 마다 첫 완료 주문 1건만 INCLUDE, 나머지는 까닭과 함께 EXCLUDE"},{"ancestorTitles":["AgencySettlementService.create — 사용 FC 기준 달(A11)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 사용 FC 기준 달(A11) 명세 기업 회차를 명세 규칙으로 담고 금액은 사용 FC × 계약가다 — 다른 기업은 그대로","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"명세 기업 회차를 명세 규칙으로 담고 금액은 사용 FC × 계약가다 — 다른 기업은 그대로"},{"ancestorTitles":["AgencySettlementService.create — 사용 FC 기준 달(A11)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 사용 FC 기준 달(A11) 주문 기준 달이면 아무것도 바꾸지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"주문 기준 달이면 아무것도 바꾸지 않는다"},{"ancestorTitles":["AgencySettlementService.create — 사용 FC 기준 달(A11)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 사용 FC 기준 달(A11) 명세 기업 판정이 실패해도 그 기업(코드)만 빼고 다른 기업 회차를 만든 뒤 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"명세 기업 판정이 실패해도 그 기업(코드)만 빼고 다른 기업 회차를 만든 뒤 던진다"},{"ancestorTitles":["AgencySettlementService.create — 사용 FC 기준 달(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 사용 FC 기준 달(A11) 명세 규칙 계산이 실패해도 그 기업 회차만 빼고 다른 기업 회차를 만든 뒤 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"명세 규칙 계산이 실패해도 그 기업 회차만 빼고 다른 기업 회차를 만든 뒤 던진다"},{"ancestorTitles":["AgencySettlementService.create — 사용 FC 기준 달(A11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 사용 FC 기준 달(A11) 계약 단가를 쓸 수 없으면 그 기업 회차만 빼고 다른 기업 회차를 만든 뒤 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"계약 단가를 쓸 수 없으면 그 기업 회차만 빼고 다른 기업 회차를 만든 뒤 던진다"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 사용 FC 기준 회차의 단가는 바꾸지 않는다(계약 단가, A17-4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사용 FC 기준 회차의 단가는 바꾸지 않는다(계약 단가, A17-4)"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 사용 FC 기준 회차는 이월하지 않는다 — 반영 · 제외는 그대로","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사용 FC 기준 회차는 이월하지 않는다 — 반영 · 제외는 그대로"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 주문 기준 회차는 지금처럼 주문 정산단가를 바꾼다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문 기준 회차는 지금처럼 주문 정산단가를 바꾼다"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 다른 확정 회차가 반영한 주문은 skipped 로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"다른 확정 회차가 반영한 주문은 skipped 로 돌려준다"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 바꾼 행이 있으면 processed 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"바꾼 행이 있으면 processed 다"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 그 사이 회차가 바뀌어(CONFIRMED · ORDER) 한 행도 안 바뀌었으면 skipped 로 옮긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"그 사이 회차가 바뀌어(CONFIRMED · ORDER) 한 행도 안 바뀌었으면 skipped 로 옮긴다"},{"ancestorTitles":["단가 일괄수정 — 회차 기준에 따라(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"단가 일괄수정 — 회차 기준에 따라(A11) 그 사이 회차가 바뀌어(PENDING · ACTIVE_MEMBER) 한 행도 안 바뀌었으면 skipped 로 옮긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"그 사이 회차가 바뀌어(PENDING · ACTIVE_MEMBER) 한 행도 안 바뀌었으면 skipped 로 옮긴다"},{"ancestorTitles":["상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3) 주문 기준 회차도 확정 전 · 명세 기업 · 계약 단가가 있으면 다시 담을 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문 기준 회차도 확정 전 · 명세 기업 · 계약 단가가 있으면 다시 담을 수 있다"},{"ancestorTitles":["상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3) CONFIRMED · 기업 34 · 단가 5500 이면 막는 까닭을 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CONFIRMED · 기업 34 · 단가 5500 이면 막는 까닭을 싣는다"},{"ancestorTitles":["상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3) PENDING · 기업 35 · 단가 5500 이면 막는 까닭을 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"PENDING · 기업 35 · 단가 5500 이면 막는 까닭을 싣는다"},{"ancestorTitles":["상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"상세의 다시 담기 판정 — 그 달 정책과 무관(A17-3) PENDING · 기업 34 · 단가 null 이면 막는 까닭을 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"PENDING · 기업 34 · 단가 null 이면 막는 까닭을 싣는다"}],"endTime":1793868736672,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/settlement-active-member.spec.ts","startTime":1793868736376,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["환불 처리 컨트롤러의 영업 사전 판정 (M6c 보완 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 처리 컨트롤러의 영업 사전 판정 (M6c 보완 MEDIUM) 상수 ON · 영업 신원: 환불 행의 기업이 담당 영업 것이 아니면 잠금 전에 403 으로 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원: 환불 행의 기업이 담당 영업 것이 아니면 잠금 전에 403 으로 거부한다"},{"ancestorTitles":["환불 처리 컨트롤러의 영업 사전 판정 (M6c 보완 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 처리 컨트롤러의 영업 사전 판정 (M6c 보완 MEDIUM) 상수 ON · 영업 신원: 담당 영업 것이면 서비스로 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원: 담당 영업 것이면 서비스로 넘긴다"},{"ancestorTitles":["환불 처리 컨트롤러의 영업 사전 판정 (M6c 보완 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"환불 처리 컨트롤러의 영업 사전 판정 (M6c 보완 MEDIUM) 상수 OFF: 판정 조회 없이 서비스로 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 OFF: 판정 조회 없이 서비스로 넘긴다"}],"endTime":1793868736705,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-admin.refund-scope.spec.ts","startTime":1793868736458,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["지정 적립 상세의 단건 판정은 조회보다 먼저 한다 (M6c R3 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 상세의 단건 판정은 조회보다 먼저 한다 (M6c R3 MEDIUM) 상수 ON · 영업 신원 · 담당 밖 지급 건: 403, 대상 목록 조회를 하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원 · 담당 밖 지급 건: 403, 대상 목록 조회를 하지 않는다"},{"ancestorTitles":["지정 적립 상세의 단건 판정은 조회보다 먼저 한다 (M6c R3 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 상세의 단건 판정은 조회보다 먼저 한다 (M6c R3 MEDIUM) 상수 ON · 영업 신원 · 없는 번호: 존재 여부를 싣지 않도록 404 가 아니라 같은 403 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원 · 없는 번호: 존재 여부를 싣지 않도록 404 가 아니라 같은 403 이다"},{"ancestorTitles":["지정 적립 상세의 단건 판정은 조회보다 먼저 한다 (M6c R3 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"지정 적립 상세의 단건 판정은 조회보다 먼저 한다 (M6c R3 MEDIUM) 상수 ON · 영업 신원 · 담당 것: 조회를 한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상수 ON · 영업 신원 · 담당 것: 조회를 한다"}],"endTime":1793868736905,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-admin.issue-scope.spec.ts","startTime":1793868736674,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["조직관리자 수정 — 소속 조직 변경 거부"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 수정 — 소속 조직 변경 거부 이름만 수정 (orgId 없음) 은 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이름만 수정 (orgId 없음) 은 통과"},{"ancestorTitles":["조직관리자 수정 — 소속 조직 변경 거부"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 수정 — 소속 조직 변경 거부 같은 orgId 재전송은 통과","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 orgId 재전송은 통과"},{"ancestorTitles":["조직관리자 수정 — 소속 조직 변경 거부"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 수정 — 소속 조직 변경 거부 부분트리 안 다른 조직으로 변경 → 403, 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"부분트리 안 다른 조직으로 변경 → 403, 쓰지 않는다"},{"ancestorTitles":["조직관리자 수정 — 소속 조직 변경 거부"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 수정 — 소속 조직 변경 거부 소속 해제 → 403 (현행)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"소속 해제 → 403 (현행)"},{"ancestorTitles":["조직관리자 수정 — 소속 조직 변경 거부"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 수정 — 소속 조직 변경 거부 기업 최고관리자의 조직 변경은 통과 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 최고관리자의 조직 변경은 통과 (현행)"},{"ancestorTitles":["조직관리자 등록 · 업로드 — 조직관리자 지정 거부"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 등록 · 업로드 — 조직관리자 지정 거부 등록 본문 memIsOrgManager=1 → 403, 0 이나 없음은 통과","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"등록 본문 memIsOrgManager=1 → 403, 0 이나 없음은 통과"},{"ancestorTitles":["조직관리자 등록 · 업로드 — 조직관리자 지정 거부"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 등록 · 업로드 — 조직관리자 지정 거부 기업 최고관리자의 조직관리자 등록은 통과 (현행)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 최고관리자의 조직관리자 등록은 통과 (현행)"},{"ancestorTitles":["조직관리자 등록 · 업로드 — 조직관리자 지정 거부"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 등록 · 업로드 — 조직관리자 지정 거부 등록 경로 배선: 조직관리자의 memIsOrgManager=1 등록은 계약 조회 전에 403","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"등록 경로 배선: 조직관리자의 memIsOrgManager=1 등록은 계약 조회 전에 403"},{"ancestorTitles":["조직관리자 등록 · 업로드 — 조직관리자 지정 거부"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직관리자 등록 · 업로드 — 조직관리자 지정 거부 신규계정 업로드 행에 조직관리자 Y 가 있으면 403, 없으면 통과","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"신규계정 업로드 행에 조직관리자 Y 가 있으면 403, 없으면 통과"}],"endTime":1793868736974,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/fc-agency-org-narrow.spec.ts","startTime":1793868736709,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["병력분석 PDF 고객명 숨김"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"병력분석 PDF 고객명 숨김 설정된 기업 소속 주문이면 이름을 숨긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"설정된 기업 소속 주문이면 이름을 숨긴다"},{"ancestorTitles":["병력분석 PDF 고객명 숨김"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"병력분석 PDF 고객명 숨김 설정된 기업 소속이 아니면 이름을 표시한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"설정된 기업 소속이 아니면 이름을 표시한다"},{"ancestorTitles":["병력분석 PDF 고객명 숨김"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"병력분석 PDF 고객명 숨김 B2C는 기업 설정과 무관하게 이름을 표시한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"B2C는 기업 설정과 무관하게 이름을 표시한다"},{"ancestorTitles":["병력분석 PDF 고객명 숨김"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"병력분석 PDF 고객명 숨김 빈 값이나 잘못된 기업 설정은 이름을 숨기지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"빈 값이나 잘못된 기업 설정은 이름을 숨기지 않는다"}],"endTime":1793868737140,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-disease-pdf.spec.ts","startTime":1793868736908,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlimtalkService.sendAnalyze institution block"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.sendAnalyze institution block 심평원 사용중지 시 발송과 저장을 모두 막는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"심평원 사용중지 시 발송과 저장을 모두 막는다"},{"ancestorTitles":["AlimtalkService.sendAnalyze institution block"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.sendAnalyze institution block 국세청 사용중지 시에도 발송과 저장을 모두 막는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"국세청 사용중지 시에도 발송과 저장을 모두 막는다"},{"ancestorTitles":["AlimtalkService.sendAnalyze institution block"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.sendAnalyze institution block 두 기관이 정상일 때는 기존 초대 발송을 유지한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"두 기관이 정상일 때는 기존 초대 발송을 유지한다"},{"ancestorTitles":["AlimtalkService.sendAnalyze institution block"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.sendAnalyze institution block 실손분석 초대는 별도 템플릿으로 알림톡만 발송한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"실손분석 초대는 별도 템플릿으로 알림톡만 발송한다"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 구독 유효 → 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구독 유효 → 통과"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 회원 탈퇴/계정중지(memIsResigned=1) → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"회원 탈퇴/계정중지(memIsResigned=1) → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 다른 회원 주문번호 변조 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"다른 회원 주문번호 변조 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 본인 주문번호 → 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"본인 주문번호 → 통과"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 없는 주문 → 500 대신 만료 응답","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"없는 주문 → 500 대신 만료 응답"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 기업 접근차단(agcDeliquent=1) → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 접근차단(agcDeliquent=1) → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 구독 해지여도 이용종료일 전이면 → 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구독 해지여도 이용종료일 전이면 → 통과"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 구독 해지 + 이용종료일 지남 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구독 해지 + 이용종료일 지남 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 구독 종료일 지남 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구독 종료일 지남 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 분석건수 소진 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"분석건수 소진 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 진행 중 예약을 포함해 분석건수가 소진되면 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"진행 중 예약을 포함해 분석건수가 소진되면 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 진행 중 재진입은 이미 예약 차감된 건수를 다시 막지 않음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"진행 중 재진입은 이미 예약 차감된 건수를 다시 막지 않음"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 결제 미완 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"결제 미완 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess 환불완료 → 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"환불완료 → 차단"},{"ancestorTitles":["AlimtalkService.validateInviteAccess"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validateInviteAccess ord_expired_at은 미사용 — 구독유효+주문만료여도 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ord_expired_at은 미사용 — 구독유효+주문만료여도 통과"},{"ancestorTitles":["AlimtalkService.validationOrder"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validationOrder 진료분석 초대도 다른 회원 주문번호를 차단한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"진료분석 초대도 다른 회원 주문번호를 차단한다"},{"ancestorTitles":["AlimtalkService.validationOrder"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.validationOrder 진료분석 초대의 본인 주문은 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"진료분석 초대의 본인 주문은 통과한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD001/null를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD001/null를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD005/null를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD005/null를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD006/null를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD006/null를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD004/null를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD004/null를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD007/null를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD007/null를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD008/null를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD008/null를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD005/ODD004를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD005/ODD004를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 분석 상태 ODD005/ODD006를 고객 화면에 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분석 상태 ODD005/ODD006를 고객 화면에 반환한다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 초대에 해당하는 요청이 아니면 상태를 노출하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"초대에 해당하는 요청이 아니면 상태를 노출하지 않는다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 초대에 해당하는 요청이 아니면 상태를 노출하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"초대에 해당하는 요청이 아니면 상태를 노출하지 않는다"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 존재하지 않는 링크는 500 대신 만료된 링크 404로 응답","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"존재하지 않는 링크는 500 대신 만료된 링크 404로 응답"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 진행 중 주문상세가 있으면 사용 링크도 재진입 허용","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"진행 중 주문상세가 있으면 사용 링크도 재진입 허용"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 실패로 이미 종결된 링크도 진입 허용","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실패로 이미 종결된 링크도 진입 허용"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 새 인증 생성 검증은 사용 링크를 계속 차단","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"새 인증 생성 검증은 사용 링크를 계속 차단"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 재인증 시작은 진행 중 기존 건이 있으면 새 주문상세를 만들지 않게 차단","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재인증 시작은 진행 중 기존 건이 있으면 새 주문상세를 만들지 않게 차단"},{"ancestorTitles":["AlimtalkService.checkAlimtalkEntry"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.checkAlimtalkEntry 스케줄러가 실패로 이미 종결한 링크도 재인증 허용","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스케줄러가 실패로 이미 종결한 링크도 재인증 허용"}],"endTime":1793868737227,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alimtalk/alimtalk-invite.spec.ts","startTime":1793868736977,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["PDF 숨은보험금 — 자부상(자동차보험) 진료내역","일반회원"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PDF 숨은보험금 — 자부상(자동차보험) 진료내역 일반회원 게이트 이전 주문은 자부상을 조회조차 하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"게이트 이전 주문은 자부상을 조회조차 하지 않는다"},{"ancestorTitles":["PDF 숨은보험금 — 자부상(자동차보험) 진료내역","일반회원"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PDF 숨은보험금 — 자부상(자동차보험) 진료내역 일반회원 게이트 이후 주문은 사고 그룹별로 자기 상세만 결합한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"게이트 이후 주문은 사고 그룹별로 자기 상세만 결합한다"},{"ancestorTitles":["PDF 숨은보험금 — 자부상(자동차보험) 진료내역","일반회원"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PDF 숨은보험금 — 자부상(자동차보험) 진료내역 일반회원 상세가 0건인 사고 그룹도 detailList: [] 로 살아남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상세가 0건인 사고 그룹도 detailList: [] 로 살아남는다"},{"ancestorTitles":["PDF 숨은보험금 — 자부상(자동차보험) 진료내역","B2C"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"PDF 숨은보험금 — 자부상(자동차보험) 진료내역 B2C 게이트 이전 주문은 자부상을 조회조차 하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"게이트 이전 주문은 자부상을 조회조차 하지 않는다"},{"ancestorTitles":["PDF 숨은보험금 — 자부상(자동차보험) 진료내역","B2C"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"PDF 숨은보험금 — 자부상(자동차보험) 진료내역 B2C 게이트 이후 주문은 사고 그룹별로 자기 상세만 결합한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"게이트 이후 주문은 사고 그룹별로 자기 상세만 결합한다"}],"endTime":1793868737364,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-car-pdf.spec.ts","startTime":1793868737142,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["expireMoneys — 실패를 삼키지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 실패를 삼키지 않는다 전건 성공이면 실패 수가 0 이고 처리 수가 대상 수와 같다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전건 성공이면 실패 수가 0 이고 처리 수가 대상 수와 같다"},{"ancestorTitles":["expireMoneys — 실패를 삼키지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 실패를 삼키지 않는다 회원 하나가 실패해도 루프는 계속 돌고 실패 수가 호출부에 도달한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"회원 하나가 실패해도 루프는 계속 돌고 실패 수가 호출부에 도달한다"},{"ancestorTitles":["expireMoneys — 실패를 삼키지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 실패를 삼키지 않는다 실패한 회원마다 EXPIRE_FAILED 감사 줄이 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"실패한 회원마다 EXPIRE_FAILED 감사 줄이 남는다"},{"ancestorTitles":["expireMoneys — 실패를 삼키지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 실패를 삼키지 않는다 성공한 회원의 줄은 EXPIRE 로 남아 실패와 어휘가 갈린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"성공한 회원의 줄은 EXPIRE 로 남아 실패와 어휘가 갈린다"},{"ancestorTitles":["expireMoneys — 실패를 삼키지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 실패를 삼키지 않는다 전건 실패여도 반환값이 그 사실을 말한다 — 조용한 정상 종료가 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전건 실패여도 반환값이 그 사실을 말한다 — 조용한 정상 종료가 아니다"},{"ancestorTitles":["expireMoneys — 실패를 삼키지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 실패를 삼키지 않는다 만료 줄은 스케줄러 축(T4)의 SYSTEM 행위자로 남는다 — HTTP 요청 맥락이 없다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"만료 줄은 스케줄러 축(T4)의 SYSTEM 행위자로 남는다 — HTTP 요청 맥락이 없다"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-1] 회원 없는 원천은 skippedCount 로 센다 (실패가 아니다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[MS12-expire-1] 회원 없는 원천은 skippedCount 로 센다 (실패가 아니다)"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-2] 대상이 0 이면 트랜잭션도 쓰기 호출도 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-expire-2] 대상이 0 이면 트랜잭션도 쓰기 호출도 없다"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-3] 회원 하나의 실패는 그 회원만 실패로 세고, 나머지 회원은 처리된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-expire-3] 회원 하나의 실패는 그 회원만 실패로 세고, 나머지 회원은 처리된다"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-4] 알 수 없는 msrMoneyType 은 그 회원을 실패로 센다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS12-expire-4] 알 수 없는 msrMoneyType 은 그 회원을 실패로 센다"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-5] 성공한 원천의 EXPIRE 감사 줄은 트랜잭션 콜백이 끝난 뒤에만 나간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[MS12-expire-5] 성공한 원천의 EXPIRE 감사 줄은 트랜잭션 콜백이 끝난 뒤에만 나간다"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-6] 같은 종류 원천 잔여 합과 칸이 다르면 (칸이 작거나 크거나) 그 회원은 실패 1 이고 쓰기가 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS12-expire-6] 같은 종류 원천 잔여 합과 칸이 다르면 (칸이 작거나 크거나) 그 회원은 실패 1 이고 쓰기가 없다"},{"ancestorTitles":["expireMoneys — 회원 단위 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"expireMoneys — 회원 단위 트랜잭션 (M12) [MS12-expire-7] 회원 칸이 일치하는 정상 경로는 칸을 한 번만 쓰고 원천 0 쓰기와 이력을 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-expire-7] 회원 칸이 일치하는 정상 경로는 칸을 한 번만 쓰고 원천 0 쓰기와 이력을 남긴다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-1] rejectRefund 는 회원 잠금으로 시작하고 모든 호출이 같은 tx 를 받는다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"[MS12-lock-1] rejectRefund 는 회원 잠금으로 시작하고 모든 호출이 같은 tx 를 받는다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-2] processCancelPayment 는 회원 잠금으로 시작하고 모든 호출이 같은 tx 를 받는다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"[MS12-lock-2] processCancelPayment 는 회원 잠금으로 시작하고 모든 호출이 같은 tx 를 받는다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-3] requestRefund 는 회원 잠금으로 시작하고 원천 차감 조회도 같은 tx 를 받는다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"[MS12-lock-3] requestRefund 는 회원 잠금으로 시작하고 원천 차감 조회도 같은 tx 를 받는다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-4] recoverSubscriptionEarnedPoint 는 회원 잠금으로 시작하고 적립 건 조회도 같은 tx 를 받는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"[MS12-lock-4] recoverSubscriptionEarnedPoint 는 회원 잠금으로 시작하고 적립 건 조회도 같은 tx 를 받는다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-5] 이미 반려된 환불을 다시 반려하면 잠금 아래 상태 재검증으로 멈추고 복구 쓰기가 0 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-lock-5] 이미 반려된 환불을 다시 반려하면 잠금 아래 상태 재검증으로 멈추고 복구 쓰기가 0 이다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-6] 전액 취소는 잠금 아래 원천 잔여가 예약값 (0) 과 다르면 반영하지 않고 던진다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-lock-6] 전액 취소는 잠금 아래 원천 잔여가 예약값 (0) 과 다르면 반영하지 않고 던진다"},{"ancestorTitles":["환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"환불 · 복구 — 회원 잠금 아래 한 트랜잭션 (M12) [MS12-lock-7] 승인은 잠금 아래 상태가 PENDING 이 아니면 멈추고 상태 쓰기가 0 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS12-lock-7] 승인은 잠금 아래 상태가 PENDING 이 아니면 멈추고 상태 쓰기가 0 이다"}],"endTime":1793868737448,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-expire.spec.ts","startTime":1793868737232,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["회원머니 발행 — 회원 잔액 전·후(기본머니)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"회원머니 발행 — 회원 잔액 전·후(기본머니) 단건 적립은 그 회원의 전·후이고 차가 단가다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"단건 적립은 그 회원의 전·후이고 차가 단가다"},{"ancestorTitles":["회원머니 발행 — 회원 잔액 전·후(기본머니)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원머니 발행 — 회원 잔액 전·후(기본머니) 두 명 적립은 합계 전·후이고 차가 단가 × 2 이며 단건 키가 없다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"두 명 적립은 합계 전·후이고 차가 단가 × 2 이며 단건 키가 없다"},{"ancestorTitles":["회원머니 발행 — 회원 잔액 전·후(기본머니)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원머니 발행 — 회원 잔액 전·후(기본머니) 단건 회수는 차가 −단가다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"단건 회수는 차가 −단가다"},{"ancestorTitles":["엑셀 발행 — 회원별로 접은 뒤 단건·합계"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"엑셀 발행 — 회원별로 접은 뒤 단건·합계 다른 회원 두 행은 합계 차가 행 금액의 합이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"다른 회원 두 행은 합계 차가 행 금액의 합이다"},{"ancestorTitles":["엑셀 발행 — 회원별로 접은 뒤 단건·합계"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"엑셀 발행 — 회원별로 접은 뒤 단건·합계 같은 회원 두 행(잔액 100 에 +10·+20)은 한 명의 100→130 이고 합계 키가 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"같은 회원 두 행(잔액 100 에 +10·+20)은 한 명의 100→130 이고 합계 키가 없다"},{"ancestorTitles":["기업 잔액 전·후"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"기업 잔액 전·후 엑셀 지급은 기업 전 − 후가 지급 합이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"엑셀 지급은 기업 전 − 후가 지급 합이다"},{"ancestorTitles":["기업 잔액 전·후"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"기업 잔액 전·후 충전요청 승인은 기업 후 − 전이 요청 금액이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"충전요청 승인은 기업 후 − 전이 요청 금액이다"},{"ancestorTitles":["memberMoneyChanges — 접기 규칙"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"memberMoneyChanges — 접기 규칙 쌍이 한 회원뿐이면 첫 전·마지막 후다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쌍이 한 회원뿐이면 첫 전·마지막 후다"},{"ancestorTitles":["memberMoneyChanges — 접기 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"memberMoneyChanges — 접기 규칙 여러 회원이면 회원별로 접은 값의 합이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"여러 회원이면 회원별로 접은 값의 합이다"},{"ancestorTitles":["memberMoneyChanges — 접기 규칙"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"memberMoneyChanges — 접기 규칙 대상이 없으면 잔액 칸을 아예 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상이 없으면 잔액 칸을 아예 싣지 않는다"}],"endTime":1793868737596,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-values.spec.ts","startTime":1793868737366,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["LossAnalysis 승인 기한 상태 전이"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 승인 기한 상태 전이 complete 실패 후에도 최초 승인 만료시각을 유지한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"complete 실패 후에도 최초 승인 만료시각을 유지한다"},{"ancestorTitles":["LossAnalysis 승인 기한 상태 전이"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 승인 기한 상태 전이 restart 실패 후에도 최초 승인 만료시각을 유지한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"restart 실패 후에도 최초 승인 만료시각을 유지한다"},{"ancestorTitles":["LossAnalysis 중복 요청과 정상 0건"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 중복 요청과 정상 0건 complete 동시 호출은 엔진을 한 번만 실행한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"complete 동시 호출은 엔진을 한 번만 실행한다"},{"ancestorTitles":["LossAnalysis 중복 요청과 정상 0건"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysis 중복 요청과 정상 0건 collect 동시 호출은 엔진을 한 번만 실행한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"collect 동시 호출은 엔진을 한 번만 실행한다"}],"endTime":1793868737677,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/loss-analysis/loss-analysis.case-matrix.spec.ts","startTime":1793868737454,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["processChargeRequest — 승인은 한 행, 반려는 행 없음"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 승인은 한 행, 반려는 행 없음 승인하면 콜백의 tx 로 승인하고 감사 행이 한 건 쌓인다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"승인하면 콜백의 tx 로 승인하고 감사 행이 한 건 쌓인다"},{"ancestorTitles":["processChargeRequest — 승인은 한 행, 반려는 행 없음"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 승인은 한 행, 반려는 행 없음 선점이 0행이면 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"선점이 0행이면 거절하고 행이 없다"},{"ancestorTitles":["processChargeRequest — 승인은 한 행, 반려는 행 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 승인은 한 행, 반려는 행 없음 반려는 트랜잭션을 열지 않고 행이 없다(UI9)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"반려는 트랜잭션을 열지 않고 행이 없다(UI9)"},{"ancestorTitles":["processChargeRequest — 승인은 한 행, 반려는 행 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 승인은 한 행, 반려는 행 없음 적재가 거부되면 같은 예외로 승인이 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"적재가 거부되면 같은 예외로 승인이 거부된다"},{"ancestorTitles":["processChargeRequest — 승인은 한 행, 반려는 행 없음"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"processChargeRequest — 승인은 한 행, 반려는 행 없음 잔액 상한 초과는 거절하고 행이 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"잔액 상한 초과는 거절하고 행이 없다"},{"ancestorTitles":["MoneyRepository.approveChargeRequest — 받은 tx 로만 쓴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MoneyRepository.approveChargeRequest — 받은 tx 로만 쓴다 선점 뒤 잠근 잔액에서 전·후를 돌려주고 자기 트랜잭션을 열지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"선점 뒤 잠근 잔액에서 전·후를 돌려주고 자기 트랜잭션을 열지 않는다"},{"ancestorTitles":["MoneyRepository.approveChargeRequest — 받은 tx 로만 쓴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MoneyRepository.approveChargeRequest — 받은 tx 로만 쓴다 선점이 0행이면 쓰지 않고 processed:false 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"선점이 0행이면 쓰지 않고 processed:false 다"},{"ancestorTitles":["MoneyRepository.approveChargeRequest — 받은 tx 로만 쓴다"],"duration":22,"failureDetails":[],"failureMessages":[],"fullName":"MoneyRepository.approveChargeRequest — 받은 tx 로만 쓴다 잔액 상한을 넘으면 이력·잔액을 쓰기 전에 던진다 — 받은 tx 가 선점까지 되돌린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"잔액 상한을 넘으면 이력·잔액을 쓰기 전에 던진다 — 받은 tx 가 선점까지 되돌린다"}],"endTime":1793868737866,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-charge-approve.spec.ts","startTime":1793868737598,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["주문 취소 — 주문 주인 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"주문 취소 — 주문 주인 대조 남의 주문은 없는 주문과 같은 답으로 막고 환불하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"남의 주문은 없는 주문과 같은 답으로 막고 환불하지 않는다"},{"ancestorTitles":["주문 취소 — 주문 주인 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"주문 취소 — 주문 주인 대조 자기 주문은 지금처럼 취소한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자기 주문은 지금처럼 취소한다"},{"ancestorTitles":["주문 취소 — 주문 주인 대조"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"주문 취소 — 주문 주인 대조 회원 경로에서 주인을 안 넘기면 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"회원 경로에서 주인을 안 넘기면 막는다"},{"ancestorTitles":["주문 취소 — 주문 주인 대조"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"주문 취소 — 주문 주인 대조 관리자 취소는 주인과 무관하게 지금처럼 간다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 취소는 주인과 무관하게 지금처럼 간다"},{"ancestorTitles":["주문 취소 — 주문 주인 대조"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"주문 취소 — 주문 주인 대조 컨트롤러는 body 가 아니라 토큰의 회원을 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"컨트롤러는 body 가 아니라 토큰의 회원을 넘긴다"}],"endTime":1793868737903,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order/order-cancel-owner.spec.ts","startTime":1793868737679,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) oddId 소유자 본인이면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"oddId 소유자 본인이면 통과한다"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) oddId 다른 계정이면 403으로 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"oddId 다른 계정이면 403으로 막는다"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) 토큰이 없으면(비로그인) 막는다 — fail-closed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"토큰이 없으면(비로그인) 막는다 — fail-closed"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) 소유자를 못 찾으면 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"소유자를 못 찾으면 막는다"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) asbId 교차계정 접근을 403으로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"asbId 교차계정 접근을 403으로 막는다"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) asbId 소유자 본인이면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"asbId 소유자 본인이면 통과한다"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) asbId 로 소유 분석을 못 찾으면 막는다 — fail-closed","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"asbId 로 소유 분석을 못 찾으면 막는다 — fail-closed"},{"ancestorTitles":["OwnAnalysisGuard (분석 소유자 검증)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OwnAnalysisGuard (분석 소유자 검증) 알려진 소유 파라미터가 없는 라우트는 막는다 — fail-closed","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"알려진 소유 파라미터가 없는 라우트는 막는다 — fail-closed"}],"endTime":1793868738064,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/user/own-analysis.guard.spec.ts","startTime":1793868737867,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["createCorpMoney — 행위자를 요청 맥락에서 정한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 행위자를 요청 맥락에서 정한다 admin 토큰은 ADMIN 로 남는다 — 하드코딩된 ADMIN 이 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin 토큰은 ADMIN 로 남는다 — 하드코딩된 ADMIN 이 아니다"},{"ancestorTitles":["createCorpMoney — 행위자를 요청 맥락에서 정한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 행위자를 요청 맥락에서 정한다 sales 토큰은 SALES 로 남는다 — 하드코딩된 ADMIN 이 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sales 토큰은 SALES 로 남는다 — 하드코딩된 ADMIN 이 아니다"},{"ancestorTitles":["createCorpMoney — 행위자를 요청 맥락에서 정한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 행위자를 요청 맥락에서 정한다 sales 충전은 ADMIN 으로 남지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"sales 충전은 ADMIN 으로 남지 않는다"},{"ancestorTitles":["createCorpMoney — 행위자를 요청 맥락에서 정한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"createCorpMoney — 행위자를 요청 맥락에서 정한다 감사 줄의 행위자와 금전 표의 행위자가 같은 요청에서 갈리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"감사 줄의 행위자와 금전 표의 행위자가 같은 요청에서 갈리지 않는다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 UNKNOWN 행위자의 충전 요청은 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UNKNOWN 행위자의 충전 요청은 거부된다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 SYSTEM 행위자의 충전 요청은 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SYSTEM 행위자의 충전 요청은 거부된다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 스코프 없는 CORP 행위자의 충전 요청은 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스코프 없는 CORP 행위자의 충전 요청은 거부된다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 거부된 요청은 금전 표에 한 행도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"거부된 요청은 금전 표에 한 행도 쓰지 않는다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 금전 컬럼의 값 도메인을 넓히지 않는다 — 'UNKNOWN' 을 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"금전 컬럼의 값 도메인을 넓히지 않는다 — 'UNKNOWN' 을 쓰지 않는다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 거부 본문은 고정 불투명 코드만 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"거부 본문은 고정 불투명 코드만 싣는다"},{"ancestorTitles":["getMoneyActor — 형태를 못 알아본 요청은 거부한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getMoneyActor — 형태를 못 알아본 요청은 거부한다 ctx 가 아예 없는 내부 호출은 예전대로 ADMIN 이다 — 이 거부는 HTTP 경로의 그물이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ctx 가 아예 없는 내부 호출은 예전대로 ADMIN 이다 — 이 거부는 HTTP 경로의 그물이다"}],"endTime":1793868738112,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-audit-actor.spec.ts","startTime":1793868737905,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertHealthService.probeDb (§D6 · §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertHealthService.probeDb (§D6 · §D7) 성공하면 ok 와 소요시간을 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"성공하면 ok 와 소요시간을 낸다"},{"ancestorTitles":["AlertHealthService.probeDb (§D6 · §D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertHealthService.probeDb (§D6 · §D7) 예외는 ok:false 로 표현된다 — throw 하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"예외는 ok:false 로 표현된다 — throw 하지 않는다"},{"ancestorTitles":["AlertHealthService.probeDb (§D6 · §D7)"],"duration":51,"failureDetails":[],"failureMessages":[],"fullName":"AlertHealthService.probeDb (§D6 · §D7) 매달리는 쿼리는 타임아웃으로 끊는다 — 상한이 없으면 폴링 주기를 통째로 먹는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"매달리는 쿼리는 타임아웃으로 끊는다 — 상한이 없으면 폴링 주기를 통째로 먹는다"},{"ancestorTitles":["AlertHealthService.probeRedis"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertHealthService.probeRedis 미구성이면 null 이다 — \"실패\"와 구분해야 A6 가 없는 축을 장애로 보고하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미구성이면 null 이다 — \"실패\"와 구분해야 A6 가 없는 축을 장애로 보고하지 않는다"},{"ancestorTitles":["AlertHealthService.probeRedis"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertHealthService.probeRedis PING 실패는 ok:false 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"PING 실패는 ok:false 다"},{"ancestorTitles":["AlertHealthService.probeRedis"],"duration":51,"failureDetails":[],"failureMessages":[],"fullName":"AlertHealthService.probeRedis PING 이 매달려도 타임아웃으로 끊는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"PING 이 매달려도 타임아웃으로 끊는다"}],"endTime":1793868738264,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-health.service.spec.ts","startTime":1793868738068,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["병명예측 구독 검사 개발 면제 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"병명예측 구독 검사 개발 면제 (K10) 구독 검사: 스위치 미설정이면 개발용 회원번호 180 도 구독 조회를 거친다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독 검사: 스위치 미설정이면 개발용 회원번호 180 도 구독 조회를 거친다"},{"ancestorTitles":["병명예측 구독 검사 개발 면제 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"병명예측 구독 검사 개발 면제 (K10) 구독 검사: 스위치를 켜면 개발용 회원번호 180 은 구독 조회 없이 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"구독 검사: 스위치를 켜면 개발용 회원번호 180 은 구독 조회 없이 통과한다"},{"ancestorTitles":["병명예측 구독 검사 개발 면제 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"병명예측 구독 검사 개발 면제 (K10) 구독 검사: 다른 회원번호는 스위치와 무관하게 구독 조회를 거친다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"구독 검사: 다른 회원번호는 스위치와 무관하게 구독 조회를 거친다"}],"endTime":1793868738397,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/subscribe/subscribe/subscribe.dev-bypass.spec.ts","startTime":1793868738113,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다 [cancel-race-1] 사용자 취소: PG 호출 중 끼어든 사용은 그 원천을 못 쓰고 취소가 DB 까지 반영된다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"[cancel-race-1] 사용자 취소: PG 호출 중 끼어든 사용은 그 원천을 못 쓰고 취소가 DB 까지 반영된다"},{"ancestorTitles":["결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다 [cancel-race-2] 관리자 전액 취소: PG 호출 중 끼어든 사용은 그 원천을 못 쓰고 취소가 DB 까지 반영된다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"[cancel-race-2] 관리자 전액 취소: PG 호출 중 끼어든 사용은 그 원천을 못 쓰고 취소가 DB 까지 반영된다"},{"ancestorTitles":["결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다 [cancel-race-3] PG 가 취소를 거절하면 원천이 원래대로 남아 다시 쓸 수 있다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"[cancel-race-3] PG 가 취소를 거절하면 원천이 원래대로 남아 다시 쓸 수 있다"},{"ancestorTitles":["결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제취소 경합 — PG 환불과 DB 반영이 어긋나지 않는다 [cancel-race-4] PG 거절 전에 같은 원천으로 사용 복구가 들어와도 예약 해제가 원천과 회원 칸을 맞춘다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[cancel-race-4] PG 거절 전에 같은 원천으로 사용 복구가 들어와도 예약 해제가 원천과 회원 칸을 맞춘다"},{"ancestorTitles":["같은 결제의 전액 취소 두 건 — 두 번째는 PG 를 부르기 전에 거절된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"같은 결제의 전액 취소 두 건 — 두 번째는 PG 를 부르기 전에 거절된다 [cancel-dbl-1] 관리자 전액 취소 두 번: 앞 요청의 PG 가 느려도 뒤 요청은 PG 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[cancel-dbl-1] 관리자 전액 취소 두 번: 앞 요청의 PG 가 느려도 뒤 요청은 PG 를 부르지 않는다"},{"ancestorTitles":["같은 결제의 전액 취소 두 건 — 두 번째는 PG 를 부르기 전에 거절된다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"같은 결제의 전액 취소 두 건 — 두 번째는 PG 를 부르기 전에 거절된다 [cancel-dbl-2] 관리자 전액 취소 두 번: 앞 요청의 PG 가 환불 없이 실패해도 DB 가 PG 와 맞는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[cancel-dbl-2] 관리자 전액 취소 두 번: 앞 요청의 PG 가 환불 없이 실패해도 DB 가 PG 와 맞는다"},{"ancestorTitles":["같은 결제의 전액 취소 두 건 — 두 번째는 PG 를 부르기 전에 거절된다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"같은 결제의 전액 취소 두 건 — 두 번째는 PG 를 부르기 전에 거절된다 [cancel-dbl-3] 사용자 취소의 PG 대기 중 들어온 관리자 전액 취소는 PG 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[cancel-dbl-3] 사용자 취소의 PG 대기 중 들어온 관리자 전액 취소는 PG 를 부르지 않는다"}],"endTime":1793868738500,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-cancel-race.spec.ts","startTime":1793868738266,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SubscribeFailedService.processResubscribe (구독실패 재구독 순차화)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"SubscribeFailedService.processResubscribe (구독실패 재구독 순차화) 실패목록을 1건씩 순차로 재구독+삭제하고, 중간 실패가 나머지를 막지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"실패목록을 1건씩 순차로 재구독+삭제하고, 중간 실패가 나머지를 막지 않는다"}],"endTime":1793868738611,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/subscribe/subscribe-failed/subscribe-failed.service.spec.ts","startTime":1793868738402,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["OrderDetailService.reAnalyze 상태 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OrderDetailService.reAnalyze 상태 가드 관리자 재분석은 분석완료 건을 거부하고 상태를 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 재분석은 분석완료 건을 거부하고 상태를 건드리지 않는다"},{"ancestorTitles":["OrderDetailService.reAnalyze 상태 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderDetailService.reAnalyze 상태 가드 관리자 재분석은 자료분석중 건을 거부하고 상태를 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 재분석은 자료분석중 건을 거부하고 상태를 건드리지 않는다"},{"ancestorTitles":["OrderDetailService.reAnalyze 상태 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderDetailService.reAnalyze 상태 가드 관리자 재분석은 인증요청중 건을 거부하고 상태를 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 재분석은 인증요청중 건을 거부하고 상태를 건드리지 않는다"},{"ancestorTitles":["OrderDetailService.reAnalyze 상태 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OrderDetailService.reAnalyze 상태 가드 관리자 재분석은 자료수집완료 건을 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 재분석은 자료수집완료 건을 받는다"},{"ancestorTitles":["OrderDetailService.reAnalyze 상태 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderDetailService.reAnalyze 상태 가드 관리자 재분석은 분석실패 건을 받는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 재분석은 분석실패 건을 받는다"}],"endTime":1793868738698,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order-detail/order-detail-reanalyze-state.spec.ts","startTime":1793868738502,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["결제 성공 뒤 주문 생성 실패 — 불일치 기록"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"결제 성공 뒤 주문 생성 실패 — 불일치 기록 결제 식별자와 주문번호를 담은 기록이 남는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"결제 식별자와 주문번호를 담은 기록이 남는다"},{"ancestorTitles":["결제 성공 뒤 주문 생성 실패 — 불일치 기록"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제 성공 뒤 주문 생성 실패 — 불일치 기록 예외를 다시 던진다 — 삼키지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"예외를 다시 던진다 — 삼키지 않는다"},{"ancestorTitles":["결제 성공 뒤 주문 생성 실패 — 불일치 기록"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"결제 성공 뒤 주문 생성 실패 — 불일치 기록 드라이버 메시지가 올라가는 예외에 실리지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"드라이버 메시지가 올라가는 예외에 실리지 않는다"},{"ancestorTitles":["결제 성공 뒤 주문 생성 실패 — 불일치 기록"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"결제 성공 뒤 주문 생성 실패 — 불일치 기록 결제가 실패한 회차는 불일치가 아니다 — 기록하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"결제가 실패한 회차는 불일치가 아니다 — 기록하지 않는다"},{"ancestorTitles":["결제 성공 뒤 주문 생성 실패 — 불일치 기록"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"결제 성공 뒤 주문 생성 실패 — 불일치 기록 주문 생성이 성공하면 기록하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"주문 생성이 성공하면 기록하지 않는다"},{"ancestorTitles":["recordPayOrphan — 기록 형태"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"recordPayOrphan — 기록 형태 수동 복구 질의의 앵커(`[pay-orphan]`)를 고정한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수동 복구 질의의 앵커(`[pay-orphan]`)를 고정한다"},{"ancestorTitles":["recordPayOrphan — 기록 형태"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"recordPayOrphan — 기록 형태 오류 원문이 아니라 코드를 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"오류 원문이 아니라 코드를 남긴다"}],"endTime":1793868738836,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order/order-pay-orphan.spec.ts","startTime":1793868738612,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlimtalkService 발송완료여부 조회 결과 (MS7)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService 발송완료여부 조회 결과 (MS7) [MS7-B1] 조회 오류 · 정상 대기 · 최종 실패 · 완료는 서로 다른 값으로 돌아오고 빈 rslt 는 완료 칸을 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"status":"passed","title":"[MS7-B1] 조회 오류 · 정상 대기 · 최종 실패 · 완료는 서로 다른 값으로 돌아오고 빈 rslt 는 완료 칸을 쓰지 않는다"},{"ancestorTitles":["AlimtalkService 발송완료여부 조회 결과 (MS7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService 발송완료여부 조회 결과 (MS7) [MS7-B2] 항목 한 건이 던지거나 query-error 면 예외가 그 수이고 뒤 항목을 모두 처리한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"[MS7-B2] 항목 한 건이 던지거나 query-error 면 예외가 그 수이고 뒤 항목을 모두 처리한다"},{"ancestorTitles":["AlimtalkService 발송완료여부 조회 결과 (MS7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService 발송완료여부 조회 결과 (MS7) [MS7-B3] 완료 · 대기 · 최종 실패만 있으면 예외는 0 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS7-B3] 완료 · 대기 · 최종 실패만 있으면 예외는 0 이다"}],"endTime":1793868738937,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alimtalk/alimtalk-status.spec.ts","startTime":1793868738702,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["OrderService.validationOrder — 회원 자체취소와 정산확정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OrderService.validationOrder — 회원 자체취소와 정산확정 정산확정 회차에 반영된 주문은 회원 문구로 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"정산확정 회차에 반영된 주문은 회원 문구로 막는다"},{"ancestorTitles":["OrderService.validationOrder — 회원 자체취소와 정산확정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderService.validationOrder — 회원 자체취소와 정산확정 확정 전이면 지금처럼 취소할 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"확정 전이면 지금처럼 취소할 수 있다"}],"endTime":1793868739028,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order/order-cancel-settled.spec.ts","startTime":1793868738838,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 actorRole 하나만 넣으면 조건은 그 칼럼·연산·값 하나다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"actorRole 하나만 넣으면 조건은 그 칼럼·연산·값 하나다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 actorLabel 하나만 넣으면 조건은 그 칼럼·연산·값 하나다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"actorLabel 하나만 넣으면 조건은 그 칼럼·연산·값 하나다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 actorRefId 하나만 넣으면 조건은 그 칼럼·연산·값 하나다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"actorRefId 하나만 넣으면 조건은 그 칼럼·연산·값 하나다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 action 하나만 넣으면 조건은 그 칼럼·연산·값 하나다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"action 하나만 넣으면 조건은 그 칼럼·연산·값 하나다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 startDate 하나만 넣으면 조건은 그 칼럼·연산·값 하나다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"startDate 하나만 넣으면 조건은 그 칼럼·연산·값 하나다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 endDate 하나만 넣으면 조건은 그 칼럼·연산·값 하나다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"endDate 하나만 넣으면 조건은 그 칼럼·연산·값 하나다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 넣지 않은 필터는 조건을 만들지 않는다 — 빈 문자열도 넣지 않은 것이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"넣지 않은 필터는 조건을 만들지 않는다 — 빈 문자열도 넣지 않은 것이다"},{"ancestorTitles":["toAuditLogCriteria — 필터 하나에 조건 하나"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toAuditLogCriteria — 필터 하나에 조건 하나 기간은 시작이 gte, 끝이 lte 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기간은 시작이 gte, 끝이 lte 다"},{"ancestorTitles":["getList — 봉투 · 쪽 고정 · 행 표시"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getList — 봉투 · 쪽 고정 · 행 표시 봉투는 { count, list, scope } 이고 목록·건수를 같은 조건으로 읽는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"봉투는 { count, list, scope } 이고 목록·건수를 같은 조건으로 읽는다"},{"ancestorTitles":["getList — 봉투 · 쪽 고정 · 행 표시"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getList — 봉투 · 쪽 고정 · 행 표시 0 쪽·거대 limit 은 1 쪽·상한으로 고정된다 — limit 없음 분기는 내보내기 전용이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"0 쪽·거대 limit 은 1 쪽·상한으로 고정된다 — limit 없음 분기는 내보내기 전용이다"},{"ancestorTitles":["getList — 봉투 · 쪽 고정 · 행 표시"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getList — 봉투 · 쪽 고정 · 행 표시 행위 라벨·금액 기준을 붙이고, 표시 맵에 없는 행위는 식별자를 라벨로 둔다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"행위 라벨·금액 기준을 붙이고, 표시 맵에 없는 행위는 식별자를 라벨로 둔다"},{"ancestorTitles":["getList — 봉투 · 쪽 고정 · 행 표시"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"getList — 봉투 · 쪽 고정 · 행 표시 JSON 칸은 객체로 내리고, 파싱에 실패하면 원문 문자열을 그대로 둔다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"JSON 칸은 객체로 내리고, 파싱에 실패하면 원문 문자열을 그대로 둔다"},{"ancestorTitles":["buildScope — 범위 고지와 기록 시작 시각"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildScope — 범위 고지와 기록 시작 시각 조회 시작일이 기록 시작보다 앞서면 고지가 기록 시작 전을 말한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조회 시작일이 기록 시작보다 앞서면 고지가 기록 시작 전을 말한다"},{"ancestorTitles":["buildScope — 범위 고지와 기록 시작 시각"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildScope — 범위 고지와 기록 시작 시각 조회 시작일이 기록 시작 뒤면 그 문장이 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조회 시작일이 기록 시작 뒤면 그 문장이 없다"},{"ancestorTitles":["buildScope — 범위 고지와 기록 시작 시각"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildScope — 범위 고지와 기록 시작 시각 기록된 행이 없으면 기간과 무관하게 그 문장이 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기록된 행이 없으면 기간과 무관하게 그 문장이 있다"},{"ancestorTitles":["buildScope — 범위 고지와 기록 시작 시각"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildScope — 범위 고지와 기록 시작 시각 덮는 행위와 덮지 않는 유형을 따로 싣고, 중간 공백은 알 수 없다고 늘 말한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"덮는 행위와 덮지 않는 유형을 따로 싣고, 중간 공백은 알 수 없다고 늘 말한다"},{"ancestorTitles":["downloadExcel — 기간 필수 · 행수 상한 · 머리 행"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"downloadExcel — 기간 필수 · 행수 상한 · 머리 행 기간이 없으면 거절하고 표를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기간이 없으면 거절하고 표를 읽지 않는다"},{"ancestorTitles":["downloadExcel — 기간 필수 · 행수 상한 · 머리 행"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"downloadExcel — 기간 필수 · 행수 상한 · 머리 행 상한을 넘으면 거절하고 행을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상한을 넘으면 거절하고 행을 읽지 않는다"},{"ancestorTitles":["downloadExcel — 기간 필수 · 행수 상한 · 머리 행"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"downloadExcel — 기간 필수 · 행수 상한 · 머리 행 목록과 같은 조건으로 1 쪽 · 내보내기 상한만큼 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"목록과 같은 조건으로 1 쪽 · 내보내기 상한만큼 읽는다"},{"ancestorTitles":["downloadExcel — 기간 필수 · 행수 상한 · 머리 행"],"duration":15,"failureDetails":[],"failureMessages":[],"fullName":"downloadExcel — 기간 필수 · 행수 상한 · 머리 행 0행이어도 머리에 고지·덮는 행위·덮지 않는 유형·기록 시작 시각이 실린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"0행이어도 머리에 고지·덮는 행위·덮지 않는 유형·기록 시작 시각이 실린다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 아는 코드 COMPENSATION 는 라벨 보상 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아는 코드 COMPENSATION 는 라벨 보상 다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 아는 코드 EVENT 는 라벨 이벤트·마케팅 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아는 코드 EVENT 는 라벨 이벤트·마케팅 다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 아는 코드 CORRECTION 는 라벨 오류 정정(오지급 회수 포함) 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아는 코드 CORRECTION 는 라벨 오류 정정(오지급 회수 포함) 다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 아는 코드 CORP_CONTRACT 는 라벨 기업 계약·충전 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아는 코드 CORP_CONTRACT 는 라벨 기업 계약·충전 다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 아는 코드 OTHER 는 라벨 기타 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아는 코드 OTHER 는 라벨 기타 다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 사유가 없는 행(null)은 시점이 아니라 사실을 말하는 고지다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"사유가 없는 행(null)은 시점이 아니라 사실을 말하는 고지다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 모르는 코드는 버리지 않고 코드 그대로 보인다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드는 버리지 않고 코드 그대로 보인다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 목록 행마다 사유 유형 라벨이 붙고 원문 코드도 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"목록 행마다 사유 유형 라벨이 붙고 원문 코드도 남는다"},{"ancestorTitles":["reasonLabel — 사유 유형 라벨은 서버가 붙인다"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"reasonLabel — 사유 유형 라벨은 서버가 붙인다 엑셀에 사유 유형 칸이 사유 코드 칸 앞에 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"엑셀에 사유 유형 칸이 사유 코드 칸 앞에 있다"},{"ancestorTitles":["미기록 고지 — 사실을 따라간다(M8 D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"미기록 고지 — 사실을 따라간다(M8 D7) M8 이 기록하는 충전요청 승인·개입 사유는 빠지고 '기업 충전요청 반려' 는 남는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"M8 이 기록하는 충전요청 승인·개입 사유는 빠지고 '기업 충전요청 반려' 는 남는다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 목록 행이 결과 칸과 보안 라벨을 서버에서 받은 값으로 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"목록 행이 결과 칸과 보안 라벨을 서버에서 받은 값으로 싣는다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 목록의 사유 칸이 '사유 미기록' 이 아니라 '해당 없음' 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"목록의 사유 칸이 '사유 미기록' 이 아니라 '해당 없음' 이다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 엑셀의 사유 칸도 같은 값이다 — 화면과 파일이 갈리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"엑셀의 사유 칸도 같은 값이다 — 화면과 파일이 갈리지 않는다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 사유 코드 칸은 접힌 표시값이 아니라 저장값(NULL)이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"사유 코드 칸은 접힌 표시값이 아니라 저장값(NULL)이다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 금전 개입 행의 사유 문구는 그대로다 — 접기가 한쪽만 건드린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"금전 개입 행의 사유 문구는 그대로다 — 접기가 한쪽만 건드린다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 자칭 계정 수가 범위 고지와 엑셀 머리에 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자칭 계정 수가 범위 고지와 엑셀 머리에 실린다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 역할을 고른 조회는 자칭을 다시 세지 않는다 — UNKNOWN 이 아니면 0건이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"역할을 고른 조회는 자칭을 다시 세지 않는다 — UNKNOWN 이 아니면 0건이다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 행위 필터가 계정 보안 행위를 받는다 — 어휘에서 유도된 허용 집합이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"행위 필터가 계정 보안 행위를 받는다 — 어휘에서 유도된 허용 집합이다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 범위 고지가 계정 보안 행위를 따로 싣는다 — 한 표에 섞인 두 유형을 화면이 갈라야 한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 고지가 계정 보안 행위를 따로 싣는다 — 한 표에 섞인 두 유형을 화면이 갈라야 한다"},{"ancestorTitles":["계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"계정 보안 행 — 결과 칸 · 보안 라벨 · 사유는 해당 없음 엑셀 셀의 수식 머리가 중화된다 — 자칭 라벨은 요청자가 고른 문자열이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"엑셀 셀의 수식 머리가 중화된다 — 자칭 라벨은 요청자가 고른 문자열이다"},{"ancestorTitles":["기업 정산 행 — 라벨 · 금액 기준 · 사유는 해당 없음(A18 결정 10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"기업 정산 행 — 라벨 · 금액 기준 · 사유는 해당 없음(A18 결정 10) 행위 필터 · 범위 고지가 정산 행위를 받는다 — 금전 목록과는 섞지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"행위 필터 · 범위 고지가 정산 행위를 받는다 — 금전 목록과는 섞지 않는다"},{"ancestorTitles":["기업 정산 행 — 라벨 · 금액 기준 · 사유는 해당 없음(A18 결정 10)"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"기업 정산 행 — 라벨 · 금액 기준 · 사유는 해당 없음(A18 결정 10) 엑셀은 정산 라벨 · 금액 기준 · 해당 없음 사유를 싣고, 머리 행이 세 유형의 행위를 모두 말한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"엑셀은 정산 라벨 · 금액 기준 · 해당 없음 사유를 싣고, 머리 행이 세 유형의 행위를 모두 말한다"}],"endTime":1793868739123,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit-log/audit-log.service.spec.ts","startTime":1793868738939,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["푸시 관리 · 상세 접근제어"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"푸시 관리 · 상세 접근제어 push: 관리 컨트롤러에 관리자 인증 · 역할 가드와 admin 역할이 걸려 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"push: 관리 컨트롤러에 관리자 인증 · 역할 가드와 admin 역할이 걸려 있다"},{"ancestorTitles":["푸시 관리 · 상세 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"푸시 관리 · 상세 접근제어 push: 관리 핸들러 열 개에 isPublic 우회가 없고 상세 핸들러는 관리 컨트롤러 밖에 있다","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"status":"passed","title":"push: 관리 핸들러 열 개에 isPublic 우회가 없고 상세 핸들러는 관리 컨트롤러 밖에 있다"},{"ancestorTitles":["푸시 관리 · 상세 접근제어"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"푸시 관리 · 상세 접근제어 push: 모듈이 관리 컨트롤러를 상세 컨트롤러보다 먼저 등록한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"push: 모듈이 관리 컨트롤러를 상세 컨트롤러보다 먼저 등록한다"},{"ancestorTitles":["푸시 관리 · 상세 접근제어","HTTP"],"duration":25,"failureDetails":[],"failureMessages":[],"fullName":"푸시 관리 · 상세 접근제어 HTTP push: 관리 경로 열 개가 무토큰 401 이고 서비스에 닿지 않는다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"push: 관리 경로 열 개가 무토큰 401 이고 서비스에 닿지 않는다"},{"ancestorTitles":["푸시 관리 · 상세 접근제어","HTTP"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"푸시 관리 · 상세 접근제어 HTTP push: fcm-users 는 회원 토큰 · sales 거부 · admin 200 이고 상세 핸들러로 새지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"push: fcm-users 는 회원 토큰 · sales 거부 · admin 200 이고 상세 핸들러로 새지 않는다"},{"ancestorTitles":["푸시 관리 · 상세 접근제어","HTTP"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"푸시 관리 · 상세 접근제어 HTTP push: 상세는 회원 access · 내부 관리자만 200 이고 refresh · 자리 바꾼 관리자 토큰 · 뷰 토큰 · sales · corp · 무토큰은 401","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"push: 상세는 회원 access · 내부 관리자만 200 이고 refresh · 자리 바꾼 관리자 토큰 · 뷰 토큰 · sales · corp · 무토큰은 401"}],"endTime":1793868739231,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/push/push-access.spec.ts","startTime":1793868739030,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlimtalkService.sendSubscriptionPaymentSuccess"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkService.sendSubscriptionPaymentSuccess UL_1280 템플릿 본문·버튼·대체문자와 일치하게 발송한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"UL_1280 템플릿 본문·버튼·대체문자와 일치하게 발송한다"}],"endTime":1793868739317,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alimtalk/alimtalk-subscription-payment.spec.ts","startTime":1793868739125,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["InvoiceDrawer — coordinate.style 자료형 정규화"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceDrawer — coordinate.style 자료형 정규화 문자열 size/spacing 으로 그린 결과가 숫자로 그린 결과와 완전히 같다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"문자열 size/spacing 으로 그린 결과가 숫자로 그린 결과와 완전히 같다"},{"ancestorTitles":["InvoiceDrawer — coordinate.style 자료형 정규화"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceDrawer — coordinate.style 자료형 정규화 문자열 style 로 그려도 pdf-lib 에 넘어가는 size 는 항상 number 다","invocations":1,"location":null,"numPassingAsserts":35,"retryReasons":[],"status":"passed","title":"문자열 style 로 그려도 pdf-lib 에 넘어가는 size 는 항상 number 다"},{"ancestorTitles":["InvoiceDrawer — coordinate.style 자료형 정규화"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceDrawer — coordinate.style 자료형 정규화 자간이 문자열 연결이 아니라 숫자 연산으로 누적된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자간이 문자열 연결이 아니라 숫자 연산으로 누적된다"},{"ancestorTitles":["InvoiceDrawer — coordinate.style 자료형 정규화"],"duration":38,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceDrawer — coordinate.style 자료형 정규화 pdf-lib 은 문자열 size 를 거부한다 — 정규화가 없으면 draw 가 예외로 죽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"pdf-lib 은 문자열 size 를 거부한다 — 정규화가 없으면 draw 가 예외로 죽는다"}],"endTime":1793868739465,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/invoice/invoice.drawer.spec.ts","startTime":1793868739235,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 1 타인 FC 상세는 403 이고 getDetail 을 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"1 타인 FC 상세는 403 이고 getDetail 을 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 2 타인 목록은 403 이고 getFcUserList 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"2 타인 목록은 403 이고 getFcUserList 를 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 3 타인 memId 의 암호화 키는 403 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"3 타인 memId 의 암호화 키는 403 이다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 4 타인 정보 수정은 403 이고 update 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"4 타인 정보 수정은 403 이고 update 를 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 5 타인 탈퇴는 403 이고 withdraw 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"5 타인 탈퇴는 403 이고 withdraw 를 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 6 타인 푸시 설정 조회는 403 이고 getPushSettings 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"6 타인 푸시 설정 조회는 403 이고 getPushSettings 를 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 7 타인 푸시 설정 수정은 403 이고 updatePushSettings 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"7 타인 푸시 설정 수정은 403 이고 updatePushSettings 를 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 8 타인 스누즈는 403 이고 snoozeEventPopup 을 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"8 타인 스누즈는 403 이고 snoozeEventPopup 을 부르지 않는다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 9 비밀번호 확인 — 쌍이 없으면(다른 회원의 로그인 ID 포함) 403 이고 조회 인자는 (토큰 memId, 로그인 ID)다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"9 비밀번호 확인 — 쌍이 없으면(다른 회원의 로그인 ID 포함) 403 이고 조회 인자는 (토큰 memId, 로그인 ID)다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 9b 쌍 조회 where 바인딩이 [memId, loginId] 순서다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"9b 쌍 조회 where 바인딩이 [memId, loginId] 순서다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 10 비밀번호 확인 — 쌍은 있고 비밀번호가 틀리면 400 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"10 비밀번호 확인 — 쌍은 있고 비밀번호가 틀리면 400 이다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 11 본인 memId 는 9 핸들러 전부 통과하고 서비스에 토큰 값이 간다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"11 본인 memId 는 9 핸들러 전부 통과하고 서비스에 토큰 값이 간다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 12 비밀번호 확인 — 본인 비밀번호가 맞으면 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"12 비밀번호 확인 — 본인 비밀번호가 맞으면 통과한다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 13 목록 memId 누락은 컨트롤러가 던지는 기존 404 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"13 목록 memId 누락은 컨트롤러가 던지는 기존 404 다"},{"ancestorTitles":["FC 소유자 대조 (보안 핫픽스 M5 K8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"FC 소유자 대조 (보안 핫픽스 M5 K8) 소속 본인 수정: orgId 는 서비스로 넘기지 않는다 (다른 필드는 그대로)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"소속 본인 수정: orgId 는 서비스로 넘기지 않는다 (다른 필드는 그대로)"}],"endTime":1793868739510,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/fc-ownership.spec.ts","startTime":1793868739318,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 남의 문의사항 상세는 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"남의 문의사항 상세는 거부한다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 본인 문의사항 상세는 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"본인 문의사항 상세는 허용한다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 남의 문의사항 삭제는 거부하고 저장소를 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"남의 문의사항 삭제는 거부하고 저장소를 건드리지 않는다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 본인 문의사항 삭제는 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"본인 문의사항 삭제는 허용한다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 남의 문의사항 수정은 거부하고, 본인 수정은 문의사항 타입으로만 넘긴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"남의 문의사항 수정은 거부하고, 본인 수정은 문의사항 타입으로만 넘긴다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 회원 수정은 본문의 상태·식별 칸을 저장소로 보내지 않고 저장된 값을 되돌려 넘긴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 수정은 본문의 상태·식별 칸을 저장소로 보내지 않고 저장된 값을 되돌려 넘긴다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 회원 등록은 본문의 식별·상태 칸을 저장소로 보내지 않고 서버 기본값을 쓴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"회원 등록은 본문의 식별·상태 칸을 저장소로 보내지 않고 서버 기본값을 쓴다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 회원 본문이 JSON 이 아니거나 없거나 객체가 아니면 500 이 아니라 400 이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"회원 본문이 JSON 이 아니거나 없거나 객체가 아니면 500 이 아니라 400 이다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 회원은 작성자 값이 남은 공지를 지울 수 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"회원은 작성자 값이 남은 공지를 지울 수 없다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 공지·FAQ 상세는 노출된 글을 로그인 회원 누구에게나 연다 (기존 동작 유지)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"공지·FAQ 상세는 노출된 글을 로그인 회원 누구에게나 연다 (기존 동작 유지)"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 노출되지 않은 공지는 회원에게 상세로 열리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"노출되지 않은 공지는 회원에게 상세로 열리지 않는다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 회원 문의 목록은 쿼리의 memId 와 무관하게 토큰의 회원으로 좁힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"회원 문의 목록은 쿼리의 memId 와 무관하게 토큰의 회원으로 좁힌다"},{"ancestorTitles":["회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 게시판 소유자 검사 (문의사항만 본인, 공지·FAQ 는 노출된 글만 공개) 회원 문의 등록은 토큰의 회원과 문의사항 타입으로만 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"회원 문의 등록은 토큰의 회원과 문의사항 타입으로만 쓴다"}],"endTime":1793868739632,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/board/board/board-member-access.spec.ts","startTime":1793868739467,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) final 발송은 S3 객체를 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"final 발송은 S3 객체를 지우지 않는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) final 발송은 발송 이력을 회차(기업·귀속 월)와 함께 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"final 발송은 발송 이력을 회차(기업·귀속 월)와 함께 남긴다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":20,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) preview 도 실제 발송이므로 이력을 남긴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"preview 도 실제 발송이므로 이력을 남긴다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) 발송 이력의 귀속 월은 발송일이 아니라 보고 기간 끝의 달이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발송 이력의 귀속 월은 발송일이 아니라 보고 기간 끝의 달이다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) final 발송을 두 번 해도 두 번째가 객체 부재로 죽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"final 발송을 두 번 해도 두 번째가 객체 부재로 죽지 않는다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) 발송 이력 기록이 실패해도 메일 발송을 되돌리지 않고 소리 내어 남긴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"발송 이력 기록이 실패해도 메일 발송을 되돌리지 않고 소리 내어 남긴다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) 발송 이력은 메일 발송 전에 쓰이고 발송 뒤에 시각이 스탬프된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"발송 이력은 메일 발송 전에 쓰이고 발송 뒤에 시각이 스탬프된다"},{"ancestorTitles":["SamsungS2ReportService — 청구 근거 보존(M2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SamsungS2ReportService — 청구 근거 보존(M2) 이력을 쓰지 못하면 메일을 보내지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이력을 쓰지 못하면 메일을 보내지 않는다"}],"endTime":1793868739686,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-agency/samsung-s2-report-retention.spec.ts","startTime":1793868739511,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertAdminController — 폴백 스냅샷 무효화(§D7 1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 폴백 스냅샷 무효화(§D7 1) 무효화 실패가 alert_enabled=false 저장을 막지 않는다 (kill switch 잠김 방지, UI16)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"무효화 실패가 alert_enabled=false 저장을 막지 않는다 (kill switch 잠김 방지, UI16)"},{"ancestorTitles":["AlertAdminController — 폴백 스냅샷 무효화(§D7 1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 폴백 스냅샷 무효화(§D7 1) 무효화 실패가 채널 삭제도 막지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"무효화 실패가 채널 삭제도 막지 않는다"},{"ancestorTitles":["AlertAdminController — 폴백 스냅샷 무효화(§D7 1)"],"duration":21,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 폴백 스냅샷 무효화(§D7 1) 무효화는 DB 쓰기보다 **먼저** 시도된다 (창을 만들지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"무효화는 DB 쓰기보다 **먼저** 시도된다 (창을 만들지 않는다)"},{"ancestorTitles":["AlertAdminController — 스누즈(M3 §D7)"],"duration":36,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 스누즈(M3 §D7) 상한 24시간을 넘기면 400 이다 — 무기한 침묵 경로를 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상한 24시간을 넘기면 400 이다 — 무기한 침묵 경로를 만들지 않는다"},{"ancestorTitles":["AlertAdminController — 스누즈(M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 스누즈(M3 §D7) 알 수 없는 규칙 id 는 400 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"알 수 없는 규칙 id 는 400 이다"},{"ancestorTitles":["AlertAdminController — 스누즈(M3 §D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 스누즈(M3 §D7) 상대시간을 서버가 절대시각으로 바꾸고 admId 를 감사 필드로 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상대시간을 서버가 절대시각으로 바꾸고 admId 를 감사 필드로 남긴다"},{"ancestorTitles":["AlertAdminController — 스누즈(M3 §D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 스누즈(M3 §D7) 해제(minutes:0)는 until 0 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"해제(minutes:0)는 until 0 이다"},{"ancestorTitles":["AlertAdminController — 스누즈(M3 §D7)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 스누즈(M3 §D7) 변경 **전에** 스냅샷을 무효화한다 — 스누즈 직후 DB 사망 시 우회를 막는다 (R6-F2)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"변경 **전에** 스냅샷을 무효화한다 — 스누즈 직후 DB 사망 시 우회를 막는다 (R6-F2)"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 서명이 없으면 treat-vendor 켜기 요청을 거부하고 아무 값도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"서명이 없으면 treat-vendor 켜기 요청을 거부하고 아무 값도 쓰지 않는다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 서명이 현재 값과 다르면 정의 버전 포함 어긋난 항목을 알리며 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"서명이 현재 값과 다르면 정의 버전 포함 어긋난 항목을 알리며 거부한다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 같은 요청이 바꾸는 값을 반영해 켜기 가드를 판정한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"같은 요청이 바꾸는 값을 반영해 켜기 가드를 판정한다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 서명이 현재 값과 맞으면 treat-vendor 켜기 요청을 통과시킨다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서명이 현재 값과 맞으면 treat-vendor 켜기 요청을 통과시킨다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 끄기 요청은 서명 가드를 거치지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"끄기 요청은 서명 가드를 거치지 않는다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 설정 읽기가 실패하면 treat-vendor 켜기 요청을 거부하고 아무 값도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"설정 읽기가 실패하면 treat-vendor 켜기 요청을 거부하고 아무 값도 쓰지 않는다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 저장된 서명이 JSON 으로 읽히지 않으면 treat-vendor 켜기 요청을 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"저장된 서명이 JSON 으로 읽히지 않으면 treat-vendor 켜기 요청을 거부한다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 가져오기 출처 source 는 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"가져오기 출처 source 는 전역 파이프를 통과한다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 설정 응답은 출처 맵과 미이관 레거시 수와 서명 상태를 낸다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"설정 응답은 출처 맵과 미이관 레거시 수와 서명 상태를 낸다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 응답은 서비스의 미이관 수를 그대로 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"응답은 서비스의 미이관 수를 그대로 싣는다"},{"ancestorTitles":["AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — MS5 켜기 가드 · 설정 응답 (Task 2(c) · (e)) 응답은 서비스의 unknown 을 그대로 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"응답은 서비스의 unknown 을 그대로 싣는다"},{"ancestorTitles":["AlertAdminController — 감사 줄에 바꾼 값의 모양을 싣는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 감사 줄에 바꾼 값의 모양을 싣는다 설정 저장은 키 이름과 숫자·불리언 값, 규칙 ON/OFF, 출처를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"설정 저장은 키 이름과 숫자·불리언 값, 규칙 ON/OFF, 출처를 싣는다"},{"ancestorTitles":["AlertAdminController — 감사 줄에 바꾼 값의 모양을 싣는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 감사 줄에 바꾼 값의 모양을 싣는다 스누즈는 분과 해제 시각을 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스누즈는 분과 해제 시각을 싣는다"},{"ancestorTitles":["AlertAdminController — 감사 줄에 바꾼 값의 모양을 싣는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertAdminController — 감사 줄에 바꾼 값의 모양을 싣는다 테스트 발송은 본문 길이·보낸 채널 id·성공 수만 싣고 URL·본문 원문은 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"테스트 발송은 본문 길이·보낸 채널 id·성공 수만 싣고 URL·본문 원문은 싣지 않는다"},{"ancestorTitles":["TestSendDto — 본문 길이 상한 (AUTHZ-4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TestSendDto — 본문 길이 상한 (AUTHZ-4) 2000자까지 받고 그 위는 400 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"2000자까지 받고 그 위는 400 이다"}],"endTime":1793868739873,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-admin.controller.spec.ts","startTime":1793868739633,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 계정 보호"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 최고관리자가 아닌 관리자가 최고관리자 계정을 수정하면 E0827 로 거부하고 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"protect: 최고관리자가 아닌 관리자가 최고관리자 계정을 수정하면 E0827 로 거부하고 쓰지 않는다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 최고관리자가 아닌 관리자가 최고관리자 계정을 섞어 삭제하면 E0827 로 거부하고 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"protect: 최고관리자가 아닌 관리자가 최고관리자 계정을 섞어 삭제하면 E0827 로 거부하고 지우지 않는다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 지정 행은 최고관리자 본인이 지우려 해도 E0828 로 막는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"protect: 지정 행은 최고관리자 본인이 지우려 해도 E0828 로 막는다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 최고관리자는 자기 아닌 계정을 지울 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"protect: 최고관리자는 자기 아닌 계정을 지울 수 있다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 최고관리자는 최고관리자 계정을 수정할 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"protect: 최고관리자는 최고관리자 계정을 수정할 수 있다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 최고관리자가 아닌 계정의 수정은 요청자와 무관하게 그대로 된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"protect: 최고관리자가 아닌 계정의 수정은 요청자와 무관하게 그대로 된다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 지정이 살아 있으면 최고관리자가 아닌 요청자는 보호 밖 계정도 지우지 못한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"protect: 지정이 살아 있으면 최고관리자가 아닌 요청자는 보호 밖 계정도 지우지 못한다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 지정 행이 없거나 칸이 없으면 비최고관리자의 삭제도 그대로 된다 (UI9)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"protect: 지정 행이 없거나 칸이 없으면 비최고관리자의 삭제도 그대로 된다 (UI9)"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 표시 칸이 없거나 지정 행이 없으면 보호 대상이 없어 수정이 그대로 된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"protect: 표시 칸이 없거나 지정 행이 없으면 보호 대상이 없어 수정이 그대로 된다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 protect: 지정 조회가 칸 없음 밖의 이유로 실패하면 수정·삭제를 쓰지 않고 실패한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"protect: 지정 조회가 칸 없음 밖의 이유로 실패하면 수정·삭제를 쓰지 않고 실패한다"},{"ancestorTitles":["최고관리자 계정 보호"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 계정 보호 wiring: 수정·삭제 핸들러가 요청자 신원을 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"wiring: 수정·삭제 핸들러가 요청자 신원을 서비스에 넘긴다"},{"ancestorTitles":["최고관리자 표시와 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 표시와 입력 display: 목록과 상세는 지정 행에만 admIsSuper 참을 싣고 지정 조회가 실패하면 전부 거짓으로 선다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"display: 목록과 상세는 지정 행에만 admIsSuper 참을 싣고 지정 조회가 실패하면 전부 거짓으로 선다"},{"ancestorTitles":["최고관리자 표시와 입력"],"duration":68,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 표시와 입력 dto: 수정 본문의 표시 칸은 파이프가 거부하고 생성·수정 쓰기는 표시 칸을 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"dto: 수정 본문의 표시 칸은 파이프가 거부하고 생성·수정 쓰기는 표시 칸을 쓰지 않는다"}],"endTime":1793868739875,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/admin-super.spec.ts","startTime":1793868739693,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B01) 관리자 갱신: 업무 갱신 → 상승 → 감사 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B01) 관리자 갱신: 업무 갱신 → 상승 → 감사 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B02) 관리자 삭제: 업무 삭제 → 상승 → 감사 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B02) 관리자 삭제: 업무 삭제 → 상승 → 감사 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B03) 기업 갱신: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B03) 기업 갱신: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B04) 기업 삭제: 업무 삭제 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B04) 기업 삭제: 업무 삭제 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B05) 조직 삭제 · 소속 해제: 회원 해제 → 상승 → 계약 · 조직 쓰기 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B05) 조직 삭제 · 소속 해제: 회원 해제 → 상승 → 계약 · 조직 쓰기 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B06) 권한 그룹 삭제: 그룹 · 권한 행 삭제 → 상승 → 감사 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B06) 권한 그룹 삭제: 그룹 · 권한 행 삭제 → 상승 → 감사 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B07) 회원 갱신 (소속 쓰기): 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B07) 회원 갱신 (소속 쓰기): 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B08) 퇴사: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B08) 퇴사: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B09) 회원 삭제: 업무 삭제 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B09) 회원 삭제: 업무 삭제 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B10) 소속 이동: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"(B10) 소속 이동: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B11) 조직관리자 지정: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"(B11) 조직관리자 지정: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B12) 자격 상실: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B12) 자격 상실: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"},{"ancestorTitles":["상승 행별 spec (M8b · 쓰기 대응표 13행)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상승 행별 spec (M8b · 쓰기 대응표 13행) (B13) 자격 복귀: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(B13) 자격 복귀: 업무 갱신 → 상승 순서이고 상승 실패면 거절 · 커밋 없음"}],"endTime":1793868740037,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-bump-sites.spec.ts","startTime":1793868739880,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["delete-fc 진입 함수 (MS9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-fc 진입 함수 (MS9) [MS9-E1] 성공 회차는 비식별 함수를 한 번 부르고 하트비트를 남기며 0 을 돌려준다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS9-E1] 성공 회차는 비식별 함수를 한 번 부르고 하트비트를 남기며 0 을 돌려준다"},{"ancestorTitles":["delete-fc 진입 함수 (MS9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-fc 진입 함수 (MS9) [MS9-E2] 실패 회차는 실패 기록만 남기고 1 을 돌려주며 하트비트를 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS9-E2] 실패 회차는 실패 기록만 남기고 1 을 돌려주며 하트비트를 남기지 않는다"},{"ancestorTitles":["delete-fc 진입 함수 (MS9)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"delete-fc 진입 함수 (MS9) [MS9-E3] 기록 쓰기가 끝내 실패하면 reject 하고, 실패 회차와 성공 회차 모두 하트비트를 남기지 않거나 전파한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS9-E3] 기록 쓰기가 끝내 실패하면 reject 하고, 실패 회차와 성공 회차 모두 하트비트를 남기지 않거나 전파한다"},{"ancestorTitles":["delete-fc 진입 함수 (MS9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-fc 진입 함수 (MS9) [MS9-E4] 종료 코드는 실패 개수 0 이면 0, 양수면 1, 던지면 1, 모르는 값 (undefined · NaN) 도 1 이다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"[MS9-E4] 종료 코드는 실패 개수 0 이면 0, 양수면 1, 던지면 1, 모르는 값 (undefined · NaN) 도 1 이다"}],"endTime":1793868740041,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/delete-fc.schdule.spec.ts","startTime":1793868739876,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService 좌표 미등록 보험사면 원본 버퍼를 그대로 돌려주고 PDF를 열지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"좌표 미등록 보험사면 원본 버퍼를 그대로 돌려주고 PDF를 열지 않는다"},{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService 보험사 좌표 조회가 빈 배열이면 원본 버퍼를 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"보험사 좌표 조회가 빈 배열이면 원본 버퍼를 그대로 돌려준다"},{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService 보험사명이 없으면 조회조차 하지 않고 원본 버퍼를 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"보험사명이 없으면 조회조차 하지 않고 원본 버퍼를 돌려준다"},{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService 같은 이름의 보험사가 둘 이상이면 좌표를 확정할 수 없으므로 원본을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 이름의 보험사가 둘 이상이면 좌표를 확정할 수 없으므로 원본을 돌려준다"},{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService 좌표 조회가 예외를 던져도 예외를 전파하지 않고 원본을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"좌표 조회가 예외를 던져도 예외를 전파하지 않고 원본을 돌려준다"},{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService PDF 로드가 실패해도 예외를 전파하지 않고 원본을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"PDF 로드가 실패해도 예외를 전파하지 않고 원본을 돌려준다"},{"ancestorTitles":["InvoiceFaxOverlayService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InvoiceFaxOverlayService 빈 버퍼는 그대로 통과시킨다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 버퍼는 그대로 통과시킨다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 0212345678 를 02-1234-5678 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"0212345678 를 02-1234-5678 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 021234567 를 02-123-4567 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"021234567 를 02-123-4567 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 0423675789 를 042-367-5789 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"0423675789 를 042-367-5789 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 05050051224 를 0505-005-1224 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"05050051224 를 0505-005-1224 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 01012345678 를 010-1234-5678 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"01012345678 를 010-1234-5678 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 0701234567 를 070-123-4567 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"0701234567 를 070-123-4567 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 15881234 를 1588-1234 로 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"15881234 를 1588-1234 로 끊는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 이미 하이픈이 있어도 같은 결과로 수렴한다 — 첫 발송본과 재발송본의 표기가 갈리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"이미 하이픈이 있어도 같은 결과로 수렴한다 — 첫 발송본과 재발송본의 표기가 갈리지 않는다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 모르는 형태(123123123213213213: 18자리 시험 데이터 (스테이징 마스터 실측))는 입력을 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 형태(123123123213213213: 18자리 시험 데이터 (스테이징 마스터 실측))는 입력을 그대로 돌려준다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 모르는 형태(1234567: 8자리 미만)는 입력을 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 형태(1234567: 8자리 미만)는 입력을 그대로 돌려준다"},{"ancestorTitles":["formatFaxNumber"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 모르는 형태(0912345678: 없는 지역번호)는 입력을 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 형태(0912345678: 없는 지역번호)는 입력을 그대로 돌려준다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 모르는 형태(0212345: 02 인데 국번+가입자가 7·8자리가 아님)는 입력을 그대로 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 형태(0212345: 02 인데 국번+가입자가 7·8자리가 아님)는 입력을 그대로 돌려준다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 빈 값과 공백은 빈 문자열로 떨어진다 — 그리기 쪽 !text 조기 반환에 걸린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 값과 공백은 빈 문자열로 떨어진다 — 그리기 쪽 !text 조기 반환에 걸린다"},{"ancestorTitles":["formatFaxNumber"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"formatFaxNumber 어떤 입력에서도 숫자열을 잃지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"어떤 입력에서도 숫자열을 잃지 않는다"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 고정팩스 + 번호 있음 → 끊어쓴 팩스번호","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"고정팩스 + 번호 있음 → 끊어쓴 팩스번호"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 고정팩스 + 번호 없음 → 콜센터 폴백 (회신처를 알 수 없다는 점이 가상팩스와 같다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"고정팩스 + 번호 없음 → 콜센터 폴백 (회신처를 알 수 없다는 점이 가상팩스와 같다)"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 가상팩스 + 고객센터번호 있음 → 콜센터 문의(번호)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가상팩스 + 고객센터번호 있음 → 콜센터 문의(번호)"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 가상팩스 + 고객센터번호 없음 → 문구만","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가상팩스 + 고객센터번호 없음 → 문구만"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 다중팩스 + 고객센터번호 있음 → 콜센터 문의(번호)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"다중팩스 + 고객센터번호 있음 → 콜센터 문의(번호)"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 다중팩스 + 고객센터번호 없음 → 문구만","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"다중팩스 + 고객센터번호 없음 → 문구만"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 가상·다중팩스는 고정 팩스번호가 있어도 무시한다 (발송마다 번호가 달라 문서에 못 박는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가상·다중팩스는 고정 팩스번호가 있어도 무시한다 (발송마다 번호가 달라 문서에 못 박는다)"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 알 수 없는 팩스타입은 콜센터 분기로 떨어진다 (FIXED 만 번호 분기다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"알 수 없는 팩스타입은 콜센터 분기로 떨어진다 (FIXED 만 번호 분기다)"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 고객센터번호가 공백만이면 없는 것으로 본다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"고객센터번호가 공백만이면 없는 것으로 본다"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 아는 형태가 아닌 고객센터번호는 끊지 않고 그대로 괄호에 넣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아는 형태가 아닌 고객센터번호는 끊지 않고 그대로 괄호에 넣는다"},{"ancestorTitles":["resolveInsurerFaxText"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveInsurerFaxText 어떤 입력에서도 빈 문자열을 돌려주지 않는다 — 최소한 문구는 나온다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"어떤 입력에서도 빈 문자열을 돌려주지 않는다 — 최소한 문구는 나온다"}],"endTime":1793868740181,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/invoice/invoice-fax-overlay.service.spec.ts","startTime":1793868740043,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatMonitorRule — 채널 경로 입력 (M5 S2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 채널 경로 입력 (M5 S2) 전역 경고는 힌트 없이 종류만 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"전역 경고는 힌트 없이 종류만 싣는다"},{"ancestorTitles":["TreatMonitorRule — 채널 경로 입력 (M5 S2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 채널 경로 입력 (M5 S2) 벤더 경고는 그 벤더 키를 힌트로, provider 를 종류로 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"벤더 경고는 그 벤더 키를 힌트로, provider 를 종류로 싣는다"},{"ancestorTitles":["TreatMonitorRule — 변환 계약"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 변환 계약 억제 키는 경고 종류 칸을 쓴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"억제 키는 경고 종류 칸을 쓴다"},{"ancestorTitles":["TreatMonitorRule — 변환 계약"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 변환 계약 warn 도 즉시 발송 대상이다 — severitySplit 을 켜지 않았다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"warn 도 즉시 발송 대상이다 — severitySplit 을 켜지 않았다"},{"ancestorTitles":["TreatMonitorRule — 변환 계약"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 변환 계약 경고가 없으면 발화가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경고가 없으면 발화가 없다"},{"ancestorTitles":["TreatMonitorRule — 진료 억제 키 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 억제 키 (MS3) MS3: 진료 경고 키는 종류별 안정 키다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: 진료 경고 키는 종류별 안정 키다"},{"ancestorTitles":["TreatMonitorRule — 진료 억제 키 (MS3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 억제 키 (MS3) MS3: 문구만 바뀌면 억제 키는 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 문구만 바뀌면 억제 키는 같다"},{"ancestorTitles":["TreatMonitorRule — 진료 억제 키 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 억제 키 (MS3) MS3: kind 가 없는 경고는 회차를 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: kind 가 없는 경고는 회차를 던진다"},{"ancestorTitles":["TreatMonitorRule — 진료 억제 키 (MS3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 억제 키 (MS3) MS3: 경고 종류 칸은 판정 입력과 일치한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: 경고 종류 칸은 판정 입력과 일치한다"},{"ancestorTitles":["TreatMonitorRule — 벤더 게이트 키 제외 (MS3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 벤더 게이트 키 제외 (MS3) MS3: 벤더 비활성이면 provider · scenario 키만 평가에서 뺀다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS3: 벤더 비활성이면 provider · scenario 키만 평가에서 뺀다"},{"ancestorTitles":["TreatMonitorRule — 벤더 게이트 키 제외 (MS3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 벤더 게이트 키 제외 (MS3) MS3: 벤더가 켜져 있으면 제외가 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS3: 벤더가 켜져 있으면 제외가 없다"},{"ancestorTitles":["TreatMonitorRule — 벤더 게이트 키 제외 (MS3)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 벤더 게이트 키 제외 (MS3) MS3: 벤더 설정 읽기가 던지면 제외 판정도 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS3: 벤더 설정 읽기가 던지면 제외 판정도 던진다"},{"ancestorTitles":["TreatMonitorRule — 진료 임계 설정 (MS4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 임계 설정 (MS4) MS4: 진료 임계 네 키가 규칙 메타에 있고 기본값은 현행 상수와 같다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MS4: 진료 임계 네 키가 규칙 메타에 있고 기본값은 현행 상수와 같다"},{"ancestorTitles":["TreatMonitorRule — 진료 임계 설정 (MS4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 임계 설정 (MS4) MS4: 규칙은 설정 임계로 판정한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 규칙은 설정 임계로 판정한다"},{"ancestorTitles":["TreatMonitorRule — 진료 임계 설정 (MS4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 임계 설정 (MS4) MS4: 임계 경계는 69 경고 · 70 경고 없음","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS4: 임계 경계는 69 경고 · 70 경고 없음"},{"ancestorTitles":["TreatMonitorRule — 진료 임계 설정 (MS4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 임계 설정 (MS4) MS4: 이탈만 있는 공급자는 성공률 경고가 0건이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 이탈만 있는 공급자는 성공률 경고가 0건이다"},{"ancestorTitles":["TreatMonitorRule — 진료 임계 설정 (MS4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 임계 설정 (MS4) MS4: 표본 5건 미만 공급자는 경고가 0건이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 표본 5건 미만 공급자는 경고가 0건이다"},{"ancestorTitles":["TreatMonitorRule — 진료 임계 설정 (MS4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatMonitorRule — 진료 임계 설정 (MS4) MS4: 경고 문면에 임계 · 표본 · 창이 들어간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS4: 경고 문면에 임계 · 표본 · 창이 들어간다"}],"endTime":1793868740189,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/treat-monitor.rule.spec.ts","startTime":1793868740039,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertSettingsService — 스누즈(M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService — 스누즈(M3 §D7) 유효한 스누즈만 돌려주고 만료·파손은 null 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"유효한 스누즈만 돌려주고 만료·파손은 null 이다"},{"ancestorTitles":["AlertSettingsService — 스누즈(M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService — 스누즈(M3 §D7) 조회 예외도 스누즈 없음으로 떨어진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조회 예외도 스누즈 없음으로 떨어진다"},{"ancestorTitles":["AlertSettingsService — 스누즈(M3 §D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService — 스누즈(M3 §D7) 전역 키는 규칙별 접두 조회에 걸리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"전역 키는 규칙별 접두 조회에 걸리지 않는다"},{"ancestorTitles":["AlertSettingsService — 스누즈(M3 §D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService — 스누즈(M3 §D7) setSnooze 는 절대시각과 감사 필드를 값에 담고, 해제도 기록으로 남긴다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"setSnooze 는 절대시각과 감사 필드를 값에 담고, 해제도 기록으로 남긴다"},{"ancestorTitles":["AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f))"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f)) MS2-10: 빈 객체 {} 는 400 이고 저장 호출이 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-10: 빈 객체 {} 는 400 이고 저장 호출이 없다"},{"ancestorTitles":["AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f)) MS2-10: 값이 문자열 \"60000\" 인 항목이 있으면 400 이고 저장 호출이 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-10: 값이 문자열 \"60000\" 인 항목이 있으면 400 이고 저장 호출이 없다"},{"ancestorTitles":["AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f)) MS2-10: 이름이 패턴을 어기면 (대문자 · 공백 · 콜론 접미) 400 이고 저장 호출이 없다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS2-10: 이름이 패턴을 어기면 (대문자 · 공백 · 콜론 접미) 400 이고 저장 호출이 없다"},{"ancestorTitles":["AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f)) MS2-10: 값이 0 이나 음수이면 400 이고 저장 호출이 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS2-10: 값이 0 이나 음수이면 400 이고 저장 호출이 없다"},{"ancestorTitles":["AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f)) MS2-10: 패턴과 값이 맞는 객체는 저장 호출이 일어난다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS2-10: 패턴과 값이 맞는 객체는 저장 호출이 일어난다"},{"ancestorTitles":["AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS2 감시 목록 저장 검증 (D4 (f)) MS2-10: 같은 요청의 다른 키가 먼저 와도 뒤 키가 400 이면 앞 키도 저장하지 않는다 (반쪽 저장 금지)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-10: 같은 요청의 다른 키가 먼저 와도 뒤 키가 400 이면 앞 키도 저장하지 않는다 (반쪽 저장 금지)"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) 가져오기 묶음 중 하나가 검증에 실패하면 저장 요청이 0건이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"가져오기 묶음 중 하나가 검증에 실패하면 저장 요청이 0건이다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) 저장은 한 번의 일괄 쓰기로 나가고 중간 실패는 앞 키도 되돌린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"저장은 한 번의 일괄 쓰기로 나가고 중간 실패는 앞 키도 되돌린다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) 산출 가져오기의 출처는 산출이고 폼 저장의 출처는 수동이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"산출 가져오기의 출처는 산출이고 폼 저장의 출처는 수동이다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) 출처 키가 없는 기존 값은 출처 미상이고 값이 없으면 기본이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"출처 키가 없는 기존 값은 출처 미상이고 값이 없으면 기본이다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) 출처 맵은 다른 규칙의 키를 지우지 않고 합친다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"출처 맵은 다른 규칙의 키를 지우지 않고 합친다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) 출처 맵이 깨져 있어도 끄기 쓰기는 막히지 않는다 (M6)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"출처 맵이 깨져 있어도 끄기 쓰기는 막히지 않는다 (M6)"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) M5: 알 수 없는 규칙 id 와 boolean 이 아닌 규칙 값은 트랜잭션 앞에서 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"M5: 알 수 없는 규칙 id 와 boolean 이 아닌 규칙 값은 트랜잭션 앞에서 거부한다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 한 묶음 저장과 출처 (Task 1(d) · 2(d)) M4: 저장되는 JSON 설정은 8192바이트를 넘으면 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"M4: 저장되는 JSON 설정은 8192바이트를 넘으면 거부한다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 켜기 가드는 서명이 없으면 쓰기 전에 거부하고 아무 값도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"켜기 가드는 서명이 없으면 쓰기 전에 거부하고 아무 값도 쓰지 않는다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 켜기 가드는 같은 요청이 바꾸는 값으로 판정하고 어긋나면 거부한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"켜기 가드는 같은 요청이 바꾸는 값으로 판정하고 어긋나면 거부한다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 켜기 가드는 설정 읽기나 벤더 목록 읽기가 실패하면 예외를 던지고 아무 값도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"켜기 가드는 설정 읽기나 벤더 목록 읽기가 실패하면 예외를 던지고 아무 값도 쓰지 않는다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 저장된 서명이 JSON 으로 읽히지 않으면 켜기 가드는 쓰기 전에 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"저장된 서명이 JSON 으로 읽히지 않으면 켜기 가드는 쓰기 전에 거부한다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 옛 형식 서명은 켜기 가드가 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"옛 형식 서명은 켜기 가드가 거부한다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 스키마가 맞지 않는 산출 승인값은 켜기 가드가 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스키마가 맞지 않는 산출 승인값은 켜기 가드가 거부한다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 서명이 현재 값과 맞으면 켜기 가드는 통과시켜 treat-vendor 를 켠다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"서명이 현재 값과 맞으면 켜기 가드는 통과시켜 treat-vendor 를 켠다"},{"ancestorTitles":["AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c))"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertSettingsService.patch — MS5 켜기 가드 (Task 2(c)) 끄기 요청은 서명 가드를 거치지 않고 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"끄기 요청은 서명 가드를 거치지 않고 쓴다"}],"endTime":1793868740300,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-settings.service.spec.ts","startTime":1793868740191,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["정산 응답 DTO — 사용 FC 기준 회차 칸(A11)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"정산 응답 DTO — 사용 FC 기준 회차 칸(A11) 상세: settlement.astBillingBasis · summary 의 리포트 포함만 두 합계","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"상세: settlement.astBillingBasis · summary 의 리포트 포함만 두 합계"},{"ancestorTitles":["정산 응답 DTO — 사용 FC 기준 회차 칸(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정산 응답 DTO — 사용 FC 기준 회차 칸(A11) 상세: 주문 기준 회차는 두 합계가 null 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상세: 주문 기준 회차는 두 합계가 null 이다"},{"ancestorTitles":["정산 응답 DTO — 사용 FC 기준 회차 칸(A11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정산 응답 DTO — 사용 FC 기준 회차 칸(A11) 상세: 다시 담기를 막는 까닭 칸이 직렬화에서 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상세: 다시 담기를 막는 까닭 칸이 직렬화에서 남는다"},{"ancestorTitles":["정산 응답 DTO — 사용 FC 기준 회차 칸(A11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정산 응답 DTO — 사용 FC 기준 회차 칸(A11) 목록: 행마다 settlement.astBillingBasis","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"목록: 행마다 settlement.astBillingBasis"},{"ancestorTitles":["정산 응답 DTO — 사용 FC 기준 회차 칸(A11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정산 응답 DTO — 사용 FC 기준 회차 칸(A11) 주문 목록: 행마다 somReason","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문 목록: 행마다 somReason"}],"endTime":1793868740324,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/settlement-response-dto.spec.ts","startTime":1793868740183,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 최초 관측 회차는 발송하지 않고 유예 시작점만 심는다 — 배포 직후 15건 폭주 차단","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최초 관측 회차는 발송하지 않고 유예 시작점만 심는다 — 배포 직후 15건 폭주 차단"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 유예(expect × grace) 안에서는 하트비트가 없어도 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"유예(expect × grace) 안에서는 하트비트가 없어도 발송하지 않는다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 유예를 넘기고도 하트비트가 없으면 critical 을 낸다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"유예를 넘기고도 하트비트가 없으면 critical 을 낸다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 기대 주기 안에 도착한 하트비트는 정상이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기대 주기 안에 도착한 하트비트는 정상이다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 마지막 실행이 유예를 넘으면 미실행으로 잡는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"마지막 실행이 유예를 넘으면 미실행으로 잡는다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) grace 를 올리면 같은 상태가 정상이 된다 (UI11 — 재배포 없이 조정)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"grace 를 올리면 같은 상태가 정상이 된다 (UI11 — 재배포 없이 조정)"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 감시 목록 밖 이름의 하트비트는 무시한다 — 목록이 사실 소스다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"감시 목록 밖 이름의 하트비트는 무시한다 — 목록이 사실 소스다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) JSON 이 파손되면 회차 전체를 보존한다 — 기본 목록으로 떨어뜨리지 않는다 (MS2 Task 4(e)(2))","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"JSON 이 파손되면 회차 전체를 보존한다 — 기본 목록으로 떨어뜨리지 않는다 (MS2 Task 4(e)(2))"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 항목 단위로 검증한다 — 나쁜 항목만 버리고 정상 항목은 살린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"항목 단위로 검증한다 — 나쁜 항목만 버리고 정상 항목은 살린다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 값이 양의 유한수가 아니면 거부한다 — true 는 Number 로 1ms 가 되어 영구 오탐을 만든다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"값이 양의 유한수가 아니면 거부한다 — true 는 Number 로 1ms 가 되어 영구 오탐을 만든다"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 전부 탈락하면 회차 전체를 보존한다 — 기본 목록으로 판정하지 않는다 (MS2 Task 4(e)(3))","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전부 탈락하면 회차 전체를 보존한다 — 기본 목록으로 판정하지 않는다 (MS2 Task 4(e)(3))"},{"ancestorTitles":["A3 하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 하트비트 (§D4) 기본 감시 목록은 배포되는 16종이며 samsung-s2-report 는 없다 (§D4 · PRD Q4)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기본 감시 목록은 배포되는 16종이며 samsung-s2-report 는 없다 (§D4 · PRD Q4)"},{"ancestorTitles":["A3 부분 실패 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 부분 실패 (감사 M5 D11) 하트비트가 정상이어도 창 안의 실패 기록이 critical 을 낸다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"하트비트가 정상이어도 창 안의 실패 기록이 critical 을 낸다"},{"ancestorTitles":["A3 부분 실패 (감사 M5 D11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 부분 실패 (감사 M5 D11) 기대 목록 밖 이름의 실패 기록도 낸다 — 목록은 하트비트의 사실 소스일 뿐이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기대 목록 밖 이름의 실패 기록도 낸다 — 목록은 하트비트의 사실 소스일 뿐이다"},{"ancestorTitles":["A3 부분 실패 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 부분 실패 (감사 M5 D11) 최초 관측 유예 중인 스케줄러의 실패도 낸다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"최초 관측 유예 중인 스케줄러의 실패도 낸다"},{"ancestorTitles":["A3 부분 실패 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 부분 실패 (감사 M5 D11) 창이 지난 기록은 내지 않는다 — 창은 설정이다(기본 24시간)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"창이 지난 기록은 내지 않는다 — 창은 설정이다(기본 24시간)"},{"ancestorTitles":["A3 부분 실패 (감사 M5 D11)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"A3 부분 실패 (감사 M5 D11) 판독 불가 기록은 창과 무관하게 낸다 — 부재만 실패 없음이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판독 불가 기록은 창과 무관하게 낸다 — 부재만 실패 없음이다"},{"ancestorTitles":["A3 부분 실패 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 부분 실패 (감사 M5 D11) 실패 기록이 없으면 하트비트 판정만 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실패 기록이 없으면 하트비트 판정만 남는다"},{"ancestorTitles":["A3 키 단위 제외 (MS2 D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 키 단위 제외 (MS2 D4) MS2-5: keyExclusion 은 목록 밖 bare 이름에만 true 다 — 목록 안 이름과 :partial 키는 false","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS2-5: keyExclusion 은 목록 밖 bare 이름에만 true 다 — 목록 안 이름과 :partial 키는 false"},{"ancestorTitles":["A3 키 단위 제외 (MS2 D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 키 단위 제외 (MS2 D4) MS2-5: 목록에서 뺀 이름의 부분 실패 기록은 목록 제외와 무관하게 evaluate 가 낸다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS2-5: 목록에서 뺀 이름의 부분 실패 기록은 목록 제외와 무관하게 evaluate 가 낸다"},{"ancestorTitles":["A3 키 단위 제외 (MS2 D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 키 단위 제외 (MS2 D4) MS2-6: 목록에 다시 들어온 이름의 기존 장애는 즉시 발화하고 최초 관측을 다시 찍지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS2-6: 목록에 다시 들어온 이름의 기존 장애는 즉시 발화하고 최초 관측을 다시 찍지 않는다"},{"ancestorTitles":["A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9) MS6-U4-1 일 1회 항목은 최종 하트비트 뒤 26.4시간 전에 발화하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS6-U4-1 일 1회 항목은 최종 하트비트 뒤 26.4시간 전에 발화하지 않는다"},{"ancestorTitles":["A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9) MS6-U4-2 일 1회 항목은 26.4시간을 넘기면 한 번 발화한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS6-U4-2 일 1회 항목은 26.4시간을 넘기면 한 번 발화한다"},{"ancestorTitles":["A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9) MS6-U4-3 하루 2회 항목의 유예는 여전히 전역 배수 2 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS6-U4-3 하루 2회 항목의 유예는 여전히 전역 배수 2 다"},{"ancestorTitles":["A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A3 일 1회 항목의 항목별 유예 (MS6 · 편차 8 · 9) MS6-U4-4 옛 기본값 15시간 저장은 24시간으로 읽고 사용자 지정값은 존중하며 실효 주기가 24시간이 아니면 일 1회 유예를 받지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS6-U4-4 옛 기본값 15시간 저장은 24시간으로 읽고 사용자 지정값은 존중하며 실효 주기가 24시간이 아니면 일 1회 유예를 받지 않는다"}],"endTime":1793868740413,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/schedule-heartbeat.rule.spec.ts","startTime":1793868740302,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["관리자 개입 기록 접근제어 (hardening M6a DD2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 개입 기록 접근제어 (hardening M6a DD2) audit: 감사 컨트롤러에 인증·역할·최고관리자 가드가 순서대로 걸려 있다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"audit: 감사 컨트롤러에 인증·역할·최고관리자 가드가 순서대로 걸려 있다"},{"ancestorTitles":["관리자 개입 기록 접근제어 (hardening M6a DD2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 개입 기록 접근제어 (hardening M6a DD2) audit: 클래스 한 자리 가드다 — 핸들러에 판정 가드를 따로 달지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"audit: 클래스 한 자리 가드다 — 핸들러에 판정 가드를 따로 달지 않는다"}],"endTime":1793868740468,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit-log/audit-log-access.spec.ts","startTime":1793868740326,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyMemberStatement 규칙(M3)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AgencyMemberStatement 규칙(M3) 귀속 월 2일 이후에 시작하는 정책 버전이 있으면 명세를 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"귀속 월 2일 이후에 시작하는 정책 버전이 있으면 명세를 만들지 않는다"},{"ancestorTitles":["AgencyMemberStatement 규칙(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyMemberStatement 규칙(M3) 단가는 계약가 하나다 — 사건마다 다른 주문이 섞여도 회원마다 한 번","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단가는 계약가 하나다 — 사건마다 다른 주문이 섞여도 회원마다 한 번"},{"ancestorTitles":["AgencyMemberStatement 규칙(M3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyMemberStatement 규칙(M3) 요약의 단가는 계약가 하나이고 금액은 인원 × 계약가다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"요약의 단가는 계약가 하나이고 금액은 인원 × 계약가다"},{"ancestorTitles":["AgencyMemberStatement 규칙(M3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyMemberStatement 규칙(M3) 줄마다 첫 완료 시각·주문번호, 요약에 리포트 포함만 금액(F8·F9)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"줄마다 첫 완료 시각·주문번호, 요약에 리포트 포함만 금액(F8·F9)"},{"ancestorTitles":["AgencyMemberStatement 규칙(M3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyMemberStatement 규칙(M3) 리포트에서 빠지는 회원도 명세에는 남고 사유 칸으로 갈린다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"리포트에서 빠지는 회원도 명세에는 남고 사유 칸으로 갈린다"}],"endTime":1793868740536,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-agency/agency-member-statement.spec.ts","startTime":1793868740415,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencySettlementService.create 편입 기간"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create 편입 기간 월초부터 익월 1일 전까지를 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"월초부터 익월 1일 전까지를 넘긴다"},{"ancestorTitles":["AgencySettlementService.create 편입 기간"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create 편입 기간 12월은 끝이 다음 해 1월 1일이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"12월은 끝이 다음 해 1월 1일이다"}],"endTime":1793868740601,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/settlement-service-boundary.spec.ts","startTime":1793868740470,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencySettlementRepository.create — 재실행 멱등(M2 D2)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementRepository.create — 재실행 멱등(M2 D2) 같은 회차가 이미 있으면 그 기업만 건너뛰고 나머지 기업 정산은 계속 만든다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"같은 회차가 이미 있으면 그 기업만 건너뛰고 나머지 기업 정산은 계속 만든다"},{"ancestorTitles":["AgencySettlementRepository.create — 재실행 멱등(M2 D2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementRepository.create — 재실행 멱등(M2 D2) 회차 유일 제약이 아닌 1062 는 삼키지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"회차 유일 제약이 아닌 1062 는 삼키지 않는다"},{"ancestorTitles":["AgencySettlementRepository.create — 재실행 멱등(M2 D2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementRepository.create — 재실행 멱등(M2 D2) 유일 제약 위반이 아닌 오류는 삼키지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"유일 제약 위반이 아닌 오류는 삼키지 않는다"},{"ancestorTitles":["AgencySettlementRepository.create — 재실행 멱등(M2 D2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementRepository.create — 재실행 멱등(M2 D2) ast_date 는 배치가 받은 날짜가 아니라 그 달의 월초로 쓰인다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ast_date 는 배치가 받은 날짜가 아니라 그 달의 월초로 쓰인다"}],"endTime":1793868740674,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/settlement-agency-idempotent.spec.ts","startTime":1793868740538,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AuditLogAdminController — 열람 기록 (D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditLogAdminController — 열람 기록 (D6) 목록 조회가 성공하면 auditView 한 줄 · audit-log.view · COMMITTED · 필터 계정 번호","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"목록 조회가 성공하면 auditView 한 줄 · audit-log.view · COMMITTED · 필터 계정 번호"},{"ancestorTitles":["AuditLogAdminController — 열람 기록 (D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditLogAdminController — 열람 기록 (D6) 내보내기가 성공하면 auditView 한 줄 · audit-log.export · COMMITTED","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"내보내기가 성공하면 auditView 한 줄 · audit-log.export · COMMITTED"},{"ancestorTitles":["AuditLogAdminController — 열람 기록 (D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditLogAdminController — 열람 기록 (D6) 목록 조회가 실패하면 같은 예외로 거부하고 auditView 한 줄 · FAILED","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"목록 조회가 실패하면 같은 예외로 거부하고 auditView 한 줄 · FAILED"},{"ancestorTitles":["AuditLogAdminController — 열람 기록 (D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditLogAdminController — 열람 기록 (D6) 내보내기가 실패하면 같은 예외로 거부하고 auditView 한 줄 · FAILED","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"내보내기가 실패하면 같은 예외로 거부하고 auditView 한 줄 · FAILED"},{"ancestorTitles":["AuditLogAdminController — 열람 기록 (D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditLogAdminController — 열람 기록 (D6) 열람 줄 방출이 던져도 조회는 성공한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"열람 줄 방출이 던져도 조회는 성공한다"}],"endTime":1793868740740,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit-log/audit-log-admin.controller.spec.ts","startTime":1793868740602,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-1 배치 네 개 지속 사건은 발화 상태로 남고 해소는 다음 완료 회차의 실패와 주문 전 예외가 0 일 때만 난다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"MS6-N1-1 배치 네 개 지속 사건은 발화 상태로 남고 해소는 다음 완료 회차의 실패와 주문 전 예외가 0 일 때만 난다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-2 다음 회차가 없거나 표본이 모자라거나 조회 창 밖으로 밀려도 사건을 유지한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS6-N1-2 다음 회차가 없거나 표본이 모자라거나 조회 창 밖으로 밀려도 사건을 유지한다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-3 임계 아래 실패는 발화도 해소도 아니고 주문 전 예외만 있는 회차는 해소하지 않으며 주문 커밋 뒤 예외만 있는 회차는 해소한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"MS6-N1-3 임계 아래 실패는 발화도 해소도 아니고 주문 전 예외만 있는 회차는 해소하지 않으며 주문 커밋 뒤 예외만 있는 회차는 해소한다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-4 발화 문면은 배치 라벨을 쓰고 치명 발화는 표본을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS6-N1-4 발화 문면은 배치 라벨을 쓰고 치명 발화는 표본을 싣지 않는다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-8 배치 라벨은 프로세스 시간대와 무관하게 KST 로 12시 59분은 09, 13시 정각은 18 로 묶인다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"MS6-N1-8 배치 라벨은 프로세스 시간대와 무관하게 KST 로 12시 59분은 09, 13시 정각은 18 로 묶인다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-9 끝나지 않은 회차는 판정하지 않고 상태를 지키며 뒤에 끝난 회차가 없으면 뒤 회차 판정을 기다린다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS6-N1-9 끝나지 않은 회차는 판정하지 않고 상태를 지키며 뒤에 끝난 회차가 없으면 뒤 회차 판정을 기다린다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":13,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-10 빈 상태 값은 미판정으로 읽고 깨진 상태 값이나 깨진 회차 기록은 판정 없이 예외로 끝난다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS6-N1-10 빈 상태 값은 미판정으로 읽고 깨진 상태 값이나 깨진 회차 기록은 판정 없이 예외로 끝난다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-11 지연 실행이 13시를 넘겨 끝나도 자기 범위의 결제만 세고 저녁 회차 판정을 막지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS6-N1-11 지연 실행이 13시를 넘겨 끝나도 자기 범위의 결제만 세고 저녁 회차 판정을 막지 않는다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-12 같은 라벨의 재실행 회차는 각각 판정되고 앞 회차 기록을 덮지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS6-N1-12 같은 라벨의 재실행 회차는 각각 판정되고 앞 회차 기록을 덮지 않는다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-13 리스를 잃은 회차의 쓰기는 무효이고 다음 회차가 저장된 옛 상태에서 같은 판정을 잇는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS6-N1-13 리스를 잃은 회차의 쓰기는 무효이고 다음 회차가 저장된 옛 상태에서 같은 판정을 잇는다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-14 뒤 회차가 끝났거나 24시간을 넘긴 미완료 회차는 판정 없이 경고로 남고 정상 판정이 나면 경고를 비운다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS6-N1-14 뒤 회차가 끝났거나 24시간을 넘긴 미완료 회차는 판정 없이 경고로 남고 정상 판정이 나면 경고를 비운다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-16 주문 전 예외만 있고 결제 행이 0건인 회차는 치명 발화이고 표본을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS6-N1-16 주문 전 예외만 있고 결제 행이 0건인 회차는 치명 발화이고 표본을 싣지 않는다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-17 집계 범위는 기록의 DB 시계 값을 초 내림으로 잡아 앱 시작 시각이 ±30초 흔들려도 같은 범위를 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS6-N1-17 집계 범위는 기록의 DB 시계 값을 초 내림으로 잡아 앱 시작 시각이 ±30초 흔들려도 같은 범위를 쓴다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-18 실패 발화는 억제 칸의 발송 확인 뒤에만 해소되고 뒤 정상 회차가 같은 평가에서 지우지 못한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS6-N1-18 실패 발화는 억제 칸의 발송 확인 뒤에만 해소되고 뒤 정상 회차가 같은 평가에서 지우지 못한다"},{"ancestorTitles":["정기결제 회차 판정 (MS6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 (MS6) MS6-N1-19 시작 기록이 없는 끝난 회차는 범위를 알 수 없어 판정하지 않고 미판정 경고로 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"MS6-N1-19 시작 기록이 없는 끝난 회차는 범위를 알 수 없어 판정하지 않고 미판정 경고로 남는다"},{"ancestorTitles":["A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2) 예외 축은 warn 이며 결제 실패 축과 섞이지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"예외 축은 warn 이며 결제 실패 축과 섞이지 않는다"},{"ancestorTitles":["A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2) FC 와 기업 축이 각자의 모집단만 센다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"FC 와 기업 축이 각자의 모집단만 센다"},{"ancestorTitles":["A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2) 시도가 0이면 그 축은 finding 0건이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"시도가 0이면 그 축은 finding 0건이다"},{"ancestorTitles":["A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A1 축 2·3 — 루프 예외 (§D2 R2-F1 · R3-F2) Redis 미구성(null)은 \"이상 없음\"이 아니라 warn 으로 드러난다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Redis 미구성(null)은 \"이상 없음\"이 아니라 warn 으로 드러난다"},{"ancestorTitles":["정기결제 회차 판정 보강 (통합 리뷰 지적)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 보강 (통합 리뷰 지적) MS6-N1-18 보강 — 이전 사건의 발송 확인은 같은 평가에서 새로 생긴 실패 회차를 해소하지 못한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"MS6-N1-18 보강 — 이전 사건의 발송 확인은 같은 평가에서 새로 생긴 실패 회차를 해소하지 못한다"},{"ancestorTitles":["정기결제 회차 판정 보강 (통합 리뷰 지적)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 보강 (통합 리뷰 지적) MS6-N1-14 보강 — 앞선 완료 회차의 판정은 뒤에 든 시작 기록 없는 회차의 미판정 경고를 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS6-N1-14 보강 — 앞선 완료 회차의 판정은 뒤에 든 시작 기록 없는 회차의 미판정 경고를 지우지 않는다"},{"ancestorTitles":["정기결제 회차 판정 보강 (통합 리뷰 지적)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 보강 (통합 리뷰 지적) MS6-N1-14 보강 — 앞선 완료 회차의 판정은 뒤에 든 오래된 미완료 회차의 경고를 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MS6-N1-14 보강 — 앞선 완료 회차의 판정은 뒤에 든 오래된 미완료 회차의 경고를 지우지 않는다"},{"ancestorTitles":["정기결제 회차 판정 보강 (통합 리뷰 2차)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 판정 보강 (통합 리뷰 2차) MS6-N1-18 보강 — 앞 사건의 억제 칸이 살아 있는 동안 새 발화는 미뤄진다 (엔진의 재발송 억제와 맞춘다)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS6-N1-18 보강 — 앞 사건의 억제 칸이 살아 있는 동안 새 발화는 미뤄진다 (엔진의 재발송 억제와 맞춘다)"}],"endTime":1793868740800,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/subscription-payment.rule.spec.ts","startTime":1793868740676,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencySettlementService.create — 건별 줄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 건별 줄 정산 한 건마다 트랜잭션 하나로 쓰고 커밋된 건마다 줄을 낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"정산 한 건마다 트랜잭션 하나로 쓰고 커밋된 건마다 줄을 낸다"},{"ancestorTitles":["AgencySettlementService.create — 건별 줄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 건별 줄 둘째 정산이 던지면 첫째 커밋 줄과 둘째 실패 줄을 낸 뒤 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"둘째 정산이 던지면 첫째 커밋 줄과 둘째 실패 줄을 낸 뒤 던진다"},{"ancestorTitles":["AgencySettlementService.create — 건별 줄"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencySettlementService.create — 건별 줄 이월 편입 건수를 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이월 편입 건수를 싣는다"}],"endTime":1793868740886,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/settlement/settlement-audit.spec.ts","startTime":1793868740741,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["maxBatchAmount — 배치 행별 최대 절대금액(D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maxBatchAmount — 배치 행별 최대 절대금액(D7) issue — 총액 칸의 최대와 행 수를 id 목록으로 읽는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"issue — 총액 칸의 최대와 행 수를 id 목록으로 읽는다"},{"ancestorTitles":["maxBatchAmount — 배치 행별 최대 절대금액(D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maxBatchAmount — 배치 행별 최대 절대금액(D7) grant — 총액 칸의 최대와 행 수를 id 목록으로 읽는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"grant — 총액 칸의 최대와 행 수를 id 목록으로 읽는다"},{"ancestorTitles":["maxBatchAmount — 배치 행별 최대 절대금액(D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maxBatchAmount — 배치 행별 최대 절대금액(D7) 빈 목록은 질의를 내지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 목록은 질의를 내지 않는다"},{"ancestorTitles":["maxBatchAmount — 배치 행별 최대 절대금액(D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maxBatchAmount — 배치 행별 최대 절대금액(D7) 행이 없으면 최대는 null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행이 없으면 최대는 null"},{"ancestorTitles":["dbOffsetMinutes — DB 세션 오프셋(D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"dbOffsetMinutes — DB 세션 오프셋(D6) NOW − UTC 순서로 묻는다 — KST 세션은 +540","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"NOW − UTC 순서로 묻는다 — KST 세션은 +540"},{"ancestorTitles":["dbOffsetMinutes — DB 세션 오프셋(D6)"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"dbOffsetMinutes — DB 세션 오프셋(D6) 읽을 수 없는 값은 던진다 — []","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"읽을 수 없는 값은 던진다 — []"},{"ancestorTitles":["dbOffsetMinutes — DB 세션 오프셋(D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"dbOffsetMinutes — DB 세션 오프셋(D6) 읽을 수 없는 값은 던진다 — [{\"offsetMin\":null}]","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"읽을 수 없는 값은 던진다 — [{\"offsetMin\":null}]"},{"ancestorTitles":["dbOffsetMinutes — DB 세션 오프셋(D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dbOffsetMinutes — DB 세션 오프셋(D6) 읽을 수 없는 값은 던진다 — [{\"offsetMin\":\"\"}]","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"읽을 수 없는 값은 던진다 — [{\"offsetMin\":\"\"}]"},{"ancestorTitles":["dbOffsetMinutes — DB 세션 오프셋(D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"dbOffsetMinutes — DB 세션 오프셋(D6) 읽을 수 없는 값은 던진다 — [{\"offsetMin\":\"x\"}]","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"읽을 수 없는 값은 던진다 — [{\"offsetMin\":\"x\"}]"},{"ancestorTitles":["dbOffsetMinutes — DB 세션 오프셋(D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"dbOffsetMinutes — DB 세션 오프셋(D6) 읽을 수 없는 값은 던진다 — [{\"offsetMin\":5000}]","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"읽을 수 없는 값은 던진다 — [{\"offsetMin\":5000}]"}],"endTime":1793868740919,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-risk.repository.spec.ts","startTime":1793868740802,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["A4 API 5xx 급증 (§D3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A4 API 5xx 급증 (§D3) 분자와 분모를 각각 읽어 sample 로만 싣는다 — 판정은 applyRatio 몫","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"분자와 분모를 각각 읽어 sample 로만 싣는다 — 판정은 applyRatio 몫"},{"ancestorTitles":["A4 API 5xx 급증 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A4 API 5xx 급증 (§D3) 요청이 0이면 critical 이 아니라 warn 으로 드러낸다 — 카운터 정지와 무트래픽은 구분되지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"요청이 0이면 critical 이 아니라 warn 으로 드러낸다 — 카운터 정지와 무트래픽은 구분되지 않는다"},{"ancestorTitles":["A4 API 5xx 급증 (§D3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A4 API 5xx 급증 (§D3) 분모(전체 요청)를 실제로 읽는다 — 없으면 절대건수 판정이 되고 그것이 실패 조건이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"분모(전체 요청)를 실제로 읽는다 — 없으면 절대건수 판정이 되고 그것이 실패 조건이다"},{"ancestorTitles":["A4 API 5xx 급증 (§D3)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"A4 API 5xx 급증 (§D3) Redis 미구성(null)이면 critical 이 아니라 warn 1건 — 조용한 무발송을 드러낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Redis 미구성(null)이면 critical 이 아니라 warn 1건 — 조용한 무발송을 드러낸다"},{"ancestorTitles":["A4 API 5xx 급증 (§D3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A4 API 5xx 급증 (§D3) 분모만 없어도 warn 이다 — 반쪽 신호로 비율을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"분모만 없어도 warn 이다 — 반쪽 신호로 비율을 만들지 않는다"},{"ancestorTitles":["A4 API 5xx 급증 (§D3)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"A4 API 5xx 급증 (§D3) 조회 예외는 그대로 던진다 — unevaluated 격리가 허위 복구를 막아야 한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조회 예외는 그대로 던진다 — unevaluated 격리가 허위 복구를 막아야 한다"}],"endTime":1793868741095,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/api-error-rate.rule.spec.ts","startTime":1793868740921,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (a) 성공 2 · 실패 1 이면 실패 객체 하나만 칼럼에 남고, 실패 기록과 종료 코드 1 이 남는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(a) 성공 2 · 실패 1 이면 실패 객체 하나만 칼럼에 남고, 실패 기록과 종료 코드 1 이 남는다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (b) 전부 성공이면 두 칼럼이 NULL 이고, 하트비트를 남기며 종료 코드 0 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(b) 전부 성공이면 두 칼럼이 NULL 이고, 하트비트를 남기며 종료 코드 0 이다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (c) 재실행은 남은 키만 다시 부르고, 성공하면 두 칼럼이 NULL 이 된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(c) 재실행은 남은 키만 다시 부르고, 성공하면 두 칼럼이 NULL 이 된다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (d) 파싱 불가 JSON 은 S3 를 건드리지 않고 청구서 실패 1 로 세며 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(d) 파싱 불가 JSON 은 S3 를 건드리지 않고 청구서 실패 1 로 세며 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (e) DB 쓰기가 throw 하면 그 청구서만 실패하고 다음 청구서는 계속 처리된다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"(e) DB 쓰기가 throw 하면 그 청구서만 실패하고 다음 청구서는 계속 처리된다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (f) 마크 기록이 reject 하면 진입 함수는 전파하고, 종료 코드는 1 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(f) 마크 기록이 reject 하면 진입 함수는 전파하고, 종료 코드는 1 이다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (g) 대상이 0건이면 DB 쓰기 없이 실패 0 으로 마크한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(g) 대상이 0건이면 DB 쓰기 없이 실패 0 으로 마크한다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (h) 모듈을 import 만 해도 스케줄 본문이 실행되지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(h) 모듈을 import 만 해도 스케줄 본문이 실행되지 않는다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (i) 문자열 원형 `[\"k1\"]` 은 실패 시 `{s3Key}` 객체로 다시 써진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(i) 문자열 원형 `[\"k1\"]` 은 실패 시 `{s3Key}` 객체로 다시 써진다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (j) 객체 배열의 한 항목에 s3Key 가 없으면 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(j) 객체 배열의 한 항목에 s3Key 가 없으면 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (k) 객체와 문자열이 섞인 배열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(k) 객체와 문자열이 섞인 배열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (l) 빈 문자열 항목이 든 배열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(l) 빈 문자열 항목이 든 배열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (m) 숫자 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(m) 숫자 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (n) 단독 객체 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(n) 단독 객체 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (o) 첫 항목은 정상이고 뒤 항목의 s3Key 가 없는 배열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(o) 첫 항목은 정상이고 뒤 항목의 s3Key 가 없는 배열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (p) `{` 로 시작하는 JSON 문자열 원형 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(p) `{` 로 시작하는 JSON 문자열 원형 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (r) 콤마가 있는 객체 문자열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(r) 콤마가 있는 객체 문자열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (s) 콤마로 이어진 따옴표 문자열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(s) 콤마로 이어진 따옴표 문자열 는 S3 를 건드리지 않고 실패 1, 행은 그대로다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (q) 삭제 중 다른 쓰기가 첨부 칼럼을 바꾸면 갱신이 거부되고 새 값은 행에 그대로 남는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(q) 삭제 중 다른 쓰기가 첨부 칼럼을 바꾸면 갱신이 거부되고 새 값은 행에 그대로 남는다"},{"ancestorTitles":["delete-invoice-files 스케줄 (MS10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"delete-invoice-files 스케줄 (MS10) (t) S3 가 undefined 로 거부해도 실패 1로 세고 다음 항목을 계속 처리한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(t) S3 가 undefined 로 거부해도 실패 1로 세고 다음 항목을 계속 처리한다"}],"endTime":1793868741129,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/delete-invoice-files.schedule.spec.ts","startTime":1793868740889,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments treatments-order-is-deterministic-across-insurance-types","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"treatments-order-is-deterministic-across-insurance-types"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments pharmacy-rows-excluded-from-both-tables","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"pharmacy-rows-excluded-from-both-tables"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments legacy-read-omits-car-rows-and-extended-axes","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"legacy-read-omits-car-rows-and-extended-axes"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments insight-inputs-read-in-one-snapshot","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"insight-inputs-read-in-one-snapshot"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments details-empty-array-means-really-none","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"details-empty-array-means-really-none"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments bundled-fee-rows-leave-the-axis-unknown","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"bundled-fee-rows-leave-the-axis-unknown"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments car-details-come-from-the-car-table-only","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"car-details-come-from-the-car-table-only"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments dispensed-by-maps-three-values-and-keeps-unknown","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"dispensed-by-maps-three-values-and-keeps-unknown"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments dispensed-by-omitted-when-pharmacy-row-is-ambiguous","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"dispensed-by-omitted-when-pharmacy-row-is-ambiguous"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments dispensed-by-omitted-when-pharmacy-drug-name-is-empty","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"dispensed-by-omitted-when-pharmacy-drug-name-is-empty"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments analysis-facts-survive-when-details-are-gone","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"analysis-facts-survive-when-details-are-gone"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":18,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments coverage-hints-carry-visit-tuples — 힌트마다 분석 행 튜플이 분석 행 단위로 실린다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"coverage-hints-carry-visit-tuples — 힌트마다 분석 행 튜플이 분석 행 단위로 실린다"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments order-with-no-detail-rows-omits-the-axis","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"order-with-no-detail-rows-omits-the-axis"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments detail-bucket-is-not-copied-onto-sibling-disease-rows","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"detail-bucket-is-not-copied-onto-sibling-disease-rows"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments dispensed-by-folds-drug-name-spacing-before-matching","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dispensed-by-folds-drug-name-spacing-before-matching"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments dispensed-by-omitted-when-a-named-pharmacy-row-matches-nothing","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dispensed-by-omitted-when-a-named-pharmacy-row-matches-nothing"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments pharmacy-only-visit-receives-the-dispensed-drugs","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"pharmacy-only-visit-receives-the-dispensed-drugs"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments pharmacy-only-drugs-stay-unknown-when-attribution-is-ambiguous","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"pharmacy-only-drugs-stay-unknown-when-attribution-is-ambiguous"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments pharmacy-only-drugs-stay-unknown-when-a-pharmacy-row-has-no-name","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"pharmacy-only-drugs-stay-unknown-when-a-pharmacy-row-has-no-name"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments details-availability-is-judged-per-insurance-source","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"details-availability-is-judged-per-insurance-source"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments matched-pharmacy-row-fills-only-empty-hospital-drug-fields","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"matched-pharmacy-row-fills-only-empty-hospital-drug-fields"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments matched-pharmacy-row-fills-hospital-days-stored-as-zero","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"matched-pharmacy-row-fills-hospital-days-stored-as-zero"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments procedure-major-accepts-both-spellings","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"procedure-major-accepts-both-spellings"},{"ancestorTitles":["AnalyzeRepository.findInsightTreatments"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalyzeRepository.findInsightTreatments surgery-fold-shared-by-request-and-response","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"surgery-fold-shared-by-request-and-response"}],"endTime":1793868741224,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze.repository.spec.ts","startTime":1793868741097,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ddx-verdict-schedule-boot"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"ddx-verdict-schedule-boot 배치 전용 모듈이 createApplicationContext 로 부팅되고 서비스가 해석된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"배치 전용 모듈이 createApplicationContext 로 부팅되고 서비스가 해석된다"},{"ancestorTitles":["ddx-verdict-schedule-boot"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"ddx-verdict-schedule-boot [MS8-D4] 배치 전용 모듈에서 AlertSignalService 가 해석된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[MS8-D4] 배치 전용 모듈에서 AlertSignalService 가 해석된다"},{"ancestorTitles":["ddx-verdict 성공 마크 (MS8 M5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-verdict 성공 마크 (MS8 M5) [MS8-D1] 정상 형태 (error 키 없음) 의 성공 회차는 마크를 한 번 0 으로 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS8-D1] 정상 형태 (error 키 없음) 의 성공 회차는 마크를 한 번 0 으로 남긴다"},{"ancestorTitles":["ddx-verdict 성공 마크 (MS8 M5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-verdict 성공 마크 (MS8 M5) [MS8-D2] 던진 실행은 마크를 남기지 않고 종료 코드 1 을 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS8-D2] 던진 실행은 마크를 남기지 않고 종료 코드 1 을 유지한다"},{"ancestorTitles":["ddx-verdict 성공 마크 (MS8 M5)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"ddx-verdict 성공 마크 (MS8 M5) [MS8-D3] 실패 키의 합이 실패 수가 되고, 모르는 값은 1 로 센다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"[MS8-D3] 실패 키의 합이 실패 수가 되고, 모르는 값은 1 로 센다"},{"ancestorTitles":["ddx-verdict 성공 마크 (MS8 M5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-verdict 성공 마크 (MS8 M5) [MS8-D5] 실패가 아닌 키는 실패로 세지 않고, 제공자 수준 실패는 그 수만큼 센다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS8-D5] 실패가 아닌 키는 실패로 세지 않고, 제공자 수준 실패는 그 수만큼 센다"}],"endTime":1793868741262,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/ddx-verdict.schedule.spec.ts","startTime":1793868741134,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["분석결과 배치 삭제 진행 감시"],"duration":30,"failureDetails":[],"failureMessages":[],"fullName":"분석결과 배치 삭제 진행 감시 일반 경로: 같은 배치가 다시 뽑히면 두 번째 배치를 지우기 전에 실패한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"일반 경로: 같은 배치가 다시 뽑히면 두 번째 배치를 지우기 전에 실패한다"},{"ancestorTitles":["분석결과 배치 삭제 진행 감시"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"분석결과 배치 삭제 진행 감시 B2C 경로: 같은 배치가 다시 뽑히면 두 번째 배치를 지우기 전에 실패한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"B2C 경로: 같은 배치가 다시 뽑히면 두 번째 배치를 지우기 전에 실패한다"},{"ancestorTitles":["분석결과 배치 삭제 진행 감시"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"분석결과 배치 삭제 진행 감시 고객사 경로: 같은 배치가 다시 뽑히면 두 번째 배치를 지우기 전에 실패한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"고객사 경로: 같은 배치가 다시 뽑히면 두 번째 배치를 지우기 전에 실패한다"}],"endTime":1793868741344,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analyze-delete-progress.spec.ts","startTime":1793868741228,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 5건 전패 · B 5건 전패 · C 4건 전승 → vendor-pool critical 1건, 벤더 축 0건","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"A 5건 전패 · B 5건 전패 · C 4건 전승 → vendor-pool critical 1건, 벤더 축 0건"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 같은 입력에 표본 하한만 3 → 여전히 vendor-pool critical (하한 변경이 풀 판정을 뒤집지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 입력에 표본 하한만 3 → 여전히 vendor-pool critical (하한 변경이 풀 판정을 뒤집지 않는다)"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 5건 전패 · B 5건 전패 · C 500건 전승 → 풀 없음, vendor:a·vendor:b warn 2건","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"A 5건 전패 · B 5건 전패 · C 500건 전승 → 풀 없음, vendor:a·vendor:b warn 2건"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 실측 물량 inhouse 109 전패 · coocon 29 전승 · octover 22 전승 → vendor-dominant:inhouse critical","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"실측 물량 inhouse 109 전패 · coocon 29 전승 · octover 22 전승 → vendor-dominant:inhouse critical"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 299/1000 · B 200/200 → vendor-dominant:b (건수 최다 A 로 귀속하면 오답)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"A 299/1000 · B 200/200 → vendor-dominant:b (건수 최다 A 로 귀속하면 오답)"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 5건 전패 · B 5건 전패 (2종만) → 설명자 0 이라 vendor-pool critical","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"A 5건 전패 · B 5건 전패 (2종만) → 설명자 0 이라 vendor-pool critical"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 3/5 · B 3/5 · C 0/10 → 설명자 2종이라 vendor-pool 이고 문면이 귀속 불가를 적는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"A 3/5 · B 3/5 · C 0/10 → 설명자 2종이라 vendor-pool 이고 문면이 귀속 불가를 적는다"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 3건 전패 · B 3건 전패 → 잔여가 둘 다 하한 미달이라 설명자 2종","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"A 3건 전패 · B 3건 전패 → 잔여가 둘 다 하한 미달이라 설명자 2종"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 5건 전패 · B 2건 전패 → 잔여 하한 미달은 판정 불가라 A 가 유일한 설명자","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"A 5건 전패 · B 2건 전패 → 잔여 하한 미달은 판정 불가라 A 가 유일한 설명자"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 판정 대상이 A 1종뿐이고 A 10건 전패 → 뺄 벤더가 없으면 풀이 아니다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"판정 대상이 A 1종뿐이고 A 10건 전패 → 뺄 벤더가 없으면 풀이 아니다"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 A 50건 전승 · B 3건 전패 → finding 0건 (B 는 표본 하한 미달, 집계 3/53)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"A 50건 전승 · B 3건 전패 → finding 0건 (B 는 표본 하한 미달, 집계 3/53)"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 전 벤더 표본 0 → finding 0건, 예외 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전 벤더 표본 0 → finding 0건, 예외 없음"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 키에 수치가 섞이지 않고 세 키의 level 이 입력과 무관하게 고정이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"키에 수치가 섞이지 않고 세 키의 level 이 입력과 무관하게 고정이다"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 noise.persistence 를 켜지 않는다 (critical 즉시성이 공용 노브에 걸리면 안 된다)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"noise.persistence 를 켜지 않는다 (critical 즉시성이 공용 노브에 걸리면 안 된다)"},{"ancestorTitles":["§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D4 판정 — 풀 축 · 벤더 축 · 귀속 검사 창은 설정에서 읽어 조회 시각을 만든다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"창은 설정에서 읽어 조회 시각을 만든다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 서명이 빈 객체면 \"산출된 것이 없다\"로 throw 한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서명이 빈 객체면 \"산출된 것이 없다\"로 throw 한다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 서명 vendors:[a,b] · 활성 a·b·c → vendors 와 c 를 담아 throw","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"서명 vendors:[a,b] · 활성 a·b·c → vendors 와 c 를 담아 throw"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 서명 vendors:[a,b,c] · 활성 a·b → vendors 와 c 를 담아 throw","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"서명 vendors:[a,b,c] · 활성 a·b → vendors 와 c 를 담아 throw"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 window_ms drift → 필드명과 양쪽 값을 담아 throw","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"window_ms drift → 필드명과 양쪽 값을 담아 throw"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":6,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 min_sample drift → 필드명과 양쪽 값을 담아 throw","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"min_sample drift → 필드명과 양쪽 값을 담아 throw"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 ratio_threshold drift 도 잡는다 — 입력 조건만 묶으면 통과하는 자리다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ratio_threshold drift 도 잡는다 — 입력 조건만 묶으면 통과하는 자리다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 서명에 있는 overrides 항목이 현재 설정에서 삭제되면 throw","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서명에 있는 overrides 항목이 현재 설정에서 삭제되면 throw"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 설정 조회가 임계만 실패해 기본값으로 떨어진 회차도 걸린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"설정 조회가 임계만 실패해 기본값으로 떨어진 회차도 걸린다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 서명이 전 항목 일치하면 throw 하지 않고 §D4 판정으로 진행한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"서명이 전 항목 일치하면 throw 하지 않고 §D4 판정으로 진행한다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 어긋난 항목을 전부 모아 한 메시지에 담는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"어긋난 항목을 전부 모아 한 메시지에 담는다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 vendors 필드 부재와 빈 배열을 다른 문장으로 적는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"vendors 필드 부재와 빈 배열을 다른 문장으로 적는다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 정의 버전이 없는 옛 서명은 항상 불일치다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정의 버전이 없는 옛 서명은 항상 불일치다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 MS4: 정의 버전이 같으면 서명 대조가 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 정의 버전이 같으면 서명 대조가 통과한다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 정의 버전이 다르거나 타입이 틀린 산출 승인값은 저장 검증에서 거부된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"정의 버전이 다르거나 타입이 틀린 산출 승인값은 저장 검증에서 거부된다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 여섯 키와 정의 버전이 맞는 산출 승인값은 저장 검증을 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"여섯 키와 정의 버전이 맞는 산출 승인값은 저장 검증을 통과한다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 M4: 벤더 이름이 20자를 넘거나 오버라이드에 알 수 없는 칸이 있으면 거부하고, 오버라이드 null 은 허용한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"M4: 벤더 이름이 20자를 넘거나 오버라이드에 알 수 없는 칸이 있으면 거부하고, 오버라이드 null 은 허용한다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 산출 승인값 칸은 라벨이 '산출 승인값' 이고 설명에 OFF·ON 영향 문장을 가진다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"산출 승인값 칸은 라벨이 '산출 승인값' 이고 설명에 OFF·ON 영향 문장을 가진다"},{"ancestorTitles":["§D10 서명 대조 — 반환값이 아니라 throw 다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D10 서명 대조 — 반환값이 아니라 throw 다 parseDerivationSignature 는 빈 문자열·비객체·파싱 실패를 전부 null 로 접는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"parseDerivationSignature 는 빈 문자열·비객체·파싱 실패를 전부 null 로 접는다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 규칙이 쓰는 범위 상수가 settings 메타의 min/max 와 같은 값이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"규칙이 쓰는 범위 상수가 settings 메타의 min/max 와 같은 값이다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 minSample 0 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 minSample 0 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 minSample 10001 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 minSample 10001 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 minSample 소수 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 minSample 소수 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 minSample NaN 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 minSample NaN 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 minSample 문자열 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 minSample 문자열 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 안쪽 minSample 1 은 채택된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경계 안쪽 minSample 1 은 채택된다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 안쪽 minSample 10000 은 채택된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경계 안쪽 minSample 10000 은 채택된다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 threshold 0 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 threshold 0 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 threshold 0.009 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 threshold 0.009 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 threshold 1.1 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 threshold 1.1 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 threshold 음수 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 threshold 음수 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 밖 threshold NaN 은 그 필드만 떨어진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계 밖 threshold NaN 은 그 필드만 떨어진다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 안쪽 threshold 0.01 은 채택된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경계 안쪽 threshold 0.01 은 채택된다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 경계 안쪽 threshold 1 은 채택된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경계 안쪽 threshold 1 은 채택된다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 한 필드가 불량이어도 형제 필드는 보존된다 (양방향)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"한 필드가 불량이어도 형제 필드는 보존된다 (양방향)"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 항목이 객체가 아니면 그 벤더만 무시되고 나머지는 살아 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"항목이 객체가 아니면 그 벤더만 무시되고 나머지는 살아 있다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 최상위 JSON 파싱 실패는 오버라이드 전체를 무시한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최상위 JSON 파싱 실패는 오버라이드 전체를 무시한다"},{"ancestorTitles":["§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D3 오버라이드 — 필드 단위 검증과 필드 단위 폴백 벤더 축이 오버라이드 값을 실제로 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"벤더 축이 오버라이드 값을 실제로 쓴다"}],"endTime":1793868741387,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/treat-vendor.rule.spec.ts","startTime":1793868741264,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 1 타인 memId 목록은 403 이고 getAlarmList 를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"1 타인 memId 목록은 403 이고 getAlarmList 를 부르지 않는다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 2 본인 memId 목록은 통과하고 query 를 그대로 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"2 본인 memId 목록은 통과하고 query 를 그대로 서비스에 넘긴다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 3 목록 memId 누락은 컨트롤러 → 실 서비스의 기존 404 이고 토큰 값으로 채우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"3 목록 memId 누락은 컨트롤러 → 실 서비스의 기존 404 이고 토큰 값으로 채우지 않는다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 4 남의 알림 읽음은 403 이고 check 를 부르지 않는다 — 컨트롤러 → 실 서비스 → 목 저장소, owned 인자는 (almId, 토큰 memId)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"4 남의 알림 읽음은 403 이고 check 를 부르지 않는다 — 컨트롤러 → 실 서비스 → 목 저장소, owned 인자는 (almId, 토큰 memId)"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 5 남의 알림 삭제는 403 이고 delete 를 부르지 않는다 — 컨트롤러 → 실 서비스 → 목 저장소, owned 인자는 (almId, 토큰 memId)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"5 남의 알림 삭제는 403 이고 delete 를 부르지 않는다 — 컨트롤러 → 실 서비스 → 목 저장소, owned 인자는 (almId, 토큰 memId)"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 6 타인 명의 시험 발송은 403 이고 addAlarm 을 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"6 타인 명의 시험 발송은 403 이고 addAlarm 을 부르지 않는다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 7 본인 명의 시험 발송은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"7 본인 명의 시험 발송은 통과한다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 8 본인 알림의 읽음 · 삭제는 실 서비스를 지나 통과한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"8 본인 알림의 읽음 · 삭제는 실 서비스를 지나 통과한다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 9 owned where 바인딩이 [almId, memId] 순서다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"9 owned where 바인딩이 [almId, memId] 순서다"},{"ancestorTitles":["알림 소유자 대조 (보안 핫픽스 M5 K11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알림 소유자 대조 (보안 핫픽스 M5 K11) 10 owned 는 행이 없으면 false, 있으면 true 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"10 owned 는 행이 없으면 false, 있으면 true 다"}],"endTime":1793868741471,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alarm/alarm-ownership.spec.ts","startTime":1793868741345,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["BoardService 보안 (BOLA + 저장형 XSS)","getDetail — 문의사항 소유자 검증(BOLA)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"BoardService 보안 (BOLA + 저장형 XSS) getDetail — 문의사항 소유자 검증(BOLA) 작성자가 아니면 비공개 문의사항 조회를 403으로 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"작성자가 아니면 비공개 문의사항 조회를 403으로 막는다"},{"ancestorTitles":["BoardService 보안 (BOLA + 저장형 XSS)","getDetail — 문의사항 소유자 검증(BOLA)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"BoardService 보안 (BOLA + 저장형 XSS) getDetail — 문의사항 소유자 검증(BOLA) 작성자 본인은 문의사항을 조회할 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"작성자 본인은 문의사항을 조회할 수 있다"},{"ancestorTitles":["BoardService 보안 (BOLA + 저장형 XSS)","getDetail — 문의사항 소유자 검증(BOLA)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"BoardService 보안 (BOLA + 저장형 XSS) getDetail — 문의사항 소유자 검증(BOLA) 공개 게시글(공지사항)은 작성자가 아니어도 조회할 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"공개 게시글(공지사항)은 작성자가 아니어도 조회할 수 있다"},{"ancestorTitles":["BoardService 보안 (BOLA + 저장형 XSS)","validate — 저장형 XSS 정제"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"BoardService 보안 (BOLA + 저장형 XSS) validate — 저장형 XSS 정제 brdContent/brdTitle 의 <script> 를 저장 전에 제거한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"brdContent/brdTitle 의 <script> 를 저장 전에 제거한다"}],"endTime":1793868741511,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/board/board/board.security.spec.ts","startTime":1793868741389,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminSalesCommissionController — 전역 ClassValidatorPipe"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController — 전역 ClassValidatorPipe createDeduction 의 body 파라미터가 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"createDeduction 의 body 파라미터가 전역 파이프를 통과한다"},{"ancestorTitles":["AdminSalesCommissionController — 전역 ClassValidatorPipe"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController — 전역 ClassValidatorPipe supersedeDeduction 의 body 파라미터가 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"supersedeDeduction 의 body 파라미터가 전역 파이프를 통과한다"},{"ancestorTitles":["AdminSalesCommissionController — 전역 ClassValidatorPipe"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController — 전역 ClassValidatorPipe closeDeduction 의 body 파라미터가 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"closeDeduction 의 body 파라미터가 전역 파이프를 통과한다"},{"ancestorTitles":["AdminSalesCommissionController — 전역 ClassValidatorPipe"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController — 전역 ClassValidatorPipe getSettlements 의 query 파라미터가 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"getSettlements 의 query 파라미터가 전역 파이프를 통과한다"},{"ancestorTitles":["AdminSalesCommissionController — 전역 ClassValidatorPipe"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController — 전역 ClassValidatorPipe supersedeDeductions 의 body 파라미터가 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"supersedeDeductions 의 body 파라미터가 전역 파이프를 통과한다"},{"ancestorTitles":["AdminSalesCommissionController — 전역 ClassValidatorPipe"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController — 전역 ClassValidatorPipe getMonthlySettlements 의 query 파라미터가 전역 파이프를 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"getMonthlySettlements 의 query 파라미터가 전역 파이프를 통과한다"}],"endTime":1793868741580,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/sales-commission-admin.pipe.spec.ts","startTime":1793868741472,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["버킷 키 (§D3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"버킷 키 (§D3) UTC 분 단위 스탬프를 쓴다 — API 태스크와 스케줄러 태스크의 로컬 TZ 가 달라도 같은 버킷","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"UTC 분 단위 스탬프를 쓴다 — API 태스크와 스케줄러 태스크의 로컬 TZ 가 달라도 같은 버킷"},{"ancestorTitles":["버킷 키 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"버킷 키 (§D3) 창에 걸치는 분만큼 키를 만들고 현재 부분 버킷을 포함한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"창에 걸치는 분만큼 키를 만들고 현재 부분 버킷을 포함한다"},{"ancestorTitles":["버킷 키 (§D3)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"버킷 키 (§D3) 창이 비정상적으로 크면 상한에서 잘린다 (MGET 폭주 방지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"창이 비정상적으로 크면 상한에서 잘린다 (MGET 폭주 방지)"},{"ancestorTitles":["카운터 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"카운터 (§D3) 최초 INCR 에만 TTL 을 건다 — 재설정하면 창이 계속 밀린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최초 INCR 에만 TTL 을 건다 — 재설정하면 창이 계속 밀린다"},{"ancestorTitles":["카운터 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"카운터 (§D3) API 카운터 TTL 은 창 상한(60분)보다 길다 — 짧으면 창을 늘려도 표본이 안 늘어난다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"API 카운터 TTL 은 창 상한(60분)보다 길다 — 짧으면 창을 늘려도 표본이 안 늘어난다"},{"ancestorTitles":["카운터 (§D3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"카운터 (§D3) 결제 카운터 TTL 은 26시간이다 — 창 상한 24시간보다 짧으면 분모가 조용히 줄어든다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"결제 카운터 TTL 은 26시간이다 — 창 상한 24시간보다 짧으면 분모가 조용히 줄어든다"},{"ancestorTitles":["카운터 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"카운터 (§D3) FC 와 기업 카운터는 서로 다른 키를 쓴다 (§D2 축 분리)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"FC 와 기업 카운터는 서로 다른 키를 쓴다 (§D2 축 분리)"},{"ancestorTitles":["창 합산 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"창 합산 (§D3) 창 안의 버킷만 더한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"창 안의 버킷만 더한다"},{"ancestorTitles":["창 합산 (§D3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"창 합산 (§D3) Redis 미구성이면 null 이다 — 0(실제로 없음)과 섞이면 조용한 무발송이 된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"Redis 미구성이면 null 이다 — 0(실제로 없음)과 섞이면 조용한 무발송이 된다"},{"ancestorTitles":["창 합산 (§D3)"],"duration":12,"failureDetails":[],"failureMessages":[],"fullName":"창 합산 (§D3) 조회 예외는 삼키지 않는다 — 규칙이 throw 해야 unevaluated 격리가 허위 복구를 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"조회 예외는 삼키지 않는다 — 규칙이 throw 해야 unevaluated 격리가 허위 복구를 막는다"},{"ancestorTitles":["하트비트 (§D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"하트비트 (§D4) DB KV 에 시각을 남기고 이름별로 되읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"DB KV 에 시각을 남기고 이름별로 되읽는다"},{"ancestorTitles":["하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"하트비트 (§D4) hbSeen 접두가 hb 조회에 섞이지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"hbSeen 접두가 hb 조회에 섞이지 않는다"},{"ancestorTitles":["하트비트 (§D4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"하트비트 (§D4) markFirstSeen 은 리스 조건부다 — 리스를 잃은 실행은 유예 기준점을 심지 못한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"markFirstSeen 은 리스 조건부다 — 리스를 잃은 실행은 유예 기준점을 심지 못한다"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) SET NX 라 리스 승자는 정확히 1명이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"SET NX 라 리스 승자는 정확히 1명이다"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) 반납은 compare-and-delete 다 — 만료 후 재획득된 남의 리스를 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"반납은 compare-and-delete 다 — 만료 후 재획득된 남의 리스를 지우지 않는다"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) 반납이 read-then-write 로 돌아가지 않는다 — 결과만 보면 두 구현을 구분할 수 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"반납이 read-then-write 로 돌아가지 않는다 — 결과만 보면 두 구현을 구분할 수 없다"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) Redis 미구성이면 리스를 못 잡는다 — 폴백 경로 자체가 성립하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"Redis 미구성이면 리스를 못 잡는다 — 폴백 경로 자체가 성립하지 않는다"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) 스냅샷 파손값은 fail-closed 로 읽힌다 (enabled 는 명시적 true 만)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스냅샷 파손값은 fail-closed 로 읽힌다 (enabled 는 명시적 true 만)"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) 툼스톤 실패는 삼키지 않는다 — 호출부가 변경 자체를 거부해야 한다(§D7 1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"툼스톤 실패는 삼키지 않는다 — 호출부가 변경 자체를 거부해야 한다(§D7 1)"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) Redis 미구성이면 툼스톤은 성공으로 본다 — 지울 스냅샷이 애초에 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"Redis 미구성이면 툼스톤은 성공으로 본다 — 지울 스냅샷이 애초에 없다"},{"ancestorTitles":["폴백 리스·스냅샷 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"폴백 리스·스냅샷 (§D7) 폴백 상태는 목적지가 비면 삭제된다 (복구 완료)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"폴백 상태는 목적지가 비면 삭제된다 (복구 완료)"},{"ancestorTitles":["부분 실패 기록 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"부분 실패 기록 (감사 M5 D11) 실패가 있으면 하트비트 옆 키에 { at, failed } 를 쓰고 하트비트를 덮지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"실패가 있으면 하트비트 옆 키에 { at, failed } 를 쓰고 하트비트를 덮지 않는다"},{"ancestorTitles":["부분 실패 기록 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"부분 실패 기록 (감사 M5 D11) 실패 0 인 실행은 기록을 쓰지 않는다 — 앞선 실패를 A3 가 읽기 전에 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"실패 0 인 실행은 기록을 쓰지 않는다 — 앞선 실패를 A3 가 읽기 전에 지우지 않는다"},{"ancestorTitles":["부분 실패 기록 (감사 M5 D11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"부분 실패 기록 (감사 M5 D11) 실패 기록을 하트비트보다 먼저 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실패 기록을 하트비트보다 먼저 쓴다"},{"ancestorTitles":["부분 실패 기록 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"부분 실패 기록 (감사 M5 D11) 두 번 던지고 세 번째에 되는 쓰기는 기록되고 하트비트가 찍힌다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"두 번 던지고 세 번째에 되는 쓰기는 기록되고 하트비트가 찍힌다"},{"ancestorTitles":["부분 실패 기록 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"부분 실패 기록 (감사 M5 D11) 세 번 다 던지면 진단 줄을 내고 하트비트 없이 호출부로 던진다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"세 번 다 던지면 진단 줄을 내고 하트비트 없이 호출부로 던진다"},{"ancestorTitles":["부분 실패 기록 (감사 M5 D11)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"부분 실패 기록 (감사 M5 D11) 실패 기록 전체를 읽고, 깨진 값은 판독 불가로 돌려준다 — 하트비트 키는 섞이지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"실패 기록 전체를 읽고, 깨진 값은 판독 불가로 돌려준다 — 하트비트 키는 섞이지 않는다"},{"ancestorTitles":["정기결제 회차 기록 (MS6 · 편차 12 · 17)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"정기결제 회차 기록 (MS6 · 편차 12 · 17) MS6-N1-23 종료 기록 쓰기가 실패해도 포인트 실패 기록은 남고 하트비트는 남지 않으며 다음 정상 실행이 기록을 이어 쓴다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS6-N1-23 종료 기록 쓰기가 실패해도 포인트 실패 기록은 남고 하트비트는 남지 않으며 다음 정상 실행이 기록을 이어 쓴다"},{"ancestorTitles":["마크 실패 헬퍼 — 경고 한 줄 · 본 작업 무영향 (MS7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"마크 실패 헬퍼 — 경고 한 줄 · 본 작업 무영향 (MS7) [MS7-M1] 던지는 마크 호출은 체인을 resolve 로 끝내고 경고 한 줄만 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS7-M1] 던지는 마크 호출은 체인을 resolve 로 끝내고 경고 한 줄만 남긴다"}],"endTime":1793868741632,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-signal.service.spec.ts","startTime":1793868741517,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 건강+자동차 모두 성공 → data 2건, 둘 다 매핑, 호출 2회","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"건강+자동차 모두 성공 → data 2건, 둘 다 매핑, 호출 2회"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 전용 필드(진료일수/자동차보험총진료비)가 채워진다 (분석 0 방지)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"자동차 전용 필드(진료일수/자동차보험총진료비)가 채워진다 (분석 0 방지)"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 자료없음(1000204) → 성공, 자동차 빈값","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자동차 자료없음(1000204) → 성공, 자동차 빈값"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 수집실패(1000300)여도 건강 성공은 유지한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자동차 수집실패(1000300)여도 건강 성공은 유지한다"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 미요청 → AB001 1회만, data 1건","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"자동차 미요청 → AB001 1회만, data 1건"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 건강 수집실패 → 전체 실패, 자동차 호출 안 함","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"건강 수집실패 → 전체 실패, 자동차 호출 안 함"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 건강 자료없음(1000204) → 성공, 건강 빈값","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"건강 자료없음(1000204) → 성공, 건강 빈값"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 부분성공(1000206) → 성공, 매핑됨","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 부분성공(1000206) → 성공, 매핑됨"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 마지막거래(1000210) → 성공, 매핑됨","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 마지막거래(1000210) → 성공, 매핑됨"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 세션 오류여도 건강 성공은 유지한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자동차 세션 오류여도 건강 성공은 유지한다"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 건강 응답에 세션 header가 없으면 자동차를 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"건강 응답에 세션 header가 없으면 자동차를 호출하지 않는다"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 호출 예외여도 건강 성공은 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 호출 예외여도 건강 성공은 유지한다"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 빈 요청(items=[]) → throw","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 요청(items=[]) → throw"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 세션(jti) 복원 실패 → CF-12000, post 미호출","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"세션(jti) 복원 실패 → CF-12000, post 미호출"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) 자동차 basicArray만(detail 없음) → octover는 정상 반환(detail 빈)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자동차 basicArray만(detail 없음) → octover는 정상 반환(detail 빈)"},{"ancestorTitles":["OctoverService.fetchTreatmentMultiple (자동차 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OctoverService.fetchTreatmentMultiple (자동차 연동) mobile 인증 + 건강/자동차 성공 → data 2건","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"mobile 인증 + 건강/자동차 성공 → data 2건"}],"endTime":1793868741690,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/octover/src/octover.service.spec.ts","startTime":1793868741581,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — ruleId 가 alc_types 로 목적지를 좁힌다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — ruleId 가 alc_types 로 목적지를 좁힌다"},{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — channelId 교집합이 브로드캐스트를 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — channelId 교집합이 브로드캐스트를 막는다"},{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — 벤더 행은 힌트 채널 하나로 선점된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — 벤더 행은 힌트 채널 하나로 선점된다"},{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — 전역 행과 벤더 행은 같은 기본 채널로 나간다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — 전역 행과 벤더 행은 같은 기본 채널로 나간다"},{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — tpr_key 의 공백이 벤더 힌트를 떨어뜨리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — tpr_key 의 공백이 벤더 힌트를 떨어뜨리지 않는다"},{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — channelId 를 찍으면 사유 없이 빠지는 후보가 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — channelId 를 찍으면 사유 없이 빠지는 후보가 없다"},{"ancestorTitles":["AlertService.sendTest — 목적지"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertService.sendTest — 목적지 sendTest 계약: 목적지 URL 정확 일치 — treat-vendor 는 힌트 채널로만 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sendTest 계약: 목적지 URL 정확 일치 — treat-vendor 는 힌트 채널로만 나간다"}],"endTime":1793868741745,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert.service.sendtest-destinations.spec.ts","startTime":1793868741633,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["SalesCommissionRepository"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository 쓰기 번역 — 대체는 기존 행을 종료자와 함께 닫고 새 행을 삽입한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쓰기 번역 — 대체는 기존 행을 종료자와 함께 닫고 새 행을 삽입한다"},{"ancestorTitles":["SalesCommissionRepository"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository 쓰기 번역 — 같은 시작일 대체와 삭제는 행 삭제이고 삭제가 삽입보다 먼저다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"쓰기 번역 — 같은 시작일 대체와 삭제는 행 삭제이고 삭제가 삽입보다 먼저다"},{"ancestorTitles":["SalesCommissionRepository"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository 쓰기 번역 — applyMutation 이 만들지 않은 객체는 쿼리를 하나도 내기 전에 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"쓰기 번역 — applyMutation 이 만들지 않은 객체는 쿼리를 하나도 내기 전에 거부한다"},{"ancestorTitles":["SalesCommissionRepository"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository 잠금 읽기 — 전체 행을 FOR UPDATE 로 읽어 도메인 행으로 옮긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"잠금 읽기 — 전체 행을 FOR UPDATE 로 읽어 도메인 행으로 옮긴다"},{"ancestorTitles":["SalesCommissionRepository"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository listPersonalRows — 주문에서 결제·구독·회원을 innerJoin 하고 채널·대리점을 leftJoin 한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"listPersonalRows — 주문에서 결제·구독·회원을 innerJoin 하고 채널·대리점을 leftJoin 한다"},{"ancestorTitles":["SalesCommissionRepository"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository listCorporateRows — 반영 주문 매핑에서 정산·기업·주문·결제를 innerJoin 하고 채널·대리점을 기업 기준으로 leftJoin 한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"listCorporateRows — 반영 주문 매핑에서 정산·기업·주문·결제를 innerJoin 하고 채널·대리점을 기업 기준으로 leftJoin 한다"},{"ancestorTitles":["SalesCommissionRepository"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"SalesCommissionRepository listCorporateSettlements — 구간 안 기업 회차를 상태와 무관하게 확정 스냅샷·배치 생성액과 함께 읽는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"listCorporateSettlements — 구간 안 기업 회차를 상태와 무관하게 확정 스냅샷·배치 생성액과 함께 읽는다"}],"endTime":1793868741765,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/sales-commission.repository.spec.ts","startTime":1793868741692,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["메뉴 조회 접근제어"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 조회 접근제어 menu: 전체 메뉴 트리 조회가 인증 가드를 단다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"menu: 전체 메뉴 트리 조회가 인증 가드를 단다"},{"ancestorTitles":["메뉴 조회 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 조회 접근제어 MenuController · getAllList · 배선 · AdminJwtAuthGuard 다음 RolesGuard · @Roles admin","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"MenuController · getAllList · 배선 · AdminJwtAuthGuard 다음 RolesGuard · @Roles admin"},{"ancestorTitles":["메뉴 조회 접근제어"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 조회 접근제어 menu: 컨트롤러에 클래스 레벨 가드가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"menu: 컨트롤러에 클래스 레벨 가드가 없다"}],"endTime":1793868741843,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/menu-access.spec.ts","startTime":1793868741768,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) /live 는 의존성과 무관하게 상수 OK — 재시작으로 못 고치는 장애에 태스크를 순환시키지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"/live 는 의존성과 무관하게 상수 OK — 재시작으로 못 고치는 장애에 태스크를 순환시키지 않는다"},{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) DB·Redis 정상이면 200 (상태코드 미변경)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"DB·Redis 정상이면 200 (상태코드 미변경)"},{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) DB 실패면 503 + 본문 db.ok=false","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"DB 실패면 503 + 본문 db.ok=false"},{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) Redis 실패면 503 + 본문 redis.ok=false — UI3 는 두 축 모두를 요구한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Redis 실패면 503 + 본문 redis.ok=false — UI3 는 두 축 모두를 요구한다"},{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) Redis 미구성(null)은 장애가 아니다 — DB 정상이면 200","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"Redis 미구성(null)은 장애가 아니다 — DB 정상이면 200"},{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) 본문에 예외 메시지를 싣지 않는다 — 무인증 경로","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"본문에 예외 메시지를 싣지 않는다 — 무인증 경로"},{"ancestorTitles":["AppController 헬스 (M2 §D6 단계 3)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AppController 헬스 (M2 §D6 단계 3) /health/detail 은 상태코드를 건드리지 않는다 — A6 규칙이 본문으로 판정한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"/health/detail 은 상태코드를 건드리지 않는다 — A6 규칙이 본문으로 판정한다"}],"endTime":1793868741852,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/app.controller.spec.ts","startTime":1793868741747,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["운영 알림 설정 접근제어"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"운영 알림 설정 접근제어 alert: 알림 설정 컨트롤러에 인증·역할·최고관리자 가드가 순서대로 걸려 있다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"alert: 알림 설정 컨트롤러에 인증·역할·최고관리자 가드가 순서대로 걸려 있다"},{"ancestorTitles":["운영 알림 설정 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"운영 알림 설정 접근제어 alert: 핸들러에 isPublic 우회가 없다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"alert: 핸들러에 isPublic 우회가 없다"}],"endTime":1793868741953,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-access.spec.ts","startTime":1793868741844,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminAuditRule — 설정 메타"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditRule — 설정 메타 설정 8종이 규칙 id 접두로 등록된다","invocations":1,"location":null,"numPassingAsserts":17,"retryReasons":[],"status":"passed","title":"설정 8종이 규칙 id 접두로 등록된다"},{"ancestorTitles":["AdminAuditRule — 설정 메타"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditRule — 설정 메타 원·시 설정에는 단위를 달지 않는다 — 화면이 unit 으로 단위 글자를 붙여 count 는 \"건\" 이 된다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"원·시 설정에는 단위를 달지 않는다 — 화면이 unit 으로 단위 글자를 붙여 count 는 \"건\" 이 된다"},{"ancestorTitles":["창 하한 — DB 로컬 문자열(D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"창 하한 — DB 로컬 문자열(D6) KST 세션이면 13:00Z 의 15분 창 하한은 21:45:00 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"KST 세션이면 13:00Z 의 15분 창 하한은 21:45:00 이다"},{"ancestorTitles":["창 하한 — DB 로컬 문자열(D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"창 하한 — DB 로컬 문자열(D6) evaluate 가 DB 오프셋으로 만든 하한을 두 질의에 넘긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"evaluate 가 DB 오프셋으로 만든 하한을 두 질의에 넘긴다"},{"ancestorTitles":["심야 판정 — 운영 시간대(D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"심야 판정 — 운영 시간대(D6) DB 가 UTC 면 13:30 행은 한국 시간 22시다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"DB 가 UTC 면 13:30 행은 한국 시간 22시다"},{"ancestorTitles":["심야 판정 — 운영 시간대(D6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"심야 판정 — 운영 시간대(D6) 자정을 넘는 구간과 빈 구간","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"자정을 넘는 구간과 빈 구간"},{"ancestorTitles":["심야 판정 — 운영 시간대(D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"심야 판정 — 운영 시간대(D6) DB 오프셋 0(UTC)의 13:30 행이 심야 금전행위로 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"DB 오프셋 0(UTC)의 13:30 행이 심야 금전행위로 나간다"},{"ancestorTitles":["심야 판정 — 운영 시간대(D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"심야 판정 — 운영 시간대(D6) KST 세션의 21:50 행은 심야가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"KST 세션의 21:50 행은 심야가 아니다"},{"ancestorTitles":["고액 — 순액 상쇄(D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"고액 — 순액 상쇄(D7) 합계 10,000원 · 행별 최대 3,000,000원 배치가 고액으로 나간다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"합계 10,000원 · 행별 최대 3,000,000원 배치가 고액으로 나간다"},{"ancestorTitles":["고액 — 순액 상쇄(D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고액 — 순액 상쇄(D7) 부호와 무관하게 크기로 본다 — 회수 −1,200,000원","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"부호와 무관하게 크기로 본다 — 회수 −1,200,000원"},{"ancestorTitles":["고액 — 순액 상쇄(D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"고액 — 순액 상쇄(D7) 임계 미만은 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"임계 미만은 나가지 않는다"},{"ancestorTitles":["고액 — 순액 상쇄(D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"고액 — 순액 상쇄(D7) 상한이 사건을 밀어내지 않는다 — 8건이면 8건","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상한이 사건을 밀어내지 않는다 — 8건이면 8건"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 배치 id 절단 표지가 있으면 불완전 finding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"배치 id 절단 표지가 있으면 불완전 finding"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 배치 id 누락 표지와 판독 불가 JSON 도 불완전 finding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"배치 id 누락 표지와 판독 불가 JSON 도 불완전 finding"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 배치 id 3개 · 업무 행 2개면 불완전 finding","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"배치 id 3개 · 업무 행 2개면 불완전 finding"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 업무 표 읽기가 던져도 규칙은 던지지 않는다 — 불완전으로 싣고 나머지 축은 계속","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"업무 표 읽기가 던져도 규칙은 던지지 않는다 — 불완전으로 싣고 나머지 축은 계속"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 삼킨 읽기 실패는 경고 로그로 남긴다 — 불완전 문면만으로는 행 부재와 DB 오류를 가를 수 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"삼킨 읽기 실패는 경고 로그로 남긴다 — 불완전 문면만으로는 행 부재와 DB 오류를 가를 수 없다"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 펼칠 배치가 EXPAND_MAX 를 넘으면 불완전 finding · 넘는 행은 펼치지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"펼칠 배치가 EXPAND_MAX 를 넘으면 불완전 finding · 넘는 행은 펼치지 않는다"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 오프셋 조회가 던지면 불완전 finding — 나머지 축은 계속, 심야만 건너뛴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"오프셋 조회가 던지면 불완전 finding — 나머지 축은 계속, 심야만 건너뛴다"},{"ancestorTitles":["불완전 통지 — 사유 넷(D5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"불완전 통지 — 사유 넷(D5) 직전에 읽은 오프셋이 있으면 조회가 실패해도 심야를 건너뛰지 않는다(거짓 복구 방지)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"직전에 읽은 오프셋이 있으면 조회가 실패해도 심야를 건너뛰지 않는다(거짓 복구 방지)"},{"ancestorTitles":["연타"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"연타 같은 계정이 창 안에서 임계 이상이면 한 건","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 계정이 창 안에서 임계 이상이면 한 건"},{"ancestorTitles":["연타"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"연타 임계 미만은 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"임계 미만은 나가지 않는다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 실패·실패·성공·실패·실패·실패 의 연속은 3이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실패·실패·성공·실패·실패·실패 의 연속은 3이다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 끝이 아니라 최장 연속이다 — 5회 실패 뒤 성공도 5","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"끝이 아니라 최장 연속이다 — 5회 실패 뒤 성공도 5"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 시각이 뒤섞인 입력에서도 연속은 3이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"시각이 뒤섞인 입력에서도 연속은 3이다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 같은 초의 행은 id 순이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 초의 행은 id 순이다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 연속 실패가 임계 이상이면 finding, 성공이 끊으면 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"연속 실패가 임계 이상이면 finding, 성공이 끊으면 없다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 라벨 10개 × 실패 2회 · 전역 임계 15 에서 finding","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"라벨 10개 × 실패 2회 · 전역 임계 15 에서 finding"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 라벨 원문이 문면·키에 가지 않는다 — 멘션·비밀번호 모양","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"라벨 원문이 문면·키에 가지 않는다 — 멘션·비밀번호 모양"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 라벨이 없는 행도 한 묶음으로 센다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"라벨이 없는 행도 한 묶음으로 센다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 대소문자·끝 공백만 바꾼 ID 는 한 연속이다 — 로그인 ID 비교가 대소문자를 가리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"대소문자·끝 공백만 바꾼 ID 는 한 연속이다 — 로그인 ID 비교가 대소문자를 가리지 않는다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 조직관리자 성공은 연속을 끊지 않는다 — 그 행의 라벨은 입력 ID 가 아니라 소속 기업 ID 다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"조직관리자 성공은 연속을 끊지 않는다 — 그 행의 라벨은 입력 ID 가 아니라 소속 기업 ID 다"},{"ancestorTitles":["로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 연속 · 정렬 · 전역 건수 · 라벨 가림(D10) 전역 건수 문면의 ID 수는 연속과 같은 접기로 센다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전역 건수 문면의 ID 수는 연속과 같은 접기로 센다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 접은 라벨과 경로의 쌍이 키다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"접은 라벨과 경로의 쌍이 키다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 도메인 없는 행은 도메인 있는 행과 같은 묶음이 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"도메인 없는 행은 도메인 있는 행과 같은 묶음이 아니다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 다른 경로의 같은 ID 성공이 연속을 끊지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"다른 경로의 같은 ID 성공이 연속을 끊지 않는다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 같은 경로의 성공은 그 경로의 연속을 끊는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 경로의 성공은 그 경로의 연속을 끊는다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 옛 행과 새 행은 연속으로는 안 합쳐지고 합 축이 잡는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"옛 행과 새 행은 연속으로는 안 합쳐지고 합 축이 잡는다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 같은 ID 를 네 경로에 나눠 쳐도 합 축이 잡는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"같은 ID 를 네 경로에 나눠 쳐도 합 축이 잡는다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 한 경로짜리 사건은 경로별 한 통으로만 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"한 경로짜리 사건은 경로별 한 통으로만 나간다"},{"ancestorTitles":["로그인 — 경로(domain)별 연속 계산"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 — 경로(domain)별 연속 계산 문면에 경로가 실린다 — 어느 로그인인지 사람이 본다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"문면에 경로가 실린다 — 어느 로그인인지 사람이 본다"}],"endTime":1793868741965,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/admin-audit.rule.spec.ts","startTime":1793868741853,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["A6 Redis 축 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A6 Redis 축 (§D7) 정상이면 finding 0건이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"정상이면 finding 0건이다"},{"ancestorTitles":["A6 Redis 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 Redis 축 (§D7) PING 실패는 critical 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"PING 실패는 critical 이다"},{"ancestorTitles":["A6 Redis 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 Redis 축 (§D7) 미구성(null)은 장애가 아니라 warn 이다 — 그래도 축이 사라진 사실은 드러낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"미구성(null)은 장애가 아니라 warn 이다 — 그래도 축이 사라진 사실은 드러낸다"},{"ancestorTitles":["A6 API 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 API 축 (§D7) ALERT_HEALTH_URL 미설정이면 축을 건너뛰고 warn 1건만 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"ALERT_HEALTH_URL 미설정이면 축을 건너뛰고 warn 1건만 낸다"},{"ancestorTitles":["A6 API 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 API 축 (§D7) 리다이렉트를 따라가지 않는다 — 무엇을 프로브했는지 알 수 없게 된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"리다이렉트를 따라가지 않는다 — 무엇을 프로브했는지 알 수 없게 된다"},{"ancestorTitles":["A6 API 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 API 축 (§D7) connect 단계에 소켓 타임아웃을 건다 — axios timeout 만으로는 SYN 블랙홀을 못 막는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"connect 단계에 소켓 타임아웃을 건다 — axios timeout 만으로는 SYN 블랙홀을 못 막는다"},{"ancestorTitles":["A6 API 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 API 축 (§D7) 200 이어도 본문 ok 가 false 면 critical 이다 — /health/detail 은 항상 200 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"200 이어도 본문 ok 가 false 면 critical 이다 — /health/detail 은 항상 200 이다"},{"ancestorTitles":["A6 API 축 (§D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"A6 API 축 (§D7) 조회 자체가 실패해도 규칙은 throw 하지 않고 critical 을 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"조회 자체가 실패해도 규칙은 throw 하지 않고 critical 을 낸다"},{"ancestorTitles":["A6 API 축 (§D7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"A6 API 축 (§D7) 두 축이 동시에 나빠도 key 는 최대 2개다 (§D1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"두 축이 동시에 나빠도 key 는 최대 2개다 (§D1)"}],"endTime":1793868742082,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/infra-health.rule.spec.ts","startTime":1793868741968,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트) (z) 삭제는 업무 삭제 → 상승 → 감사 순서로 같은 tx 에서 돈다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(z) 삭제는 업무 삭제 → 상승 → 감사 순서로 같은 tx 에서 돈다"},{"ancestorTitles":["(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트) (z) 수정은 업무 갱신 → 상승 → 감사 순서로 같은 tx 에서 돈다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(z) 수정은 업무 갱신 → 상승 → 감사 순서로 같은 tx 에서 돈다"},{"ancestorTitles":["(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트) (z) 이름·연락처만 바꾼 수정은 상승하지 않는다 (binding 불변)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(z) 이름·연락처만 바꾼 수정은 상승하지 않는다 (binding 불변)"},{"ancestorTitles":["(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트)"],"duration":38,"failureDetails":[],"failureMessages":[],"fullName":"(z) 관리자 계정 쓰기의 상승 위치 (리뷰 R1 MEDIUM · 두 사이트) (z) 비밀번호만 바꾼 수정은 상승하지 않는다 (사용자 결정 · m8b 항목 10)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(z) 비밀번호만 바꾼 수정은 상승하지 않는다 (사용자 결정 · m8b 항목 10)"}],"endTime":1793868742092,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/admin-version-bump.spec.ts","startTime":1793868741962,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 provider: 최고관리자를 포함해 누구에게나 목록과 웹훅 조회의 URL 이 가려진다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"provider: 최고관리자를 포함해 누구에게나 목록과 웹훅 조회의 URL 이 가려진다"},{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 provider: 웹훅 값이 그대로면 판정과 무관하게 단가·한도 수정이 된다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"provider: 웹훅 값이 그대로면 판정과 무관하게 단가·한도 수정이 된다"},{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 레거시 목적지 값을 바꾸는 쓰기는 400 으로 거부되고 아무 값도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"레거시 목적지 값을 바꾸는 쓰기는 400 으로 거부되고 아무 값도 쓰지 않는다"},{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 레거시 목적지 값이 저장된 값과 같으면 (종류 순서 무관) 저장 요청은 통과하고 저장 호출은 없다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"레거시 목적지 값이 저장된 값과 같으면 (종류 순서 무관) 저장 요청은 통과하고 저장 호출은 없다"},{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 저장된 목적지를 읽지 못하면 레거시 목적지 쓰기는 503 으로 거부되고 아무 값도 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"저장된 목적지를 읽지 못하면 레거시 목적지 쓰기는 503 으로 거부되고 아무 값도 쓰지 않는다"},{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 마스킹된 왕복 값은 저장된 원문을 덮지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"마스킹된 왕복 값은 저장된 원문을 덮지 않는다"},{"ancestorTitles":["진료 공급자 설정 — 웹훅 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 설정 — 웹훅 판정 provider: 웹훅 설정 메서드에 최고관리자 가드가 걸려 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"provider: 웹훅 설정 메서드에 최고관리자 가드가 걸려 있다"},{"ancestorTitles":["진료 공급자 표시명 검증 (ADM-SEC-4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 표시명 검증 (ADM-SEC-4) 시드·픽스처 이름과 빈 값은 통과한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"시드·픽스처 이름과 빈 값은 통과한다"},{"ancestorTitles":["진료 공급자 표시명 검증 (ADM-SEC-4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"진료 공급자 표시명 검증 (ADM-SEC-4) 수식 머리(= + - @ 탭 CR)와 50자 초과는 400 이다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"수식 머리(= + - @ 탭 CR)와 50자 초과는 400 이다"}],"endTime":1793868742180,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/provider/treat-provider-admin.controller.spec.ts","startTime":1793868742084,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 목록: 담당 밖 기업 (sagId 5) 의 조직 목록은 403 이고 서비스를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"목록: 담당 밖 기업 (sagId 5) 의 조직 목록은 403 이고 서비스를 부르지 않는다"},{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 목록: 담당 기업 (sagId 4) 은 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"목록: 담당 기업 (sagId 4) 은 통과한다"},{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 목록: 담당 영업이 없는 기업 (sagId null) 은 403 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"목록: 담당 영업이 없는 기업 (sagId null) 은 403 이다"},{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 상세 · 수정 · 이동: 조직이 담당 밖 기업 소속이면 거부하고 쓰기 0회다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"상세 · 수정 · 이동: 조직이 담당 밖 기업 소속이면 거부하고 쓰기 0회다"},{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 수정: 담당 기업 조직이면 서비스를 부른다 (양성)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"수정: 담당 기업 조직이면 서비스를 부른다 (양성)"},{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 상세 · 수정 · 이동 판정은 조직 행만 읽는다 (상세 조회 0회, 반사실: 옛 경로는 상세를 읽어 붉다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상세 · 수정 · 이동 판정은 조직 행만 읽는다 (상세 조회 0회, 반사실: 옛 경로는 상세를 읽어 붉다)"},{"ancestorTitles":["강제 ON · 기업 조직 라우트 (I2 영업 범위)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 조직 라우트 (I2 영업 범위) 기업 번호가 숫자가 아니면 SQL 전에 403 이다 (NaN 을 저장소로 보내지 않는다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"기업 번호가 숫자가 아니면 SQL 전에 403 이다 (NaN 을 저장소로 보내지 않는다)"},{"ancestorTitles":["강제 OFF · 기업 조직 라우트 (응답 불변)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 OFF · 기업 조직 라우트 (응답 불변) OFF: 같은 영업 신원이 담당 밖 기업 목록을 봐도 현행대로 서비스를 부른다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"OFF: 같은 영업 신원이 담당 밖 기업 목록을 봐도 현행대로 서비스를 부른다"}],"endTime":1793868742198,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/organization/organization-admin.scope.spec.ts","startTime":1793868742094,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminSalesCommissionService"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 위반이 있으면 BadRequest 이고 쓰기를 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"위반이 있으면 BadRequest 이고 쓰기를 호출하지 않는다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 생성·종료·대체·삭제 모두 트랜잭션 콜백의 같은 tx 로 잠금·코드 확인·쓰기를 한다","invocations":1,"location":null,"numPassingAsserts":32,"retryReasons":[],"status":"passed","title":"생성·종료·대체·삭제 모두 트랜잭션 콜백의 같은 tx 로 잠금·코드 확인·쓰기를 한다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 서비스는 applyMutations 에 kstToday 반환값을 오늘로 넘긴다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"서비스는 applyMutations 에 kstToday 반환값을 오늘로 넘긴다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 자정을 넘겨 오늘이 바뀌면 쓰기를 롤백한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자정을 넘겨 오늘이 바뀌면 쓰기를 롤백한다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 존재하지 않는 상품코드·채널코드·대상 행은 거부한다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"존재하지 않는 상품코드·채널코드·대상 행은 거부한다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 기업 범위 원가 등록은 기업 코드 실재를 같은 tx 로 확인하고 없으면 BadRequest 이며 쓰기를 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"기업 범위 원가 등록은 기업 코드 실재를 같은 tx 로 확인하고 없으면 BadRequest 이며 쓰기를 호출하지 않는다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 회차 산출은 트랜잭션 콜백의 같은 tx 로 설정 잠금 읽기와 개인 축 행 읽기를 하고 쓰기를 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"회차 산출은 트랜잭션 콜백의 같은 tx 로 설정 잠금 읽기와 개인 축 행 읽기를 하고 쓰기를 호출하지 않는다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 회차 산출은 같은 tx 로 설정 잠금 · 개인 축 행 · 기업 회차 · 기업 주문 행을 차례로 읽고 쓰기를 호출하지 않는다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"회차 산출은 같은 tx 로 설정 잠금 · 개인 축 행 · 기업 회차 · 기업 주문 행을 차례로 읽고 쓰기를 호출하지 않는다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService from·to 가 문자열 실재 날짜가 아니거나(배열·누락 포함) from 이 to 보다 이르지 않으면 BadRequest 이고 DB 를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"from·to 가 문자열 실재 날짜가 아니거나(배열·누락 포함) from 이 to 보다 이르지 않으면 BadRequest 이고 DB 를 읽지 않는다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 구간 상한 — 366일은 산출하고 367일은 BadRequest 이며 DB 를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"구간 상한 — 366일은 산출하고 367일은 BadRequest 이며 DB 를 읽지 않는다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 관리자 식별자가 양의 정수가 아니면 트랜잭션을 열지 않고 거부한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"관리자 식별자가 양의 정수가 아니면 트랜잭션을 열지 않고 거부한다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 일괄 대체는 한 tx 로 잠금 · 새 행마다 코드 확인 · 쓰기 한 번을 하고, 봉인된 변경 하나에 모든 행의 닫기와 새 행이 실린다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"일괄 대체는 한 tx 로 잠금 · 새 행마다 코드 확인 · 쓰기 한 번을 하고, 봉인된 변경 하나에 모든 행의 닫기와 새 행이 실린다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 일괄 대체 중간 행이 실패하면 앞 행이 통과했어도 쓰기를 부르지 않고 롤백한다 — 검증 위반 · 없는 행 · 없는 범위 코드","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"일괄 대체 중간 행이 실패하면 앞 행이 통과했어도 쓰기를 부르지 않고 롤백한다 — 검증 위반 · 없는 행 · 없는 범위 코드"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 일괄 대체 형상 — ids 가 겹치지 않는 양의 정수 1~200개가 아니거나 method 가 FLAT·RATE 가 아니면 트랜잭션을 열지 않고 BadRequest","invocations":1,"location":null,"numPassingAsserts":17,"retryReasons":[],"status":"passed","title":"일괄 대체 형상 — ids 가 겹치지 않는 양의 정수 1~200개가 아니거나 method 가 FLAT·RATE 가 아니면 트랜잭션을 열지 않고 BadRequest"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 월별 산출은 한 tx 로 네 읽기를 구간 전체로 한 번씩 하고, 각 달은 저장소가 그 달로 읽었을 때의 settlements 와 같다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"월별 산출은 한 tx 로 네 읽기를 구간 전체로 한 번씩 하고, 각 달은 저장소가 그 달로 읽었을 때의 settlements 와 같다"},{"ancestorTitles":["AdminSalesCommissionService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionService 월별 산출도 구간 규칙이 같다 — 잘못된 날짜 · 367일은 BadRequest 이고 DB 를 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"월별 산출도 구간 규칙이 같다 — 잘못된 날짜 · 367일은 BadRequest 이고 DB 를 읽지 않는다"}],"endTime":1793868742293,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/sales-commission-admin.service.spec.ts","startTime":1793868742181,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["영업비 정산 접근제어 (hardening M6a DD3·DD4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업비 정산 접근제어 (hardening M6a DD3·DD4) sales: 영업비 컨트롤러에 인증·역할·최고관리자 가드가 순서대로 걸려 있다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"sales: 영업비 컨트롤러에 인증·역할·최고관리자 가드가 순서대로 걸려 있다"},{"ancestorTitles":["영업비 정산 접근제어 (hardening M6a DD3·DD4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업비 정산 접근제어 (hardening M6a DD3·DD4) sales: 판정 전용 permission 핸들러가 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"sales: 판정 전용 permission 핸들러가 없다"}],"endTime":1793868742297,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/sales-commission-access.spec.ts","startTime":1793868742200,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminSalesCommissionController"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController 모든 핸들러가 admin 역할만 허용한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"모든 핸들러가 admin 역할만 허용한다"},{"ancestorTitles":["AdminSalesCommissionController"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminSalesCommissionController 영업비 컨트롤러가 최고관리자 가드를 클래스 가드로 단다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업비 컨트롤러가 최고관리자 가드를 클래스 가드로 단다"}],"endTime":1793868742394,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/sales-commission-admin.controller.spec.ts","startTime":1793868742299,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["(a) 발급 키 집합 · (n) 이행기 · 로그인 경로"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"(a) 발급 키 집합 · (n) 이행기 · 로그인 경로 (a) 네 종류의 발급 키 집합은 현행 키 집합에 pv 한 칸을 더한 것과 같다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"(a) 네 종류의 발급 키 집합은 현행 키 집합에 pv 한 칸을 더한 것과 같다"},{"ancestorTitles":["(a) 발급 키 집합 · (n) 이행기 · 로그인 경로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(a) 발급 키 집합 · (n) 이행기 · 로그인 경로 (n) 버전이 null (이행기) 이면 pv 키가 payload 에 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(n) 버전이 null (이행기) 이면 pv 키가 payload 에 없다"},{"ancestorTitles":["(a) 발급 키 집합 · (n) 이행기 · 로그인 경로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(a) 발급 키 집합 · (n) 이행기 · 로그인 경로 (n) 버전 읽기가 던지면 로그인은 503 이고 sign 을 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(n) 버전 읽기가 던지면 로그인은 503 이고 sign 을 부르지 않는다"},{"ancestorTitles":["(a) 발급 키 집합 · (n) 이행기 · 로그인 경로"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"(a) 발급 키 집합 · (n) 이행기 · 로그인 경로 (p) 발급 순서는 version → lookup → sign 이고, sign 의 pv 는 첫 버전 값이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(p) 발급 순서는 version → lookup → sign 이고, sign 의 pv 는 첫 버전 값이다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (b) admin 토큰의 버전이 같으면 원천 행을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(b) admin 토큰의 버전이 같으면 원천 행을 읽지 않는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (c) admin 토큰의 버전이 다르면 재해석 1회 뒤 재발급하고, exp 는 원 exp 와 같고, pv 는 전역 값이다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"(c) admin 토큰의 버전이 다르면 재해석 1회 뒤 재발급하고, exp 는 원 exp 와 같고, pv 는 전역 값이다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (c) 재발급은 모듈 기본 수명이 있어도 원 exp 로 서명된다 (exp 충돌 없음)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(c) 재발급은 모듈 기본 수명이 있어도 원 exp 로 서명된다 (exp 충돌 없음)"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (c) exp 없는 admin 토큰은 버전이 달라도 재발급하지 않고 401 이다 (쿠키를 쓰지 않는다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(c) exp 없는 admin 토큰은 버전이 달라도 재발급하지 않고 401 이다 (쿠키를 쓰지 않는다)"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (d) 재발급받은 admin 토큰의 다음 요청은 원천 행을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(d) 재발급받은 admin 토큰의 다음 요청은 원천 행을 읽지 않는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (e) admin 행이 없으면 401 이고 쿠키가 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(e) admin 행이 없으면 401 이고 쿠키가 바뀌지 않는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (f) 조직관리자가 memIsOrgManager 0 · memIsResigned 1 · orgPath 없음 중 하나면 401 이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"(f) 조직관리자가 memIsOrgManager 0 · memIsResigned 1 · orgPath 없음 중 하나면 401 이다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (g) 조직관리자의 orgPath 가 토큰과 DB 에서 다르면 재발급 토큰에 DB 값이 실린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(g) 조직관리자의 orgPath 가 토큰과 DB 에서 다르면 재발급 토큰에 DB 값이 실린다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (h) pv 가 없는 구 admin 토큰은 재해석 1회 뒤 재발급된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(h) pv 가 없는 구 admin 토큰은 재해석 1회 뒤 재발급된다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (i) 재발급 토큰은 구 서버의 판정 함수에서 같은 종류로 통과한다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"(i) 재발급 토큰은 구 서버의 판정 함수에서 같은 종류로 통과한다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (j) admin 행의 athId 가 null 이어도 가드는 401 을 내지 않는다 (판정은 평가기 몫)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(j) admin 행의 athId 가 null 이어도 가드는 401 을 내지 않는다 (판정은 평가기 몫)"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (k) 재해석 중 버전이 다시 올랐다면 다음 요청이 다시 재해석한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(k) 재해석 중 버전이 다시 올랐다면 다음 요청이 다시 재해석한다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (l) 버전 읽기가 판정 불가를 던지면 가드는 503 이고 쿠키가 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(l) 버전 읽기가 판정 불가를 던지면 가드는 503 이고 쿠키가 바뀌지 않는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (s) 선택적 가드: 행 부재 · 판정 불가는 req.admin 을 채우지 않고 true 를 돌려주며 쿠키를 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(s) 선택적 가드: 행 부재 · 판정 불가는 req.admin 을 채우지 않고 true 를 돌려주며 쿠키를 건드리지 않는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (s) 선택적 가드: 정상 행은 DB 값 클레임을 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(s) 선택적 가드: 정상 행은 DB 값 클레임을 싣는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (범위) 영업 · 기업 · 조직 토큰은 요청마다 원천을 대조한다 — 버전이 같아도 행을 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(범위) 영업 · 기업 · 조직 토큰은 요청마다 원천을 대조한다 — 버전이 같아도 행을 읽는다"},{"ancestorTitles":["(b)~(k) 필수 가드 재해석 · 재발급"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"(b)~(k) 필수 가드 재해석 · 재발급 (범위) 범위 키가 원천 값과 다르면 재발급 토큰에 원천 값이 실린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(범위) 범위 키가 원천 값과 다르면 재발급 토큰에 원천 값이 실린다"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (m) 상승은 갱신 행 수가 1 이 아니면 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(m) 상승은 갱신 행 수가 1 이 아니면 던진다"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (q) 조직관리자 자격 표: 자격이 빠진 행은 null 이다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"(q) 조직관리자 자격 표: 자격이 빠진 행은 null 이다"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (q) 조직관리자 로그인 ID 가 없는 기업 (nullable) 도 자격을 잃지 않는다 — 로그인 조회와 같은 조건","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(q) 조직관리자 로그인 ID 가 없는 기업 (nullable) 도 자격을 잃지 않는다 — 로그인 조회와 같은 조건"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (q) 통과한 행의 클레임은 범위 키를 행의 값으로 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(q) 통과한 행의 클레임은 범위 키를 행의 값으로 싣는다"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (r) 이행기 (버전 null): admin 은 payload 를 그대로 주고 재발급하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(r) 이행기 (버전 null): admin 은 payload 를 그대로 주고 재발급하지 않는다"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (r) 이행기: 영업 행 부재와 조직관리자 자격 상실은 버전이 null 이어도 거부다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(r) 이행기: 영업 행 부재와 조직관리자 자격 상실은 버전이 null 이어도 거부다"},{"ancestorTitles":["(m) 상승 · (q) 자격 표 · (r) 이행기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(m) 상승 · (q) 자격 표 · (r) 이행기 (r) 이행기: 범위 종류는 원천을 그래도 대조하고 재발급하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"(r) 이행기: 범위 종류는 원천을 그래도 대조하고 재발급하지 않는다"},{"ancestorTitles":["(t) readGlobalVersion 분류 (실제 구현)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(t) readGlobalVersion 분류 (실제 구현) (t) 표 이름이 맞는 1146 은 null 이다 (이행기)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(t) 표 이름이 맞는 1146 은 null 이다 (이행기)"},{"ancestorTitles":["(t) readGlobalVersion 분류 (실제 구현)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(t) readGlobalVersion 분류 (실제 구현) (t) 칸 이름이 맞는 1054 는 null 이다 (이행기)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(t) 칸 이름이 맞는 1054 는 null 이다 (이행기)"},{"ancestorTitles":["(t) readGlobalVersion 분류 (실제 구현)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(t) readGlobalVersion 분류 (실제 구현) (t) 이름이 다른 1146 은 던진다 (바깥 문장이 표 이름을 담아도 안쪽 메시지로 본다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(t) 이름이 다른 1146 은 던진다 (바깥 문장이 표 이름을 담아도 안쪽 메시지로 본다)"},{"ancestorTitles":["(t) readGlobalVersion 분류 (실제 구현)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(t) readGlobalVersion 분류 (실제 구현) (t) 이름이 다른 1054 는 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(t) 이름이 다른 1054 는 던진다"},{"ancestorTitles":["(t) readGlobalVersion 분류 (실제 구현)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(t) readGlobalVersion 분류 (실제 구현) (t) ER_NO_SUCH_TABLE 코드만 있고 이름이 없으면 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(t) ER_NO_SUCH_TABLE 코드만 있고 이름이 없으면 던진다"},{"ancestorTitles":["(t) readGlobalVersion 분류 (실제 구현)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(t) readGlobalVersion 분류 (실제 구현) (t) 그 밖의 오류 · 행 없음 · 정수가 아닌 값은 던진다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(t) 그 밖의 오류 · 행 없음 · 정수가 아닌 값은 던진다"},{"ancestorTitles":["(o) 쿠키 옵션"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(o) 쿠키 옵션 (o) 종류 네 개 × NODE_ENV 두 값에서 현행 리터럴과 같다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"(o) 종류 네 개 × NODE_ENV 두 값에서 현행 리터럴과 같다"},{"ancestorTitles":["(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그 (w) 이행기 (버전 null) 는 요청마다 warn 한 줄을 남긴다 — admin 이 payload 를 그대로 받아도","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(w) 이행기 (버전 null) 는 요청마다 warn 한 줄을 남긴다 — admin 이 payload 를 그대로 받아도"},{"ancestorTitles":["(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그 (w) 버전이 정해진 상태에서는 이행기 warn 을 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(w) 버전이 정해진 상태에서는 이행기 warn 을 남기지 않는다"},{"ancestorTitles":["(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그 (x) 종류와 행 모양이 다르면 자격이 없다 (null) — 빈 클레임을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(x) 종류와 행 모양이 다르면 자격이 없다 (null) — 빈 클레임을 만들지 않는다"},{"ancestorTitles":["(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그 (x) nullable 로그인 ID 는 null 로 그대로 싣는다 (캐스트로 지우지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(x) nullable 로그인 ID 는 null 로 그대로 싣는다 (캐스트로 지우지 않는다)"},{"ancestorTitles":["(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(w) 이행기 로그 · (x) 종류별 행 모양 · (y) 선택적 가드 로그 (y) 선택적 가드: 판정 불가는 warn, 그 밖의 오류는 error 로그를 남기고 익명으로 통과한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"(y) 선택적 가드: 판정 불가는 warn, 그 밖의 오류는 error 로그를 남기고 익명으로 통과한다"}],"endTime":1793868742399,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/admin-token-version.spec.ts","startTime":1793868742297,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 저장 검증 — 잔여 항목의 유효기간이 겹치면 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"저장 검증 — 잔여 항목의 유효기간이 겹치면 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 저장 검증 — 잔여 행 합집합이 끊기거나 끝이 무기한이 아니면 거부한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"저장 검증 — 잔여 행 합집합이 끊기거나 끝이 무기한이 아니면 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 저장 검증 — 잔여 시작일 이전에 시작하는 원가·보상 행은 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"저장 검증 — 잔여 시작일 이전에 시작하는 원가·보상 행은 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 저장 검증 — 같은 수취인·적용범위의 유효기간이 겹치면 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"저장 검증 — 같은 수취인·적용범위의 유효기간이 겹치면 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 저장 검증 — 허용 밖 수취인·산정방식·적용범위 조합과 값 형상을 거부한다","invocations":1,"location":null,"numPassingAsserts":77,"retryReasons":[],"status":"passed","title":"저장 검증 — 허용 밖 수취인·산정방식·적용범위 조합과 값 형상을 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 원가 > 판매 공급가액 — 저장 검증은 상품 가격을 보지 않는다: 판매가보다 큰 정액 원가 · 원가와 보상 정률 합 100% 초과도 저장된다(R17-A 사용자 답 2)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"원가 > 판매 공급가액 — 저장 검증은 상품 가격을 보지 않는다: 판매가보다 큰 정액 원가 · 원가와 보상 정률 합 100% 초과도 저장된다(R17-A 사용자 답 2)"},{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 대체·종료 본문은 자기 필드만 읽는다 — 수취인·적용범위를 실어도 기존 행 값을 물려받는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"대체·종료 본문은 자기 필드만 읽는다 — 수취인·적용범위를 실어도 기존 행 값을 물려받는다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 과거 불변 — 오늘 이전·오늘 시작일 생성, 오늘까지 효력 있는 행 삭제, 오늘 이하로 당긴 종료를 거부한다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"과거 불변 — 오늘 이전·오늘 시작일 생성, 오늘까지 효력 있는 행 삭제, 오늘 이하로 당긴 종료를 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 과거 불변 — 오늘 시작한 행의 같은 날 삭제·대체를 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"과거 불변 — 오늘 시작한 행의 같은 날 삭제·대체를 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 과거 불변 — 이미 끝난 행의 종료일을 늘리는 종료·대체를 거부한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"과거 불변 — 이미 끝난 행의 종료일을 늘리는 종료·대체를 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 커버리지 역방향 — 잔여 행의 종료·삭제가 잔여 공백을 만들면 거부한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"커버리지 역방향 — 잔여 행의 종료·삭제가 잔여 공백을 만들면 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 대체 — 잔여 행을 끊김 없이 교체하고 새 행은 기존 종료일을 물려받는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"대체 — 잔여 행을 끊김 없이 교체하고 새 행은 기존 종료일을 물려받는다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 대체 — 효력 전 예정 행을 같은 시작일로 대체하면 기존 행이 삭제된다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"대체 — 효력 전 예정 행을 같은 시작일로 대체하면 기존 행이 삭제된다"},{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 오늘 — kstToday 는 프로세스 시간대와 무관하게 UTC+9 날짜다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"오늘 — kstToday 는 프로세스 시간대와 무관하게 UTC+9 날짜다"},{"ancestorTitles":["deduction-rules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules AcceptedMutation 은 위반이 있으면 만들어지지 않는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"AcceptedMutation 은 위반이 있으면 만들어지지 않는다"},{"ancestorTitles":["deduction-rules"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules AcceptedMutation — 캐스트로 만든 객체와 복제본은 assertAccepted 가 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"AcceptedMutation — 캐스트로 만든 객체와 복제본은 assertAccepted 가 거부한다"},{"ancestorTitles":["deduction-rules"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 기업 범위 원가 — HQ 수취인에만 CORPORATE 범위가 허용되고 채널·대리점 수취인의 CORPORATE 행은 거부된다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"기업 범위 원가 — HQ 수취인에만 CORPORATE 범위가 허용되고 채널·대리점 수취인의 CORPORATE 행은 거부된다"},{"ancestorTitles":["deduction-rules"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules 기업 범위 원가 — 같은 기업 코드의 유효기간 겹침은 거부되고 같은 기간의 상품 범위 행과는 겹침이 아니다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기업 범위 원가 — 같은 기업 코드의 유효기간 겹침은 거부되고 같은 기간의 상품 범위 행과는 겹침이 아니다"},{"ancestorTitles":["deduction-rules — 일괄 대체 applyMutations (R11-A)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules — 일괄 대체 applyMutations (R11-A) 행마다 단건 대체를 차례로 적용한 결과를 하나로 봉인한다 — 닫기·지우기·새 행이 단건 결과를 이어 붙인 것과 같다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"행마다 단건 대체를 차례로 적용한 결과를 하나로 봉인한다 — 닫기·지우기·새 행이 단건 결과를 이어 붙인 것과 같다"},{"ancestorTitles":["deduction-rules — 일괄 대체 applyMutations (R11-A)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules — 일괄 대체 applyMutations (R11-A) 한 행이라도 위반이면 accepted 가 없다 — 앞 행이 통과했어도 쓰기 대상이 0 이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"한 행이라도 위반이면 accepted 가 없다 — 앞 행이 통과했어도 쓰기 대상이 0 이다"},{"ancestorTitles":["deduction-rules — 일괄 대체 applyMutations (R11-A)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules — 일괄 대체 applyMutations (R11-A) 같은 행을 두 번 겨누면 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 행을 두 번 겨누면 거부한다"},{"ancestorTitles":["deduction-rules — 일괄 대체 applyMutations (R11-A)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"deduction-rules — 일괄 대체 applyMutations (R11-A) 지금 값과 같은 새 값도 단건 대체처럼 받는다 — 같은 값 행이 날짜로 쪼개질 뿐이다(이중 리뷰 판정)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"지금 값과 같은 새 값도 단건 대체처럼 받는다 — 같은 값 행이 날짜로 쪼개질 뿐이다(이중 리뷰 판정)"}],"endTime":1793868742439,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/sales-commission/deduction-rules.spec.ts","startTime":1793868742401,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 적용 시작일은 서울 기준 내일 이후만 받는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"적용 시작일은 서울 기준 내일 이후만 받는다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 수정도 적용 시작일이 서울 기준 내일 이후여야 한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"수정도 적용 시작일이 서울 기준 내일 이후여야 한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 수정 본문에 agcId 를 담으면 ValidationPipe 가 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수정 본문에 agcId 를 담으면 ValidationPipe 가 거부한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 수정 UPDATE 가 0행이면 구간 행을 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"수정 UPDATE 가 0행이면 구간 행을 건드리지 않는다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 수정은 버전 행과 구간 행을 한 트랜잭션에서 쓴다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"수정은 버전 행과 구간 행을 한 트랜잭션에서 쓴다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 수정 UPDATE 의 WHERE 에 적용 시작일이 서울 오늘보다 뒤라는 조건이 들어간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"수정 UPDATE 의 WHERE 에 적용 시작일이 서울 오늘보다 뒤라는 조건이 들어간다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 상태는 서울 오늘 기준으로 적용 예정·적용 중·지난 버전으로 계산한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상태는 서울 오늘 기준으로 적용 예정·적용 중·지난 버전으로 계산한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 수정 가능은 적용 예정 버전에만 참이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"수정 가능은 적용 예정 버전에만 참이다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 새 버전 시작일 하한은 서울 기준 내일이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"새 버전 시작일 하한은 서울 기준 내일이다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 구간의 상품 id 가 없는 상품이면 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"구간의 상품 id 가 없는 상품이면 거부한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 적용 중이거나 지난 버전은 수정과 삭제를 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적용 중이거나 지난 버전은 수정과 삭제를 거부한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 구간별 상품 버전은 겹치지 않는 구간이 한 개 이상 있어야 한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"구간별 상품 버전은 겹치지 않는 구간이 한 개 이상 있어야 한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 계약 상품 버전에 구간을 보내면 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"계약 상품 버전에 구간을 보내면 거부한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 사용 FC 기준 청구를 저장한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"사용 FC 기준 청구를 저장한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 사용 FC 기준은 청구 명세를 내는 기업에만 저장한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"사용 FC 기준은 청구 명세를 내는 기업에만 저장한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 정책 조회 응답이 사용 FC 기준을 고를 수 있는 기업인지 알려 준다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정책 조회 응답이 사용 FC 기준을 고를 수 있는 기업인지 알려 준다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 정책 조회 응답이 처음 명세 달의 계약 단가를 싣는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"정책 조회 응답이 처음 명세 달의 계약 단가를 싣는다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 같은 기업의 같은 적용 시작일 버전을 거부한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"같은 기업의 같은 적용 시작일 버전을 거부한다"},{"ancestorTitles":["AgencyPolicyService 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 규칙 정책 쓰기 요청은 JSON 본문만 받는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"정책 쓰기 요청은 JSON 본문만 받는다"},{"ancestorTitles":["AgencyPolicyService 목록 검색·필터(M5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 목록 검색·필터(M5) 목록은 검색어·필터·서울 오늘을 리포지터리에 그대로 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"목록은 검색어·필터·서울 오늘을 리포지터리에 그대로 넘긴다"},{"ancestorTitles":["AgencyPolicyService 목록 검색·필터(M5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 목록 검색·필터(M5) 목록은 기업마다 적용 중 버전을 따로 고른다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"목록은 기업마다 적용 중 버전을 따로 고른다"},{"ancestorTitles":["AgencyPolicyService 목록 검색·필터(M5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyService 목록 검색·필터(M5) 허용값 밖 policyFilter 는 DTO 검증에서 거부된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"허용값 밖 policyFilter 는 DTO 검증에서 거부된다"}],"endTime":1793868742499,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/policy/policy.service.spec.ts","startTime":1793868742399,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["관리자 신규등록 — 최고관리자 전용"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 신규등록 — 최고관리자 전용 protect: 최고관리자가 지정된 환경에서 최고관리자가 아닌 관리자가 생성하면 E0827 로 거부하고 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"protect: 최고관리자가 지정된 환경에서 최고관리자가 아닌 관리자가 생성하면 E0827 로 거부하고 쓰지 않는다"},{"ancestorTitles":["관리자 신규등록 — 최고관리자 전용"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 신규등록 — 최고관리자 전용 protect: 최고관리자는 생성할 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"protect: 최고관리자는 생성할 수 있다"},{"ancestorTitles":["관리자 신규등록 — 최고관리자 전용"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 신규등록 — 최고관리자 전용 비파괴: 최고관리자 미지정 환경은 수정·삭제와 같게 통과시킨다(단일 공용관리자 모델, #75)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비파괴: 최고관리자 미지정 환경은 수정·삭제와 같게 통과시킨다(단일 공용관리자 모델, #75)"},{"ancestorTitles":["관리자 신규등록 — 최고관리자 전용"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 신규등록 — 최고관리자 전용 wiring: 생성 핸들러가 요청자 신원을 서비스에 넘긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"wiring: 생성 핸들러가 요청자 신원을 서비스에 넘긴다"}],"endTime":1793868742602,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/admin-create-super.spec.ts","startTime":1793868742440,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertMonitorService — GET /monitor 조립(M3 §D8)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"AlertMonitorService — GET /monitor 조립(M3 §D8) 응답 전체에 원문 웹훅 URL 이 없다 (UI8 · R5-F1)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"응답 전체에 원문 웹훅 URL 이 없다 (UI8 · R5-F1)"},{"ancestorTitles":["AlertMonitorService — GET /monitor 조립(M3 §D8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertMonitorService — GET /monitor 조립(M3 §D8) 판정 결과와 서버 시각을 함께 낸다 — 화면이 임계를 계산하지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"판정 결과와 서버 시각을 함께 낸다 — 화면이 임계를 계산하지 않는다"},{"ancestorTitles":["AlertMonitorService — GET /monitor 조립(M3 §D8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertMonitorService — GET /monitor 조립(M3 §D8) 이력 조회 실패는 available:false 이고 판정이 초록으로 남지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이력 조회 실패는 available:false 이고 판정이 초록으로 남지 않는다"},{"ancestorTitles":["AlertMonitorService — GET /monitor 조립(M3 §D8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertMonitorService — GET /monitor 조립(M3 §D8) 규칙 ON/OFF 는 규칙 수와 무관하게 조회 1회다 (N+1 회귀 방지)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"규칙 ON/OFF 는 규칙 수와 무관하게 조회 1회다 (N+1 회귀 방지)"},{"ancestorTitles":["AlertMonitorService — GET /monitor 조립(M3 §D8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertMonitorService — GET /monitor 조립(M3 §D8) 채널별 이력 조회는 채널 수만큼 나되 동시에 나간다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"채널별 이력 조회는 채널 수만큼 나되 동시에 나간다"}],"endTime":1793868742627,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-monitor.service.spec.ts","startTime":1793868742501,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 가드가 던진 401 은 UNKNOWN 행위자로 남는다 — 검증 실패한 토큰은 신원이 아니다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"가드가 던진 401 은 UNKNOWN 행위자로 남는다 — 검증 실패한 토큰은 신원이 아니다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 403 은 실제 행위자로 남는다 — 이쪽이 조사 가치가 훨씬 높다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"403 은 실제 행위자로 남는다 — 이쪽이 조사 가치가 훨씬 높다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 /admin/ 밖 경로는 기록하지 않는다 — 이 축의 범위는 관리자 경로다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"/admin/ 밖 경로는 기록하지 않는다 — 이 축의 범위는 관리자 경로다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 400 는 거부 축이 아니므로 이 층이 기록하지 않는다 — T2 인터셉터가 진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"400 는 거부 축이 아니므로 이 층이 기록하지 않는다 — T2 인터셉터가 진다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 500 는 거부 축이 아니므로 이 층이 기록하지 않는다 — T2 인터셉터가 진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"500 는 거부 축이 아니므로 이 층이 기록하지 않는다 — T2 인터셉터가 진다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 비 HttpException 는 거부 축이 아니므로 이 층이 기록하지 않는다 — T2 인터셉터가 진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비 HttpException 는 거부 축이 아니므로 이 층이 기록하지 않는다 — T2 인터셉터가 진다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 행위 어휘와 요청 식별자가 T2 층과 같다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"행위 어휘와 요청 식별자가 T2 층과 같다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 서비스 계층이 던진 401 은 실제 행위자가 실린다 — 상태코드가 조건이 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"서비스 계층이 던진 401 은 실제 행위자가 실린다 — 상태코드가 조건이 아니다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 감사 층이 주입되지 않아도 응답 경로는 그대로다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"감사 층이 주입되지 않아도 응답 경로는 그대로다"},{"ancestorTitles":["AllExceptionFilter — 가드 거부를 기록한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AllExceptionFilter — 가드 거부를 기록한다 감사 줄이 던져도 응답이 막히지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"감사 줄이 던져도 응답이 막히지 않는다"}],"endTime":1793868742711,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/fliters/all-exception.filter.spec.ts","startTime":1793868742604,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) 건강+자동차 성공 → data 2건, 자동차 전용필드 정확 매핑, 호출 2회","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"건강+자동차 성공 → data 2건, 자동차 전용필드 정확 매핑, 호출 2회"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) 자동차 자료없음(errYn=N, 빈 list) → 성공, 자동차 빈값","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 자료없음(errYn=N, 빈 list) → 성공, 자동차 빈값"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) 자동차 수집실패(errYn=Y) → 전체 실패","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자동차 수집실패(errYn=Y) → 전체 실패"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) 자동차 미요청 → 호출 1회, data 1건","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"자동차 미요청 → 호출 1회, data 1건"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) 건강 수집실패 → 전체 실패, 자동차 호출 안 함","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"건강 수집실패 → 전체 실패, 자동차 호출 안 함"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) 세션(jti) 복원 실패 → CF-12000, post 미호출","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"세션(jti) 복원 실패 → CF-12000, post 미호출"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) split=2 → 건강 2구간 순차 수집·병합, cookieData 구간 간 체이닝, 자동차 미요청","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"split=2 → 건강 2구간 순차 수집·병합, cookieData 구간 간 체이닝, 자동차 미요청"},{"ancestorTitles":["HyphenService.fetchTreatmentMultiple (자동차 B0003 연동)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"HyphenService.fetchTreatmentMultiple (자동차 B0003 연동) split=2, 2구간 수집실패 → 전체 실패(부분 저장 안 함)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"split=2, 2구간 수집실패 → 전체 실패(부분 저장 안 함)"}],"endTime":1793868742727,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/hyphen/src/hyphen.service.spec.ts","startTime":1793868742629,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 전 구간 42110000 → 빈 분석 성공(CF-00000, 빈 리스트, 환불 안 됨)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전 구간 42110000 → 빈 분석 성공(CF-00000, 빈 리스트, 환불 안 됨)"},{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 분할 2구간 중 1구간만 42110000 → 있는 구간은 살리고 성공","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"분할 2구간 중 1구간만 42110000 → 있는 구간은 살리고 성공"},{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 8000F101(기관 무응답)은 그대로 실패 처리","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"8000F101(기관 무응답)은 그대로 실패 처리"},{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 건강+자동차 성공 → data 2건, 자동차 전용필드(진료일수/자동차보험총진료비) 매핑","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"건강+자동차 성공 → data 2건, 자동차 전용필드(진료일수/자동차보험총진료비) 매핑"},{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 자동차 자료없음(42110000) → 성공, 자동차 미저장(data 1건)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 자료없음(42110000) → 성공, 자동차 미저장(data 1건)"},{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 자동차 수집실패(8000F101)여도 건강 성공은 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 수집실패(8000F101)여도 건강 성공은 유지한다"},{"ancestorTitles":["CooconService 자료없음(42110000) 처리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CooconService 자료없음(42110000) 처리 자동차 호출 예외여도 건강 성공은 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자동차 호출 예외여도 건강 성공은 유지한다"}],"endTime":1793868742817,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/coocon/src/coocon.service.spec.ts","startTime":1793868742714,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ClientSettlementService.create — 건별 줄"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ClientSettlementService.create — 건별 줄 커밋된 정산마다 거래처 · 금액 · 주문상세 수를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"커밋된 정산마다 거래처 · 금액 · 주문상세 수를 싣는다"},{"ancestorTitles":["ClientSettlementService.create — 건별 줄"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"ClientSettlementService.create — 건별 줄 둘째 정산이 던지면 첫째 커밋 줄과 둘째 실패 줄을 낸 뒤 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"둘째 정산이 던지면 첫째 커밋 줄과 둘째 실패 줄을 낸 뒤 던진다"}],"endTime":1793868742822,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/client/settlement/settlement-audit.spec.ts","startTime":1793868742729,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 조직관리자 · POST · @AllowOrgWrite 없음 → 조직관리자만 빠진다, 있으면 들어간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"조직관리자 · POST · @AllowOrgWrite 없음 → 조직관리자만 빠진다, 있으면 들어간다"},{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 신원 종류 낱말: corp-super 만 받는 핸들러에 조직관리자 · 영업은 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"신원 종류 낱말: corp-super 만 받는 핸들러에 조직관리자 · 영업은 없다"},{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 SuperAdminGuard → 비관리자 전부 제외, CarViewAdminGuard → 영업만 제외","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"SuperAdminGuard → 비관리자 전부 제외, CarViewAdminGuard → 영업만 제외"},{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 분석 수준은 기업 종류 행에만 싣는다 (영업은 수준 없음)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"분석 수준은 기업 종류 행에만 싣는다 (영업은 수준 없음)"},{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 모르는 가드 → 표에서 빠지고 제외 목록에 이름이 남는다 (음성)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"모르는 가드 → 표에서 빠지고 제외 목록에 이름이 남는다 (음성)"},{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 AdminJwtAuthGuard 가 없는 핸들러(회원 JwtAuthGuard 등)는 표에도 제외 목록에도 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard 가 없는 핸들러(회원 JwtAuthGuard 등)는 표에도 제외 목록에도 없다"},{"ancestorTitles":["비관리자 엔드포인트 표 — 알려진 가드 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비관리자 엔드포인트 표 — 알려진 가드 표 골든 한 줄 = 정확 키 \\t 종류 목록 (@n = 분석 수준)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"골든 한 줄 = 정확 키 \\t 종류 목록 (@n = 분석 수준)"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 표의 가드 이름 집합 = 이 동등성 시험이 만드는 가드 집합","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표의 가드 이름 집합 = 이 동등성 시험이 만드는 가드 집합"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AdminJwtAuthGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AdminJwtAuthGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 RolesGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"RolesGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpReadonlyGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpReadonlyGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CorpAnalysisViewGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CorpAnalysisViewGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AnalysisRowGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AnalysisRowGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 SuperAdminGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SuperAdminGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 CarViewAdminGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CarViewAdminGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 OriginCheckGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OriginCheckGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · sales · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · sales · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · sales · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · sales · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · sales · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · sales · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · sales · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · sales · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · corp-super · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · corp-super · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · corp-super · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · corp-super · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · corp-super · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · corp-super · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · corp-super · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · corp-super · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · org-manager · GET · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · org-manager · GET · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · org-manager · GET · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · org-manager · GET · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · org-manager · POST · 메타 false","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · org-manager · POST · 메타 false"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 AgencyPolicyJsonBodyGuard · org-manager · POST · 메타 true","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"AgencyPolicyJsonBodyGuard · org-manager · POST · 메타 true"},{"ancestorTitles":["알려진 가드 표 = 실제 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"알려진 가드 표 = 실제 가드 분석 수준: 실제 가드는 기업 값 < 요구 수준이면 기업 종류를 막고, 표는 그 요구 수준을 행에 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"분석 수준: 실제 가드는 기업 값 < 요구 수준이면 기업 종류를 막고, 표는 그 요구 수준을 행에 싣는다"}],"endTime":1793868742905,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-contract/identity-endpoints.spec.ts","startTime":1793868742819,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminAllowIpController 접근제어"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAllowIpController 접근제어 관리 컨트롤러에 관리자 인증·역할 가드와 admin 역할이 걸려 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리 컨트롤러에 관리자 인증·역할 가드와 admin 역할이 걸려 있다"}],"endTime":1793868742922,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/allow-ip/allow-ip-admin.controller.spec.ts","startTime":1793868742824,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["car-view reconcile --out 배선"],"duration":34,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile --out 배선 [M11] --out 서버 루트 아래 경로는 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] --out 서버 루트 아래 경로는 거부한다"},{"ancestorTitles":["car-view reconcile --out 배선"],"duration":27,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile --out 배선 [M11] --out 상위 워크트리 루트 아래 경로는 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] --out 상위 워크트리 루트 아래 경로는 거부한다"},{"ancestorTitles":["car-view reconcile --out 배선"],"duration":17,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile --out 배선 [M11] --out 워크트리 밖 경로는 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] --out 워크트리 밖 경로는 허용한다"}],"endTime":1793868743007,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/seeds/car-view-reconcile.spec.ts","startTime":1793868742908,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["계약 저장과 옛 구간"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"계약 저장과 옛 구간 계약 저장은 initialPlans 를 받아도 구간 행을 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"계약 저장은 initialPlans 를 받아도 구간 행을 쓰지 않는다"},{"ancestorTitles":["계약 저장과 옛 구간"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"계약 저장과 옛 구간 옛 관리자 화면의 계약 저장 본문을 ValidationPipe 가 통과시킨다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"옛 관리자 화면의 계약 저장 본문을 ValidationPipe 가 통과시킨다"}],"endTime":1793868743015,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/contract/contract-initial-plan-ignored.spec.ts","startTime":1793868742927,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["초대별 분석 상태 조회 격리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"초대별 분석 상태 조회 격리 초대 invite-a와 요청 20를 모두 조건에 포함한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"초대 invite-a와 요청 20를 모두 조건에 포함한다"},{"ancestorTitles":["초대별 분석 상태 조회 격리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"초대별 분석 상태 조회 격리 초대 invite-b와 요청 21를 모두 조건에 포함한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"초대 invite-b와 요청 21를 모두 조건에 포함한다"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"리마인드 요청은 이름·번호 대체 없이 정확한 초대의 최신 최초 인증만 조회한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"리마인드 요청은 이름·번호 대체 없이 정확한 초대의 최신 최초 인증만 조회한다"}],"endTime":1793868743096,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alimtalk/alimtalk.repository.spec.ts","startTime":1793868743009,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 관리 컨트롤러 배선"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 관리 컨트롤러 배선 가드 순서는 인증 · 역할 · 최고관리자 판정이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가드 순서는 인증 · 역할 · 최고관리자 판정이다"},{"ancestorTitles":["권한 관리 컨트롤러 배선"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 관리 컨트롤러 배선 역할 메타데이터는 admin 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할 메타데이터는 admin 이다"},{"ancestorTitles":["권한 관리 컨트롤러 배선"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 관리 컨트롤러 배선 모든 POST 는 OriginCheckGuard 를 단다 (역할 생성 · 역할 저장 · binding)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모든 POST 는 OriginCheckGuard 를 단다 (역할 생성 · 역할 저장 · binding)"},{"ancestorTitles":["권한 관리 컨트롤러 배선"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 관리 컨트롤러 배선 읽기 경로 (카탈로그 · 역할 · 영향 · 이력) 가 컨트롤러에 있다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"읽기 경로 (카탈로그 · 역할 · 영향 · 이력) 가 컨트롤러에 있다"},{"ancestorTitles":["권한 관리 컨트롤러 배선"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 관리 컨트롤러 배선 PermissionAdminController 는 AuthorityModule 에 등록된다 (E2 활성화)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"PermissionAdminController 는 AuthorityModule 에 등록된다 (E2 활성화)"},{"ancestorTitles":["권한 관리 컨트롤러 배선"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"권한 관리 컨트롤러 배선 어느 다른 *.module.ts 에도 등록되지 않는다 (등록 자리는 한 곳)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"어느 다른 *.module.ts 에도 등록되지 않는다 (등록 자리는 한 곳)"},{"ancestorTitles":["권한 카탈로그 응답 (E5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 카탈로그 응답 (E5) 칸 코드 키 구조이고 권한 쓰기 칸의 최고관리자 전용 여부를 준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"칸 코드 키 구조이고 권한 쓰기 칸의 최고관리자 전용 여부를 준다"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 영향 미리보기의 codes 가 같은 키 반복 (배열) 이면 500 이 아니라 400 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영향 미리보기의 codes 가 같은 키 반복 (배열) 이면 500 이 아니라 400 이다"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 menus 가 없으면 400 이고 서비스를 부르지 않는다 (전 권한 삭제로 해석하지 않는다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"menus 가 없으면 400 이고 서비스를 부르지 않는다 (전 권한 삭제로 해석하지 않는다)"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 menus 는 {menuCode, level} 배열이고 level 은 full 또는 read 다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"menus 는 {menuCode, level} 배열이고 level 은 full 또는 read 다"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 명시적 빈 배열은 허용되고, 칸 목록은 서비스로 넘어간다 (이름 없으면 이름 undefined)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"명시적 빈 배열은 허용되고, 칸 목록은 서비스로 넘어간다 (이름 없으면 이름 undefined)"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 역할 이름이 있으면 trim 해서 넘기고, 빈 이름 · 21자 이상은 400 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"역할 이름이 있으면 trim 해서 넘기고, 빈 이름 · 21자 이상은 400 이다"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 expectedVersion 이 없거나 정수가 아니면 400 이고 서비스를 부르지 않는다 (낡은 저장 차단의 입력 계약)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"expectedVersion 이 없거나 정수가 아니면 400 이고 서비스를 부르지 않는다 (낡은 저장 차단의 입력 계약)"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 역할 생성은 이름과 칸 목록을 받고 이름이 없으면 400 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"역할 생성은 이름과 칸 목록을 받고 이름이 없으면 400 이다"},{"ancestorTitles":["권한 쓰기 컨트롤러 입력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 컨트롤러 입력 binding 본문은 양의 정수 또는 null (회수) 만 받는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"binding 본문은 양의 정수 또는 null (회수) 만 받는다"}],"endTime":1793868743164,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-admin.controller.spec.ts","startTime":1793868743016,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlertRepository — 발송 이력(M3 §D1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 발송 이력(M3 §D1) insertHistory 는 마스킹된 URL 만 싣고 원문 컬럼을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"insertHistory 는 마스킹된 URL 만 싣고 원문 컬럼을 만들지 않는다"},{"ancestorTitles":["AlertRepository — 발송 이력(M3 §D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 발송 이력(M3 §D1) insertHistory 는 컬럼 상한을 넘는 값을 잘라 INSERT 가 길이로 실패하지 않게 한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"insertHistory 는 컬럼 상한을 넘는 값을 잘라 INSERT 가 길이로 실패하지 않게 한다"},{"ancestorTitles":["AlertRepository — 발송 이력(M3 §D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 발송 이력(M3 §D1) findRecentHistory 는 최신순 상한을 지키고 0 이하 요청도 1건으로 눌러 준다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"findRecentHistory 는 최신순 상한을 지키고 0 이하 요청도 1건으로 눌러 준다"},{"ancestorTitles":["AlertRepository — 발송 이력(M3 §D1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 발송 이력(M3 §D1) findRecentHistoryByChannel 은 채널 조건을 걸어 전역 창과 다른 표본을 만든다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"findRecentHistoryByChannel 은 채널 조건을 걸어 전역 창과 다른 표본을 만든다"},{"ancestorTitles":["AlertRepository — 벤더별 진료 집계(M4 Task 1)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 벤더별 진료 집계(M4 Task 1) 벤더 0종이면 빈 배열이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"벤더 0종이면 빈 배열이다"},{"ancestorTitles":["AlertRepository — 벤더별 진료 집계(M4 Task 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 벤더별 진료 집계(M4 Task 1) 벤더 1종에서 total = 성공 + 실패 이고 값이 전부 숫자형이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"벤더 1종에서 total = 성공 + 실패 이고 값이 전부 숫자형이다"},{"ancestorTitles":["AlertRepository — 벤더별 진료 집계(M4 Task 1)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlertRepository — 벤더별 진료 집계(M4 Task 1) 벤더 N종에서 행마다 독립으로 정규화하고 NULL 집계를 0 으로 눌러 준다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"벤더 N종에서 행마다 독립으로 정규화하고 NULL 집계를 0 으로 눌러 준다"}],"endTime":1793868743191,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert.repository.spec.ts","startTime":1793868743101,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["OrderRepository collection/expiry ownership"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderRepository collection/expiry ownership does not refund quantity when collection already owns the row","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"does not refund quantity when collection already owns the row"},{"ancestorTitles":["OrderRepository collection/expiry ownership"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderRepository collection/expiry ownership refunds quantity once when expiry wins the row","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"refunds quantity once when expiry wins the row"},{"ancestorTitles":["OrderRepository collection/expiry ownership"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"OrderRepository collection/expiry ownership returns the affected row count from the collection claim","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"returns the affected row count from the collection claim"}],"endTime":1793868743274,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order/order-lifecycle-race.spec.ts","startTime":1793868743193,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyFcRepository 월중 가입 구간의 출처"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcRepository 월중 가입 구간의 출처 getAgencyContract 는 계약 구간 행이 아니라 서울 오늘의 정책 버전 구간을 돌려준다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"getAgencyContract 는 계약 구간 행이 아니라 서울 오늘의 정책 버전 구간을 돌려준다"},{"ancestorTitles":["AgencyFcRepository 월중 가입 구간의 출처"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyFcRepository 월중 가입 구간의 출처 getAgencyFcForSubscribe 는 계약 구간 행이 아니라 서울 오늘의 정책 버전 구간을 돌려준다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"getAgencyFcForSubscribe 는 계약 구간 행이 아니라 서울 오늘의 정책 버전 구간을 돌려준다"}],"endTime":1793868743276,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/agency-fc-policy.spec.ts","startTime":1793868743192,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AlimtalkStallRule (MS7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkStallRule (MS7) [MS7-A1] 접수 29분은 발화하지 않고 30분 경계에서 발화한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[MS7-A1] 접수 29분은 발화하지 않고 30분 경계에서 발화한다"},{"ancestorTitles":["AlimtalkStallRule (MS7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AlimtalkStallRule (MS7) [MS7-A2] 접수 뒤 30 · 60 · 180분마다 발화하고, 완료 칸을 채운 시점에 해소한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS7-A2] 접수 뒤 30 · 60 · 180분마다 발화하고, 완료 칸을 채운 시점에 해소한다"}],"endTime":1793868743360,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/alimtalk-stall.rule.spec.ts","startTime":1793868743276,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 oddId 를 분석 건 번호로 풀어 요청에 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"oddId 를 분석 건 번호로 풀어 요청에 남긴다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 asbId 를 분석 건 번호로 풀어 요청에 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"asbId 를 분석 건 번호로 풀어 요청에 남긴다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 acbId 를 분석 건 번호로 풀어 요청에 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"acbId 를 분석 건 번호로 풀어 요청에 남긴다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 지수 표기 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"지수 표기 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 빈 값 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 값 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 0 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"0 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 음수 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음수 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 모르는 번호 칸 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"모르는 번호 칸 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 번호 칸 없음 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"번호 칸 없음 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 풀리지 않는 asbId 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"풀리지 않는 asbId 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 풀리지 않는 acbId 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"풀리지 않는 acbId 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 지수 표기 asbId 는 거부 코드 E0607 로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"지수 표기 asbId 는 거부 코드 E0607 로 막는다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 범위 밖 행 · 없는 행은 같은 E0607 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"범위 밖 행 · 없는 행은 같은 E0607 이다"},{"ancestorTitles":["AnalysisRowGuard 경로 값 풀기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisRowGuard 경로 값 풀기 역할 없는 신원은 판정 질의 없이 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할 없는 신원은 판정 질의 없이 막는다"}],"endTime":1793868743362,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/analysis-row.guard.spec.ts","startTime":1793868743278,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 판정 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 엔드포인트 permission: 최고관리자에게 isSuper 참을 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"permission: 최고관리자에게 isSuper 참을 낸다"},{"ancestorTitles":["최고관리자 판정 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 엔드포인트 permission: 최고관리자가 아닌 내부 관리자에게 isSuper 거짓을 200 으로 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"permission: 최고관리자가 아닌 내부 관리자에게 isSuper 거짓을 200 으로 낸다"},{"ancestorTitles":["최고관리자 판정 엔드포인트"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 엔드포인트 permission: 판정을 내지 못하면 던져 비-200 이 된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"permission: 판정을 내지 못하면 던져 비-200 이 된다"},{"ancestorTitles":["최고관리자 판정 엔드포인트"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 엔드포인트 permission: 컨트롤러에 인증·역할 가드만 있고 최고관리자 가드가 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"permission: 컨트롤러에 인증·역할 가드만 있고 최고관리자 가드가 없다"}],"endTime":1793868743431,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/super-admin-permission.controller.spec.ts","startTime":1793868743361,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["DdxVerdictRepository.selectTargets 선정 조건"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"DdxVerdictRepository.selectTargets 선정 조건 완료 게이트 — 분석이 끝난 것만 고른다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"완료 게이트 — 분석이 끝난 것만 고른다"},{"ancestorTitles":["DdxVerdictRepository.selectTargets 선정 조건"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxVerdictRepository.selectTargets 선정 조건 완료 게이트가 인용하는 상태는 `분석완료` 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"완료 게이트가 인용하는 상태는 `분석완료` 다"},{"ancestorTitles":["DdxVerdictRepository.selectTargets 선정 조건"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"DdxVerdictRepository.selectTargets 선정 조건 지운 분석은 고르지 않는다 — 실명이 외부로 새로 나가지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"지운 분석은 고르지 않는다 — 실명이 외부로 새로 나가지 않는다"},{"ancestorTitles":["DdxVerdictRepository.selectTargets 선정 조건"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxVerdictRepository.selectTargets 선정 조건 기존 조건은 그대로 남는다 — 30일 창 · usrId · 판정 상태 · 시도 상한","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"기존 조건은 그대로 남는다 — 30일 창 · usrId · 판정 상태 · 시도 상한"}],"endTime":1793868743443,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/ddx-verdict.repository.spec.ts","startTime":1793868743364,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["상세 조회의 읽기 순서"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"상세 조회의 읽기 순서 권한 버전을 상세 데이터보다 먼저 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"권한 버전을 상세 데이터보다 먼저 읽는다"}],"endTime":1793868743492,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/admin-detail-order.spec.ts","startTime":1793868743432,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["OrderRepository.reconcileReservedQty"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"OrderRepository.reconcileReservedQty 국세청 정체를 인증실패와 자료수집실패로 분리한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"국세청 정체를 인증실패와 자료수집실패로 분리한다"}],"endTime":1793868743529,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/order/order/order-reservation-reconcile.spec.ts","startTime":1793868743445,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 회원 access 토큰(Bearer)은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"member: 회원 access 토큰(Bearer)은 통과한다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 회원 access 토큰(_aT 쿠키)은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"member: 회원 access 토큰(_aT 쿠키)은 통과한다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: refresh 토큰(Bearer)은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: refresh 토큰(Bearer)은 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: refresh 토큰(_aT 쿠키)은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: refresh 토큰(_aT 쿠키)은 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 관리자 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: 관리자 토큰은 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 조직관리자 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: 조직관리자 토큰은 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: refresh 와 access 가 함께 오면 access 를 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"member: refresh 와 access 가 함께 오면 access 를 쓴다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: refresh 쿠키와 access Bearer 가 함께 오면 access 를 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"member: refresh 쿠키와 access Bearer 가 함께 오면 access 를 쓴다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 같은 비밀의 송장 열람 형상 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: 같은 비밀의 송장 열람 형상 토큰은 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 연체 기업회원 access 는 지금처럼 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: 연체 기업회원 access 는 지금처럼 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 개발 swagger 조건에서도 refresh 토큰은 DEV 회원으로 바뀌지 않고 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: 개발 swagger 조건에서도 refresh 토큰은 DEV 회원으로 바뀌지 않고 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 개발 swagger 조건에서 만료 access 와 refresh 가 함께 오면 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"member: 개발 swagger 조건에서 만료 access 와 refresh 가 함께 오면 401 이다"},{"ancestorTitles":["JwtAuthGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtAuthGuard 토큰 종류 (E4) member: 개발 swagger 조건에서 토큰이 없으면 지금처럼 DEV 회원이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"member: 개발 swagger 조건에서 토큰이 없으면 지금처럼 DEV 회원이다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 회원 access 토큰은 신원을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 회원 access 토큰은 신원을 싣는다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: refresh 토큰은 익명으로 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: refresh 토큰은 익명으로 통과한다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 관리자 토큰은 익명으로 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 관리자 토큰은 익명으로 통과한다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: refresh 다음에 access 가 오면 access 신원을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: refresh 다음에 access 가 오면 access 신원을 싣는다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 연체 기업회원 access 는 익명으로 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 연체 기업회원 access 는 익명으로 통과한다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 탈퇴 기업회원 access 는 익명으로 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 탈퇴 기업회원 access 는 익명으로 통과한다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 정상 기업회원 access 는 신원을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 정상 기업회원 access 는 신원을 싣는다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 토큰이 없으면 익명으로 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 토큰이 없으면 익명으로 통과한다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 개발 swagger 조건에서도 refresh 토큰은 DEV 회원으로 바뀌지 않고 익명이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 개발 swagger 조건에서도 refresh 토큰은 DEV 회원으로 바뀌지 않고 익명이다"},{"ancestorTitles":["JwtOptionalGuard 토큰 종류 (E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"JwtOptionalGuard 토큰 종류 (E4) optional: 개발 swagger 조건에서 검증 실패 토큰은 지금처럼 DEV 회원이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"optional: 개발 swagger 조건에서 검증 실패 토큰은 지금처럼 DEV 회원이다"}],"endTime":1793868743576,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/user/member-token-kind.spec.ts","startTime":1793868743494,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["principal · 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 판정 principal · 판정 (a) 발급 형상 4종과 회원 access 는 각각 정확히 한 종류로 파생된다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"principal · 판정 (a) 발급 형상 4종과 회원 access 는 각각 정확히 한 종류로 파생된다"},{"ancestorTitles":["principal · 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 판정 principal · 판정 (b) 이행기 · 클레임 없는 구 토큰은 형상으로 판정된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"principal · 판정 (b) 이행기 · 클레임 없는 구 토큰은 형상으로 판정된다"},{"ancestorTitles":["principal · 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 판정 principal · 음성 · corp 형상이지만 corpScope 가 없으면 null (의도된 좁힘)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"principal · 음성 · corp 형상이지만 corpScope 가 없으면 null (의도된 좁힘)"},{"ancestorTitles":["principal · 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 판정 principal · 음성 · 클레임 불일치는 null (fail-closed)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"principal · 음성 · 클레임 불일치는 null (fail-closed)"},{"ancestorTitles":["principal · 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 판정 principal · 음성 · ADMIN_ROLES 에 새 역할을 더해도 기존 신원으로 분류되지 않는다 (fail-closed)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"principal · 음성 · ADMIN_ROLES 에 새 역할을 더해도 기존 신원으로 분류되지 않는다 (fail-closed)"},{"ancestorTitles":["principal · 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 판정 principal · 음성 · 상호 배타: 나열한 형상 어느 것도 관리자와 회원 판정이 동시에 참이 아니다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"principal · 음성 · 상호 배타: 나열한 형상 어느 것도 관리자와 회원 판정이 동시에 참이 아니다"},{"ancestorTitles":["principal · 복수 후보 · selectPrincipal"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 복수 후보 · selectPrincipal principal · 복수 후보 · 회원 access 하나만 고른다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"principal · 복수 후보 · 회원 access 하나만 고른다"},{"ancestorTitles":["principal · 복수 후보 · selectPrincipal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 복수 후보 · selectPrincipal principal · 음성 · 관리자 토큰만 있으면 wrongKind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"principal · 음성 · 관리자 토큰만 있으면 wrongKind"},{"ancestorTitles":["principal · 복수 후보 · selectPrincipal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 복수 후보 · selectPrincipal principal · 음성 · refresh 단독은 wrongKind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"principal · 음성 · refresh 단독은 wrongKind"},{"ancestorTitles":["principal · 복수 후보 · selectPrincipal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 복수 후보 · selectPrincipal principal · 음성 · 클레임 불일치 단독은 wrongKind","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"principal · 음성 · 클레임 불일치 단독은 wrongKind"},{"ancestorTitles":["principal · 복수 후보 · selectPrincipal"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 복수 후보 · selectPrincipal principal · 음성 · 검증된 후보 0개는 null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"principal · 음성 · 검증된 후보 0개는 null"},{"ancestorTitles":["principal · 가드 결과"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · AdminJwtAuthGuard · 관리자 4종 통과 · principalKind 가 req.admin 에 실린다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminJwtAuthGuard · 관리자 4종 통과 · principalKind 가 req.admin 에 실린다"},{"ancestorTitles":["principal · 가드 결과"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · AdminJwtAuthGuard · 음성 · 회원 access 는 401","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminJwtAuthGuard · 음성 · 회원 access 는 401"},{"ancestorTitles":["principal · 가드 결과"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · AdminJwtAuthGuard · 음성 · refresh 는 401","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminJwtAuthGuard · 음성 · refresh 는 401"},{"ancestorTitles":["principal · 가드 결과"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · AdminOptionalGuard · 관리자 토큰이면 principalKind 가 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminOptionalGuard · 관리자 토큰이면 principalKind 가 실린다"},{"ancestorTitles":["principal · 가드 결과"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · AdminOptionalGuard · 음성 · 회원 access 를 _aaT 에 넣으면 req.admin 이 세워지지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminOptionalGuard · 음성 · 회원 access 를 _aaT 에 넣으면 req.admin 이 세워지지 않는다"},{"ancestorTitles":["principal · 가드 결과"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · AdminOptionalGuard · 음성 · 옛 열람 토큰은 쿠키 신원을 덮지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminOptionalGuard · 음성 · 옛 열람 토큰은 쿠키 신원을 덮지 않는다"},{"ancestorTitles":["principal · 가드 결과"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · JwtAuthGuard · 회원 access 통과","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtAuthGuard · 회원 access 통과"},{"ancestorTitles":["principal · 가드 결과"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · JwtAuthGuard · 음성 · 관리자 토큰은 401","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtAuthGuard · 음성 · 관리자 토큰은 401"},{"ancestorTitles":["principal · 가드 결과"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · JwtAuthGuard · 음성 · refresh 단독은 401 (DEV_AUTH_BYPASS 를 켠 조건 포함)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtAuthGuard · 음성 · refresh 단독은 401 (DEV_AUTH_BYPASS 를 켠 조건 포함)"},{"ancestorTitles":["principal · 가드 결과"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · JwtOptionalGuard · 회원 access 통과","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtOptionalGuard · 회원 access 통과"},{"ancestorTitles":["principal · 가드 결과"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · JwtOptionalGuard · 음성 · 관리자 토큰이면 user 가 null (익명)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtOptionalGuard · 음성 · 관리자 토큰이면 user 가 null (익명)"},{"ancestorTitles":["principal · 가드 결과"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 가드 결과 가드 결과 · JwtOptionalGuard · 음성 · refresh 단독 + DEV_AUTH_BYPASS 면 user 가 null 이고 DEV_USER 가 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtOptionalGuard · 음성 · refresh 단독 + DEV_AUTH_BYPASS 면 user 가 null 이고 DEV_USER 가 아니다"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · AdminJwtAuthGuard · 클레임 포함 토큰은 통과하고 클레임과 같은 principalKind 를 싣는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminJwtAuthGuard · 클레임 포함 토큰은 통과하고 클레임과 같은 principalKind 를 싣는다"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · AdminJwtAuthGuard · 음성 · 클레임이 형상과 어긋난 토큰은 401","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminJwtAuthGuard · 음성 · 클레임이 형상과 어긋난 토큰은 401"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · AdminOptionalGuard · 클레임 포함 토큰은 principalKind 를 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminOptionalGuard · 클레임 포함 토큰은 principalKind 를 싣는다"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · AdminOptionalGuard · 음성 · 클레임이 형상과 어긋난 토큰은 req.admin 을 세우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · AdminOptionalGuard · 음성 · 클레임이 형상과 어긋난 토큰은 req.admin 을 세우지 않는다"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · JwtAuthGuard · 클레임 포함 회원 토큰은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtAuthGuard · 클레임 포함 회원 토큰은 통과한다"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · JwtAuthGuard · 음성 · 클레임이 형상과 어긋난 회원 토큰은 401","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtAuthGuard · 음성 · 클레임이 형상과 어긋난 회원 토큰은 401"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · JwtOptionalGuard · 클레임 포함 회원 토큰은 신원을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtOptionalGuard · 클레임 포함 회원 토큰은 신원을 싣는다"},{"ancestorTitles":["principal · 발급 형상 토큰 (클레임 포함)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"principal · 발급 형상 토큰 (클레임 포함) 가드 결과 · JwtOptionalGuard · 음성 · 클레임이 형상과 어긋난 회원 토큰은 user 가 null (익명)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가드 결과 · JwtOptionalGuard · 음성 · 클레임이 형상과 어긋난 회원 토큰은 user 가 null (익명)"}],"endTime":1793868743643,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/principal/principal.spec.ts","startTime":1793868743533,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치 미설정이면 두 사무실 IP 로 토큰 없이 401 — NODE_ENV dev","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치 미설정이면 두 사무실 IP 로 토큰 없이 401 — NODE_ENV dev"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치 미설정이면 NODE_ENV 가 dev 든 production 이든 swagger 조건으로 토큰 없이 401","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치 미설정이면 NODE_ENV 가 dev 든 production 이든 swagger 조건으로 토큰 없이 401"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치를 켜면 사무실 IP 로 토큰 없이 DEV 회원(memId 180)이 된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치를 켜면 사무실 IP 로 토큰 없이 DEV 회원(memId 180)이 된다"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치 미설정이면 NODE_ENV production 에서도 사무실 IP 로 401","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치 미설정이면 NODE_ENV production 에서도 사무실 IP 로 401"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치를 켜면 NODE_ENV production 에서도 사무실 IP 로 DEV 회원이 된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치를 켜면 NODE_ENV production 에서도 사무실 IP 로 DEV 회원이 된다"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치를 켜도 사무실 IP 가 아니거나 출발 IP 가 없으면 토큰 없이 401","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치를 켜도 사무실 IP 가 아니거나 출발 IP 가 없으면 토큰 없이 401"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치 값이 정확히 true 가 아니면 사무실 IP 여도 토큰 없이 401 이다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치 값이 정확히 true 가 아니면 사무실 IP 여도 토큰 없이 401 이다"},{"ancestorTitles":["회원 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"회원 가드 개발 우회 스위치 (K10) 회원 가드: 스위치를 켜도 정상 access 토큰이 있으면 사무실 IP · swagger 조건보다 토큰 신원을 쓴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"회원 가드: 스위치를 켜도 정상 access 토큰이 있으면 사무실 IP · swagger 조건보다 토큰 신원을 쓴다"},{"ancestorTitles":["선택 인증 가드 개발 우회 스위치 (K10)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"선택 인증 가드 개발 우회 스위치 (K10) 선택 인증 가드: 스위치 미설정이면 NODE_ENV 가 dev 든 production 이든 두 사무실 IP · swagger 조건 · 검증 실패 토큰이 익명이다","invocations":1,"location":null,"numPassingAsserts":16,"retryReasons":[],"status":"passed","title":"선택 인증 가드: 스위치 미설정이면 NODE_ENV 가 dev 든 production 이든 두 사무실 IP · swagger 조건 · 검증 실패 토큰이 익명이다"},{"ancestorTitles":["선택 인증 가드 개발 우회 스위치 (K10)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"선택 인증 가드 개발 우회 스위치 (K10) 선택 인증 가드: 스위치를 켜면 사무실 IP · 검증 실패 토큰이 DEV 회원이다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"선택 인증 가드: 스위치를 켜면 사무실 IP · 검증 실패 토큰이 DEV 회원이다"},{"ancestorTitles":["선택 인증 가드 개발 우회 스위치 (K10)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"선택 인증 가드 개발 우회 스위치 (K10) 선택 인증 가드: 스위치를 켜도 사무실 IP 가 아니거나 출발 IP 가 없으면 검증 실패 토큰이 익명이다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"선택 인증 가드: 스위치를 켜도 사무실 IP 가 아니거나 출발 IP 가 없으면 검증 실패 토큰이 익명이다"},{"ancestorTitles":["선택 인증 가드 개발 우회 스위치 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"선택 인증 가드 개발 우회 스위치 (K10) 선택 인증 가드: 스위치를 켜도 정상 access 토큰이 있으면 사무실 IP 여도 토큰 신원을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"선택 인증 가드: 스위치를 켜도 정상 access 토큰이 있으면 사무실 IP 여도 토큰 신원을 싣는다"},{"ancestorTitles":["관리자 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 가드 개발 우회 스위치 (K10) 관리자 가드: 스위치 미설정이면 NODE_ENV 가 dev 든 production 이든 swagger 조건에서 쿠키 없는 요청이 401","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"관리자 가드: 스위치 미설정이면 NODE_ENV 가 dev 든 production 이든 swagger 조건에서 쿠키 없는 요청이 401"},{"ancestorTitles":["관리자 가드 개발 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 가드 개발 우회 스위치 (K10) 관리자 가드: 스위치를 켜면 swagger 조건에서 DEV 관리자(admId 19)가 된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 가드: 스위치를 켜면 swagger 조건에서 DEV 관리자(admId 19)가 된다"}],"endTime":1793868743720,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/user/dev-auth-bypass.spec.ts","startTime":1793868743645,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 칸 표에 없는 칸은 거부된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"칸 표에 없는 칸은 거부된다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 같은 칸이 두 번 들어오면 거부된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 칸이 두 번 들어오면 거부된다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 비최고관리자는 최고관리자 전용 코드를 주는 칸을 저장하면 거부된다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"비최고관리자는 최고관리자 전용 코드를 주는 칸을 저장하면 거부된다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 비최고관리자는 최고관리자 전용 코드를 가진 역할을 회수하지 못한다 (잠금 아래 이전 집합으로 판정)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"비최고관리자는 최고관리자 전용 코드를 가진 역할을 회수하지 못한다 (잠금 아래 이전 집합으로 판정)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 최고관리자 판정 조회가 실패하면 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자 판정 조회가 실패하면 쓰지 않는다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService DI 가 두 의존성을 실제 클래스로 찾는다 (Nest 가 읽는 design:paramtypes)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"DI 가 두 의존성을 실제 클래스로 찾는다 (Nest 가 읽는 design:paramtypes)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":10,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 버전 sentinel 행이 없으면 던진다 (잠금 단계에서 중단하고 쓰지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"버전 sentinel 행이 없으면 던진다 (잠금 단계에서 중단하고 쓰지 않는다)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 상승 뒤 버전을 못 읽으면 던진다 (0 이나 낡은 값을 돌려주지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상승 뒤 버전을 못 읽으면 던진다 (0 이나 낡은 값을 돌려주지 않는다)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 쓰기 트랜잭션은 sentinel 잠금 → 역할 잠금 → 이전 집합 · 이전 배정 읽기 순서다 (잠금 전 읽기는 낡는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쓰기 트랜잭션은 sentinel 잠금 → 역할 잠금 → 이전 집합 · 이전 배정 읽기 순서다 (잠금 전 읽기는 낡는다)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 권한 쓰기는 칸 배정 · 권한 행을 바꾼 뒤 같은 트랜잭션에서 버전을 올리고, 감사 행은 마지막이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"권한 쓰기는 칸 배정 · 권한 행을 바꾼 뒤 같은 트랜잭션에서 버전을 올리고, 감사 행은 마지막이다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService expectedVersion 이 현재 버전과 다르면 409 이고 쓰지 않는다 (낡은 화면 저장 차단)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"expectedVersion 이 현재 버전과 다르면 409 이고 쓰지 않는다 (낡은 화면 저장 차단)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 잠금 아래에서 역할이 없으면 쓰지 않는다 (바깥 확인과 쓰기 사이의 삭제)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"잠금 아래에서 역할이 없으면 쓰지 않는다 (바깥 확인과 쓰기 사이의 삭제)"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 칸 표가 관리하지 않는 기존 코드는 보존되고, 칸이 관리하는 코드는 칸이 준 것만 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"칸 표가 관리하지 않는 기존 코드는 보존되고, 칸이 관리하는 코드는 칸이 준 것만 남는다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 칸 수준 full 은 보기 · 변경 코드를 함께 준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"칸 수준 full 은 보기 · 변경 코드를 함께 준다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 이름이 주어지고 바뀌면 같은 트랜잭션에서 tn_auth 이름을 고친다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이름이 주어지고 바뀌면 같은 트랜잭션에서 tn_auth 이름을 고친다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 감사 행의 aud_changes 는 권한 · 칸의 추가와 삭제를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"감사 행의 aud_changes 는 권한 · 칸의 추가와 삭제를 싣는다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService aud_changes 가 1KB 를 넘으면 개수와 고위험 변경만 남기고 절단을 표시한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"aud_changes 가 1KB 를 넘으면 개수와 고위험 변경만 남기고 절단을 표시한다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 역할 생성은 칸 표로 메뉴 배정과 권한 코드를 같은 트랜잭션에 쓰고 새 번호를 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"역할 생성은 칸 표로 메뉴 배정과 권한 코드를 같은 트랜잭션에 쓰고 새 번호를 돌려준다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 역할 생성도 최고관리자 전용 코드를 주는 칸이면 거부되고 쓰지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"역할 생성도 최고관리자 전용 코드를 주는 칸이면 거부되고 쓰지 않는다"},{"ancestorTitles":["권한 쓰기 서비스 PermissionAdminService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 쓰기 서비스 PermissionAdminService 시드 스크립트의 감사 줄 버전은 감사 모듈과 같다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"시드 스크립트의 감사 줄 버전은 감사 모듈과 같다"}],"endTime":1793868743737,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-admin.service.spec.ts","startTime":1793868743578,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["CardService.deleteCard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 남의 카드나 없는 카드가 섞이면 토스를 부르지 않고 403 이며 행을 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 삭제: 남의 카드나 없는 카드가 섞이면 토스를 부르지 않고 403 이며 행을 지우지 않는다"},{"ancestorTitles":["CardService.deleteCard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 소유 확인 → 토스 폐기 → 행 삭제 순서로 간다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"카드 삭제: 소유 확인 → 토스 폐기 → 행 삭제 순서로 간다"},{"ancestorTitles":["CardService.deleteCard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 토스가 이미 없음이면 행을 지운다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"카드 삭제: 토스가 이미 없음이면 행을 지운다"},{"ancestorTitles":["CardService.deleteCard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 토스 폐기가 실패해도 행을 지우고, 회원·카드 id 를 오류 로그에 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 삭제: 토스 폐기가 실패해도 행을 지우고, 회원·카드 id 를 오류 로그에 남긴다"},{"ancestorTitles":["CardService.deleteCard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 다건 중 하나가 실패해도 나머지 카드도 토스에 보내고 전부 지운다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 삭제: 다건 중 하나가 실패해도 나머지 카드도 토스에 보내고 전부 지운다"},{"ancestorTitles":["CardService.deleteCard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 폐기됐거나 이미 없으면 오류 로그를 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"카드 삭제: 폐기됐거나 이미 없으면 오류 로그를 남기지 않는다"},{"ancestorTitles":["CardService.deleteCard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 같은 id 가 반복돼도 토스는 카드당 한 번만 부른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 삭제: 같은 id 가 반복돼도 토스는 카드당 한 번만 부른다"},{"ancestorTitles":["CardService.deleteCard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardService.deleteCard 카드 삭제: 빈 id 목록은 토스를 부르지 않고 빈 목록으로 지운다(무동작)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 삭제: 빈 id 목록은 토스를 부르지 않고 빈 목록으로 지운다(무동작)"}],"endTime":1793868743791,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/card/card-billing-revoke.spec.ts","startTime":1793868743721,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["CreateMoneyIssueDto — 사유 유형이 필수다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyIssueDto — 사유 유형이 필수다 reasonCode 가 없으면 그 필드에 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 없으면 그 필드에 오류가 난다"},{"ancestorTitles":["CreateMoneyIssueDto — 사유 유형이 필수다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyIssueDto — 사유 유형이 필수다 reasonCode 가 문자열이 아니면 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 문자열이 아니면 오류가 난다"},{"ancestorTitles":["CreateMoneyIssueDto — 사유 유형이 필수다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyIssueDto — 사유 유형이 필수다 reasonCode 가 있으면 그 필드에 오류가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 있으면 그 필드에 오류가 없다"},{"ancestorTitles":["CreateMoneyCorpDto — 사유 유형이 필수다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyCorpDto — 사유 유형이 필수다 reasonCode 가 없으면 그 필드에 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 없으면 그 필드에 오류가 난다"},{"ancestorTitles":["CreateMoneyCorpDto — 사유 유형이 필수다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyCorpDto — 사유 유형이 필수다 reasonCode 가 문자열이 아니면 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 문자열이 아니면 오류가 난다"},{"ancestorTitles":["CreateMoneyCorpDto — 사유 유형이 필수다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyCorpDto — 사유 유형이 필수다 reasonCode 가 있으면 그 필드에 오류가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 있으면 그 필드에 오류가 없다"},{"ancestorTitles":["CreateMoneyGrantDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyGrantDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다 reasonCode 가 없어도 그 필드에 오류가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 없어도 그 필드에 오류가 없다"},{"ancestorTitles":["CreateMoneyGrantDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyGrantDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다 reasonCode 가 문자열이 아니면 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 문자열이 아니면 오류가 난다"},{"ancestorTitles":["CreateMoneyGrantSingleDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyGrantSingleDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다 reasonCode 가 없어도 그 필드에 오류가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 없어도 그 필드에 오류가 없다"},{"ancestorTitles":["CreateMoneyGrantSingleDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CreateMoneyGrantSingleDto — 기업 콘솔이 생략하므로 DTO 에서는 선택이다 reasonCode 가 문자열이 아니면 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"reasonCode 가 문자열이 아니면 오류가 난다"},{"ancestorTitles":["ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다 승인(APPROVE) 인데 reasonCode 가 없으면 오류가 난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"승인(APPROVE) 인데 reasonCode 가 없으면 오류가 난다"},{"ancestorTitles":["ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다 승인(APPROVE) 에 reasonCode 가 있으면 오류가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"승인(APPROVE) 에 reasonCode 가 있으면 오류가 없다"},{"ancestorTitles":["ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다 반려(REJECT) 는 reasonCode 가 없어도 오류가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"반려(REJECT) 는 reasonCode 가 없어도 오류가 없다"},{"ancestorTitles":["ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ProcessMoneyChargeRequestDto — 승인만 사유 유형을 요구한다 반려(REJECT) 가 reasonCode 를 실어 와도 모르는 필드로 거절하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"반려(REJECT) 가 reasonCode 를 실어 와도 모르는 필드로 거절하지 않는다"}],"endTime":1793868743807,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/money/money-reason.dto.spec.ts","startTime":1793868743739,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합) 자동차(isAuto=true): resVisitDays→resTreatDate, resPublicCharge→resMedicalFee 별칭 채움","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"자동차(isAuto=true): resVisitDays→resTreatDate, resPublicCharge→resMedicalFee 별칭 채움"},{"ancestorTitles":["InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합) 엔진이 resTreatDate/resMedicalFee를 직접 주면 그 값이 우선(?? fallback)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"엔진이 resTreatDate/resMedicalFee를 직접 주면 그 값이 우선(?? fallback)"},{"ancestorTitles":["InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합) 건강(isAuto=false): 자동차 alias 미적용 → resTreatDate/resMedicalFee 없음(레코드 청결)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"건강(isAuto=false): 자동차 alias 미적용 → resTreatDate/resMedicalFee 없음(레코드 청결)"},{"ancestorTitles":["InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합) 비진료 형태(약 요약 등)는 그대로 통과","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비진료 형태(약 요약 등)는 그대로 통과"},{"ancestorTitles":["InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService.normalizeTreatment — 자동차 alias (3벤더 표준 정합) 빈 진료 리스트도 안전(빈 배열 유지)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 진료 리스트도 안전(빈 배열 유지)"},{"ancestorTitles":["InhouseService.cancelCertify"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService.cancelCertify uses the existing engine cancel endpoint with the sticky cookie","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"uses the existing engine cancel endpoint with the sticky cookie"},{"ancestorTitles":["InhouseService 간편인증 전달"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService 간편인증 전달 1차 loginTypeLevel을 엔진에 전달한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"1차 loginTypeLevel을 엔진에 전달한다"},{"ancestorTitles":["InhouseService 간편인증 전달"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService 간편인증 전달 2차 simpleAuth를 엔진에 전달한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"2차 simpleAuth를 엔진에 전달한다"},{"ancestorTitles":["InhouseService 국세청 오류 전달"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"InhouseService 국세청 오류 전달 엔진 non-2xx 응답의 세션 상태와 사용자 메시지를 보존한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"엔진 non-2xx 응답의 세션 상태와 사용자 메시지를 보존한다"}],"endTime":1793868743856,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/inhouse/src/inhouse.service.spec.ts","startTime":1793868743794,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["로그인 감사 — 성공 적재"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 성공 적재 서비스관리자 로그인 성공이 검증된 계정으로 남는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"서비스관리자 로그인 성공이 검증된 계정으로 남는다"},{"ancestorTitles":["로그인 감사 — 성공 적재"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 성공 적재 적재가 업무 트랜잭션 자리를 빌려 쓴다 — tx 없이 쓸 경로를 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"적재가 업무 트랜잭션 자리를 빌려 쓴다 — tx 없이 쓸 경로를 남기지 않는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) signin — 없는 계정 — 자칭 계정으로 한 행이 남는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"signin — 없는 계정 — 자칭 계정으로 한 행이 남는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) signin — 비밀번호 불일치 — 자칭 계정으로 한 행이 남는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"signin — 비밀번호 불일치 — 자칭 계정으로 한 행이 남는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) salesSignin — 없는 계정 — 자칭 계정으로 한 행이 남는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"salesSignin — 없는 계정 — 자칭 계정으로 한 행이 남는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) salesSignin — 비밀번호 칸이 비었다 — 자칭 계정으로 한 행이 남는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"salesSignin — 비밀번호 칸이 비었다 — 자칭 계정으로 한 행이 남는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) corpSignin — 비밀번호 불일치 — 자칭 계정으로 한 행이 남는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"corpSignin — 비밀번호 불일치 — 자칭 계정으로 한 행이 남는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) corpOrgSignin — 소속 조직 미배정 — 자칭 계정으로 한 행이 남는다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"corpOrgSignin — 소속 조직 미배정 — 자칭 계정으로 한 행이 남는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) 거절 사유를 행으로 가르지 않는다 — 계정 존재 확인 수단을 만들지 않는다(D7a)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"거절 사유를 행으로 가르지 않는다 — 계정 존재 확인 수단을 만들지 않는다(D7a)"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) 비밀번호가 어느 칸에도 실리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"비밀번호가 어느 칸에도 실리지 않는다"},{"ancestorTitles":["로그인 감사 — 거절 전건 적재(자칭 계정)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 거절 전건 적재(자칭 계정) 자칭 라벨의 제어문자·bidi 가 지워진다 — 표시 스푸핑과 값 기인 적재 실패를 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"자칭 라벨의 제어문자·bidi 가 지워진다 — 표시 스푸핑과 값 기인 적재 실패를 막는다"},{"ancestorTitles":["로그인 감사 — 실패 규약(D12 fail-open)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 실패 규약(D12 fail-open) 적재가 던져도 로그인은 성공한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재가 던져도 로그인은 성공한다"},{"ancestorTitles":["로그인 감사 — 실패 규약(D12 fail-open)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 감사 — 실패 규약(D12 fail-open) 실패 적재가 던져도 원래 거절이 그대로 나가고, 진단이 노려진 계정을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"실패 적재가 던져도 원래 거절이 그대로 나가고, 진단이 노려진 계정을 싣는다"}],"endTime":1793868743879,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/auth-audit.spec.ts","startTime":1793868743811,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 통합관리자 토큰은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin: 통합관리자 토큰은 통과한다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 영업 토큰은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin: 영업 토큰은 통과한다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 기업 최고관리자 토큰은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin: 기업 최고관리자 토큰은 통과한다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 조직관리자 토큰은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin: 조직관리자 토큰은 통과한다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 회원 access 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin: 회원 access 토큰은 401 이다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 회원 refresh 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin: 회원 refresh 토큰은 401 이다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 모르는 역할 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin: 모르는 역할 토큰은 401 이다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 개발 swagger 조건에서도 회원 토큰은 DEV 관리자로 바뀌지 않고 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin: 개발 swagger 조건에서도 회원 토큰은 DEV 관리자로 바뀌지 않고 401 이다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 개발 swagger 조건에서 토큰이 없으면 지금처럼 DEV 관리자다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin: 개발 swagger 조건에서 토큰이 없으면 지금처럼 DEV 관리자다"},{"ancestorTitles":["AdminJwtAuthGuard 토큰 종류 (N2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminJwtAuthGuard 토큰 종류 (N2) admin: 다른 비밀로 서명한 토큰은 401 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin: 다른 비밀로 서명한 토큰은 401 이다"}],"endTime":1793868743948,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/admin-token-kind.spec.ts","startTime":1793868743881,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["관리자 감시 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 관리자 쿠키가 있으면 판정 입력을 붙이고 통과시킨다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 쿠키가 있으면 판정 입력을 붙이고 통과시킨다"},{"ancestorTitles":["관리자 감시 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 HEAD 요청도 GET 행과 같은 코드로 판정한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"HEAD 요청도 GET 행과 같은 코드로 판정한다"},{"ancestorTitles":["관리자 감시 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 경로 맵에 없는 라우트는 code 가 null 인 입력으로 넘긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경로 맵에 없는 라우트는 code 가 null 인 입력으로 넘긴다"},{"ancestorTitles":["관리자 감시 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 영업 등 관리자 계열 다른 종류는 판정하지 않고 종류 칸으로만 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"영업 등 관리자 계열 다른 종류는 판정하지 않고 종류 칸으로만 남긴다"},{"ancestorTitles":["관리자 감시 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 위조된 관리자 쿠키는 invalid 칸으로 남고 판정하지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"위조된 관리자 쿠키는 invalid 칸으로 남고 판정하지 않는다"},{"ancestorTitles":["관리자 감시 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 관리자 쿠키가 없으면 아무것도 붙이지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 쿠키가 없으면 아무것도 붙이지 않는다"},{"ancestorTitles":["관리자 감시 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 옛 열람 토큰 헤더는 신원이 아니라 칸을 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"옛 열람 토큰 헤더는 신원이 아니라 칸을 남기지 않는다"},{"ancestorTitles":["관리자 감시 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 판정 준비가 던져도 통과시키고 guard-error 칸으로 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"판정 준비가 던져도 통과시키고 guard-error 칸으로 남긴다"},{"ancestorTitles":["관리자 감시 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 요청 객체가 비정상이어도 던지지 않고 true 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"요청 객체가 비정상이어도 던지지 않고 true 다"},{"ancestorTitles":["판정하지 않는 신원 칸 (R2 타입)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"판정하지 않는 신원 칸 (R2 타입) 계수 칸 이름은 닫힌 집합이다 (오타 칸은 컴파일되지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"계수 칸 이름은 닫힌 집합이다 (오타 칸은 컴파일되지 않는다)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 취소 가능: ON 경로는 풀 · 시한을 넘겨 취소 가능 판정 연결을 부른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"취소 가능: ON 경로는 풀 · 시한을 넘겨 취소 가능 판정 연결을 부른다"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 시한 초과: 판정이 시한을 넘으면 503 으로 접는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"시한 초과: 판정이 시한을 넘으면 503 으로 접는다"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 복원 실패: 복원이 던지면 판정 없이 503 으로 닫고 기록에 실패를 남긴다 (fail-closed)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"복원 실패: 복원이 던지면 판정 없이 503 으로 닫고 기록에 실패를 남긴다 (fail-closed)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 복원 실패 원인: 복원이 던지면 원인 코드를 로그에 남긴다 (메시지 · 본문은 싣지 않는다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"복원 실패 원인: 복원이 던지면 원인 코드를 로그에 남긴다 (메시지 · 본문은 싣지 않는다)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 복원 실패 원인: 권한 버전 판정 불가는 사유 토큰도 로그에 남긴다 (PVU 는 code 가 없다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"복원 실패 원인: 권한 버전 판정 불가는 사유 토큰도 로그에 남긴다 (PVU 는 code 가 없다)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 판정 불가: 권한 버전을 못 읽으면 PERMISSION_VERSION_UNAVAILABLE 로 503 으로 닫는다 (PVU 분기)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정 불가: 권한 버전을 못 읽으면 PERMISSION_VERSION_UNAVAILABLE 로 503 으로 닫는다 (PVU 분기)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 복원 기록 null: 복원이 null 이면 판정 없이 401 로 닫는다 (뒤 가드에 기대지 않는다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"복원 기록 null: 복원이 null 이면 판정 없이 401 로 닫는다 (뒤 가드에 기대지 않는다)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 확정 신원 번호가 정수가 아니면 판정하지 않고 503 으로 닫는다 (캐스트 없음)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"확정 신원 번호가 정수가 아니면 판정하지 않고 503 으로 닫는다 (캐스트 없음)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 판정 신원: 판정은 복원 결과의 관리자 번호로 한다 (확정 신원)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"판정 신원: 판정은 복원 결과의 관리자 번호로 한다 (확정 신원)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 풀 없음: 공용 풀이 없으면 판정하지 않고 503 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"풀 없음: 공용 풀이 없으면 판정하지 않고 503 이다"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 익명 요청은 스위치가 켜져도 풀을 쓰지 않는다 (판정 대상이 아니다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"익명 요청은 스위치가 켜져도 풀을 쓰지 않는다 (판정 대상이 아니다)"},{"ancestorTitles":["관리자 감시 가드 · 강제 ON 경로 (M9b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"관리자 감시 가드 · 강제 ON 경로 (M9b) 스위치 OFF: 스위치가 꺼지면 복원도 판정 연결도 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"스위치 OFF: 스위치가 꺼지면 복원도 판정 연결도 부르지 않는다"},{"ancestorTitles":["맵 밖 관리자 경로 기본 거부 (D5-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"맵 밖 관리자 경로 기본 거부 (D5-3) 관리자 신원의 맵 밖 /admin 경로는 예외 원장에 없으면 reason=unmapped 403 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 신원의 맵 밖 /admin 경로는 예외 원장에 없으면 reason=unmapped 403 이다"},{"ancestorTitles":["맵 밖 관리자 경로 기본 거부 (D5-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"맵 밖 관리자 경로 기본 거부 (D5-3) 맵 행이 있는 /admin 경로와 예외 원장의 /admin 경로는 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"맵 행이 있는 /admin 경로와 예외 원장의 /admin 경로는 통과한다"},{"ancestorTitles":["맵 밖 관리자 경로 기본 거부 (D5-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"맵 밖 관리자 경로 기본 거부 (D5-3) 관리자 쿠키가 없는 맵 밖 /admin 경로는 통과한다 (익명은 컨트롤러 가드 몫)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 쿠키가 없는 맵 밖 /admin 경로는 통과한다 (익명은 컨트롤러 가드 몫)"},{"ancestorTitles":["맵 밖 관리자 경로 기본 거부 (D5-3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"맵 밖 관리자 경로 기본 거부 (D5-3) 스위치를 끄면 맵 밖 /admin 경로도 현행대로 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스위치를 끄면 맵 밖 /admin 경로도 현행대로 통과한다"},{"ancestorTitles":["영역 0 강제 스위치 (D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영역 0 강제 스위치 (D6) 스위치를 켜면 영역 0 코드도 판정하고 권한이 없으면 영역 2 와 같은 403 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"스위치를 켜면 영역 0 코드도 판정하고 권한이 없으면 영역 2 와 같은 403 이다"},{"ancestorTitles":["영역 0 강제 스위치 (D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영역 0 강제 스위치 (D6) 스위치를 켜고 권한이 있으면 영역 0 코드도 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스위치를 켜고 권한이 있으면 영역 0 코드도 통과한다"},{"ancestorTitles":["영역 0 강제 스위치 (D6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영역 0 강제 스위치 (D6) 스위치를 끄면 영역 0 코드는 판정하지 않고 통과한다 (커밋 값)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스위치를 끄면 영역 0 코드는 판정하지 않고 통과한다 (커밋 값)"}],"endTime":1793868743958,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/access-control.guard.spec.ts","startTime":1793868743857,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["agency-fc 응답의 기업머니 잔액 노출 범위"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"agency-fc 응답의 기업머니 잔액 노출 범위 목록 응답은 agency.agcMoney 를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"목록 응답은 agency.agcMoney 를 싣는다"},{"ancestorTitles":["agency-fc 응답의 기업머니 잔액 노출 범위"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"agency-fc 응답의 기업머니 잔액 노출 범위 상세 응답은 agency.agcMoney 를 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상세 응답은 agency.agcMoney 를 싣지 않는다"}],"endTime":1793868744027,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/agency-fc-money-exposure.spec.ts","startTime":1793868743960,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 그룹 변경 — 트랜잭션 안 적재"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — 트랜잭션 안 적재 생성이 그룹명과 메뉴 수를 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"생성이 그룹명과 메뉴 수를 남긴다"},{"ancestorTitles":["권한 그룹 변경 — 트랜잭션 안 적재"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — 트랜잭션 안 적재 수정이 그룹명과 메뉴 수의 전·후를 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"수정이 그룹명과 메뉴 수의 전·후를 남긴다"},{"ancestorTitles":["권한 그룹 변경 — 트랜잭션 안 적재"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — 트랜잭션 안 적재 메뉴를 바꿔 끼운 수정은 수가 같아도 더해진 수·빠진 수로 드러난다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"메뉴를 바꿔 끼운 수정은 수가 같아도 더해진 수·빠진 수로 드러난다"},{"ancestorTitles":["권한 그룹 변경 — 트랜잭션 안 적재"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — 트랜잭션 안 적재 메뉴를 전부 뗀 수정도 메뉴 수 0 으로 남는다 — 등록 분기가 안 돌아도 기록은 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"메뉴를 전부 뗀 수정도 메뉴 수 0 으로 남는다 — 등록 분기가 안 돌아도 기록은 남는다"},{"ancestorTitles":["권한 그룹 변경 — 트랜잭션 안 적재"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — 트랜잭션 안 적재 삭제가 **그룹마다 한 행**을 남기고 각 행이 그룹명을 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"삭제가 **그룹마다 한 행**을 남기고 각 행이 그룹명을 싣는다"},{"ancestorTitles":["권한 그룹 변경 — 트랜잭션 안 적재"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — 트랜잭션 안 적재 삭제는 그룹의 권한 행(tn_auth_permission)도 같은 트랜잭션에서 지운다 — M4 인계","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"삭제는 그룹의 권한 행(tn_auth_permission)도 같은 트랜잭션에서 지운다 — M4 인계"},{"ancestorTitles":["권한 그룹 변경 — fail-closed(D12)"],"duration":11,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — fail-closed(D12) 생성: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"생성: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다"},{"ancestorTitles":["권한 그룹 변경 — fail-closed(D12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — fail-closed(D12) 수정: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수정: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다"},{"ancestorTitles":["권한 그룹 변경 — fail-closed(D12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 변경 — fail-closed(D12) 삭제: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"삭제: 적재가 거부되면 예외가 그대로 올라가 변경이 롤백된다"},{"ancestorTitles":["권한 그룹 삭제 — 잠금 순서 · 이행기"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 삭제 — 잠금 순서 · 이행기 역할 행을 지우기 전에 권한 버전 sentinel 을 잠근다 (setRolePermissions 와 같은 순서)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할 행을 지우기 전에 권한 버전 sentinel 을 잠근다 (setRolePermissions 와 같은 순서)"},{"ancestorTitles":["권한 그룹 삭제 — 잠금 순서 · 이행기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 삭제 — 잠금 순서 · 이행기 tn_auth_permission 표가 없는 이행기에도 역할 삭제는 500 이 되지 않고 권한 행만 건너뛴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"tn_auth_permission 표가 없는 이행기에도 역할 삭제는 500 이 되지 않고 권한 행만 건너뛴다"},{"ancestorTitles":["권한 그룹 삭제 — 잠금 순서 · 이행기"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 그룹 삭제 — 잠금 순서 · 이행기 표 부재가 아닌 오류 (교착 1213) 는 삭제를 막지 않고 그대로 올라가 롤백된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표 부재가 아닌 오류 (교착 1213) 는 삭제를 막지 않고 그대로 올라가 롤백된다"}],"endTime":1793868744029,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/authority/authority-audit.spec.ts","startTime":1793868743953,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["로그인 실패 — 경로마다 자기 도메인을 싣는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 실패 — 경로마다 자기 도메인을 싣는다 내부 관리자 경로는 admin","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"내부 관리자 경로는 admin"},{"ancestorTitles":["로그인 실패 — 경로마다 자기 도메인을 싣는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 실패 — 경로마다 자기 도메인을 싣는다 영업대리점 경로는 sales","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업대리점 경로는 sales"},{"ancestorTitles":["로그인 실패 — 경로마다 자기 도메인을 싣는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 실패 — 경로마다 자기 도메인을 싣는다 기업관리자 경로는 corp","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기업관리자 경로는 corp"},{"ancestorTitles":["로그인 실패 — 경로마다 자기 도메인을 싣는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 실패 — 경로마다 자기 도메인을 싣는다 조직관리자 경로는 member","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"조직관리자 경로는 member"},{"ancestorTitles":["로그인 실패 — 경로마다 자기 도메인을 싣는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"로그인 실패 — 경로마다 자기 도메인을 싣는다 네 경로의 도메인이 서로 다르다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"네 경로의 도메인이 서로 다르다"},{"ancestorTitles":["로그인 성공 — 같은 어휘를 싣는다(R1 Codex F3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 성공 — 같은 어휘를 싣는다(R1 Codex F3) 내부 관리자 성공 행도 admin 도메인을 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"내부 관리자 성공 행도 admin 도메인을 싣는다"},{"ancestorTitles":["로그인 성공 — 같은 어휘를 싣는다(R1 Codex F3)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"로그인 성공 — 같은 어휘를 싣는다(R1 Codex F3) 영업대리점 성공 행도 sales 도메인을 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업대리점 성공 행도 sales 도메인을 싣는다"}],"endTime":1793868744083,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/auth-signin-domain.spec.ts","startTime":1793868744029,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminAuthService.signin"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin admId=1의 자동차 조회 capability를 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admId=1의 자동차 조회 capability를 반환한다"},{"ancestorTitles":["AdminAuthService.signin"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin admId=3의 자동차 조회 capability를 반환한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admId=3의 자동차 조회 capability를 반환한다"},{"ancestorTitles":["AdminAuthService.signin"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin 발급 실물 · 관리자 통합 · payload 와 응답 모두 principalKind 는 admin","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발급 실물 · 관리자 통합 · payload 와 응답 모두 principalKind 는 admin"},{"ancestorTitles":["AdminAuthService.signin"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin [M11] 발급 경로 행 보유자 참 (로그인): 행 판정이 참이면 응답의 canViewCar 가 참이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[M11] 발급 경로 행 보유자 참 (로그인): 행 판정이 참이면 응답의 canViewCar 가 참이다"},{"ancestorTitles":["AdminAuthService.signin"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin 발급 실물 · 영업 · payload 와 응답 principalKind 는 sales","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발급 실물 · 영업 · payload 와 응답 principalKind 는 sales"},{"ancestorTitles":["AdminAuthService.signin"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin 발급 실물 · 기업 최고 · payload 와 응답 principalKind 는 corp-super","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발급 실물 · 기업 최고 · payload 와 응답 principalKind 는 corp-super"},{"ancestorTitles":["AdminAuthService.signin"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuthService.signin 발급 실물 · 기업 조직 · payload 와 응답 principalKind 는 org-manager","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발급 실물 · 기업 조직 · payload 와 응답 principalKind 는 org-manager"}],"endTime":1793868744090,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/auth.service.spec.ts","startTime":1793868744031,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["강제 ON · 조직 쓰기의 영업 판정 (Task 6 다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 영업 판정 (Task 6 다) 수정: 담당 영업 행을 잠근 뒤 판정하고, 판정이 맞으면 같은 트랜잭션에서 쓴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"수정: 담당 영업 행을 잠근 뒤 판정하고, 판정이 맞으면 같은 트랜잭션에서 쓴다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 영업 판정 (Task 6 다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 영업 판정 (Task 6 다) 수정: 잠근 뒤 담당이 바뀌었으면 (sagId 5) 403 이고 쓰기 0회다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수정: 잠근 뒤 담당이 바뀌었으면 (sagId 5) 403 이고 쓰기 0회다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 영업 판정 (Task 6 다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 영업 판정 (Task 6 다) 수정: 담당 영업이 없는 기업 (sagId null) 은 403 이고 쓰기 0회다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"수정: 담당 영업이 없는 기업 (sagId null) 은 403 이고 쓰기 0회다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 영업 판정 (Task 6 다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 영업 판정 (Task 6 다) 강제 OFF: 영업 신원이어도 트랜잭션과 잠금을 타지 않는다 (현행 경로)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"강제 OFF: 영업 신원이어도 트랜잭션과 잠금을 타지 않는다 (현행 경로)"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 등록: 이름 중복 검사와 등록 뒤 상세 조회를 같은 트랜잭션에서 한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"등록: 이름 중복 검사와 등록 뒤 상세 조회를 같은 트랜잭션에서 한다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 수정: 상세 응답 조회를 같은 트랜잭션에서 한다 (쓰기 전 값이 아니라 쓰기 뒤 값을 준다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"수정: 상세 응답 조회를 같은 트랜잭션에서 한다 (쓰기 전 값이 아니라 쓰기 뒤 값을 준다)"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 이동: 대상 조회 · 이동 · 상세 조회가 모두 같은 트랜잭션이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"이동: 대상 조회 · 이동 · 상세 조회가 모두 같은 트랜잭션이다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 삭제: 하위 조직 조회 · 활성 계약 가드 · 삭제가 모두 같은 트랜잭션이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"삭제: 하위 조직 조회 · 활성 계약 가드 · 삭제가 모두 같은 트랜잭션이다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 삭제: 기업 행 잠금 앞 트랜잭션 안에는 잠금 없는 읽기가 없고, 회원 재확인만 잠금 뒤 잠금 없는 읽기다 (M6c Task 3)","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"삭제: 기업 행 잠금 앞 트랜잭션 안에는 잠금 없는 읽기가 없고, 회원 재확인만 잠금 뒤 잠금 없는 읽기다 (M6c Task 3)"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 삭제: 기업 잠금 뒤 회원 재확인이 달라지면 한 번 더 하고, 그때 같으면 성공한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"삭제: 기업 잠금 뒤 회원 재확인이 달라지면 한 번 더 하고, 그때 같으면 성공한다"},{"ancestorTitles":["강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 조직 쓰기의 읽기도 쓰기 트랜잭션을 탄다 (M6b 보완 · 풀 두 번째 연결 방지) 삭제: 재확인이 두 번 다르면 409 이고 삭제 0회다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"삭제: 재확인이 두 번 다르면 409 이고 삭제 0회다"},{"ancestorTitles":["강제 ON · 기업 · 조직관리자 삭제도 같은 잠금 순서를 탄다 (M6c R3 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 · 조직관리자 삭제도 같은 잠금 순서를 탄다 (M6c R3 MEDIUM) 삭제: 기업 신원도 회원 선행 잠금 → 기업 행 잠금 → 재확인 순서로 트랜잭션 안에서 지운다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"삭제: 기업 신원도 회원 선행 잠금 → 기업 행 잠금 → 재확인 순서로 트랜잭션 안에서 지운다"},{"ancestorTitles":["강제 ON · 기업 · 조직관리자 삭제도 같은 잠금 순서를 탄다 (M6c R3 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"강제 ON · 기업 · 조직관리자 삭제도 같은 잠금 순서를 탄다 (M6c R3 MEDIUM) 강제 OFF: 기업 신원의 삭제는 트랜잭션을 타지 않는다 (현행 경로)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"강제 OFF: 기업 신원의 삭제는 트랜잭션을 타지 않는다 (현행 경로)"}],"endTime":1793868744139,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/organization/organization.service.sales-write.spec.ts","startTime":1793868744085,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AnalysisTargetGuard"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard 대상 ID 를 둘 이상 주면 막는다 — oddId 와 bodId","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상 ID 를 둘 이상 주면 막는다 — oddId 와 bodId"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard 대상 ID 를 둘 이상 주면 막는다 — oddId 와 codId","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상 ID 를 둘 이상 주면 막는다 — oddId 와 codId"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard 대상 ID 를 둘 이상 주면 막는다 — bodId 와 codId","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상 ID 를 둘 이상 주면 막는다 — bodId 와 codId"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard bodId 는 그 bodId 의 B2C 인증 쿠키 · 통합관리자만 통과시킨다","invocations":1,"location":null,"numPassingAsserts":17,"retryReasons":[],"status":"passed","title":"bodId 는 그 bodId 의 B2C 인증 쿠키 · 통합관리자만 통과시킨다"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard B2C 쿠키의 고정값 verified 는 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"B2C 쿠키의 고정값 verified 는 막는다"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard B2C 쿠키 서명을 다른 bodId 이름으로 옮기면 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"B2C 쿠키 서명을 다른 bodId 이름으로 옮기면 막는다"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard B2C 쿠키 서명이 변조되거나 만료되면 막는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"B2C 쿠키 서명이 변조되거나 만료되면 막는다"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard codId 는 통합관리자만 통과시킨다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"codId 는 통합관리자만 통과시킨다"},{"ancestorTitles":["AnalysisTargetGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard oddId 단독 · ID 없음은 서비스 검증에 맡기고 통과시킨다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"oddId 단독 · ID 없음은 서비스 검증에 맡기고 통과시킨다"},{"ancestorTitles":["AnalysisTargetGuard","oddId 단독 + 관리자 신원"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard oddId 단독 + 관리자 신원 판정이 참이면 번호를 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정이 참이면 번호를 남긴다"},{"ancestorTitles":["AnalysisTargetGuard","oddId 단독 + 관리자 신원"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard oddId 단독 + 관리자 신원 판정이 거짓이어도 던지지 않고 번호를 남기지 않는다 (회원 소유자 판정이 서비스에 있다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정이 거짓이어도 던지지 않고 번호를 남기지 않는다 (회원 소유자 판정이 서비스에 있다)"},{"ancestorTitles":["AnalysisTargetGuard","oddId 단독 + 관리자 신원"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard oddId 단독 + 관리자 신원 숫자 문자열이 아닌 oddId 는 판정 질의를 돌리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"숫자 문자열이 아닌 oddId 는 판정 질의를 돌리지 않는다"},{"ancestorTitles":["AnalysisTargetGuard","oddId 단독 + 관리자 신원"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AnalysisTargetGuard oddId 단독 + 관리자 신원 관리자 신원이 없으면 판정 질의를 돌리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 신원이 없으면 판정 질의를 돌리지 않는다"}],"endTime":1793868744161,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/analysis-target.guard.spec.ts","startTime":1793868744092,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록이 있으면 컨트롤러 가드는 복원을 한 번도 다시 하지 않는다 (재조회 없음)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"확정 기록이 있으면 컨트롤러 가드는 복원을 한 번도 다시 하지 않는다 (재조회 없음)"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록이 있으면 컨트롤러 가드는 확정 값을 덮지 않는다 (원 토큰 pv 4 대신 확정 pv 5)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"확정 기록이 있으면 컨트롤러 가드는 확정 값을 덮지 않는다 (원 토큰 pv 4 대신 확정 pv 5)"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록의 재발급 판단이 참이면 쿠키를 한 번 다시 쓰고 복원은 재조회하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"확정 기록의 재발급 판단이 참이면 쿠키를 한 번 다시 쓰고 복원은 재조회하지 않는다"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록이 null 이면 선택 가드는 익명이고 복원을 다시 하지 않는다 (익명 · 재조회 없음)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"확정 기록이 null 이면 선택 가드는 익명이고 복원을 다시 하지 않는다 (익명 · 재조회 없음)"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록이 오류면 선택 가드는 익명이고 원인을 로그에 남긴다 (판정 불가 · 저장소 오류, 재조회 없음)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"확정 기록이 오류면 선택 가드는 익명이고 원인을 로그에 남긴다 (판정 불가 · 저장소 오류, 재조회 없음)"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록이 null 이면 컨트롤러 가드는 401 이고 재조회하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"확정 기록이 null 이면 컨트롤러 가드는 401 이고 재조회하지 않는다"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 확정 기록이 판정 불가 오류면 컨트롤러 가드는 503 으로 현행 매핑을 낸다 (재조회 없음)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"확정 기록이 판정 불가 오류면 컨트롤러 가드는 503 으로 현행 매핑을 낸다 (재조회 없음)"},{"ancestorTitles":["확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 기록을 읽는 컨트롤러 · 선택 가드 (admin-guard-confirmed) 기록이 없으면 현행대로 복원을 한 번 하고 결과를 요청에 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기록이 없으면 현행대로 복원을 한 번 하고 결과를 요청에 쓴다"}],"endTime":1793868744214,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/admin-guard-confirmed.spec.ts","startTime":1793868744140,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 SND001 결제 → 결제내역","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SND001 결제 → 결제내역"},{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 SND002 분석(일반) → 일반분석 목록","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SND002 분석(일반) → 일반분석 목록"},{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 SND002 분석(실손) → 실손분석 목록","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SND002 분석(실손) → 실손분석 목록"},{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 SND003 팩스 → 청구서 목록 (죽은 팩스 경로로 보내지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SND003 팩스 → 청구서 목록 (죽은 팩스 경로로 보내지 않는다)"},{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 미지 타입 → 메인 (파생 실패가 이벤트 상세로 새지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"미지 타입 → 메인 (파생 실패가 이벤트 상세로 새지 않는다)"},{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 알람타입 코드는 AlarmType enum 이 정본이다 — 유틸이 문자열을 다시 적지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"알람타입 코드는 AlarmType enum 이 정본이다 — 유틸이 문자열을 다시 적지 않는다"},{"ancestorTitles":["resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAlarmDeepLink — 알람타입별 인앱 목적지 결정 반환값은 항상 인앱 상대경로다 — 절대 URL 을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"반환값은 항상 인앱 상대경로다 — 절대 URL 을 만들지 않는다"}],"endTime":1793868744223,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alarm/alarm-deeplink.util.spec.ts","startTime":1793868744162,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 기동 seed — 지정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 지정 seed: 대상 번호와 로그인 아이디가 함께 맞으면 표시 칸을 1 로 지정하고 그 행을 출력한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"seed: 대상 번호와 로그인 아이디가 함께 맞으면 표시 칸을 1 로 지정하고 그 행을 출력한다"},{"ancestorTitles":["최고관리자 기동 seed — 지정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 지정 seed: 번호는 같고 로그인 아이디가 다르면 지정하지 않고 멈춘다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"seed: 번호는 같고 로그인 아이디가 다르면 지정하지 않고 멈춘다"},{"ancestorTitles":["최고관리자 기동 seed — 지정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 지정 seed: 대상 번호의 행이 없으면 만들지 않고 멈춘다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"seed: 대상 번호의 행이 없으면 만들지 않고 멈춘다"},{"ancestorTitles":["최고관리자 기동 seed — 지정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 지정 seed: 다른 계정이 이미 최고관리자면 옮기지 않고 멈춘다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"seed: 다른 계정이 이미 최고관리자면 옮기지 않고 멈춘다"},{"ancestorTitles":["최고관리자 기동 seed — 지정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 지정 seed: 대상이 이미 최고관리자면 쓰지 않고 그 행을 출력한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"seed: 대상이 이미 최고관리자면 쓰지 않고 그 행을 출력한다"},{"ancestorTitles":["최고관리자 기동 seed — DDL"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — DDL ddl: 칸이 없으면 잠금 대기 상한을 건 연결에서 칸·유일 인덱스·값 제약을 한 문장으로 더하고 상한을 되돌린다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"ddl: 칸이 없으면 잠금 대기 상한을 건 연결에서 칸·유일 인덱스·값 제약을 한 문장으로 더하고 상한을 되돌린다"},{"ancestorTitles":["최고관리자 기동 seed — DDL"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — DDL ddl: 잠금 상한 복원이 실패하면 그 연결을 파기한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"ddl: 잠금 상한 복원이 실패하면 그 연결을 파기한다"},{"ancestorTitles":["최고관리자 기동 seed — DDL"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — DDL ddl: 풀 경로와 트랜잭션 경로가 같은 세 문장을 쓴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"ddl: 풀 경로와 트랜잭션 경로가 같은 세 문장을 쓴다"},{"ancestorTitles":["최고관리자 기동 seed — DDL"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — DDL ddl: 칸과 유일 인덱스가 있으면 DDL 을 건너뛴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"ddl: 칸과 유일 인덱스가 있으면 DDL 을 건너뛴다"},{"ancestorTitles":["최고관리자 기동 seed — DDL"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — DDL ddl: 칸은 있는데 유일 인덱스가 없으면 지정하지 않고 멈춘다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ddl: 칸은 있는데 유일 인덱스가 없으면 지정하지 않고 멈춘다"},{"ancestorTitles":["최고관리자 기동 seed — DDL"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — DDL ddl: 칸 추가가 중복 칸 오류면 다시 읽어 칸과 유일 인덱스가 있으면 이어 간다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ddl: 칸 추가가 중복 칸 오류면 다시 읽어 칸과 유일 인덱스가 있으면 이어 간다"},{"ancestorTitles":["최고관리자 기동 seed — 실행기와 출력"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 실행기와 출력 runner: seed 가 던져도 runSeeds 는 던지지 않고 실패를 오류 로그로 남긴다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"runner: seed 가 던져도 runSeeds 는 던지지 않고 실패를 오류 로그로 남긴다"},{"ancestorTitles":["최고관리자 기동 seed — 실행기와 출력"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 기동 seed — 실행기와 출력 log: 출력은 번호·로그인 아이디·생성일만 싣고 이름·연락처·비밀번호 칸을 읽지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"log: 출력은 번호·로그인 아이디·생성일만 싣고 이름·연락처·비밀번호 칸을 읽지 않는다"}],"endTime":1793868744274,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/seeds/super-admin.seed.spec.ts","startTime":1793868744215,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["소비처 같은 값 (consumers-same-value)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"소비처 같은 값 (consumers-same-value) 대표 소비처 세 곳이 읽는 관리자 칸은 가드가 채운 확정 객체와 같은 값이다 (낡은 원 토큰 값 아님)","invocations":1,"location":null,"numPassingAsserts":31,"retryReasons":[],"status":"passed","title":"대표 소비처 세 곳이 읽는 관리자 칸은 가드가 채운 확정 객체와 같은 값이다 (낡은 원 토큰 값 아님)"},{"ancestorTitles":["소비처 같은 값 (consumers-same-value)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"소비처 같은 값 (consumers-same-value) 소비처가 읽는 칸 role · corpScope · agcId 는 복원 결과 값이고 원 토큰 값이 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"소비처가 읽는 칸 role · corpScope · agcId 는 복원 결과 값이고 원 토큰 값이 아니다"}],"endTime":1793868744285,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/consumers-same-value.spec.ts","startTime":1793868744224,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 judge: strict 는 admin 역할이고 admin-view 토큰이 아니며 그 번호가 지정 행이면 참이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: strict 는 admin 역할이고 admin-view 토큰이 아니며 그 번호가 지정 행이면 참이다"},{"ancestorTitles":["최고관리자 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 judge: strict 는 지정 행이 다른 번호면 거짓이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: strict 는 지정 행이 다른 번호면 거짓이다"},{"ancestorTitles":["최고관리자 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 judge: corp·sales 역할은 번호가 같아도 최고관리자가 아니다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"judge: corp·sales 역할은 번호가 같아도 최고관리자가 아니다"},{"ancestorTitles":["최고관리자 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 judge: 역할이나 신원이 없으면 두 경로 모두 DB 를 묻지 않고 거짓이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"judge: 역할이나 신원이 없으면 두 경로 모두 DB 를 묻지 않고 거짓이다"},{"ancestorTitles":["최고관리자 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 judge: 조회가 실패하면 가드 경로는 거짓이고 판정 경로는 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 조회가 실패하면 가드 경로는 거짓이고 판정 경로는 던진다"},{"ancestorTitles":["최고관리자 판정"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 judge: 표시 칸이 없으면 가드 경로는 거짓이고 판정 경로는 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"judge: 표시 칸이 없으면 가드 경로는 거짓이고 판정 경로는 던진다"},{"ancestorTitles":["최고관리자 판정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 designation: 표시 칸이 1 인 행을 요청마다 다시 읽는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"designation: 표시 칸이 1 인 행을 요청마다 다시 읽는다"},{"ancestorTitles":["최고관리자 판정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 판정 designation: 표시 칸이 없으면(1054) 칸 없음이고 다른 조회 실패는 던진다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"designation: 표시 칸이 없으면(1054) 칸 없음이고 다른 조회 실패는 던진다"}],"endTime":1793868744339,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/super-admin.service.spec.ts","startTime":1793868744275,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["CarViewAdminGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard car: 최고관리자 지정을 요청마다 물어 admin 을 통과시킨다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"car: 최고관리자 지정을 요청마다 물어 admin 을 통과시킨다"},{"ancestorTitles":["CarViewAdminGuard"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard car: 지정되지 않은 admin 은 차단한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"car: 지정되지 않은 admin 은 차단한다"},{"ancestorTitles":["CarViewAdminGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard car: corp 역할은 최고관리자 판정과 무관하게 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"car: corp 역할은 최고관리자 판정과 무관하게 통과한다"},{"ancestorTitles":["CarViewAdminGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard [M11] 행 허용: 권한 행 판정이 참이면 최고관리자 판정을 묻지 않고 통과한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[M11] 행 허용: 권한 행 판정이 참이면 최고관리자 판정을 묻지 않고 통과한다"},{"ancestorTitles":["CarViewAdminGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard [M11] 행 없음 차단: 행 판정이 거짓이고 최고관리자도 아니면 차단한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[M11] 행 없음 차단: 행 판정이 거짓이고 최고관리자도 아니면 차단한다"},{"ancestorTitles":["CarViewAdminGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard car: role 이 admin 이 아니면 최고관리자 판정을 묻지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"car: role 이 admin 이 아니면 최고관리자 판정을 묻지 않는다"},{"ancestorTitles":["CarViewAdminGuard","CAR_VIEW_ADMIN_IDS 허용목록"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard CAR_VIEW_ADMIN_IDS 허용목록 [M11] env 허용: 목록에 든 admin 은 행 판정도 최고관리자 판정도 묻지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[M11] env 허용: 목록에 든 admin 은 행 판정도 최고관리자 판정도 묻지 않는다"},{"ancestorTitles":["CarViewAdminGuard","CAR_VIEW_ADMIN_IDS 허용목록"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard CAR_VIEW_ADMIN_IDS 허용목록 car: 목록에 든 비-최고관리자 admin 은 최고관리자 판정을 묻지 않고 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"car: 목록에 든 비-최고관리자 admin 은 최고관리자 판정을 묻지 않고 통과한다"},{"ancestorTitles":["CarViewAdminGuard","CAR_VIEW_ADMIN_IDS 허용목록"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard CAR_VIEW_ADMIN_IDS 허용목록 car: 목록 밖 admin 은 최고관리자 판정을 그대로 탄다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"car: 목록 밖 admin 은 최고관리자 판정을 그대로 탄다"},{"ancestorTitles":["CarViewAdminGuard","CAR_VIEW_ADMIN_IDS 허용목록"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard CAR_VIEW_ADMIN_IDS 허용목록 car: 빈 목록은 아무도 통과시키지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"car: 빈 목록은 아무도 통과시키지 않는다"},{"ancestorTitles":["CarViewAdminGuard","CAR_VIEW_ADMIN_IDS 허용목록"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CarViewAdminGuard CAR_VIEW_ADMIN_IDS 허용목록 car: 목록은 admin 역할에만 닿는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"car: 목록은 admin 역할에만 닿는다"}],"endTime":1793868744362,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/car-view-admin.guard.spec.ts","startTime":1793868744291,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyPolicyRepository 유효 버전·구간 상품"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 유효 버전·구간 상품 적용 시작일이 기준일 이하인 가장 늦은 버전을 고른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적용 시작일이 기준일 이하인 가장 늦은 버전을 고른다"},{"ancestorTitles":["AgencyPolicyRepository 유효 버전·구간 상품"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 유효 버전·구간 상품 버전이 없는 기업은 구간 없이 계약 상품이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"버전이 없는 기업은 구간 없이 계약 상품이다"},{"ancestorTitles":["AgencyPolicyRepository 유효 버전·구간 상품"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 유효 버전·구간 상품 가입일과 무관하게 계약 상품인 버전은 구간을 돌려주지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"가입일과 무관하게 계약 상품인 버전은 구간을 돌려주지 않는다"},{"ancestorTitles":["AgencyPolicyRepository 유효 버전·구간 상품"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 유효 버전·구간 상품 모든 버전의 구간 상품을 모아 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모든 버전의 구간 상품을 모아 돌려준다"},{"ancestorTitles":["AgencyPolicyRepository 유효 버전·구간 상품"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 유효 버전·구간 상품 적용이 시작되지 않은 예약 버전의 구간 상품은 모으지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"적용이 시작되지 않은 예약 버전의 구간 상품은 모으지 않는다"},{"ancestorTitles":["AgencyPolicyRepository 목록 검색·필터(M5)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 목록 검색·필터(M5) 검색·필터 파라미터가 없으면 목록과 건수 쿼리에 조건을 걸지 않는다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"검색·필터 파라미터가 없으면 목록과 건수 쿼리에 조건을 걸지 않는다"},{"ancestorTitles":["AgencyPolicyRepository 목록 검색·필터(M5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 목록 검색·필터(M5) 검색·필터가 있으면 목록과 건수 쿼리에 같은 조건 객체를 건다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"검색·필터가 있으면 목록과 건수 쿼리에 같은 조건 객체를 건다"},{"ancestorTitles":["AgencyPolicyRepository 목록 검색·필터(M5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 목록 검색·필터(M5) 정책 필터 셋은 적용 시작일을 기준일과 <= 또는 > 로 비교한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"정책 필터 셋은 적용 시작일을 기준일과 <= 또는 > 로 비교한다"},{"ancestorTitles":["AgencyPolicyRepository 목록 검색·필터(M5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 목록 검색·필터(M5) 검색어의 %·_·! 를 ! 로 이스케이프해 ESCAPE 절과 함께 파라미터로 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"검색어의 %·_·! 를 ! 로 이스케이프해 ESCAPE 절과 함께 파라미터로 넘긴다"},{"ancestorTitles":["AgencyPolicyRepository 버전 이력"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AgencyPolicyRepository 버전 이력 등록자 이름(adm_name 암호문)을 FN_DECRYPT 로 풀어 고른다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"등록자 이름(adm_name 암호문)을 FN_DECRYPT 로 풀어 고른다"}],"endTime":1793868744399,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/policy/policy.repository.spec.ts","startTime":1793868744343,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatCarCanaryService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatCarCanaryService B2C/타 공급자/master OFF는 자동차 좌석을 예약하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"B2C/타 공급자/master OFF는 자동차 좌석을 예약하지 않는다"},{"ancestorTitles":["TreatCarCanaryService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatCarCanaryService master+자동차 카나리 ON이면 inhouse가 전역 3석을 예약한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"master+자동차 카나리 ON이면 inhouse가 전역 3석을 예약한다"},{"ancestorTitles":["TreatCarCanaryService"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"TreatCarCanaryService master+자동차 카나리 ON이면 coocon가 전역 3석을 예약한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"master+자동차 카나리 ON이면 coocon가 전역 3석을 예약한다"},{"ancestorTitles":["TreatCarCanaryService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatCarCanaryService master+자동차 카나리 ON이면 octover가 전역 3석을 예약한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"master+자동차 카나리 ON이면 octover가 전역 3석을 예약한다"},{"ancestorTitles":["TreatCarCanaryService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatCarCanaryService Redis 만석/장애면 건강만 진행하도록 null이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"Redis 만석/장애면 건강만 진행하도록 null이다"},{"ancestorTitles":["TreatCarCanaryService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatCarCanaryService 자동차 후행 호출이 끝나면 strict 좌석을 반납한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 후행 호출이 끝나면 strict 좌석을 반납한다"}],"endTime":1793868744426,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/treat-car-canary.service.spec.ts","startTime":1793868744363,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["LossAnalysisRepository retention"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisRepository retention 상태와 무관하게 30일이 지난 행의 분석 내용과 연결 usr_id 를 비운다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"상태와 무관하게 30일이 지난 행의 분석 내용과 연결 usr_id 를 비운다"},{"ancestorTitles":["LossAnalysisRepository retention"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisRepository retention 로그는 30일이 지난 행을 500건 배치로 지우고 0건이 되면 멈춘다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"로그는 30일이 지난 행을 500건 배치로 지우고 0건이 되면 멈춘다"},{"ancestorTitles":["의료비·보험금분석 상태 기준"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"의료비·보험금분석 상태 기준 진료분석 공통 상태로 변환한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"진료분석 공통 상태로 변환한다"},{"ancestorTitles":["의료비·보험금분석 상태 기준"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"의료비·보험금분석 상태 기준 인증 요청 성공 전 초대는 분석목록에서 제외한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"인증 요청 성공 전 초대는 분석목록에서 제외한다"},{"ancestorTitles":["LossAnalysisRepository 인증 시작"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisRepository 인증 시작 재사용 가능한 승인 세션 복구 시 원래 만료 기준시각을 보존한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"재사용 가능한 승인 세션 복구 시 원래 만료 기준시각을 보존한다"},{"ancestorTitles":["LossAnalysisRepository 인증 시작"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"LossAnalysisRepository 인증 시작 초대 선점·수량 예약·STARTING 행을 한 트랜잭션에서 만든다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"초대 선점·수량 예약·STARTING 행을 한 트랜잭션에서 만든다"},{"ancestorTitles":["실손 변경 전화번호 저장"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"실손 변경 전화번호 저장 STARTING 선점 결과 1에 따라 번호를 암호화 저장한다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"STARTING 선점 결과 1에 따라 번호를 암호화 저장한다"},{"ancestorTitles":["실손 변경 전화번호 저장"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"실손 변경 전화번호 저장 STARTING 선점 결과 0에 따라 번호를 암호화 저장한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"STARTING 선점 결과 0에 따라 번호를 암호화 저장한다"},{"ancestorTitles":[],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이전 세션 취소가 갱신에 실패하면 새 요청의 예약을 환불하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"이전 세션 취소가 갱신에 실패하면 새 요청의 예약을 환불하지 않는다"}],"endTime":1793868744455,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/loss-analysis/loss-analysis.repository.spec.ts","startTime":1793868744401,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["runDeleteTreat (묶음 격리)"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"runDeleteTreat (묶음 격리) (a) 세 묶음이 모두 성공하면 0 을 돌려주고 성공 하트비트를 한 번 남긴다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"(a) 세 묶음이 모두 성공하면 0 을 돌려주고 성공 하트비트를 한 번 남긴다"},{"ancestorTitles":["runDeleteTreat (묶음 격리)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runDeleteTreat (묶음 격리) (b) 심평원 묶음이 던져도 나머지 두 묶음은 한 번씩 돌고, 실패 하트비트를 남긴다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"(b) 심평원 묶음이 던져도 나머지 두 묶음은 한 번씩 돌고, 실패 하트비트를 남긴다"},{"ancestorTitles":["runDeleteTreat (묶음 격리)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runDeleteTreat (묶음 격리) (c) 마크 기록 쓰기가 실패하면 runDeleteTreat 가 그 오류로 reject 한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(c) 마크 기록 쓰기가 실패하면 runDeleteTreat 가 그 오류로 reject 한다"},{"ancestorTitles":["runDeleteTreat (묶음 격리)"],"duration":24,"failureDetails":[],"failureMessages":[],"fullName":"runDeleteTreat (묶음 격리) (d) 스펙 파일을 import 만 해도 DB 를 열지 않고 프로세스를 끝내지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(d) 스펙 파일을 import 만 해도 DB 를 열지 않고 프로세스를 끝내지 않는다"},{"ancestorTitles":["runAsMain (종료 코드)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runAsMain (종료 코드) (e1) run 이 0 을 돌려주면 종료 코드 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"(e1) run 이 0 을 돌려주면 종료 코드 0"},{"ancestorTitles":["runAsMain (종료 코드)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"runAsMain (종료 코드) (e2) 실패 개수 1 · 3, undefined, NaN 은 모두 종료 코드 1","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(e2) 실패 개수 1 · 3, undefined, NaN 은 모두 종료 코드 1"},{"ancestorTitles":["runAsMain (종료 코드)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"runAsMain (종료 코드) (e3) run 이 던지면 종료 코드 1 이고, 로그는 오류 종류와 드라이버 코드만 싣는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(e3) run 이 던지면 종료 코드 1 이고, 로그는 오류 종류와 드라이버 코드만 싣는다"}],"endTime":1793868744492,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/delete-treat.schedule.spec.ts","startTime":1793868744428,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TossService.deleteBillingKey"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: DELETE 를 결제 엔드포인트 + 빌링키 경로로 시크릿 키 기본 인증과 함께 보낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"빌링키 폐기: DELETE 를 결제 엔드포인트 + 빌링키 경로로 시크릿 키 기본 인증과 함께 보낸다"},{"ancestorTitles":["TossService.deleteBillingKey"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: 200 이면 폐기됨으로 답한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빌링키 폐기: 200 이면 폐기됨으로 답한다"},{"ancestorTitles":["TossService.deleteBillingKey"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: 404 NOT_FOUND_BILLING 이면 이미 없음으로 답한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빌링키 폐기: 404 NOT_FOUND_BILLING 이면 이미 없음으로 답한다"},{"ancestorTitles":["TossService.deleteBillingKey"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: 400 ALREADY_REMOVED_BILLING_KEY(이미 폐기한 키) 면 이미 없음으로 답한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빌링키 폐기: 400 ALREADY_REMOVED_BILLING_KEY(이미 폐기한 키) 면 이미 없음으로 답한다"},{"ancestorTitles":["TossService.deleteBillingKey"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: 다른 오류 코드(404 NOT_FOUND 포함) · 5xx · 응답 없음은 던진다","invocations":1,"location":null,"numPassingAsserts":14,"retryReasons":[],"status":"passed","title":"빌링키 폐기: 다른 오류 코드(404 NOT_FOUND 포함) · 5xx · 응답 없음은 던진다"},{"ancestorTitles":["TossService.deleteBillingKey"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: 2xx 라도 본문이 비어 있지 않은 문자열이면 폐기됨으로 읽지 않고 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빌링키 폐기: 2xx 라도 본문이 비어 있지 않은 문자열이면 폐기됨으로 읽지 않고 던진다"},{"ancestorTitles":["TossService.deleteBillingKey"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TossService.deleteBillingKey 빌링키 폐기: 빈 빌링키는 토스를 부르지 않고 이미 없음으로 답한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"빌링키 폐기: 빈 빌링키는 토스를 부르지 않고 이미 없음으로 답한다"}],"endTime":1793868744535,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/pg/src/toss/toss-billing-delete.spec.ts","startTime":1793868744458,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 콘솔로 옮긴 메뉴 목록이 비어 있지 않다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"menu: 콘솔로 옮긴 메뉴 목록이 비어 있지 않다"},{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 콘솔로 옮긴 메뉴는 관리자 개입 기록과 영업비 정산이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"menu: 콘솔로 옮긴 메뉴는 관리자 개입 기록과 영업비 정산이다"},{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 콘솔로 옮긴 메뉴가 최고관리자 사이드바 트리에서 빠진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"menu: 콘솔로 옮긴 메뉴가 최고관리자 사이드바 트리에서 빠진다"},{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 콘솔로 옮긴 메뉴가 권한 배분 사이드바 트리에서도 빠진다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"menu: 콘솔로 옮긴 메뉴가 권한 배분 사이드바 트리에서도 빠진다"},{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 권한 설정용 전체 트리에는 콘솔로 옮긴 메뉴가 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"menu: 권한 설정용 전체 트리에는 콘솔로 옮긴 메뉴가 남는다"},{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 콘솔로 옮긴 메뉴의 자손도 목록에서 함께 빠진다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"menu: 콘솔로 옮긴 메뉴의 자손도 목록에서 함께 빠진다"},{"ancestorTitles":["콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"콘솔로 옮긴 메뉴의 사이드바 제외 (hardening M6a DD6) menu: 같은 부모의 형제 메뉴는 사이드바에 남는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"menu: 같은 부모의 형제 메뉴는 사이드바에 남는다"},{"ancestorTitles":["숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김) menu: 숨긴 기능 메뉴 목록이 고정되어 있다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"menu: 숨긴 기능 메뉴 목록이 고정되어 있다"},{"ancestorTitles":["숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김) menu: 숨긴 메뉴는 최고관리자·그룹관리자 사이드바에서 모두 빠진다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"menu: 숨긴 메뉴는 최고관리자·그룹관리자 사이드바에서 모두 빠진다"},{"ancestorTitles":["숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김) menu: 숨긴 메뉴만 자식이던 빈 그룹은 사이드바에서 함께 빠진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"menu: 숨긴 메뉴만 자식이던 빈 그룹은 사이드바에서 함께 빠진다"},{"ancestorTitles":["숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김) menu: 자식이 하나라도 남은 그룹은 숨김 뒤에도 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"menu: 자식이 하나라도 남은 그룹은 숨김 뒤에도 남는다"},{"ancestorTitles":["숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"숨긴 기능 메뉴의 사이드바 제외 (손해사정 숨김) menu: 권한 설정용 전체 트리에는 숨긴 메뉴가 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"menu: 권한 설정용 전체 트리에는 숨긴 메뉴가 남는다"}],"endTime":1793868744559,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/menu.service.spec.ts","startTime":1793868744494,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["RISK_MONEY_ACTIONS — 금전 어휘 × durable 유도(D4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"RISK_MONEY_ACTIONS — 금전 어휘 × durable 유도(D4) 내구 행이 있는 금전 행위 7종이고 만료·보안 어휘가 없다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"내구 행이 있는 금전 행위 7종이고 만료·보안 어휘가 없다"},{"ancestorTitles":["countRiskMoney — 어휘 좁힘 · 집계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"countRiskMoney — 어휘 좁힘 · 집계 조건이 금전 어휘로 좁히고 창 하한·SYSTEM 배제를 건다","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"조건이 금전 어휘로 좁히고 창 하한·SYSTEM 배제를 건다"},{"ancestorTitles":["countRiskMoney — 어휘 좁힘 · 집계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"countRiskMoney — 어휘 좁힘 · 집계 행을 가져오지 않고 묶어 센다 — count · max · min · 5칸 groupBy","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"행을 가져오지 않고 묶어 센다 — count · max · min · 5칸 groupBy"},{"ancestorTitles":["countRiskMoney — 어휘 좁힘 · 집계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"countRiskMoney — 어휘 좁힘 · 집계 드라이버 문자열을 수로 바꾸고 null 은 null 로 둔다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"드라이버 문자열을 수로 바꾸고 null 은 null 로 둔다"},{"ancestorTitles":["findRiskBatches — 배치 행(D7)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"findRiskBatches — 배치 행(D7) 배치 칸이 있는 금전 행만 · 최신 먼저","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"배치 칸이 있는 금전 행만 · 최신 먼저"},{"ancestorTitles":["findRiskSignins — 로그인 성공·실패(D10)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"findRiskSignins — 로그인 성공·실패(D10) 두 로그인 행위 · 두 결과를 함께 읽고 자칭 라벨 칸을 낸다","invocations":1,"location":null,"numPassingAsserts":13,"retryReasons":[],"status":"passed","title":"두 로그인 행위 · 두 결과를 함께 읽고 자칭 라벨 칸을 낸다"}],"endTime":1793868744611,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit-log/audit-log-risk.spec.ts","startTime":1793868744539,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["조직 이동 · 서비스 경로의 예외 상태"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직 이동 · 서비스 경로의 예외 상태 잠금 뒤 순환 재판정 (저장소가 400 을 던짐) 은 서비스에서도 400 이고 500 으로 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"잠금 뒤 순환 재판정 (저장소가 400 을 던짐) 은 서비스에서도 400 이고 500 으로 바뀌지 않는다"}],"endTime":1793868744675,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/organization/organization.service.move.spec.ts","startTime":1793868744561,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["MedicationStandardRepository.getDosing30DayGroups"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"MedicationStandardRepository.getDosing30DayGroups 일반회원 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"일반회원 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다"},{"ancestorTitles":["MedicationStandardRepository.getDosing30DayGroups"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MedicationStandardRepository.getDosing30DayGroups B2C 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"B2C 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다"},{"ancestorTitles":["MedicationStandardRepository.getDosing30DayGroups"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"MedicationStandardRepository.getDosing30DayGroups 고객사 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"고객사 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다"},{"ancestorTitles":["MedicationStandardRepository.getDosing30DayGroups"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MedicationStandardRepository.getDosing30DayGroups 30일 미만이면 기본진료를 추가 조회하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"30일 미만이면 기본진료를 추가 조회하지 않는다"},{"ancestorTitles":["MedicationStandardRepository.getDosing30DayGroups"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MedicationStandardRepository.getDosing30DayGroups minTotalDays 를 0 으로 주면 30일 미만 분류도 돌려준다 — 상병별 판정 입력","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"minTotalDays 를 0 으로 주면 30일 미만 분류도 돌려준다 — 상병별 판정 입력"}],"endTime":1793868744679,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/medication-standard/medication-standard.repository.spec.ts","startTime":1793868744613,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 사이드바 메뉴"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 사이드바 메뉴 menu: 최고관리자에게는 권한 그룹 매핑과 무관하게 콘솔로 옮긴 메뉴를 뺀 전체 메뉴 트리를 낸다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"menu: 최고관리자에게는 권한 그룹 매핑과 무관하게 콘솔로 옮긴 메뉴를 뺀 전체 메뉴 트리를 낸다"},{"ancestorTitles":["최고관리자 사이드바 메뉴"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 사이드바 메뉴 menu: 최고관리자가 아니면 권한 그룹 매핑 메뉴만 낸다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"menu: 최고관리자가 아니면 권한 그룹 매핑 메뉴만 낸다"}],"endTime":1793868744727,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/menu-super.spec.ts","startTime":1793868744681,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["CardRepository 빌링키 폐기 보조 쿼리"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CardRepository 빌링키 폐기 보조 쿼리 카드 저장소: 소유 조회는 요청 id 와 토큰 회원 둘 다로 거른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 저장소: 소유 조회는 요청 id 와 토큰 회원 둘 다로 거른다"},{"ancestorTitles":["CardRepository 빌링키 폐기 보조 쿼리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardRepository 빌링키 폐기 보조 쿼리 카드 저장소: 삭제는 폐기된 id 와 토큰 회원 둘 다로 거른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 저장소: 삭제는 폐기된 id 와 토큰 회원 둘 다로 거른다"},{"ancestorTitles":["CardRepository 빌링키 폐기 보조 쿼리"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CardRepository 빌링키 폐기 보조 쿼리 카드 저장소: 소유 조회는 crdId 오름차순으로 돌려준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카드 저장소: 소유 조회는 crdId 오름차순으로 돌려준다"}],"endTime":1793868744732,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/card/card.repository.spec.ts","startTime":1793868744677,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AgencyTermsRepository fixed types"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AgencyTermsRepository fixed types 공개 약관과 기본내용 조회를 지원 타입으로 제한한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"공개 약관과 기본내용 조회를 지원 타입으로 제한한다"}],"endTime":1793868744780,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/terms/terms.repository.spec.ts","startTime":1793868744729,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 지정 상태 알림 규칙"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 지정 상태 알림 규칙 rule: 지정 행이 있으면 경고가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rule: 지정 행이 있으면 경고가 없다"},{"ancestorTitles":["최고관리자 지정 상태 알림 규칙"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 지정 상태 알림 규칙 rule: 표시 칸이 없거나 지정 행이 없으면 사유를 담은 주의 경고 하나를 낸다","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"rule: 표시 칸이 없거나 지정 행이 없으면 사유를 담은 주의 경고 하나를 낸다"},{"ancestorTitles":["최고관리자 지정 상태 알림 규칙"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 지정 상태 알림 규칙 rule: 지정 조회가 실패하면 던져 미평가로 남긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"rule: 지정 조회가 실패하면 던져 미평가로 남긴다"}],"endTime":1793868744786,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/rules/super-admin.rule.spec.ts","startTime":1793868744734,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AligoService 문자 대체발송 스위치(ALIGO_FORCE_SMS)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AligoService 문자 대체발송 스위치(ALIGO_FORCE_SMS) 스위치가 없으면 알림톡 API 로 보낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"스위치가 없으면 알림톡 API 로 보낸다"},{"ancestorTitles":["AligoService 문자 대체발송 스위치(ALIGO_FORCE_SMS)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AligoService 문자 대체발송 스위치(ALIGO_FORCE_SMS) ALIGO_FORCE_SMS=Y 면 대체문자 내용을 문자 API 로 보내고 알림톡 응답 모양으로 돌려준다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"ALIGO_FORCE_SMS=Y 면 대체문자 내용을 문자 API 로 보내고 알림톡 응답 모양으로 돌려준다"},{"ancestorTitles":["AligoService 문자 대체발송 스위치(ALIGO_FORCE_SMS)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AligoService 문자 대체발송 스위치(ALIGO_FORCE_SMS) 문자 API 실패(result_code≠1)는 code≠0 으로 돌려 호출부가 실패로 기록하게 한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"문자 API 실패(result_code≠1)는 code≠0 으로 돌려 호출부가 실패로 기록하게 한다"}],"endTime":1793868744834,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/aligo/src/aligo.service.spec.ts","startTime":1793868744782,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["백분위·반올림·클램프"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"백분위·반올림·클램프 percentile 은 알려진 입력에 알려진 값을 낸다(최근접 순위, 보간 없음)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"percentile 은 알려진 입력에 알려진 값을 낸다(최근접 순위, 보간 없음)"},{"ancestorTitles":["백분위·반올림·클램프"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"백분위·반올림·클램프 ceil2 는 부동소수 오차를 흡수하고 올림 방향이 발화를 줄이는 쪽이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"ceil2 는 부동소수 오차를 흡수하고 올림 방향이 발화를 줄이는 쪽이다"},{"ancestorTitles":["백분위·반올림·클램프"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"백분위·반올림·클램프 clampThreshold 가 설정 정의역 경계에서 동작한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"clampThreshold 가 설정 정의역 경계에서 동작한다"},{"ancestorTitles":["백분위·반올림·클램프"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"백분위·반올림·클램프 --min-buckets 기본값이 --target-fpr 과 함께 움직인다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"--min-buckets 기본값이 --target-fpr 과 함께 움직인다"},{"ancestorTitles":["백분위·반올림·클램프"],"duration":16,"failureDetails":[],"failureMessages":[],"fullName":"백분위·반올림·클램프 parseArgs 는 기본값을 갖고 벤더 목록을 정렬한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"parseArgs 는 기본값을 갖고 벤더 목록을 정렬한다"},{"ancestorTitles":["§D5-2 적격 버킷 한정 — 저표본은 진단 통계로만"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D5-2 적격 버킷 한정 — 저표본은 진단 통계로만 적격 30개에 1건짜리 저표본 100개를 섞어도 백분위가 변하지 않는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"적격 30개에 1건짜리 저표본 100개를 섞어도 백분위가 변하지 않는다"},{"ancestorTitles":["§D5-2 적격 버킷 한정 — 저표본은 진단 통계로만"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-2 적격 버킷 한정 — 저표본은 진단 통계로만 적격 버킷 수가 하한 미만이면 판정이 INSUFFICIENT_SAMPLE 이고 권고 필드가 빈다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적격 버킷 수가 하한 미만이면 판정이 INSUFFICIENT_SAMPLE 이고 권고 필드가 빈다"},{"ancestorTitles":["§D5-4b 골든 픽스처 — 백분위에서 적용 임계로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 골든 픽스처 — 백분위에서 적용 임계로 실패율 0.00~0.99 버킷 100개 · --target-fpr 1 → 권고 임계 0.98","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"실패율 0.00~0.99 버킷 100개 · --target-fpr 1 → 권고 임계 0.98"},{"ancestorTitles":["§D5-4b 골든 픽스처 — 백분위에서 적용 임계로"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 골든 픽스처 — 백분위에서 적용 임계로 --target-fpr 을 키우면 임계가 단조로 내려간다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"--target-fpr 을 키우면 임계가 단조로 내려간다"},{"ancestorTitles":["§D5-4b 골든 픽스처 — 백분위에서 적용 임계로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 골든 픽스처 — 백분위에서 적용 임계로 전 버킷이 100% 실패면 클램프 상한 1 이 나온다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전 버킷이 100% 실패면 클램프 상한 1 이 나온다"},{"ancestorTitles":["§D5-4b 골든 픽스처 — 백분위에서 적용 임계로"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 골든 픽스처 — 백분위에서 적용 임계로 전 버킷이 무실패면 클램프 하한 0.01 이 나온다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전 버킷이 무실패면 클램프 하한 0.01 이 나온다"},{"ancestorTitles":["§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다 스냅샷 밖 벤더가 아무리 큰 물량을 가져도 벤더 백분위와 풀 백분위가 모두 불변이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"스냅샷 밖 벤더가 아무리 큰 물량을 가져도 벤더 백분위와 풀 백분위가 모두 불변이다"},{"ancestorTitles":["§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다 풀은 버킷별 합산에서 나온다 — 벤더별 실패율의 평균이 아니다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"풀은 버킷별 합산에서 나온다 — 벤더별 실패율의 평균이 아니다"},{"ancestorTitles":["§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다 창 시작 이전의 관측은 버킷에 들어가지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"창 시작 이전의 관측은 버킷에 들어가지 않는다"},{"ancestorTitles":["§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다 미래 시각 행 1건이 버킷 배열을 부풀리지 않는다 (SQL 에 상한이 없다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"미래 시각 행 1건이 버킷 배열을 부풀리지 않는다 (SQL 에 상한이 없다)"},{"ancestorTitles":["§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-0 스냅샷 필터 — 제외는 버킷 집계 단계에서 일어난다 상한 경계(toMs) 관측은 남고 그 밖은 버린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상한 경계(toMs) 관측은 남고 그 밖은 버린다"},{"ancestorTitles":["§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다 전 축 OK 면 서명이 나오고 실행값·권고값을 그대로 담는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"전 축 OK 면 서명이 나오고 실행값·권고값을 그대로 담는다"},{"ancestorTitles":["§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다 벤더 하나만 미달이어도 서명이 나오지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"벤더 하나만 미달이어도 서명이 나오지 않는다"},{"ancestorTitles":["§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다 풀 축이 미달이면 벤더가 전부 OK 여도 서명이 나오지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"풀 축이 미달이면 벤더가 전부 OK 여도 서명이 나오지 않는다"},{"ancestorTitles":["§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"§D5-4b 부분 미달 — 서명은 전 축이 OK 일 때만 나온다 풀 적격 버킷 수는 어떤 벤더의 적격 버킷 수보다 작을 수 없다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"풀 적격 버킷 수는 어떤 벤더의 적격 버킷 수보다 작을 수 없다"},{"ancestorTitles":["출력"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"출력 첫 줄이 붙여넣기 가능한 서명 JSON 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"첫 줄이 붙여넣기 가능한 서명 JSON 이다"},{"ancestorTitles":["출력"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"출력 서명이 없으면 그 사실을 적고 JSON 을 내지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서명이 없으면 그 사실을 적고 JSON 을 내지 않는다"},{"ancestorTitles":["출력"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"출력 행이 벤더 N개 + 풀 1개이고 진단 통계가 판정하지 못한 벤더 수를 보고한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"행이 벤더 N개 + 풀 1개이고 진단 통계가 판정하지 못한 벤더 수를 보고한다"},{"ancestorTitles":["설정 읽기 — 부재는 기본값, 범위 밖은 선다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"설정 읽기 — 부재는 기본값, 범위 밖은 선다 행이 없거나 빈 문자열이면 기본값이고 그 사실을 출처에 적는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"행이 없거나 빈 문자열이면 기본값이고 그 사실을 출처에 적는다"},{"ancestorTitles":["설정 읽기 — 부재는 기본값, 범위 밖은 선다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"설정 읽기 — 부재는 기본값, 범위 밖은 선다 범위 안의 값은 그대로 쓰고 출처가 설정으로 바뀐다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"범위 안의 값은 그대로 쓰고 출처가 설정으로 바뀐다"},{"ancestorTitles":["설정 읽기 — 부재는 기본값, 범위 밖은 선다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"설정 읽기 — 부재는 기본값, 범위 밖은 선다 숫자가 아니면 선다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"숫자가 아니면 선다"},{"ancestorTitles":["설정 읽기 — 부재는 기본값, 범위 밖은 선다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"설정 읽기 — 부재는 기본값, 범위 밖은 선다 window_ms = 0 은 범위 밖이라 선다 — bucketize 까지 흘러가면 도구가 죽는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"window_ms = 0 은 범위 밖이라 선다 — bucketize 까지 흘러가면 도구가 죽는다"},{"ancestorTitles":["설정 읽기 — 부재는 기본값, 범위 밖은 선다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"설정 읽기 — 부재는 기본값, 범위 밖은 선다 상한 밖도 선다 — 런타임은 메타 기본값으로 되돌려 판정하므로 그대로 쓰면 두 파일이 갈린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상한 밖도 선다 — 런타임은 메타 기본값으로 되돌려 판정하므로 그대로 쓰면 두 파일이 갈린다"},{"ancestorTitles":["설정 읽기 — 부재는 기본값, 범위 밖은 선다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"설정 읽기 — 부재는 기본값, 범위 밖은 선다 경계값은 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"경계값은 통과한다"},{"ancestorTitles":["신호 정의 승계"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"신호 정의 승계 성공은 ODD006 + 완료시각, 실패는 상태/최종상태 + 실패시각이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"성공은 ODD006 + 완료시각, 실패는 상태/최종상태 + 실패시각이다"},{"ancestorTitles":["신호 정의 승계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"신호 정의 승계 ODD006 + 최종상태 실패 행은 관측 2건이다 (런타임 이중계상 재현)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"ODD006 + 최종상태 실패 행은 관측 2건이다 (런타임 이중계상 재현)"},{"ancestorTitles":["신호 정의 승계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"신호 정의 승계 MS4: 분류 함수는 이탈 행의 실패를 세지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 분류 함수는 이탈 행의 실패를 세지 않는다"},{"ancestorTitles":["신호 정의 승계"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"신호 정의 승계 MS4: 분류 함수는 로그 없는 실패를 센다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 분류 함수는 로그 없는 실패를 센다"},{"ancestorTitles":["MS4 산출 서명 정의 버전"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MS4 산출 서명 정의 버전 MS4: 산출 서명은 정의 버전을 담는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"MS4: 산출 서명은 정의 버전을 담는다"},{"ancestorTitles":["MS5 산출 하한 문자열 · 안내"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"MS5 산출 하한 문자열 · 안내 산출 하한 문자열은 런타임 하한과 같은 로컬 기준으로 만든다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"산출 하한 문자열은 런타임 하한과 같은 로컬 기준으로 만든다"},{"ancestorTitles":["MS5 산출 하한 문자열 · 안내"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"MS5 산출 하한 문자열 · 안내 산출 안내는 내부 키 이름과 DB 쓰기 문장을 담지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"산출 안내는 내부 키 이름과 DB 쓰기 문장을 담지 않는다"}],"endTime":1793868744840,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/scripts/alert-threshold-derive.spec.ts","startTime":1793868744787,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["역할 상세의 읽기 순서"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"역할 상세의 읽기 순서 권한 버전을 역할 데이터보다 먼저 읽는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"권한 버전을 역할 데이터보다 먼저 읽는다"}],"endTime":1793868744888,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-admin.read-order.spec.ts","startTime":1793868744836,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["최고관리자 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"최고관리자 가드 guard: 판정이 참이면 통과하고 거짓이면 403 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"guard: 판정이 참이면 통과하고 거짓이면 403 이다"}],"endTime":1793868744889,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/super-admin.guard.spec.ts","startTime":1793868744842,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatRepository 자동차 best-effort"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatRepository 자동차 best-effort 정회원 자동차 조회가 실패해도 건강 분석 성공을 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정회원 자동차 조회가 실패해도 건강 분석 성공을 유지한다"},{"ancestorTitles":["TreatRepository 자동차 best-effort"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatRepository 자동차 best-effort B2C 자동차 정리가 실패해도 건강 분석 성공을 유지한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"B2C 자동차 정리가 실패해도 건강 분석 성공을 유지한다"}],"endTime":1793868744937,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/treat.repository.spec.ts","startTime":1793868744890,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatProviderService 자동차 정책"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatProviderService 자동차 정책 global ON + 카나리 ON이면 inhouse·coocon·octover만 자동차를 사용한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"global ON + 카나리 ON이면 inhouse·coocon·octover만 자동차를 사용한다"},{"ancestorTitles":["TreatProviderService 자동차 정책"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatProviderService 자동차 정책 단일 공급자 모드는 위조된 dispatcher 태그가 있어도 자동차를 차단한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단일 공급자 모드는 위조된 dispatcher 태그가 있어도 자동차를 차단한다"},{"ancestorTitles":["TreatProviderService 자동차 정책"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatProviderService 자동차 정책 global ON이어도 카나리 OFF면 모든 공급자의 자동차를 차단한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"global ON이어도 카나리 OFF면 모든 공급자의 자동차를 차단한다"},{"ancestorTitles":["TreatProviderService 자동차 정책"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatProviderService 자동차 정책 카나리 ON이어도 global OFF면 master kill로 전체 차단한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카나리 ON이어도 global OFF면 master kill로 전체 차단한다"},{"ancestorTitles":["TreatProviderService 자동차 정책"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatProviderService 자동차 정책 master/canary 설정 DB 조회가 실패하면 전체 자동차를 fail-closed 한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"master/canary 설정 DB 조회가 실패하면 전체 자동차를 fail-closed 한다"}],"endTime":1793868744937,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.spec.ts","startTime":1793868744894,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["조직 하위 추가 · 서비스 경로의 예외 상태"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"조직 하위 추가 · 서비스 경로의 예외 상태 잠금 뒤 부모 재읽기 404 (저장소가 던짐) 은 서비스에서도 404 이고 500 으로 바뀌지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"잠금 뒤 부모 재읽기 404 (저장소가 던짐) 은 서비스에서도 404 이고 500 으로 바뀌지 않는다"}],"endTime":1793868745002,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/agency/organization/organization.service.create.spec.ts","startTime":1793868744943,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B1] 비최고관리자가 rbac.manage 를 담은 역할을 부여하면 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B1] 비최고관리자가 rbac.manage 를 담은 역할을 부여하면 거부한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B1] 비최고관리자가 rbac.manage 역할을 가진 계정의 binding 을 회수하면 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B1] 비최고관리자가 rbac.manage 역할을 가진 계정의 binding 을 회수하면 거부한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B2] 자기 계정의 athId 를 바꾸면 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B2] 자기 계정의 athId 를 바꾸면 거부한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B2] rbac.manage 보유자는 자기 계정의 비밀번호를 바꾸지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B2] rbac.manage 보유자는 자기 계정의 비밀번호를 바꾸지 못한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B2 범위] rbac.manage 를 갖지 않은 행위자는 자기 비밀번호를 바꿀 수 있다 (일반 관리자의 본인 변경은 막지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B2 범위] rbac.manage 를 갖지 않은 행위자는 자기 비밀번호를 바꿀 수 있다 (일반 관리자의 본인 변경은 막지 않는다)"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B3] 고권한 계정 (행위자 집합 밖의 코드를 가진 계정) 의 binding 변경은 최고관리자만 한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B3] 고권한 계정 (행위자 집합 밖의 코드를 가진 계정) 의 binding 변경은 최고관리자만 한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B4] 행위자 권한 밖의 코드를 담은 역할은 부여할 수 없다 (재위임 상한)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B4] 행위자 권한 밖의 코드를 담은 역할은 부여할 수 없다 (재위임 상한)"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [반례 b] 고권한 계정의 비밀번호 변경은 최고관리자만 한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[반례 b] 고권한 계정의 비밀번호 변경은 최고관리자만 한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [최고] 비최고관리자는 최고관리자 계정을 바꾸지 못한다 (자격증명 · binding 모두)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[최고] 비최고관리자는 최고관리자 계정을 바꾸지 못한다 (자격증명 · binding 모두)"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B1] 생성 (대상 없음) 도 rbac.manage 역할을 부여하면 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B1] 생성 (대상 없음) 도 rbac.manage 역할을 부여하면 거부한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) [B4] 생성 (대상 없음) 도 행위자 권한 밖의 역할이면 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B4] 생성 (대상 없음) 도 행위자 권한 밖의 역할이면 거부한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) 신원이 없으면 자격증명 변경은 거부한다 (fail-closed)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"신원이 없으면 자격증명 변경은 거부한다 (fail-closed)"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) 이름 · 연락처 같은 판정 밖 변경 (자격증명 불변) 은 행위자가 누구든 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이름 · 연락처 같은 판정 밖 변경 (자격증명 불변) 은 행위자가 누구든 통과한다"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) 같은 값으로 보낸 athId 는 바뀐 것이 아니다 (B1 · B3 가 걸리지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 값으로 보낸 athId 는 바뀐 것이 아니다 (B1 · B3 가 걸리지 않는다)"},{"ancestorTitles":["계정 쓰기 판정 (decideAccountGuardrail)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"계정 쓰기 판정 (decideAccountGuardrail) 최고관리자 행위자는 모든 규칙에서 면제된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"최고관리자 행위자는 모든 규칙에서 면제된다"},{"ancestorTitles":["역할 편집 판정 (decideRoleGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"역할 편집 판정 (decideRoleGuardrail) [반례 a] 행위자가 보유한 역할의 내용은 편집할 수 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[반례 a] 행위자가 보유한 역할의 내용은 편집할 수 없다"},{"ancestorTitles":["역할 편집 판정 (decideRoleGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"역할 편집 판정 (decideRoleGuardrail) [B1] rbac.manage 를 담거나 가진 역할의 편집은 최고관리자만 한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[B1] rbac.manage 를 담거나 가진 역할의 편집은 최고관리자만 한다"},{"ancestorTitles":["역할 편집 판정 (decideRoleGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"역할 편집 판정 (decideRoleGuardrail) [B4] 행위자 집합 밖의 코드를 담는 편집은 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B4] 행위자 집합 밖의 코드를 담는 편집은 거부한다"},{"ancestorTitles":["역할 편집 판정 (decideRoleGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"역할 편집 판정 (decideRoleGuardrail) 행위자 집합 안에서만 고치는 편집은 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행위자 집합 안에서만 고치는 편집은 통과한다"},{"ancestorTitles":["역할 편집 판정 (decideRoleGuardrail)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"역할 편집 판정 (decideRoleGuardrail) [B3] 행위자 집합 밖의 코드를 가진 역할은 줄이는 편집도 최고관리자만 한다 (보유 계정 강등 후 자격증명 변경 우회 차단)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[B3] 행위자 집합 밖의 코드를 가진 역할은 줄이는 편집도 최고관리자만 한다 (보유 계정 강등 후 자격증명 변경 우회 차단)"},{"ancestorTitles":["역할 편집 판정 (decideRoleGuardrail)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"역할 편집 판정 (decideRoleGuardrail) 최고관리자는 모든 역할을 편집한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"최고관리자는 모든 역할을 편집한다"},{"ancestorTitles":["권한 표 부재 (이행기 · DDL 미적용)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 표 부재 (이행기 · DDL 미적용) 권한 표가 없으면 빈 집합으로 읽지 않고 503 이다 (판정을 건너뛰어 쓰기를 통과시키지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"권한 표가 없으면 빈 집합으로 읽지 않고 503 이다 (판정을 건너뛰어 쓰기를 통과시키지 않는다)"},{"ancestorTitles":["버전 검사 · 요청자 신원 (동시 편집)"],"duration":8,"failureDetails":[],"failureMessages":[],"fullName":"버전 검사 · 요청자 신원 (동시 편집) [동시] 버전이 다르면 409 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[동시] 버전이 다르면 409 이다"},{"ancestorTitles":["버전 검사 · 요청자 신원 (동시 편집)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"버전 검사 · 요청자 신원 (동시 편집) [동시] 버전이 같으면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[동시] 버전이 같으면 통과한다"},{"ancestorTitles":["버전 검사 · 요청자 신원 (동시 편집)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"버전 검사 · 요청자 신원 (동시 편집) expectedVersion 이 없으면 400 이다 (자격증명 변경의 입력 계약)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"expectedVersion 이 없으면 400 이다 (자격증명 변경의 입력 계약)"},{"ancestorTitles":["버전 검사 · 요청자 신원 (동시 편집)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"버전 검사 · 요청자 신원 (동시 편집) [동시] 권한 버전을 못 읽으면 expectedVersion 이 없어도 409 다 (400 으로 가리지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[동시] 권한 버전을 못 읽으면 expectedVersion 이 없어도 409 다 (400 으로 가리지 않는다)"},{"ancestorTitles":["버전 검사 · 요청자 신원 (동시 편집)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"버전 검사 · 요청자 신원 (동시 편집) 관리자 토큰이 아니면 신원이 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"관리자 토큰이 아니면 신원이 없다"}],"endTime":1793868745009,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-guardrail.spec.ts","startTime":1793868744939,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) NODE_ENV=stg 에 플래그가 없으면 닫힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"NODE_ENV=stg 에 플래그가 없으면 닫힌다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) NODE_ENV=dev 에 플래그가 없으면 닫힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"NODE_ENV=dev 에 플래그가 없으면 닫힌다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) NODE_ENV=production 에 플래그가 없으면 닫힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"NODE_ENV=production 에 플래그가 없으면 닫힌다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) NODE_ENV=undefined 에 플래그가 없으면 닫힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"NODE_ENV=undefined 에 플래그가 없으면 닫힌다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) SWAGGER_ENABLED=true 일 때만 연다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SWAGGER_ENABLED=true 일 때만 연다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) SWAGGER_ENABLED=\"1\" 는 연다고 보지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SWAGGER_ENABLED=\"1\" 는 연다고 보지 않는다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) SWAGGER_ENABLED=\"TRUE\" 는 연다고 보지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SWAGGER_ENABLED=\"TRUE\" 는 연다고 보지 않는다"},{"ancestorTitles":["isSwaggerEnabled (swagger 는 명시 스위치로만 연다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isSwaggerEnabled (swagger 는 명시 스위치로만 연다) SWAGGER_ENABLED=\"\" 는 연다고 보지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SWAGGER_ENABLED=\"\" 는 연다고 보지 않는다"}],"endTime":1793868745047,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/swagger.spec.ts","startTime":1793868745007,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 컬렉터를 열지 않은 요청은 이전 줄과 같다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"컬렉터를 열지 않은 요청은 이전 줄과 같다"},{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 성공 줄에 대상 유형 · 서로 다른 대상 수 · 전이별 건수와 id 묶음이 실린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"성공 줄에 대상 유형 · 서로 다른 대상 수 · 전이별 건수와 id 묶음이 실린다"},{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 일부 커밋 뒤 던진 요청은 실패 줄이 커밋된 항목과 실패한 항목을 함께 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"일부 커밋 뒤 던진 요청은 실패 줄이 커밋된 항목과 실패한 항목을 함께 싣는다"},{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 대상이 하나면 targetId 가 그 id 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상이 하나면 targetId 가 그 id 다"},{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 본문의 같은 이름 키는 서버 값을 덮지 못하고, 컬렉터는 HTTP 상태를 덮지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"본문의 같은 이름 키는 서버 값을 덮지 못하고, 컬렉터는 HTTP 상태를 덮지 못한다"},{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 컬렉터는 요청마다 따로다 — 동시 요청의 대상이 섞이지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"컬렉터는 요청마다 따로다 — 동시 요청의 대상이 섞이지 않는다"},{"ancestorTitles":["AdminAuditInterceptor — 서버측 컬렉터 합류"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminAuditInterceptor — 서버측 컬렉터 합류 대상 없이 변경만 실은 줄은 대상 칸이 컬렉터 없을 때와 같다 (운영 알림 설정, AUTHZ-3)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대상 없이 변경만 실은 줄은 대상 칸이 컬렉터 없을 때와 같다 (운영 알림 설정, AUTHZ-3)"}],"endTime":1793868745049,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/interceptors/admin-audit.interceptor.spec.ts","startTime":1793868745011,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["[CSRF] 쓰기 출처 검사 OriginCheckGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"[CSRF] 쓰기 출처 검사 OriginCheckGuard [CSRF] 허용 목록에 있는 출처는 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[CSRF] 허용 목록에 있는 출처는 통과한다"},{"ancestorTitles":["[CSRF] 쓰기 출처 검사 OriginCheckGuard"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"[CSRF] 쓰기 출처 검사 OriginCheckGuard [CSRF] 허용 목록 밖의 출처는 403 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[CSRF] 허용 목록 밖의 출처는 403 이다"},{"ancestorTitles":["[CSRF] 쓰기 출처 검사 OriginCheckGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"[CSRF] 쓰기 출처 검사 OriginCheckGuard [CSRF] Origin 헤더가 없으면 403 이다 (fail-closed)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[CSRF] Origin 헤더가 없으면 403 이다 (fail-closed)"},{"ancestorTitles":["[CSRF] 쓰기 출처 검사 OriginCheckGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"[CSRF] 쓰기 출처 검사 OriginCheckGuard [CSRF] 허용 목록 설정이 없으면 모든 쓰기를 403 으로 막는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[CSRF] 허용 목록 설정이 없으면 모든 쓰기를 403 으로 막는다"}],"endTime":1793868745081,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/origin-check.guard.spec.ts","startTime":1793868745049,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["DdxClient.assertConfigured"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient.assertConfigured baseUrl 과 apiKey 가 둘 다 있으면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"baseUrl 과 apiKey 가 둘 다 있으면 통과한다"},{"ancestorTitles":["DdxClient.assertConfigured"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient.assertConfigured baseUrl 이 없으면 DDX_BASE_URL 을 지목하고 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"baseUrl 이 없으면 DDX_BASE_URL 을 지목하고 던진다"},{"ancestorTitles":["DdxClient.assertConfigured"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient.assertConfigured apiKey 가 없으면 DDX_API_KEY 를 지목하고 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"apiKey 가 없으면 DDX_API_KEY 를 지목하고 던진다"},{"ancestorTitles":["DdxClient.assertConfigured"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient.assertConfigured 둘 다 없으면 두 이름을 함께 낸다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"둘 다 없으면 두 이름을 함께 낸다"},{"ancestorTitles":["DdxClient.assertConfigured"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient.assertConfigured 실패 문면에 키 값을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실패 문면에 키 값을 싣지 않는다"},{"ancestorTitles":["DdxClient.assertConfigured"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient.assertConfigured 빈 문자열은 결손으로 본다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 문자열은 결손으로 본다"},{"ancestorTitles":["DdxClient — AI Insight 대상"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient — AI Insight 대상 getInsightFromTreatments 는 insight 주소와 키로 보낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"getInsightFromTreatments 는 insight 주소와 키로 보낸다"},{"ancestorTitles":["DdxClient — AI Insight 대상"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient — AI Insight 대상 판정 호출은 계속 ddx 주소와 키로 보낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정 호출은 계속 ddx 주소와 키로 보낸다"},{"ancestorTitles":["DdxClient — AI Insight 대상"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"DdxClient — AI Insight 대상 insight 설정이 비면 INSIGHT_ 이름을 지목하고 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"insight 설정이 비면 INSIGHT_ 이름을 지목하고 던진다"}],"endTime":1793868745089,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/ddx.client.spec.ts","startTime":1793868745051,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason COMPENSATION 는 상세가 있으면 통과하고 그 코드를 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"COMPENSATION 는 상세가 있으면 통과하고 그 코드를 돌려준다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason EVENT 는 상세가 있으면 통과하고 그 코드를 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"EVENT 는 상세가 있으면 통과하고 그 코드를 돌려준다"},{"ancestorTitles":["assertInterventionReason"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason CORRECTION 는 상세가 있으면 통과하고 그 코드를 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CORRECTION 는 상세가 있으면 통과하고 그 코드를 돌려준다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason CORP_CONTRACT 는 상세가 있으면 통과하고 그 코드를 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"CORP_CONTRACT 는 상세가 있으면 통과하고 그 코드를 돌려준다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason OTHER 는 상세가 있으면 통과하고 그 코드를 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"OTHER 는 상세가 있으면 통과하고 그 코드를 돌려준다"},{"ancestorTitles":["assertInterventionReason"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 모르는 코드 \"UNKNOWN\" 는 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드 \"UNKNOWN\" 는 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 모르는 코드 undefined 는 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드 undefined 는 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 모르는 코드 null 는 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드 null 는 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 모르는 코드 \"\" 는 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드 \"\" 는 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 모르는 코드 \"other\" 는 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드 \"other\" 는 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 모르는 코드 1 는 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 코드 1 는 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 인데 상세가 [\"\"] 이면 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세가 [\"\"] 이면 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 인데 상세가 [\"  \"] 이면 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세가 [\"  \"] 이면 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 인데 상세가 [] 이면 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세가 [] 이면 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 인데 상세가 [null] 이면 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세가 [null] 이면 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 인데 상세가 [undefined] 이면 거절한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기타(OTHER) 인데 상세가 [undefined] 이면 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 는 여러 상세 중 한 칸만 비어도 거절한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기타(OTHER) 는 여러 상세 중 한 칸만 비어도 거절한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 기타(OTHER) 의 상세가 전부 차 있으면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기타(OTHER) 의 상세가 전부 차 있으면 통과한다"},{"ancestorTitles":["assertInterventionReason"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason COMPENSATION 는 상세가 비어도 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"COMPENSATION 는 상세가 비어도 통과한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason EVENT 는 상세가 비어도 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"EVENT 는 상세가 비어도 통과한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason CORRECTION 는 상세가 비어도 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CORRECTION 는 상세가 비어도 통과한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason CORP_CONTRACT 는 상세가 비어도 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CORP_CONTRACT 는 상세가 비어도 통과한다"},{"ancestorTitles":["assertInterventionReason"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 행 라벨이 오면 거절 문장이 상세가 빈 행만 말한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행 라벨이 오면 거절 문장이 상세가 빈 행만 말한다"},{"ancestorTitles":["assertInterventionReason"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"assertInterventionReason 빈 행이 20건을 넘으면 앞부분만 적고 나머지는 수로 센다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"빈 행이 20건을 넘으면 앞부분만 적고 나머지는 수로 센다"}],"endTime":1793868745119,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-reason.spec.ts","startTime":1793868745086,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["CorpReadonlyGuard"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"CorpReadonlyGuard ORG + POST 는 403 이고 code 는 E0607 · reason 은 permission 이다 (음성)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ORG + POST 는 403 이고 code 는 E0607 · reason 은 permission 이다 (음성)"},{"ancestorTitles":["CorpReadonlyGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CorpReadonlyGuard ORG + GET 은 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ORG + GET 은 통과한다"},{"ancestorTitles":["CorpReadonlyGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CorpReadonlyGuard ORG + POST 라도 @AllowOrgWrite 가 있으면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ORG + POST 라도 @AllowOrgWrite 가 있으면 통과한다"},{"ancestorTitles":["CorpReadonlyGuard"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"CorpReadonlyGuard corpScope 가 ORG 가 아니면 POST 도 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"corpScope 가 ORG 가 아니면 POST 도 통과한다"}],"endTime":1793868745122,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/corp-readonly.guard.spec.ts","startTime":1793868745092,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["sanitizeTermsContent"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"sanitizeTermsContent 약관 표 형식은 보존하고 실행 가능한 HTML은 제거한다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"약관 표 형식은 보존하고 실행 가능한 HTML은 제거한다"},{"ancestorTitles":["sanitizeBoardContent"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"sanitizeBoardContent 에디터의 업로드 이미지와 글자색·배경색은 남기고 실행 가능한 HTML은 제거한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"에디터의 업로드 이미지와 글자색·배경색은 남기고 실행 가능한 HTML은 제거한다"},{"ancestorTitles":["sanitizeBoardTitle"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"sanitizeBoardTitle 태그는 지우고 & 는 그대로 두며 꺾쇠는 이스케이프한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"태그는 지우고 & 는 그대로 두며 꺾쇠는 이스케이프한다"}],"endTime":1793868745145,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/sanitize.helper.spec.ts","startTime":1793868745120,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["TreatReservationService reserveStrict"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatReservationService reserveStrict Redis가 없으면 null이고 기존 reserve는 계속 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"Redis가 없으면 null이고 기존 reserve는 계속 통과한다"},{"ancestorTitles":["TreatReservationService reserveStrict"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"TreatReservationService reserveStrict Redis 오류면 null이고 기존 reserve는 계속 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"Redis 오류면 null이고 기존 reserve는 계속 통과한다"},{"ancestorTitles":["TreatReservationService reserveStrict"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatReservationService reserveStrict 만석이면 null을 반환한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"만석이면 null을 반환한다"},{"ancestorTitles":["TreatReservationService reserveStrict"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"TreatReservationService reserveStrict 여유가 있으면 예약 ID를 반환한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"여유가 있으면 예약 ID를 반환한다"}],"endTime":1793868745155,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/dispatch/treat-reservation.service.unit.spec.ts","startTime":1793868745123,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["공개 표지와 역할 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"공개 표지와 역할 가드 핸들러 표지는 역할 검사를 건너뛴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"핸들러 표지는 역할 검사를 건너뛴다"},{"ancestorTitles":["공개 표지와 역할 가드"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"공개 표지와 역할 가드 클래스 표지는 역할 검사를 끄지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"클래스 표지는 역할 검사를 끄지 않는다"},{"ancestorTitles":["공개 표지와 역할 가드"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"공개 표지와 역할 가드 신원이 없으면 403 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"신원이 없으면 403 이다"},{"ancestorTitles":["공개 표지와 역할 가드"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"공개 표지와 역할 가드 역할이 맞으면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할이 맞으면 통과한다"}],"endTime":1793868745183,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/public-marker.spec.ts","startTime":1793868745146,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 식별자·금액·수량·구분값·플래그를 통과시킨다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"식별자·금액·수량·구분값·플래그를 통과시킨다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 admPassword 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 admPassword 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 memName 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 memName 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 usrPhone 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 usrPhone 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 memEmail 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 memEmail 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 usrBirth 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 usrBirth 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 cardNumber 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 cardNumber 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 bankAccount 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 bankAccount 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 accessToken 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 accessToken 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 authorization 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 authorization 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 mngReason 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 mngReason 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 mngTitle 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 mngTitle 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 mcpMemo 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 mcpMemo 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 민감 어휘 description 는 값 형태와 무관하게 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"민감 어휘 description 는 값 형태와 무관하게 버린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 허용 패턴에 없는 키는 버린다 — 기본은 통과가 아니라 폐기다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"허용 패턴에 없는 키는 버린다 — 기본은 통과가 아니라 폐기다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 배열·객체는 내용을 싣지 않고 크기만 남긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"배열·객체는 내용을 싣지 않고 크기만 남긴다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 긴 문자열은 64자로 자르고 잘렸음을 표시한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"긴 문자열은 64자로 자르고 잘렸음을 표시한다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 버린 개수를 남긴다 — 조용히 줄이면 \"본문에 이것뿐\" 으로 오해된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"버린 개수를 남긴다 — 조용히 줄이면 \"본문에 이것뿐\" 으로 오해된다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 null 는 null 을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"null 는 null 을 돌려준다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 배열 는 null 을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"배열 는 null 을 돌려준다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 문자열 는 null 을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"문자열 는 null 을 돌려준다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 빈 객체 는 null 을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 객체 는 null 을 돌려준다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 통과 항목 0건 는 null 을 돌려준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"통과 항목 0건 는 null 을 돌려준다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 한국어 자유 서술 는 통과하지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"한국어 자유 서술 는 통과하지 못한다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 공백이 든 서술 는 통과하지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"공백이 든 서술 는 통과하지 못한다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 주민등록번호(하이픈) 는 통과하지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민등록번호(하이픈) 는 통과하지 못한다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 주민등록번호(붙임) 는 통과하지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민등록번호(붙임) 는 통과하지 못한다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 대문자 코드 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"대문자 코드 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 하이픈 식별자 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"하이픈 식별자 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 영숫자 로그인 id 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영숫자 로그인 id 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 빈 문자열 — 비웠다는 관측이다 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 문자열 — 비웠다는 관측이다 는 그대로 남는다 — 형태 규칙이 코드값까지 죽이지 않는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 키 어휘 resident 는 값이 코드 형태여도 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"키 어휘 resident 는 값이 코드 형태여도 막는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 키 어휘 rrn 는 값이 코드 형태여도 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"키 어휘 rrn 는 값이 코드 형태여도 막는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 키 어휘 passport 는 값이 코드 형태여도 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"키 어휘 passport 는 값이 코드 형태여도 막는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 키 어휘 license 는 값이 코드 형태여도 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"키 어휘 license 는 값이 코드 형태여도 막는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 키 어휘 social 는 값이 코드 형태여도 막는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"키 어휘 social 는 값이 코드 형태여도 막는다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 주민등록번호 형태가 아닌 숫자열은 살린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민등록번호 형태가 아닌 숫자열은 살린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 주민등록번호 형태의 **숫자**도 버린다 — 13자리","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민등록번호 형태의 **숫자**도 버린다 — 13자리"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 주민등록번호 형태의 **숫자**도 버린다 — 앞자리 0 이 날아간 12자리","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민등록번호 형태의 **숫자**도 버린다 — 앞자리 0 이 날아간 12자리"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 금액·수량은 그 폭에 닿지 않는다 — 11자리 이하는 살린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"금액·수량은 그 폭에 닿지 않는다 — 11자리 이하는 살린다"},{"ancestorTitles":["extractChanges — 감사 줄에 실을 값만 통과시킨다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"extractChanges — 감사 줄에 실을 값만 통과시킨다 키 수 상한(24)을 넘으면 자르고 버린 수를 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"키 수 상한(24)을 넘으면 자르고 버린 수를 남긴다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 null 은 그대로 null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"null 은 그대로 null"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 상한 이하는 **같은 객체**를 그대로 돌려준다 — 직렬화하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상한 이하는 **같은 객체**를 그대로 돌려준다 — 직렬화하지 않는다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 방출되는 changes 의 중첩 키가 살아 있다 — 소비자 쿼리가 읽는 자리다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"방출되는 changes 의 중첩 키가 살아 있다 — 소비자 쿼리가 읽는 자리다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 상한을 넘으면 자르되 잘렸다는 사실을 값에 남긴다 — 봉투도 객체다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"상한을 넘으면 자르되 잘렸다는 사실을 값에 남긴다 — 봉투도 객체다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 평범한 문자 로 채워도 봉투의 직렬화 크기가 상한 이하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"평범한 문자 로 채워도 봉투의 직렬화 크기가 상한 이하다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 따옴표 로 채워도 봉투의 직렬화 크기가 상한 이하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"따옴표 로 채워도 봉투의 직렬화 크기가 상한 이하다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 역슬래시 로 채워도 봉투의 직렬화 크기가 상한 이하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역슬래시 로 채워도 봉투의 직렬화 크기가 상한 이하다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 개행 로 채워도 봉투의 직렬화 크기가 상한 이하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"개행 로 채워도 봉투의 직렬화 크기가 상한 이하다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 비ASCII 로 채워도 봉투의 직렬화 크기가 상한 이하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비ASCII 로 채워도 봉투의 직렬화 크기가 상한 이하다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 잘린 결과도 JSON 으로 왕복 가능하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잘린 결과도 JSON 으로 왕복 가능하다"},{"ancestorTitles":["capChanges — 크기만 자르고 형태는 보존한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"capChanges — 크기만 자르고 형태는 보존한다 순환 참조는 줄을 죽이지 않고 사유를 객체로 남긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"순환 참조는 줄을 죽이지 않고 사유를 객체로 남긴다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 빈 목록은 null — 실을 것이 없으면 키를 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 목록은 null — 실을 것이 없으면 키를 만들지 않는다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 식별자와 총수를 싣고, 자르지 않았으면 절단 표시가 없다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"식별자와 총수를 싣고, 자르지 않았으면 절단 표시가 없다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 상한 직전(999건)은 999건을 싣고 절단 표시는 undefined","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상한 직전(999건)은 999건을 싣고 절단 표시는 undefined"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 상한 정각(1000건)은 1000건을 싣고 절단 표시는 undefined","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상한 정각(1000건)은 1000건을 싣고 절단 표시는 undefined"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 상한 초과(1001건)은 1000건을 싣고 절단 표시는 true","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"상한 초과(1001건)은 1000건을 싣고 절단 표시는 true"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 서버가 만든 양의 정수 PK 가 아닌 값은 버린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서버가 만든 양의 정수 PK 가 아닌 값은 버린다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 전부 버려지면 null — 빈 목록과 같은 답을 낸다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전부 버려지면 null — 빈 목록과 같은 답을 낸다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 기대 건수보다 적게 모였으면 못 모은 수를 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기대 건수보다 적게 모였으면 못 모은 수를 남긴다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 같을 때 는 유실 표시를 만들지 않는다 — 정상이 값으로 실리면 이상이 묻힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같을 때 는 유실 표시를 만들지 않는다 — 정상이 값으로 실리면 이상이 묻힌다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 기대치가 더 작을 때 는 유실 표시를 만들지 않는다 — 정상이 값으로 실리면 이상이 묻힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기대치가 더 작을 때 는 유실 표시를 만들지 않는다 — 정상이 값으로 실리면 이상이 묻힌다"},{"ancestorTitles":["batchIds — 업무 배치와 감사 줄을 잇는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"batchIds — 업무 배치와 감사 줄을 잇는다 기대치를 안 넘겼을 때 는 유실 표시를 만들지 않는다 — 정상이 값으로 실리면 이상이 묻힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기대치를 안 넘겼을 때 는 유실 표시를 만들지 않는다 — 정상이 값으로 실리면 이상이 묻힌다"},{"ancestorTitles":["valueShapes — 서버가 검증한 키의 값을 모양만 남긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"valueShapes — 서버가 검증한 키의 값을 모양만 남긴다 숫자·불리언은 값, 문자열은 길이, 배열·객체는 크기만 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"숫자·불리언은 값, 문자열은 길이, 배열·객체는 크기만 싣는다"},{"ancestorTitles":["valueShapes — 서버가 검증한 키의 값을 모양만 남긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"valueShapes — 서버가 검증한 키의 값을 모양만 남긴다 숫자로 온 주민등록번호 폭은 버리고, 빈 입력은 빈 객체다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"숫자로 온 주민등록번호 폭은 버리고, 빈 입력은 빈 객체다"}],"endTime":1793868745190,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-changes.spec.ts","startTime":1793868745159,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AUDIT_SYSTEM_ACTION"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SYSTEM_ACTION 식별자가 전건 유일하고 `<도메인>.<동작>` 형태다","invocations":1,"location":null,"numPassingAsserts":11,"retryReasons":[],"status":"passed","title":"식별자가 전건 유일하고 `<도메인>.<동작>` 형태다"},{"ancestorTitles":["AUDIT_SYSTEM_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SYSTEM_ACTION 금전 어휘와 키·값이 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"금전 어휘와 키·값이 겹치지 않는다"},{"ancestorTitles":["AUDIT_SYSTEM_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SYSTEM_ACTION 보안 어휘와 키·값이 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"보안 어휘와 키·값이 겹치지 않는다"},{"ancestorTitles":["recordSystem — 시스템 행위를 T4 줄로 낸다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"recordSystem — 시스템 행위를 T4 줄로 낸다 내구 행을 동반하지 않는 T4 줄에 스케줄러 행위자와 행위가 실린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"내구 행을 동반하지 않는 T4 줄에 스케줄러 행위자와 행위가 실린다"}],"endTime":1793868745214,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-system.spec.ts","startTime":1793868745185,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["alert-engine-log"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-engine-log [MS8-E1] 정상 결과의 키 집합은 다섯 개이고 event 가 alert-engine-run, ok 가 1 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[MS8-E1] 정상 결과의 키 집합은 다섯 개이고 event 가 alert-engine-run, ok 가 1 이다"},{"ancestorTitles":["alert-engine-log"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"alert-engine-log [MS8-E2] 실패 값은 ok 가 0 이고 키 집합이 그대로이며 JSON 으로 왕복한다","invocations":1,"location":null,"numPassingAsserts":30,"retryReasons":[],"status":"passed","title":"[MS8-E2] 실패 값은 ok 가 0 이고 키 집합이 그대로이며 JSON 으로 왕복한다"},{"ancestorTitles":["alert-engine-log"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-engine-log [MS8-E3] nestjs-pino Logger 는 객체 인자를 최상위 필드로 펼쳐 쓴다 (문자열 msg 가 아니다)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS8-E3] nestjs-pino Logger 는 객체 인자를 최상위 필드로 펼쳐 쓴다 (문자열 msg 가 아니다)"},{"ancestorTitles":["alert-engine-log"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-engine-log [MS8-E4] 집합 안의 값은 ok 1 (null 포함), 집합 밖 값과 타입 밖 값은 ok 0 이다","invocations":1,"location":null,"numPassingAsserts":15,"retryReasons":[],"status":"passed","title":"[MS8-E4] 집합 안의 값은 ok 1 (null 포함), 집합 밖 값과 타입 밖 값은 ok 0 이다"},{"ancestorTitles":["alert-engine-log"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-engine-log [MS8-E5] alert.service.ts 의 skipped 리터럴 집합이 ENGINE_OK_SKIPS 와 실패 목록의 합집합과 양방향으로 같다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[MS8-E5] alert.service.ts 의 skipped 리터럴 집합이 ENGINE_OK_SKIPS 와 실패 목록의 합집합과 양방향으로 같다"}],"endTime":1793868745220,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-engine-log.spec.ts","startTime":1793868745192,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AuditService — 내구 행의 동반 여부를 층별로 말한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 내구 행의 동반 여부를 층별로 말한다 recordMoney 가 낸 줄의 store 는 db 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"recordMoney 가 낸 줄의 store 는 db 다"},{"ancestorTitles":["AuditService — 내구 행의 동반 여부를 층별로 말한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 내구 행의 동반 여부를 층별로 말한다 recordRequest 가 낸 줄의 store 는 none 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"recordRequest 가 낸 줄의 store 는 none 다"},{"ancestorTitles":["AuditService — 내구 행의 동반 여부를 층별로 말한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 내구 행의 동반 여부를 층별로 말한다 recordSystem 가 낸 줄의 store 는 none 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"recordSystem 가 낸 줄의 store 는 none 다"},{"ancestorTitles":["AuditService — 내구 행의 동반 여부를 층별로 말한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 내구 행의 동반 여부를 층별로 말한다 T1·T2·T4 가 각각 생산자를 갖는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"T1·T2·T4 가 각각 생산자를 갖는다"},{"ancestorTitles":["AuditService — 내구 행의 동반 여부를 층별로 말한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 내구 행의 동반 여부를 층별로 말한다 줄 형태 버전은 2 다 — txDurationMs 가 null 에 의미를 부여했다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"줄 형태 버전은 2 다 — txDurationMs 가 null 에 의미를 부여했다"},{"ancestorTitles":["AuditService — txDurationMs 는 부재와 값을 가른다(D4b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — txDurationMs 는 부재와 값을 가른다(D4b) 트랜잭션이 없는 계층(T4)의 null 이 0 으로 접히지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"트랜잭션이 없는 계층(T4)의 null 이 0 으로 접히지 않는다"},{"ancestorTitles":["AuditService — txDurationMs 는 부재와 값을 가른다(D4b)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — txDurationMs 는 부재와 값을 가른다(D4b) T1 이 잰 경과는 그대로 실린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"T1 이 잰 경과는 그대로 실린다"},{"ancestorTitles":["AuditService — txDurationMs 는 부재와 값을 가른다(D4b)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — txDurationMs 는 부재와 값을 가른다(D4b) 값이 없으면 키가 사라지는 대신 null 이 실린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"값이 없으면 키가 사라지는 대신 null 이 실린다"},{"ancestorTitles":["AuditService — 방출 봉투의 형태"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 방출 봉투의 형태 changes 는 객체로 나가고 중첩 키가 살아 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"changes 는 객체로 나가고 중첩 키가 살아 있다"},{"ancestorTitles":["AuditService — 방출 봉투의 형태"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 방출 봉투의 형태 상한을 넘는 changes 는 잘리되 그 사실이 값에 남는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"상한을 넘는 changes 는 잘리되 그 사실이 값에 남는다"},{"ancestorTitles":["AuditService — 방출 봉투의 형태"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 방출 봉투의 형태 batch 는 changes 상한과 무관한 최상위 키다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"batch 는 changes 상한과 무관한 최상위 키다"},{"ancestorTitles":["AuditService — 방출 봉투의 형태"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 방출 봉투의 형태 batch 가 없는 행위는 null 을 싣는다 — 키가 사라지지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"batch 가 없는 행위는 null 을 싣는다 — 키가 사라지지 않는다"},{"ancestorTitles":["AuditService — 방출 봉투의 형태"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 방출 봉투의 형태 corp 개인 식별자가 줄에 실린다 — 정규화만 고치면 조사자에게는 안 보인다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"corp 개인 식별자가 줄에 실린다 — 정규화만 고치면 조사자에게는 안 보인다"},{"ancestorTitles":["AuditService.appendMoney — 내구 행의 칸"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditService.appendMoney — 내구 행의 칸 이벤트의 칸을 빠짐없이 적재 행에 옮긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이벤트의 칸을 빠짐없이 적재 행에 옮긴다"},{"ancestorTitles":["AuditService.appendMoney — 내구 행의 칸"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService.appendMoney — 내구 행의 칸 폭을 넘는 문자열은 DDL 폭으로 잘리고 빈 값은 null 이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"폭을 넘는 문자열은 DDL 폭으로 잘리고 빈 값은 null 이다"},{"ancestorTitles":["AuditService.appendMoney — 내구 행의 칸"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService.appendMoney — 내구 행의 칸 적재 실패 진단은 드라이버 메시지가 아니라 오류 코드만 싣는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"적재 실패 진단은 드라이버 메시지가 아니라 오류 코드만 싣는다"},{"ancestorTitles":["AuditService — 방출 실패는 본 요청을 죽이지 않는다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditService — 방출 실패는 본 요청을 죽이지 않는다 로거가 던져도 호출부로 새지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"로거가 던져도 호출부로 새지 않는다"},{"ancestorTitles":["AuditService.appendSettlement — 적재 실패(A18 결정 10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AuditService.appendSettlement — 적재 실패(A18 결정 10) 정산 진단 줄을 남기고 같은 예외를 다시 던진다 — 회차 변경이 롤백된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정산 진단 줄을 남기고 같은 예외를 다시 던진다 — 회차 변경이 롤백된다"}],"endTime":1793868745255,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit.service.spec.ts","startTime":1793868745223,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 집합 조회 어댑터"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 집합 조회 어댑터 권한 집합 조회는 표지 코드 두 개를 거른다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"권한 집합 조회는 표지 코드 두 개를 거른다"},{"ancestorTitles":["권한 집합 조회 어댑터"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 집합 조회 어댑터 바인딩 조회는 관리자 행의 athId 를 준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"바인딩 조회는 관리자 행의 athId 를 준다"},{"ancestorTitles":["권한 집합 조회 어댑터"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 집합 조회 어댑터 바인딩 행이 없으면 null 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"바인딩 행이 없으면 null 이다"},{"ancestorTitles":["권한 집합 조회 어댑터"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 집합 조회 어댑터 isSuper 는 최고관리자 행의 번호가 같으면 참이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"isSuper 는 최고관리자 행의 번호가 같으면 참이다"}],"endTime":1793868745256,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-adapter.spec.ts","startTime":1793868745217,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AxiosWebClientService 로그 마스킹"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AxiosWebClientService 로그 마스킹 옥토버 연결 세션 header를 요청·응답 본문에서 숨긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"옥토버 연결 세션 header를 요청·응답 본문에서 숨긴다"},{"ancestorTitles":["AxiosWebClientService 로그 마스킹"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AxiosWebClientService 로그 마스킹 알림톡 자격증명·수신자·메시지를 숨긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"알림톡 자격증명·수신자·메시지를 숨긴다"},{"ancestorTitles":["AxiosWebClientService 로그 마스킹"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AxiosWebClientService 로그 마스킹 알리고 문자 발송의 API 키·수신번호·본문을 숨긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"알리고 문자 발송의 API 키·수신번호·본문을 숨긴다"}],"endTime":1793868745288,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/libs/webclient/src/webclient.service.spec.ts","startTime":1793868745257,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 전역 레거시는 규칙 단위 행으로, 벤더 레거시는 힌트 단위 행으로 옮긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전역 레거시는 규칙 단위 행으로, 벤더 레거시는 힌트 단위 행으로 옮긴다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 이관 계획은 규칙·힌트별 목적지 쌍을 보존한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이관 계획은 규칙·힌트별 목적지 쌍을 보존한다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 같은 URL 이라도 비활성 · 다른 규칙 행은 재사용하지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"같은 URL 이라도 비활성 · 다른 규칙 행은 재사용하지 않는다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 재실행은 새 행 0건이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"재실행은 새 행 0건이다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 같은 힌트를 구독하는 일반 채널은 우선순위 탈락으로 집계된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"같은 힌트를 구독하는 일반 채널은 우선순위 탈락으로 집계된다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 전역 레거시의 종류가 기본 집합과 다르면 부분 종류로 집계된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전역 레거시의 종류가 기본 집합과 다르면 부분 종류로 집계된다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 공백 URL 은 옮기지 않고 같은 URL 이 전역과 벤더에 있으면 원천마다 행을 하나씩 만든다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"공백 URL 은 옮기지 않고 같은 URL 이 전역과 벤더에 있으면 원천마다 행을 하나씩 만든다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 출력 전문과 오류 출력에 URL 원문과 호스트가 없다","invocations":1,"location":null,"numPassingAsserts":17,"retryReasons":[],"status":"passed","title":"출력 전문과 오류 출력에 URL 원문과 호스트가 없다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 기존 힌트 채널이 같은 힌트를 먼저 잡으면 옛 벤더 URL 은 보존 실패로 집계되고 --apply 는 거부된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기존 힌트 채널이 같은 힌트를 먼저 잡으면 옛 벤더 URL 은 보존 실패로 집계되고 --apply 는 거부된다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 전역 옛 URL 도 힌트 발화에서 밀리면 보존 실패로 집계된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"전역 옛 URL 도 힌트 발화에서 밀리면 보존 실패로 집계된다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 승인된 추가 수신과 우선순위 탈락은 보존 실패가 아니다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"승인된 추가 수신과 우선순위 탈락은 보존 실패가 아니다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) 승인 해시는 같은 계획에 같은 값을, 다른 계획에 다른 값을 낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"승인 해시는 같은 계획에 같은 값을, 다른 계획에 다른 값을 낸다"},{"ancestorTitles":["이관 계획 (검사 #6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"이관 계획 (검사 #6) sql 필드에 URL 이 든 예외도 출력에 URL 이 없다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"sql 필드에 URL 이 든 예외도 출력에 URL 이 없다"}],"endTime":1793868745290,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/scripts/legacy-destination-migrate.spec.ts","startTime":1793868745258,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["범위 감시 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 목록 조건은 범위 키를 절 목록으로 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"목록 조건은 범위 키를 절 목록으로 싣는다"},{"ancestorTitles":["범위 감시 함수"],"duration":9,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 범위 키가 없으면 목록 조건을 만들지 않고 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 키가 없으면 목록 조건을 만들지 않고 던진다"},{"ancestorTitles":["범위 감시 함수"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 목록 조건도 종류의 필수 키가 빠지면 던진다 (기업 경계 키 누락)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"목록 조건도 종류의 필수 키가 빠지면 던진다 (기업 경계 키 누락)"},{"ancestorTitles":["범위 감시 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 단건 판정은 원천이 같으면 allow 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단건 판정은 원천이 같으면 allow 다"},{"ancestorTitles":["범위 감시 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 단건 판정은 원천이 다르면 deny 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단건 판정은 원천이 다르면 deny 다"},{"ancestorTitles":["범위 감시 함수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 ORG 신원에 orgPath 가 없으면 deny 다 (orgPath 누락 거부)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ORG 신원에 orgPath 가 없으면 deny 다 (orgPath 누락 거부)"},{"ancestorTitles":["범위 감시 함수"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 자동 칸 행은 판정하지 않고 undeclared 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동 칸 행은 판정하지 않고 undeclared 다"},{"ancestorTitles":["범위 감시 함수 · 조직 경로 (구분자 경계)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 조직 경로 (구분자 경계) 구분자 경계: 실제 ULID 세 단계 경로의 상위 조회는 하위 행을 허용한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구분자 경계: 실제 ULID 세 단계 경로의 상위 조회는 하위 행을 허용한다"},{"ancestorTitles":["범위 감시 함수 · 조직 경로 (구분자 경계)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 조직 경로 (구분자 경계) 구분자 경계: 형제 세그먼트 (/A/B/ 대 /A/BC/) 는 차단한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구분자 경계: 형제 세그먼트 (/A/B/ 대 /A/BC/) 는 차단한다"},{"ancestorTitles":["범위 감시 함수 · 조직 경로 (구분자 경계)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 조직 경로 (구분자 경계) 구분자 경계: 1/2 는 1/23 과 다르다 (1/23 행은 차단한다)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"구분자 경계: 1/2 는 1/23 과 다르다 (1/23 행은 차단한다)"},{"ancestorTitles":["범위 감시 함수 · 조직 경로 (구분자 경계)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 조직 경로 (구분자 경계) 빈 orgPath 와 루트 / 는 정규화 뒤에도 던진다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"빈 orgPath 와 루트 / 는 정규화 뒤에도 던진다"},{"ancestorTitles":["범위 감시 함수 · 조직 경로 (구분자 경계)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 조직 경로 (구분자 경계) 행의 orgPath 가 형식에 맞지 않으면 deny 다 (LIKE 와일드카드 행을 허용하지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행의 orgPath 가 형식에 맞지 않으면 deny 다 (LIKE 와일드카드 행을 허용하지 않는다)"},{"ancestorTitles":["범위 감시 함수 · 단건 3의미 (합치지 않는다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 단건 3의미 (합치지 않는다) memId 동일: 소유 회원이 같을 때만 allow, 관리자도 이 의미로는 allow 하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"memId 동일: 소유 회원이 같을 때만 allow, 관리자도 이 의미로는 allow 하지 않는다"},{"ancestorTitles":["범위 감시 함수 · 단건 3의미 (합치지 않는다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 단건 3의미 (합치지 않는다) 주문 소유자만: 소유 회원 일치만 allow, 관리자 신원은 주문 판정을 열지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"주문 소유자만: 소유 회원 일치만 allow, 관리자 신원은 주문 판정을 열지 않는다"},{"ancestorTitles":["범위 감시 함수 · 단건 3의미 (합치지 않는다)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 단건 3의미 (합치지 않는다) 소유자 또는 관리자 열람: 관리자는 allow, 그 밖은 소유 회원 일치","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"소유자 또는 관리자 열람: 관리자는 allow, 그 밖은 소유 회원 일치"},{"ancestorTitles":["범위 감시 함수 · 단건 3의미 (합치지 않는다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 단건 3의미 (합치지 않는다) 자동 칸 행은 단건 3의미 모두 undeclared 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동 칸 행은 단건 3의미 모두 undeclared 다"},{"ancestorTitles":["범위 감시 함수 · ORG 쌍 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · ORG 쌍 키 ORG 신원은 자동 칸이어도 orgPath 누락을 먼저 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ORG 신원은 자동 칸이어도 orgPath 누락을 먼저 거부한다"},{"ancestorTitles":["범위 감시 함수 · ORG 쌍 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · ORG 쌍 키 ORG 판정은 agcId · orgPath 쌍 키가 없으면 던진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ORG 판정은 agcId · orgPath 쌍 키가 없으면 던진다"},{"ancestorTitles":["범위 감시 함수 · 범위 키 누락 (R2)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 범위 키 누락 (R2) 범위 키 목록이 비면 단건 판정도 던진다 (allow 를 내지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"범위 키 목록이 비면 단건 판정도 던진다 (allow 를 내지 않는다)"},{"ancestorTitles":["범위 감시 함수 · 범위 키 누락 (R2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 범위 키 누락 (R2) 종류의 필수 키가 빠진 호출은 던진다 (고른 키만 비교하지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"종류의 필수 키가 빠진 호출은 던진다 (고른 키만 비교하지 않는다)"},{"ancestorTitles":["범위 감시 함수 · 범위 키 누락 (R2)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · 범위 키 누락 (R2) 필수 키를 다 넘기면 추가 키가 있어도 판정한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"필수 키를 다 넘기면 추가 키가 있어도 판정한다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 단건 영업 sagId: 행 sagId 가 신원 sagId 와 같을 때만 allow 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"단건 영업 sagId: 행 sagId 가 신원 sagId 와 같을 때만 allow 다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 단건 기업 agcId: 기업 최고는 행 agcId 가 같을 때만 allow 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"단건 기업 agcId: 기업 최고는 행 agcId 가 같을 때만 allow 다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 단건 조직관리자 orgPath: 기업이 같고 행 경로가 신원 경로 아래일 때만 allow 다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"단건 조직관리자 orgPath: 기업이 같고 행 경로가 신원 경로 아래일 때만 allow 다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 조직 접두 경계 (단건): 신원 /A/B/ 는 /A/B/C/ 를 덮고 /A/BC/ 는 덮지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"조직 접두 경계 (단건): 신원 /A/B/ 는 /A/B/C/ 를 덮고 /A/BC/ 는 덮지 않는다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 기업 행 조직관리자 거부: 행 orgPath 가 없으면 조직관리자는 deny 다 (정책 3)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기업 행 조직관리자 거부: 행 orgPath 가 없으면 조직관리자는 deny 다 (정책 3)"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 키 부재 deny: 행이나 신원에 키가 없으면 던지지 않고 deny 를 낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"키 부재 deny: 행이나 신원에 키가 없으면 던지지 않고 deny 를 낸다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 관리자 memId 거부: 관리자 신원은 memId 동일 · 주문 소유자만 의미에서 deny 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"관리자 memId 거부: 관리자 신원은 memId 동일 · 주문 소유자만 의미에서 deny 다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 3의미 동일 키: 영업 · 기업 · 조직관리자의 판정은 의미 이름과 무관하다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"3의미 동일 키: 영업 · 기업 · 조직관리자의 판정은 의미 이름과 무관하다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 memId 경로 보존: 회원 신원은 M6b 와 같은 memId 비교 결과를 낸다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"memId 경로 보존: 회원 신원은 M6b 와 같은 memId 비교 결과를 낸다"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 corpScope 미지값 deny: 기업 신원의 알 수 없는 corpScope 는 판정 신원이 없다 (null)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"corpScope 미지값 deny: 기업 신원의 알 수 없는 corpScope 는 판정 신원이 없다 (null)"},{"ancestorTitles":["범위 감시 함수 · M6c 단건 신원별 키"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 감시 함수 · M6c 단건 신원별 키 빈 신원 orgPath deny: 조직관리자 신원의 orgPath 가 비면 행과 무관하게 deny 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 신원 orgPath deny: 조직관리자 신원의 orgPath 가 비면 행과 무관하게 deny 다"}],"endTime":1793868745318,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/scope-monitor.spec.ts","startTime":1793868745289,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AUDIT_SETTLEMENT_ACTION"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SETTLEMENT_ACTION 식별자가 전건 유일하고 감사 표의 행위 칸 폭 안이다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"식별자가 전건 유일하고 감사 표의 행위 칸 폭 안이다"},{"ancestorTitles":["AUDIT_SETTLEMENT_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SETTLEMENT_ACTION money 어휘와 값 · 키가 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"money 어휘와 값 · 키가 겹치지 않는다"},{"ancestorTitles":["AUDIT_SETTLEMENT_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SETTLEMENT_ACTION security 어휘와 값 · 키가 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"security 어휘와 값 · 키가 겹치지 않는다"},{"ancestorTitles":["AUDIT_SETTLEMENT_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SETTLEMENT_ACTION system 어휘와 값 · 키가 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"system 어휘와 값 · 키가 겹치지 않는다"},{"ancestorTitles":["AuditService.appendSettlement"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AuditService.appendSettlement 회차 번호 · 금액 · 변경 · 배치를 한 행으로 옮기고 사유는 비운다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"회차 번호 · 금액 · 변경 · 배치를 한 행으로 옮기고 사유는 비운다"}],"endTime":1793868745319,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-settlement.spec.ts","startTime":1793868745291,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["(u) 상승 쓰기의 이행기 분류 (리뷰 R1 HIGH)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(u) 상승 쓰기의 이행기 분류 (리뷰 R1 HIGH) (u) 표 부재 1146 은 상승을 생략하고 warn 을 한 줄 남기며 쓰기를 살린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(u) 표 부재 1146 은 상승을 생략하고 warn 을 한 줄 남기며 쓰기를 살린다"},{"ancestorTitles":["(u) 상승 쓰기의 이행기 분류 (리뷰 R1 HIGH)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(u) 상승 쓰기의 이행기 분류 (리뷰 R1 HIGH) (u) 칸 부재 1054 perm_version 도 상승을 생략하고 warn 을 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(u) 칸 부재 1054 perm_version 도 상승을 생략하고 warn 을 남긴다"},{"ancestorTitles":["(u) 상승 쓰기의 이행기 분류 (리뷰 R1 HIGH)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(u) 상승 쓰기의 이행기 분류 (리뷰 R1 HIGH) (u) 이름이 다른 1146 과 그 밖의 오류는 그대로 던진다 (상승을 조용히 빼지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(u) 이름이 다른 1146 과 그 밖의 오류는 그대로 던진다 (상승을 조용히 빼지 않는다)"},{"ancestorTitles":["(v) 판정 불가의 원인은 로그에 남는다 (리뷰 R1 MEDIUM)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"(v) 판정 불가의 원인은 로그에 남는다 (리뷰 R1 MEDIUM) (v) 읽기의 그 밖의 오류는 원인 메시지를 error 로그에 싣고 판정 불가로 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(v) 읽기의 그 밖의 오류는 원인 메시지를 error 로그에 싣고 판정 불가로 던진다"},{"ancestorTitles":["(v) 판정 불가의 원인은 로그에 남는다 (리뷰 R1 MEDIUM)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"(v) 판정 불가의 원인은 로그에 남는다 (리뷰 R1 MEDIUM) (v) 표 부재 1146 은 이행기라 error 로그를 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(v) 표 부재 1146 은 이행기라 error 로그를 남기지 않는다"}],"endTime":1793868745345,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-version.spec.ts","startTime":1793868745319,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["carViewRowAllowedWith"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 행 허용: 표지가 있고 granted 로 허용하면 참이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[M11] 행 허용: 표지가 있고 granted 로 허용하면 참이다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 행 없음 차단: 평가가 거부하면 거짓이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 행 없음 차단: 평가가 거부하면 거짓이다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 판정 불가 차단: unknown 판정은 허용이 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 판정 불가 차단: unknown 판정은 허용이 아니다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 표지 없으면 행이 있어도 차단: 표지 점 조회가 거짓이면 평가를 묻지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[M11] 표지 없으면 행이 있어도 차단: 표지 점 조회가 거짓이면 평가를 묻지 않는다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 평가 예외 차단: 판정 중 던지면 거짓이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 평가 예외 차단: 판정 중 던지면 거짓이다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 판정 실패는 오류 코드만 남기고 거짓이다: 로그에 코드가 있고 메시지 값은 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[M11] 판정 실패는 오류 코드만 남기고 거짓이다: 로그에 코드가 있고 메시지 값은 없다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 판정 불가는 사유 코드만 남기고 거짓이다: unknown 판정은 reason 을 로그에 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[M11] 판정 불가는 사유 코드만 남기고 거짓이다: unknown 판정은 reason 을 로그에 남긴다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 최고관리자 판정 허용은 행 허용이 아니다: super 사유는 거짓이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 최고관리자 판정 허용은 행 허용이 아니다: super 사유는 거짓이다"},{"ancestorTitles":["carViewRowAllowedWith"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"carViewRowAllowedWith [M11] 표지 조회 뒤 훅: afterMarker 는 표지를 읽은 뒤, 평가 앞에 한 번 불린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 표지 조회 뒤 훅: afterMarker 는 표지를 읽은 뒤, 평가 앞에 한 번 불린다"}],"endTime":1793868745348,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin/car-view-row.query.spec.ts","startTime":1793868745320,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["settleInBatches"],"duration":14,"failureDetails":[],"failureMessages":[],"fullName":"settleInBatches 1건씩 순차 처리하고 실패도 순서대로 남긴다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"1건씩 순차 처리하고 실패도 순서대로 남긴다"}],"endTime":1793868745374,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/fc/agency/subscription-batch.spec.ts","startTime":1793868745347,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 구획 이름 4종을 항상 낸다 — 비어 있어도 자리가 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"구획 이름 4종을 항상 낸다 — 비어 있어도 자리가 남는다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView bucket·role·label 셋이 서로 다른 값으로 보존된다 (UI3)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"bucket·role·label 셋이 서로 다른 값으로 보존된다 (UI3)"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 합성 pending 사례 — 판정 대기는 그룹 안의 네 번째 칸이다 (UI4·D4)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"합성 pending 사례 — 판정 대기는 그룹 안의 네 번째 칸이다 (UI4·D4)"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 상병 미상 그룹은 이름을 얻고 목록 맨 뒤에 선다 (D6)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"상병 미상 그룹은 이름을 얻고 목록 맨 뒤에 선다 (D6)"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 행정 목적 상병은 일반 상병 뒤, 상병 미상 앞에 선다 (D5)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"행정 목적 상병은 일반 상병 뒤, 상병 미상 앞에 선다 (D5)"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 모르는 bucket 값은 버리지도 무관으로 밀지도 않고 뒤에 덧붙인다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"모르는 bucket 값은 버리지도 무관으로 밀지도 않고 뒤에 덧붙인다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 실명 필드를 어떤 경로로도 내보내지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"실명 필드를 어떤 경로로도 내보내지 않는다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 적재본이 없으면 none 이다 — 화면은 판정을 기다리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"적재본이 없으면 none 이다 — 화면은 판정을 기다리지 않는다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 처방 회차를 전달한다 — 진료시작일·병의원·투약량이 화면에 도달한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"처방 회차를 전달한다 — 진료시작일·병의원·투약량이 화면에 도달한다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 회차는 가장 최근이 앞이다 — 화면이 prescriptions[0] 하나를 편다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"회차는 가장 최근이 앞이다 — 화면이 prescriptions[0] 하나를 편다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 그룹의 기간은 구획을 가로질러 회차 날짜의 최소·최대다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"그룹의 기간은 구획을 가로질러 회차 날짜의 최소·최대다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 날짜 없는 약이 앞에 서도 기간은 뒤 약의 날짜에서 나온다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"날짜 없는 약이 앞에 서도 기간은 뒤 약의 날짜에서 나온다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 날짜를 가진 회차가 없으면 기간은 둘 다 null 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"날짜를 가진 회차가 없으면 기간은 둘 다 null 이다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 약이 자기 상병을 실어 보내면 그것을 쓰고, 아니면 그룹의 것으로 채운다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"약이 자기 상병을 실어 보내면 그것을 쓰고, 아니면 그룹의 것으로 채운다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 처방 회차가 없거나 배열이 아니어도 빈 배열이다 — 화면이 그 부재를 견딘다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"처방 회차가 없거나 배열이 아니어도 빈 배열이다 — 화면이 그 부재를 견딘다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 처방 회차에도 실명이 실리지 않는다 — whitelist 가 새 키를 통과시키지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"처방 회차에도 실명이 실리지 않는다 — whitelist 가 새 키를 통과시키지 않는다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView v0.6 — medicationDays 는 적재 그룹에 키가 있을 때만 선다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"v0.6 — medicationDays 는 적재 그룹에 키가 있을 때만 선다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView v0.6 — byDate 는 키가 없으면 null, 비었으면 빈 배열이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"v0.6 — byDate 는 키가 없으면 null, 비었으면 빈 배열이다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView v0.6 — byDate 는 최근 날짜 먼저이고 날짜 없는 묶음은 뒤다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"v0.6 — byDate 는 최근 날짜 먼저이고 날짜 없는 묶음은 뒤다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView v0.6 — 약효분류 뷰도 실명 필드를 내보내지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"v0.6 — 약효분류 뷰도 실명 필드를 내보내지 않는다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView v0.6 — 이전 정제기를 거친 v0.6 판정은 ingestRevision 이 null 이고 byDate 는 선다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"v0.6 — 이전 정제기를 거친 v0.6 판정은 ingestRevision 이 null 이고 byDate 는 선다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 상병 30일 — 적재 그룹의 medication_days 가 30 미만이면 목록에서 뺀다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상병 30일 — 적재 그룹의 medication_days 가 30 미만이면 목록에서 뺀다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 상병 30일 — 옛 판정(키 없음)은 처방 회차를 날짜별 최대로 더해 30 미만이면 뺀다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상병 30일 — 옛 판정(키 없음)은 처방 회차를 날짜별 최대로 더해 30 미만이면 뺀다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 상병 30일 — 셀 수 없으면(일수 없는 회차, 회차 없는 약, 판정 대기 약) 빼지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상병 30일 — 셀 수 없으면(일수 없는 회차, 회차 없는 약, 판정 대기 약) 빼지 않는다"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-04-20\",28],[\"2025-04-21\",7]] → 35일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-04-20\",28],[\"2025-04-21\",7]] → 35일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2022-07-04\",60],[\"2022-07-04\",60]] → 60일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2022-07-04\",60],[\"2022-07-04\",60]] → 60일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2022-07-04\",60],[\"2022-07-04\",30]] → 60일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2022-07-04\",60],[\"2022-07-04\",30]] → 60일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-01\",30],[\"2025-01-31\",30]] → 60일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-01\",30],[\"2025-01-31\",30]] → 60일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2022-07-04\",60],[\"2022-09-01\",30]] → 90일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2022-07-04\",60],[\"2022-09-01\",30]] → 90일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-06\",10],[\"2025-01-01\",10]] → 20일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-06\",10],[\"2025-01-01\",10]] → 20일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-01\",90],[\"2025-02-01\",1]] → 91일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-01\",90],[\"2025-02-01\",1]] → 91일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[null,10],[\"2025-01-01\",5]] → 15일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[null,10],[\"2025-01-01\",5]] → 15일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-02-30\",10]] → 10일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-02-30\",10]] → 10일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-01\",null],[\"2025-01-01\",0]] → 0일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dosingDays — 같은 날 최대 · 날짜끼리 합 [[\"2025-01-01\",null],[\"2025-01-01\",0]] → 0일"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 상병 30일 — 옛 판정(키 없음)도 회차로 셀 수 있으면 medicationDays 를 싣는다(화면 · AI 인사이트가 같은 수)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상병 30일 — 옛 판정(키 없음)도 회차로 셀 수 있으면 medicationDays 를 싣는다(화면 · AI 인사이트가 같은 수)"},{"ancestorTitles":["toDiagnosisGroupsView"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"toDiagnosisGroupsView 상병 30일 — 적재된 medication_days 보다 회차로 다시 센 값이 먼저다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"상병 30일 — 적재된 medication_days 보다 회차로 다시 센 값이 먼저다"}],"endTime":1793868745378,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/ddx-view.spec.ts","startTime":1793868745352,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 admin 은 admId·admLoginId 를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin 은 admId·admLoginId 를 싣는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 sales 는 sagId 를 싣고 ADMIN 으로 떨어지지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"sales 는 sagId 를 싣고 ADMIN 으로 떨어지지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 corp SUPER 는 orgPath 를 갖지 않는다 — 전사 범위이기 때문","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"corp SUPER 는 orgPath 를 갖지 않는다 — 전사 범위이기 때문"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 corp ORG 만 부분트리 경로를 싣는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"corp ORG 만 부분트리 경로를 싣는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 null 는 UNKNOWN 이고 refId 를 채우지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"null 는 UNKNOWN 이고 refId 를 채우지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 undefined 는 UNKNOWN 이고 refId 를 채우지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"undefined 는 UNKNOWN 이고 refId 를 채우지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 문자열 는 UNKNOWN 이고 refId 를 채우지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"문자열 는 UNKNOWN 이고 refId 를 채우지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 모르는 role 는 UNKNOWN 이고 refId 를 채우지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모르는 role 는 UNKNOWN 이고 refId 를 채우지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 role 없음 는 UNKNOWN 이고 refId 를 채우지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"role 없음 는 UNKNOWN 이고 refId 를 채우지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 0·음수·비수치 id 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"0·음수·비수치 id 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다"},{"ancestorTitles":["resolveAuditActor — 세 payload 형태 흡수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — 세 payload 형태 흡수 과길이 라벨은 잘린다(64자)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"과길이 라벨은 잘린다(64자)"},{"ancestorTitles":["systemActor"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"systemActor 스케줄러 이름을 라벨에 싣고 refId 는 비운다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스케줄러 이름을 라벨에 싣고 refId 는 비운다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) ORG 토큰의 memId 가 personId 로 실린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"ORG 토큰의 memId 가 personId 로 실린다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) SUPER 는 personId 가 null 이다 — 기업 계정 자체가 신원이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"SUPER 는 personId 가 null 이다 — 기업 계정 자체가 신원이다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) 같은 기업의 조직관리자 둘이 personId 로 갈린다 — refId 만으로는 같은 값이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"같은 기업의 조직관리자 둘이 personId 로 갈린다 — refId 만으로는 같은 값이다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) 0 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"0 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) 음수 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음수 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) 비수치 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비수치 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) 없음 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"없음 memId 는 null 로 떨어진다 — 거짓 신원을 만들지 않는다"},{"ancestorTitles":["resolveAuditActor — corp 개인 식별(personId)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveAuditActor — corp 개인 식별(personId) admin·sales 는 personId 를 갖지 않는다 — 기업 계정 뒤가 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"admin·sales 는 personId 를 갖지 않는다 — 기업 계정 뒤가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 영문+숫자 혼합 장문 은 비밀번호 형태다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영문+숫자 혼합 장문 은 비밀번호 형태다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 임계 길이 정확히 은 비밀번호 형태다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"임계 길이 정확히 은 비밀번호 형태다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 기호 섞인 비밀번호 은 비밀번호 형태다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기호 섞인 비밀번호 은 비밀번호 형태다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 평범한 로그인 ID 은 비밀번호 형태가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"평범한 로그인 ID 은 비밀번호 형태가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 숫자 없는 긴 ID 은 비밀번호 형태가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"숫자 없는 긴 ID 은 비밀번호 형태가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 영문 없는 숫자열 은 비밀번호 형태가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영문 없는 숫자열 은 비밀번호 형태가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 짧은 혼합 은 비밀번호 형태가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"짧은 혼합 은 비밀번호 형태가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — looksLikeSecret"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — looksLikeSecret 빈 값 은 비밀번호 형태가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 값 은 비밀번호 형태가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — maskSecretLabel"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — maskSecretLabel 원문을 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"원문을 남기지 않는다"},{"ancestorTitles":["비밀번호 형태 가림 — maskSecretLabel"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — maskSecretLabel 길이와 구성 요약을 남긴다 — 조사자가 형태를 본다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"길이와 구성 요약을 남긴다 — 조사자가 형태를 본다"},{"ancestorTitles":["비밀번호 형태 가림 — maskSecretLabel"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — maskSecretLabel 길이·구성이 같아도 값이 다르면 라벨이 다르다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"길이·구성이 같아도 값이 다르면 라벨이 다르다"},{"ancestorTitles":["비밀번호 형태 가림 — maskSecretLabel"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — maskSecretLabel 같은 값은 같은 라벨이다 — 반복을 볼 수 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"같은 값은 같은 라벨이다 — 반복을 볼 수 있다"},{"ancestorTitles":["비밀번호 형태 가림 — maskSecretLabel"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — maskSecretLabel 지문이 평문 sha256 의 앞자리가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"지문이 평문 sha256 의 앞자리가 아니다"},{"ancestorTitles":["비밀번호 형태 가림 — maskSecretLabel"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"비밀번호 형태 가림 — maskSecretLabel 키가 지문에 반영된다 — 키가 다르면 같은 값의 지문도 다르다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"키가 지문에 반영된다 — 키가 다르면 같은 값의 지문도 다르다"},{"ancestorTitles":["claimedActor — 저장 시점 가림"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"claimedActor — 저장 시점 가림 비밀번호 형태 입력은 원문이 refLabel 에 남지 않는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"비밀번호 형태 입력은 원문이 refLabel 에 남지 않는다"},{"ancestorTitles":["claimedActor — 저장 시점 가림"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"claimedActor — 저장 시점 가림 평범한 로그인 ID 는 그대로 남는다 — 목적물을 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"평범한 로그인 ID 는 그대로 남는다 — 목적물을 지우지 않는다"},{"ancestorTitles":["claimedActor — 저장 시점 가림"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"claimedActor — 저장 시점 가림 64자를 넘는 비밀번호 형태도 가려진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"64자를 넘는 비밀번호 형태도 가려진다"},{"ancestorTitles":["claimedActor — 저장 시점 가림"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"claimedActor — 저장 시점 가림 제어문자를 지운 뒤 판정한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"제어문자를 지운 뒤 판정한다"}],"endTime":1793868745398,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-actor.spec.ts","startTime":1793868745380,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 거부 403 (E0607)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 거부 403 (E0607) code 상수는 E0607 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"code 상수는 E0607 이다"},{"ancestorTitles":["권한 거부 403 (E0607)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 거부 403 (E0607) 본문은 code · message · reason 세 키이고 예외 타입은 ForbiddenException 이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"본문은 code · message · reason 세 키이고 예외 타입은 ForbiddenException 이다"},{"ancestorTitles":["권한 거부 403 (E0607)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 거부 403 (E0607) 메시지는 호출하는 곳의 문구를 그대로 보존한다 (상수 하나로 덮지 않는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"메시지는 호출하는 곳의 문구를 그대로 보존한다 (상수 하나로 덮지 않는다)"},{"ancestorTitles":["권한 거부 403 (E0607)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 거부 403 (E0607) 사유 3종 (permission · super-only · scope) 이 본문에 그대로 실린다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"사유 3종 (permission · super-only · scope) 이 본문에 그대로 실린다"}],"endTime":1793868745399,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/admin/permission-denied.spec.ts","startTime":1793868745375,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["범위 절 어댑터 · 실제 SQL"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 절 어댑터 · 실제 SQL eq: 담당 영업 열을 값과 같다고 묶는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"eq: 담당 영업 열을 값과 같다고 묶는다"},{"ancestorTitles":["범위 절 어댑터 · 실제 SQL"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 절 어댑터 · 실제 SQL prefix: 경계 접두 LIKE 는 자신과 하위만 잡는 값 /A/B/% 를 넘긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"prefix: 경계 접두 LIKE 는 자신과 하위만 잡는 값 /A/B/% 를 넘긴다"},{"ancestorTitles":["범위 절 어댑터 · 실제 SQL"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"범위 절 어댑터 · 실제 SQL 두 절은 AND 로 묶인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"두 절은 AND 로 묶인다"},{"ancestorTitles":["범위 절 어댑터 · 실제 SQL"],"duration":5,"failureDetails":[],"failureMessages":[],"fullName":"범위 절 어댑터 · 실제 SQL 빈 절 목록은 조건 없음 (undefined) 을 돌려주지 않고 던진다 (전건 노출 차단)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 절 목록은 조건 없음 (undefined) 을 돌려주지 않고 던진다 (전건 노출 차단)"},{"ancestorTitles":["범위 절 어댑터 · 실제 SQL"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"범위 절 어댑터 · 실제 SQL 음성: 와일드카드가 든 접두 값은 LIKE 로 넘기지 않고 던진다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음성: 와일드카드가 든 접두 값은 LIKE 로 넘기지 않고 던진다"}],"endTime":1793868745421,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/scope-condition.spec.ts","startTime":1793868745401,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AdminViewTokenService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminViewTokenService v2 토큰의 서명된 관리자/자동차 claim을 검증한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"v2 토큰의 서명된 관리자/자동차 claim을 검증한다"},{"ancestorTitles":["AdminViewTokenService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminViewTokenService 기존 3-field 토큰은 identity 없는 일반보기 claim으로만 검증한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기존 3-field 토큰은 identity 없는 일반보기 claim으로만 검증한다"},{"ancestorTitles":["AdminViewTokenService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminViewTokenService 문자열이 아닌 토큰(쿼리 객체 · 배열)은 던지지 않고 null 이다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"문자열이 아닌 토큰(쿼리 객체 · 배열)은 던지지 않고 null 이다"},{"ancestorTitles":["AdminViewTokenService"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AdminViewTokenService ttl 생략 시 ADMIN_VIEW_TOKEN_TTL_MS 만큼 산다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"ttl 생략 시 ADMIN_VIEW_TOKEN_TTL_MS 만큼 산다"},{"ancestorTitles":["AdminViewTokenService"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AdminViewTokenService ttl 인자를 주면 그 기간을 쓰고 지나면 거부한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"ttl 인자를 주면 그 기간을 쓰고 지나면 거부한다"}],"endTime":1793868745423,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/admin-view-token/admin-view-token.service.spec.ts","startTime":1793868745401,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 문항 열 개를 고정 순서로 내고 창은 주문일 기준이다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"문항 열 개를 고정 순서로 내고 창은 주문일 기준이다"},{"ancestorTitles":["toDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 1년 내 검사 — 상병마다 탭의 검사 건수(COUNT(asd_examination))를 더한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"1년 내 검사 — 상병마다 탭의 검사 건수(COUNT(asd_examination))를 더한다"},{"ancestorTitles":["toDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 7일 이상 치료 — 탭과 같은 진료를 동일 상병으로 묶고 7일 이상만 싣는다(2026-10-14)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"7일 이상 치료 — 탭과 같은 진료를 동일 상병으로 묶고 7일 이상만 싣는다(2026-10-14)"},{"ancestorTitles":["toDisclosureScreen"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 30일 이상 투약 — 상병별 탭 뷰의 투약일수 그대로이고, 판정이 없으면 pending","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"30일 이상 투약 — 상병별 탭 뷰의 투약일수 그대로이고, 판정이 없으면 pending"},{"ancestorTitles":["toDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 중대질병 — 카드마다 상세 행을 싣고 분류명은 asb_disease 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"중대질병 — 카드마다 상세 행을 싣고 분류명은 asb_disease 다"},{"ancestorTitles":["toDisclosureScreen"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 3개월 내 — 탭의 최신 조제이력 카드를 표지 붙은 묶음으로 싣는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"3개월 내 — 탭의 최신 조제이력 카드를 표지 붙은 묶음으로 싣는다"},{"ancestorTitles":["toDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toDisclosureScreen 입원/수술 — 행마다 진료형태 · 수술명을 싣고 진료일 없는 행은 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"입원/수술 — 행마다 진료형태 · 수술명을 싣고 진료일 없는 행은 싣지 않는다"},{"ancestorTitles":["buildRecordLinker"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildRecordLinker 같은 날 · 같은 병원 · 같은 상병 입원 둘(0일 · 15일)을 각각 잇는다(2026-10-14 고객사)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"같은 날 · 같은 병원 · 같은 상병 입원 둘(0일 · 15일)을 각각 잇는다(2026-10-14 고객사)"},{"ancestorTitles":["buildRecordLinker"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"buildRecordLinker 입원/수술 문항 — 두 입원 행이 두 진료로 이어진다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"입원/수술 문항 — 두 입원 행이 두 진료로 이어진다"},{"ancestorTitles":["buildRecordLinker"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildRecordLinker (진료일, 기관, 상병) → 진료형태로 좁힘 → 기관이 다르면 (진료일, 상병) 한 건만","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"(진료일, 기관, 상병) → 진료형태로 좁힘 → 기관이 다르면 (진료일, 상병) 한 건만"},{"ancestorTitles":["buildRecordLinker"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildRecordLinker toScreenDate — 없는 날짜는 null 이다(ddx 422 방지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"toScreenDate — 없는 날짜는 null 이다(ddx 422 방지)"},{"ancestorTitles":["buildRecordLinker"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"buildRecordLinker toScreenDate — YYYY-MM-DD · YYYYMMDD 만 받는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"toScreenDate — YYYY-MM-DD · YYYYMMDD 만 받는다"},{"ancestorTitles":["withDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"withDisclosureScreen 마지막 키로 붙고, id 가 없는 요청에는 T-0001 부터 매긴다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"마지막 키로 붙고, id 가 없는 요청에는 T-0001 부터 매긴다"},{"ancestorTitles":["withDisclosureScreen"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"withDisclosureScreen 주문일을 못 읽으면 싣지 않는다(ddx 422 방지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문일을 못 읽으면 싣지 않는다(ddx 422 방지)"},{"ancestorTitles":["withDisclosureScreen"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"withDisclosureScreen 측정값이 정수가 아니거나 음수면 null 이다(ddx 422 방지)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"측정값이 정수가 아니거나 음수면 null 이다(ddx 422 방지)"},{"ancestorTitles":["withDisclosureScreen"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"withDisclosureScreen id 가 있으면 그대로 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"id 가 있으면 그대로 쓴다"}],"endTime":1793868745445,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-screen.spec.ts","startTime":1793868745422,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["alert-noise — MS3 규칙별 지속성 · 복구 연속 수"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — MS3 규칙별 지속성 · 복구 연속 수 MS3: 규칙별 지속성은 있으면 덮고 없으면 공용 값을 쓴다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"MS3: 규칙별 지속성은 있으면 덮고 없으면 공용 값을 쓴다"},{"ancestorTitles":["alert-noise — MS3 규칙별 지속성 · 복구 연속 수"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — MS3 규칙별 지속성 · 복구 연속 수 MS3: 규칙별 복구 연속 수는 부재면 즉시 복구다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"MS3: 규칙별 복구 연속 수는 부재면 즉시 복구다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 1 passesRatio — 표본 하한 (M7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 1 passesRatio — 표본 하한 (M7) 표본이 하한 미만이면 실패율이 100%여도 발송하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표본이 하한 미만이면 실패율이 100%여도 발송하지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 1 passesRatio — 표본 하한 (M7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 1 passesRatio — 표본 하한 (M7) 표본이 하한 이상이고 실패율이 임계 이상이면 통과한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표본이 하한 이상이고 실패율이 임계 이상이면 통과한다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 1 passesRatio — 표본 하한 (M7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 1 passesRatio — 표본 하한 (M7) 표본은 충분하지만 실패율이 임계 미만이면 통과하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표본은 충분하지만 실패율이 임계 미만이면 통과하지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 1 passesRatio — 표본 하한 (M7)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 1 passesRatio — 표본 하한 (M7) 표본 0 은 나눗셈 이전에 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표본 0 은 나눗셈 이전에 거부된다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 2 passesPersistence — 지속성 (M8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 2 passesPersistence — 지속성 (M8) 1회만 잡히면 연속 3회 임계를 넘지 못한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"1회만 잡히면 연속 3회 임계를 넘지 못한다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 2 passesPersistence — 지속성 (M8)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 2 passesPersistence — 지속성 (M8) 연속 3회면 발송한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"연속 3회면 발송한다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 2 passesPersistence — 지속성 (M8)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 2 passesPersistence — 지속성 (M8) 임계 기본값(1)에서는 첫 관측부터 발송한다 — 기존 동작 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"임계 기본값(1)에서는 첫 관측부터 발송한다 — 기존 동작 보존"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 3 partitionBySeverity"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 3 partitionBySeverity warn 은 immediate 에 들어가지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"warn 은 immediate 에 들어가지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 3 partitionBySeverity"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 3 partitionBySeverity 빈 입력은 빈 결과다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 입력은 빈 결과다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 동시 3건은 메시지 1건으로 묶인다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"동시 3건은 메시지 1건으로 묶인다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 규칙이 본문에 박아 둔 마커를 겹쳐 붙이지 않는다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"규칙이 본문에 박아 둔 마커를 겹쳐 붙이지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 머리는 최고 심각도 마커 + 총 건수이고 메시지의 첫 토큰이다 (계측이 이것으로 분류한다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"머리는 최고 심각도 마커 + 총 건수이고 메시지의 첫 토큰이다 (계측이 이것으로 분류한다)"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 경고만 묶이면 머리도 주의다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경고만 묶이면 머리도 주의다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 같은 그룹은 한 블록으로 접고 건수를 제목에 적는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"같은 그룹은 한 블록으로 접고 건수를 제목에 적는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 머리와 같은 심각도인 항목은 마커를 반복하지 않고, 다른 항목만 남긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"머리와 같은 심각도인 항목은 마커를 반복하지 않고, 다른 항목만 남긴다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 1건짜리는 머리·블록 없이 한 줄이다 (한 건에 3층은 과하다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"1건짜리는 머리·블록 없이 한 줄이다 (한 건에 3층은 과하다)"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 빈 입력이면 메시지를 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 입력이면 메시지를 만들지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 상한을 넘으면 메시지를 나누고 finding 은 한 건도 잃지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"상한을 넘으면 메시지를 나누고 finding 은 한 건도 잃지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","원칙 4 groupFindings — 발송 문구 템플릿"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) 원칙 4 groupFindings — 발송 문구 템플릿 한 줄이 단독으로 상한을 넘으면 잘라서라도 보낸다 — 통째로 버리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"한 줄이 단독으로 상한을 넘으면 잘라서라도 보낸다 — 통째로 버리지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","stripSeverityMarker — level 이 사실 소스다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) stripSeverityMarker — level 이 사실 소스다 몇 겹이든 걷어낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"몇 겹이든 걷어낸다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","stripSeverityMarker — level 이 사실 소스다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) stripSeverityMarker — level 이 사실 소스다 마커가 없으면 그대로 둔다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"마커가 없으면 그대로 둔다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","stripSeverityMarker — level 이 사실 소스다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) stripSeverityMarker — level 이 사실 소스다 앞이 아닌 자리의 마커는 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"앞이 아닌 자리의 마커는 건드리지 않는다"},{"ancestorTitles":["alert-noise — 억제 4원칙 (순수 함수)","stripSeverityMarker — level 이 사실 소스다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-noise — 억제 4원칙 (순수 함수) stripSeverityMarker — level 이 사실 소스다 level 과 본문 마커가 어긋나면 level 을 따른다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"level 과 본문 마커가 어긋나면 level 을 따른다"},{"ancestorTitles":["해소(복구) 문면 — 상태가 심각도를 대체한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"해소(복구) 문면 — 상태가 심각도를 대체한다 발화 원문의 심각도 마커를 걷어낸다 — `✅ [복구] 🔴 [위험]` 은 나오지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"발화 원문의 심각도 마커를 걷어낸다 — `✅ [복구] 🔴 [위험]` 은 나오지 않는다"},{"ancestorTitles":["해소(복구) 문면 — 상태가 심각도를 대체한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"해소(복구) 문면 — 상태가 심각도를 대체한다 지속 시간을 붙인다 — 1분 미만·미상(0)은 붙이지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"지속 시간을 붙인다 — 1분 미만·미상(0)은 붙이지 않는다"},{"ancestorTitles":["해소(복구) 문면 — 상태가 심각도를 대체한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"해소(복구) 문면 — 상태가 심각도를 대체한다 formatResolvedIn 경계","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"formatResolvedIn 경계"},{"ancestorTitles":["해소(복구) 문면 — 상태가 심각도를 대체한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"해소(복구) 문면 — 상태가 심각도를 대체한다 여러 건은 발송과 같은 3층 구조로 한 통에 묶인다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"여러 건은 발송과 같은 3층 구조로 한 통에 묶인다"},{"ancestorTitles":["해소(복구) 문면 — 상태가 심각도를 대체한다"],"duration":7,"failureDetails":[],"failureMessages":[],"fullName":"해소(복구) 문면 — 상태가 심각도를 대체한다 상한을 넘으면 발송과 같은 규약으로 나눈다 — 해소만 400 을 받고 유실되지 않게","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"상한을 넘으면 발송과 같은 규약으로 나눈다 — 해소만 400 을 받고 유실되지 않게"},{"ancestorTitles":["해소(복구) 문면 — 상태가 심각도를 대체한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"해소(복구) 문면 — 상태가 심각도를 대체한다 빈 입력은 빈 배열이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 입력은 빈 배열이다"}],"endTime":1793868745457,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-noise.spec.ts","startTime":1793868745427,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 기준 상태는 live 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기준 상태는 live 다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 틱이 없으면 never 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"틱이 없으면 never 다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 dead 가 snoozed·stopped 보다 먼저 판정된다 — OFF 가 죽음을 가리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"dead 가 snoozed·stopped 보다 먼저 판정된다 — OFF 가 죽음을 가리지 않는다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 틱 시각이 미래면 초록이 아니라 unknown 이다 — 시계가 앞선 런너의 죽음을 가리지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"틱 시각이 미래면 초록이 아니라 unknown 이다 — 시계가 앞선 런너의 죽음을 가리지 않는다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 unknown 은 dead 보다 뒤다 — 두 번 틱하고 죽은 런너를 숨기지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"unknown 은 dead 보다 뒤다 — 두 번 틱하고 죽은 런너를 숨기지 않는다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 전체 OFF·라벨 미설정·활성 채널 0 은 stopped 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전체 OFF·라벨 미설정·활성 채널 0 은 stopped 다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 모든 규칙이 개별 OFF 면 stopped 다 — 아무것도 감시하지 않는데 초록일 수 없다 (R1 F1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"모든 규칙이 개별 OFF 면 stopped 다 — 아무것도 감시하지 않는데 초록일 수 없다 (R1 F1)"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 활성 규칙이 한 번도 점검되지 않았으면 degraded 다 (R1 F1)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"활성 규칙이 한 번도 점검되지 않았으면 degraded 다 (R1 F1)"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 주기 불일치는 dead 가 아니라 degraded 사유다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"주기 불일치는 dead 가 아니라 degraded 사유다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 직전 회차 카운터가 0 이어도 채널 실패율이 0 을 넘으면 live 로 돌아오지 않는다 (R6-F1)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"직전 회차 카운터가 0 이어도 채널 실패율이 0 을 넘으면 live 로 돌아오지 않는다 (R6-F1)"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 미검증 활성 채널이 있으면 live 가 아니다 (R8-F1)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"미검증 활성 채널이 있으면 live 가 아니다 (R8-F1)"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 이력 조회 실패와 구멍은 각각 degraded 사유다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"이력 조회 실패와 구멍은 각각 degraded 사유다"},{"ancestorTitles":["decideOverall — 판정 순서"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"decideOverall — 판정 순서 dead·stopped·snoozed 일 때 규칙 stale 을 원인으로 세지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"dead·stopped·snoozed 일 때 규칙 stale 을 원인으로 세지 않는다"},{"ancestorTitles":["observedCadence — 실측이 설정을 이긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"observedCadence — 실측이 설정을 이긴다 median 은 튀는 값 하나에 흔들리지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"median 은 튀는 값 하나에 흔들리지 않는다"},{"ancestorTitles":["observedCadence — 실측이 설정을 이긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"observedCadence — 실측이 설정을 이긴다 alert_poll_interval_ms 를 최소값 60000 으로 내려도 5분 주기 런너가 dead 가 아니다 (R1-F1)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"alert_poll_interval_ms 를 최소값 60000 으로 내려도 5분 주기 런너가 dead 가 아니다 (R1-F1)"},{"ancestorTitles":["observedCadence — 실측이 설정을 이긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"observedCadence — 실측이 설정을 이긴다 실측이 설정보다 길면 실측이 이기고, 짧으면 설정이 하한으로 이긴다 (R2-F1 양방향)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"실측이 설정보다 길면 실측이 이기고, 짧으면 설정이 하한으로 이긴다 (R2-F1 양방향)"},{"ancestorTitles":["observedCadence — 실측이 설정을 이긴다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"observedCadence — 실측이 설정을 이긴다 간격을 하나도 못 본 첫 틱 직후에만 임계를 60분으로 넓힌다 (R4-F1 · R5-F3)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"간격을 하나도 못 본 첫 틱 직후에만 임계를 60분으로 넓힌다 (R4-F1 · R5-F3)"},{"ancestorTitles":["observedCadence — 실측이 설정을 이긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"observedCadence — 실측이 설정을 이긴다 긴 간격 1회가 임계를 영구히 키우지 않는다 (R3-F1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"긴 간격 1회가 임계를 영구히 키우지 않는다 (R3-F1)"},{"ancestorTitles":["observedCadence — 실측이 설정을 이긴다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"observedCadence — 실측이 설정을 이긴다 범위를 벗어난 alert_schedule_expect 는 clamp 되고 그 사실이 드러난다 (R5-F3)","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"범위를 벗어난 alert_schedule_expect 는 clamp 되고 그 사실이 드러난다 (R5-F3)"},{"ancestorTitles":["classifyRule"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyRule OFF·스누즈가 error 보다 앞이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"OFF·스누즈가 error 보다 앞이다"},{"ancestorTitles":["classifyRule"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyRule throw 회차는 error 이고 checkedAt 이 밀리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"throw 회차는 error 이고 checkedAt 이 밀리지 않는다"},{"ancestorTitles":["classifyRule"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"classifyRule checkedAt 이 없으면 never, 오래되면 stale","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"checkedAt 이 없으면 never, 오래되면 stale"},{"ancestorTitles":["classifyRule"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"classifyRule 만료된 스누즈는 스누즈가 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"만료된 스누즈는 스누즈가 아니다"},{"ancestorTitles":["listRules"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"listRules 규칙 ON/OFF 미설정은 켜짐으로 읽고 카탈로그 순서를 유지한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"규칙 ON/OFF 미설정은 켜짐으로 읽고 카탈로그 순서를 유지한다"},{"ancestorTitles":["listSuppressed — 키를 split 하지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"listSuppressed — 키를 split 하지 않는다 접두 비교로 ruleId 를 얻고 나머지는 엔트리 값에서 읽는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"접두 비교로 ruleId 를 얻고 나머지는 엔트리 값에서 읽는다"},{"ancestorTitles":["listSuppressed — 키를 split 하지 않는다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"listSuppressed — 키를 split 하지 않는다 카탈로그에 없는 접두는 ruleId:null 로 그대로 보여 준다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"카탈로그에 없는 접두는 ruleId:null 로 그대로 보여 준다"},{"ancestorTitles":["listSnoozeSuppressed"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"listSnoozeSuppressed 스누즈로 막힌 경고를 최신순으로 내고 해소 여부를 구분한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"스누즈로 막힌 경고를 최신순으로 내고 해소 여부를 구분한다"},{"ancestorTitles":["channelRates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"channelRates 조회 실패는 available:false 이고 빈 원장과 다르다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"조회 실패는 available:false 이고 빈 원장과 다르다"},{"ancestorTitles":["channelRates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"channelRates 한 번도 발송이 없는 채널은 rate:null 이다 — 0% 가 아니다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"한 번도 발송이 없는 채널은 rate:null 이다 — 0% 가 아니다"},{"ancestorTitles":["channelRates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"channelRates 채널마다 자기 최근 N건만 본다 — 잦은 채널이 드문 채널의 표본을 밀어내지 않는다 (R7-F3)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"채널마다 자기 최근 N건만 본다 — 잦은 채널이 드문 채널의 표본을 밀어내지 않는다 (R7-F3)"},{"ancestorTitles":["channelRates"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"channelRates 채널 수정 시각 이전 행은 세지 않는다 — 새 목적지가 옛 성공을 상속하지 않는다 (R1 F2)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"채널 수정 시각 이전 행은 세지 않는다 — 새 목적지가 옛 성공을 상속하지 않는다 (R1 F2)"},{"ancestorTitles":["channelRates"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"channelRates 창이 명시적이다 — entries·since 를 함께 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"창이 명시적이다 — entries·since 를 함께 낸다"},{"ancestorTitles":["historyView · gapInWindow"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"historyView · gapInWindow 조회 실패만 available:false 다. 빈 원장은 available:true + list:[]","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"조회 실패만 available:false 다. 빈 원장은 available:true + list:[]"},{"ancestorTitles":["historyView · gapInWindow"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"historyView · gapInWindow 창 밖으로 밀려난 옛 구멍은 degraded 로 세지 않는다 (R6-F4)","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"창 밖으로 밀려난 옛 구멍은 degraded 로 세지 않는다 (R6-F4)"}],"endTime":1793868745471,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-monitor.spec.ts","startTime":1793868745449,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-00016 → DUPLICATE, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-00016 → DUPLICATE, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-00025 → AUTH_EXPIRED, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-00025 → AUTH_EXPIRED, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-01004 → AUTH_TIMEOUT, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-01004 → AUTH_TIMEOUT, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12001 → AUTH_TIMEOUT, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12001 → AUTH_TIMEOUT, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12003 → VENDOR_ERROR, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12003 → VENDOR_ERROR, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12050 → VENDOR_ERROR, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12050 → VENDOR_ERROR, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12100 → VENDOR_ERROR, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12100 → VENDOR_ERROR, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12051 → AGE_RESTRICTED, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12051 → AGE_RESTRICTED, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12200 → NETWORK_ERROR, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12200 → NETWORK_ERROR, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12804 → INPUT_INVALID, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12804 → INPUT_INVALID, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12835 → INPUT_INVALID, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12835 → INPUT_INVALID, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-13000 → INPUT_INVALID, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-13000 → INPUT_INVALID, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12871 → AUTH_APP_MISSING, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12871 → AUTH_APP_MISSING, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-13002 → REQUEST_INVALID, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-13002 → REQUEST_INVALID, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-13300 → AUTH_CODE_WRONG, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-13300 → AUTH_CODE_WRONG, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-12872 → UNKNOWN, 메시지 보존","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-12872 → UNKNOWN, 메시지 보존"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","codef — 기존 codefErrorMessage 동작 보존"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 codef — 기존 codefErrorMessage 동작 보존 CF-00000 / CF-03002 → OK (실패 아님)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"CF-00000 / CF-03002 → OK (실패 아님)"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","★ retryable — 일시오류와 진짜실패 구분 (갭 A 해결)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 ★ retryable — 일시오류와 진짜실패 구분 (갭 A 해결) 일시/시스템 사유 → retryable true","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"일시/시스템 사유 → retryable true"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","★ retryable — 일시오류와 진짜실패 구분 (갭 A 해결)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 ★ retryable — 일시오류와 진짜실패 구분 (갭 A 해결) 사용자 입력·조건 사유 → retryable false","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"사용자 입력·조건 사유 → retryable false"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 00000000 → OK","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"00000000 → OK"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 80002231 → INPUT_INVALID","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"80002231 → INPUT_INVALID"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 8000B122 → INPUT_INVALID","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"8000B122 → INPUT_INVALID"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 800033E2 → INPUT_INVALID","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"800033E2 → INPUT_INVALID"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 80004133 → AUTH_EXPIRED","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"80004133 → AUTH_EXPIRED"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 80004126 → AUTH_CODE_WRONG","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"80004126 → AUTH_CODE_WRONG"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 80004100 → AUTH_CERT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"80004100 → AUTH_CERT"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 42110000 → NO_DATA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"42110000 → NO_DATA"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 GWSM0005 → SYSTEM_ERROR","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"GWSM0005 → SYSTEM_ERROR"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","coocon — native(8자리) 직접 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 coocon — native(8자리) 직접 매핑 80002F20 → VENDOR_ERROR","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"80002F20 → VENDOR_ERROR"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","octover — DOZN 공통 오류코드 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 octover — DOZN 공통 오류코드 매핑 1000200 → OK","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"1000200 → OK"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","octover — DOZN 공통 오류코드 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 octover — DOZN 공통 오류코드 매핑 1000035(조회내역 없음) → NO_DATA","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"1000035(조회내역 없음) → NO_DATA"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","octover — DOZN 공통 오류코드 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 octover — DOZN 공통 오류코드 매핑 1000111(IP 차단) → RATE_LIMIT","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"1000111(IP 차단) → RATE_LIMIT"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","octover — DOZN 공통 오류코드 매핑"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 octover — DOZN 공통 오류코드 매핑 사전 미수록 코드 → UNKNOWN","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"사전 미수록 코드 → UNKNOWN"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","hyphen — 통신코드 + errMsg [업무코드] 보정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 hyphen — 통신코드 + errMsg [업무코드] 보정 통신 resCd 직접 매핑","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"통신 resCd 직접 매핑"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","hyphen — 통신코드 + errMsg [업무코드] 보정"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 hyphen — 통신코드 + errMsg [업무코드] 보정 ★ 통신성공(CF-99999/0000)이어도 errMsg [업무코드]를 끌어올려 분류","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"★ 통신성공(CF-99999/0000)이어도 errMsg [업무코드]를 끌어올려 분류"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","hyphen — 통신코드 + errMsg [업무코드] 보정"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 hyphen — 통신코드 + errMsg [업무코드] 보정 errMsg에 매핑 안 되는 코드면 통신코드 유지","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"errMsg에 매핑 안 되는 코드면 통신코드 유지"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","미수록 코드 폴백 + 메타 일관성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 미수록 코드 폴백 + 메타 일관성 어떤 벤더든 미수록 코드 → UNKNOWN (ops generic)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"어떤 벤더든 미수록 코드 → UNKNOWN (ops generic)"},{"ancestorTitles":["resolveTreatError 통합 벤더 에러 분류","미수록 코드 폴백 + 메타 일관성"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolveTreatError 통합 벤더 에러 분류 미수록 코드 폴백 + 메타 일관성 null/undefined/공백 코드도 안전하게 UNKNOWN","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"null/undefined/공백 코드도 안전하게 UNKNOWN"}],"endTime":1793868745478,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/error/treat-error-resolver.spec.ts","startTime":1793868745458,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords 정상 행을 스펙 필드로 옮기고 그룹 값을 drug_class·class_total_days 에 싣는다","invocations":1,"location":null,"numPassingAsserts":9,"retryReasons":[],"status":"passed","title":"정상 행을 스펙 필드로 옮기고 그룹 값을 drug_class·class_total_days 에 싣는다"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 정수 는 90 → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 정수 는 90 → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 0 는 0 → 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 0 는 0 → 0"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 정수형 문자열 는 \"90\" → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 정수형 문자열 는 \"90\" → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 결측(null) 는 null → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 결측(null) 는 null → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 단위 붙은 문자열 는 \"90일\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 단위 붙은 문자열 는 \"90일\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 소수 는 1.5 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 소수 는 1.5 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 음수 는 -1 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 음수 는 -1 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords days_supplied — 빈 문자열 는 \"\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"days_supplied — 빈 문자열 는 \"\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 정수 는 90 → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 정수 는 90 → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 0 는 0 → 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 0 는 0 → 0"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 정수형 문자열 는 \"90\" → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 정수형 문자열 는 \"90\" → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 결측(null) 는 null → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 결측(null) 는 null → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 단위 붙은 문자열 는 \"90일\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 단위 붙은 문자열 는 \"90일\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 소수 는 1.5 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 소수 는 1.5 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 음수 는 -1 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 음수 는 -1 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords dose_per_administration — 빈 문자열 는 \"\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"dose_per_administration — 빈 문자열 는 \"\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 정수 는 90 → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 정수 는 90 → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 0 는 0 → 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 0 는 0 → 0"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 정수형 문자열 는 \"90\" → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 정수형 문자열 는 \"90\" → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 결측(null) 는 null → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 결측(null) 는 null → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 단위 붙은 문자열 는 \"90일\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 단위 붙은 문자열 는 \"90일\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 소수 는 1.5 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 소수 는 1.5 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 음수 는 -1 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 음수 는 -1 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords administrations_per_day — 빈 문자열 는 \"\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"administrations_per_day — 빈 문자열 는 \"\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 정수 는 90 → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 정수 는 90 → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 0 는 0 → 0","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 0 는 0 → 0"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 정수형 문자열 는 \"90\" → 90","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 정수형 문자열 는 \"90\" → 90"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 결측(null) 는 null → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 결측(null) 는 null → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 단위 붙은 문자열 는 \"90일\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 단위 붙은 문자열 는 \"90일\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 소수 는 1.5 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 소수 는 1.5 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 음수 는 -1 → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 음수 는 -1 → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords class_total_days — 빈 문자열 는 \"\" → null","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"class_total_days — 빈 문자열 는 \"\" → null"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords 약품명이 없는 행은 산출에서 제외한다 (스펙 required · minLength 1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"약품명이 없는 행은 산출에서 제외한다 (스펙 required · minLength 1)"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords 빈 진단 배열은 빈 배열 두 개로 나가고 키를 지우지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 진단 배열은 빈 배열 두 개로 나가고 키를 지우지 않는다"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords 코드·명이 둘 다 빈 진단 원소는 버리고, 한쪽만 있는 원소는 빈 문자열로 짝을 맞춘다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"코드·명이 둘 다 빈 진단 원소는 버리고, 한쪽만 있는 원소는 빈 문자열로 짝을 맞춘다"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords indication 키를 만들지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"indication 키를 만들지 않는다"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords 키 순서가 결정적이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"키 순서가 결정적이다"},{"ancestorTitles":["ddx-payload.toPrescriptionRecords"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.toPrescriptionRecords 빈 입력과 null 입력에서 빈 배열을 낸다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 입력과 null 입력에서 빈 배열을 낸다"},{"ancestorTitles":["ddx-payload.buildAnalyzeRequest"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"ddx-payload.buildAnalyzeRequest 요청 본문의 키 순서와 직렬화가 결정적이다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"요청 본문의 키 순서와 직렬화가 결정적이다"}],"endTime":1793868745491,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/ddx-payload.spec.ts","startTime":1793868745473,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["menu map isolation (M11)"],"duration":4,"failureDetails":[],"failureMessages":[],"fullName":"menu map isolation (M11) [M11] 메뉴 맵 참조 0: 대상 소스 어디에도 메뉴 맵 테이블 참조가 없다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"[M11] 메뉴 맵 참조 0: 대상 소스 어디에도 메뉴 맵 테이블 참조가 없다"},{"ancestorTitles":["menu map isolation (M11)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"menu map isolation (M11) [M11] 스캐너 음성: 참조 한 줄을 넣은 임시 대상에서는 적중한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 스캐너 음성: 참조 한 줄을 넣은 임시 대상에서는 적중한다"}],"endTime":1793868745495,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/menu-map-isolation.spec.ts","startTime":1793868745480,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-reads-only-whitelisted-columns","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"synth-view-reads-only-whitelisted-columns"},{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-drops-expired-prescription-rows","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"synth-view-drops-expired-prescription-rows"},{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-keeps-empty-claim-item-as-unmapped","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"synth-view-keeps-empty-claim-item-as-unmapped"},{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-folds-multi-facility-car-period","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"synth-view-folds-multi-facility-car-period"},{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-splits-disability-by-view-name-lexicon","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"synth-view-splits-disability-by-view-name-lexicon"},{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-state-is-independent-of-ddx-state","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"synth-view-state-is-independent-of-ddx-state"},{"ancestorTitles":["toSynthView (저장소 합성 4종)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toSynthView (저장소 합성 4종) synth-view-replays-frozen-fixture-from-frozen-input","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"synth-view-replays-frozen-fixture-from-frozen-input"}],"endTime":1793868745510,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/analyze/synth-view.spec.ts","startTime":1793868745494,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 혼합 분할: 혼합 역할의 허용자만 새 역할로 옮기고 원 역할의 car.read 를 뺀다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"[M11] 혼합 분할: 혼합 역할의 허용자만 새 역할로 옮기고 원 역할의 car.read 를 뺀다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 혼합 역할 둘 분할: 이름이 둘이면 두 역할을 한 계획에서 나눈다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[M11] 혼합 역할 둘 분할: 이름이 둘이면 두 역할을 한 계획에서 나눈다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 메뉴 보존: 분할 역할은 원 메뉴 목록을 그대로 받고 원 역할의 메뉴는 연산에서 빠지지 않는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[M11] 메뉴 보존: 분할 역할은 원 메뉴 목록을 그대로 받고 원 역할의 메뉴는 연산에서 빠지지 않는다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 재실행 빈 계획: 적용한 상태를 다시 계획하면 연산이 0 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"[M11] 재실행 빈 계획: 적용한 상태를 다시 계획하면 연산이 0 이다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 적용 후 대조 0 (계획 시뮬레이션): 적용 뒤 계획 상태의 보유자 집합이 env 집합과 같다 — 실행기 SQL 은 격리 실측이 잰다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[M11] 적용 후 대조 0 (계획 시뮬레이션): 적용 뒤 계획 상태의 보유자 집합이 env 집합과 같다 — 실행기 SQL 은 격리 실측이 잰다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 허용자만 있는 역할: car.read 가 없으면 더한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 허용자만 있는 역할: car.read 가 없으면 더한다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 비허용자만 있는 역할: car.read 를 뺀다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 비허용자만 있는 역할: car.read 를 뺀다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 분할 이름 누락 거부: 이름이 없는 혼합 역할은 needNames 에 들고 적용을 거부한다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"[M11] 분할 이름 누락 거부: 이름이 없는 혼합 역할은 needNames 에 들고 적용을 거부한다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 빈 허용목록은 적용을 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 빈 허용목록은 적용을 거부한다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 허용목록 번호가 DB 계정과 하나도 안 묶이면 거부한다 (오타 목록의 전 역할 행 제거 방지)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 허용목록 번호가 DB 계정과 하나도 안 묶이면 거부한다 (오타 목록의 전 역할 행 제거 방지)"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] 기존 역할 이름과 겹치는 분할 이름은 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"[M11] 기존 역할 이름과 겹치는 분할 이름은 거부한다"},{"ancestorTitles":["car-view reconcile plan (R20 fixture)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"car-view reconcile plan (R20 fixture) [M11] --out 워크트리 밖만 허용: 안쪽 경로는 거부하고 접두만 같은 바깥 경로는 허용한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"[M11] --out 워크트리 밖만 허용: 안쪽 경로는 거부하고 접두만 같은 바깥 경로는 허용한다"}],"endTime":1793868745512,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/car-view-reconcile.plan.spec.ts","startTime":1793868745498,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toInsightReport — whitelist"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — whitelist 미끼 값이 산출 어디에도 없다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"미끼 값이 산출 어디에도 없다"},{"ancestorTitles":["toInsightReport — whitelist"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — whitelist 금지 키가 산출 어디에도 없다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"금지 키가 산출 어디에도 없다"},{"ancestorTitles":["toInsightReport — whitelist"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — whitelist `null` 과 「전 블록이 비었다」를 구분한다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"`null` 과 「전 블록이 비었다」를 구분한다"},{"ancestorTitles":["toInsightReport — 블록 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — 블록 축 채운 fixture 에서 개수가 원본과 같다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"채운 fixture 에서 개수가 원본과 같다"},{"ancestorTitles":["toInsightReport — 블록 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — 블록 축 `doubt` 는 개수가 아니라 존재 여부다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"`doubt` 는 개수가 아니라 존재 여부다"},{"ancestorTitles":["toInsightReport — 블록 축"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — 블록 축 관측된 문면 축은 그대로 옮긴다","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"관측된 문면 축은 그대로 옮긴다"},{"ancestorTitles":["toInsightReport — 블록 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — 블록 축 `emptyBlocks` 는 세 문면만 싣는다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"`emptyBlocks` 는 세 문면만 싣는다"},{"ancestorTitles":["toInsightReport — 블록 축"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReport — 블록 축 결측 문면은 이름 붙은 기본값으로 간다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"결측 문면은 이름 붙은 기본값으로 간다"}],"endTime":1793868745527,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-report.spec.ts","startTime":1793868745512,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toInsightReportV2 — insight-v0.9 (수정요청 10.12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — insight-v0.9 (수정요청 10.12) v0.9 — 새 필드가 값 그대로 선다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"v0.9 — 새 필드가 값 그대로 선다"},{"ancestorTitles":["toInsightReportV2 — insight-v0.9 (수정요청 10.12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — insight-v0.9 (수정요청 10.12) v0.9 — 원본에 없는 새 키는 빈 배열 · null 로 선다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"v0.9 — 원본에 없는 새 키는 빈 배열 · null 로 선다"},{"ancestorTitles":["toInsightReportV2 — insight-v0.9 (수정요청 10.12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — insight-v0.9 (수정요청 10.12) v0.9 — 형이 맞지 않는 새 필드는 null · 빈 배열이고 객체가 아닌 진료 원소는 빠진다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"v0.9 — 형이 맞지 않는 새 필드는 null · 빈 배열이고 객체가 아닌 진료 원소는 빠진다"},{"ancestorTitles":["toInsightReportV2 — insight-v0.9 (수정요청 10.12)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — insight-v0.9 (수정요청 10.12) v0.9 — 진료 원소는 이름 붙은 세 키만 옮긴다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"v0.9 — 진료 원소는 이름 붙은 세 키만 옮긴다"},{"ancestorTitles":["toInsightReportV2 — insight-v0.9 (수정요청 10.12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — insight-v0.9 (수정요청 10.12) v0.9 — 자동차 항목 행과 carRecords 는 사고 번호까지 짝이 맞는다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"v0.9 — 자동차 항목 행과 carRecords 는 사고 번호까지 짝이 맞는다"},{"ancestorTitles":["toInsightReportV2 — insight-v0.9 (수정요청 10.12)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — insight-v0.9 (수정요청 10.12) v0.9 — 항목 수준 accidents 는 싣지 않는다(화면이 읽지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"v0.9 — 항목 수준 accidents 는 싣지 않는다(화면이 읽지 않는다)"}],"endTime":1793868745529,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-report-v2.revision6.spec.ts","startTime":1793868745514,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["영업 · 기업 파생 메뉴 (합성 신원 골든 대조)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업 · 기업 파생 메뉴 (합성 신원 골든 대조) 영업 메뉴 파생은 현행 salesCode 집합과 같은 리프를 낸다 (합성 영업 신원)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 메뉴 파생은 현행 salesCode 집합과 같은 리프를 낸다 (합성 영업 신원)"},{"ancestorTitles":["영업 · 기업 파생 메뉴 (합성 신원 골든 대조)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업 · 기업 파생 메뉴 (합성 신원 골든 대조) 영업 메뉴에 진료 모니터링이 없고 분석 관리는 남는다 (합성 영업 신원)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"영업 메뉴에 진료 모니터링이 없고 분석 관리는 남는다 (합성 영업 신원)"},{"ancestorTitles":["영업 · 기업 파생 메뉴 (합성 신원 골든 대조)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업 · 기업 파생 메뉴 (합성 신원 골든 대조) 기업 최고관리자 파생은 분석 관리 게이트 0 과 1 의 현행 리프와 같다 (합성 신원)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"기업 최고관리자 파생은 분석 관리 게이트 0 과 1 의 현행 리프와 같다 (합성 신원)"},{"ancestorTitles":["영업 · 기업 파생 메뉴 (합성 신원 골든 대조)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"영업 · 기업 파생 메뉴 (합성 신원 골든 대조) 기업 조직관리자 파생은 숨김 코드를 빼고 분석 관리 게이트를 따른다 (합성 신원)","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"기업 조직관리자 파생은 숨김 코드를 빼고 분석 관리 게이트를 따른다 (합성 신원)"},{"ancestorTitles":["영업 · 기업 파생 메뉴 (합성 신원 골든 대조)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"영업 · 기업 파생 메뉴 (합성 신원 골든 대조) 기업 scope 가 SUPER 도 ORG 도 아니면 조직관리자 규칙을 따른다 (합성 신원 · 불명 scope)","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"기업 scope 가 SUPER 도 ORG 도 아니면 조직관리자 규칙을 따른다 (합성 신원 · 불명 scope)"}],"endTime":1793868745542,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/sales-corp-menu.spec.ts","startTime":1793868745530,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 허용 호스트의 https 는 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"허용 호스트의 https 는 통과한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) http 는 거부한다 (조건 1)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"http 는 거부한다 (조건 1)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 자격증명이 있으면 거부한다 (조건 2)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자격증명이 있으면 거부한다 (조건 2)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 비표준 포트는 거부한다 (조건 3)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"비표준 포트는 거부한다 (조건 3)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 접미사 매칭은 라벨 경계를 지킨다 (조건 4)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"접미사 매칭은 라벨 경계를 지킨다 (조건 4)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) IP 리터럴은 접미사 축을 우회하므로 거부한다 (조건 5)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"IP 리터럴은 접미사 축을 우회하므로 거부한다 (조건 5)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 정규화 — 대문자 호스트와 후행 점을 처리한다 (Santa R10 A)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정규화 — 대문자 호스트와 후행 점을 처리한다 (Santa R10 A)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 파싱 실패는 거부한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"파싱 실패는 거부한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","이름 축 (조건 1~5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 이름 축 (조건 1~5) 빈 값·공백은 통과한다 — \"목적지 없음\"이며 검증 대상이 아니다 (회귀 방지)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 값·공백은 통과한다 — \"목적지 없음\"이며 검증 대상이 아니다 (회귀 방지)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","maskWebhookUrl — 출력 형식 고정 (D9-b 변경 여부 판정이 문자열 비교를 한다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) maskWebhookUrl — 출력 형식 고정 (D9-b 변경 여부 판정이 문자열 비교를 한다) 경로·쿼리를 한 조각도 남기지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"경로·쿼리를 한 조각도 남기지 않는다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","maskWebhookUrl — 출력 형식 고정 (D9-b 변경 여부 판정이 문자열 비교를 한다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) maskWebhookUrl — 출력 형식 고정 (D9-b 변경 여부 판정이 문자열 비교를 한다) 빈 값은 그대로 — 비활성 상태를 감추지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"빈 값은 그대로 — 비활성 상태를 감추지 않는다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","maskWebhookUrl — 출력 형식 고정 (D9-b 변경 여부 판정이 문자열 비교를 한다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) maskWebhookUrl — 출력 형식 고정 (D9-b 변경 여부 판정이 문자열 비교를 한다) 파싱 실패는 전량 마스킹한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"파싱 실패는 전량 마스킹한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","허용목록 항목 검사 — 이름 규칙 (D9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 허용목록 항목 검사 — 이름 규칙 (D9) IP 리터럴·단일 라벨·내부 접미사만 제외되고 나머지는 남는다 (Santa R9)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"IP 리터럴·단일 라벨·내부 접미사만 제외되고 나머지는 남는다 (Santa R9)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","허용목록 항목 검사 — 이름 규칙 (D9)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 허용목록 항목 검사 — 이름 규칙 (D9) 전 항목이 거부되면 유효 허용목록이 비어 모든 발송이 막힌다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"전 항목이 거부되면 유효 허용목록이 비어 모든 발송이 막힌다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","허용목록 항목 검사 — 이름 규칙 (D9)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 허용목록 항목 검사 — 이름 규칙 (D9) env 가 비면 기본값(구글챗·슬랙)을 쓴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"env 가 비면 기본값(구글챗·슬랙)을 쓴다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) 사설·loopback·link-local·멀티캐스트를 거부한다","invocations":1,"location":null,"numPassingAsserts":12,"retryReasons":[],"status":"passed","title":"사설·loopback·link-local·멀티캐스트를 거부한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) IPv4-mapped 는 매핑을 푼 뒤 IPv4 규칙을 적용한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"IPv4-mapped 는 매핑을 푼 뒤 IPv4 규칙을 적용한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) 미지정 주소 :: 는 0.0.0.0 과 같이 거부한다 — v6 표기로 우회할 수 없다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"미지정 주소 :: 는 0.0.0.0 과 같이 거부한다 — v6 표기로 우회할 수 없다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) NAT64·6to4 는 품고 있는 IPv4 를 풀어서 판정한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"NAT64·6to4 는 품고 있는 IPv4 를 풀어서 판정한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) 공인 주소는 통과한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"공인 주소는 통과한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) 허용 접미사 호스트가 사설 대역으로 해석되면 거부한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"허용 접미사 호스트가 사설 대역으로 해석되면 거부한다"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) 해석 실패와 결과 0건은 거부한다 (fail-closed)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"해석 실패와 결과 0건은 거부한다 (fail-closed)"},{"ancestorTitles":["alert-url — 웹훅 목적지 검증 (D9)","주소 축 (조건 6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"alert-url — 웹훅 목적지 검증 (D9) 주소 축 (조건 6) 공인 주소면 통과하고 그 주소를 그대로 돌려준다 (agent lookup 고정용)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"공인 주소면 통과하고 그 주소를 그대로 돌려준다 (agent lookup 고정용)"}],"endTime":1793868745547,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/alert/alert-url.spec.ts","startTime":1793868745529,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["getSeoulToday"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getSeoulToday 서울 자정(UTC 15시)을 경계로 YYYY-MM-DD 날짜가 바뀐다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"서울 자정(UTC 15시)을 경계로 YYYY-MM-DD 날짜가 바뀐다"}],"endTime":1793868745556,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/date.helper.spec.ts","startTime":1793868745546,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 실제 표: 카탈로그 코드는 칸 표 또는 메뉴 밖 목록에 있고, 칸 표 코드는 카탈로그 안이고, 사유가 있다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"실제 표: 카탈로그 코드는 칸 표 또는 메뉴 밖 목록에 있고, 칸 표 코드는 카탈로그 안이고, 사유가 있다"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 13 문서 3-7 연결 어긋남 3건은 칸에 들어 있다 (분석 · 고객사분석 · 기업회원)","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"13 문서 3-7 연결 어긋남 3건은 칸에 들어 있다 (분석 · 고객사분석 · 기업회원)"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 음성: 카탈로그에 새 코드를 더하고 칸 · 메뉴 밖 어디에도 안 걸면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 카탈로그에 새 코드를 더하고 칸 · 메뉴 밖 어디에도 안 걸면 위반이다"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 음성: 칸 표의 코드가 카탈로그 밖이면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 칸 표의 코드가 카탈로그 밖이면 위반이다"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 음성: 메뉴 밖 사유가 빈칸이면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 메뉴 밖 사유가 빈칸이면 위반이다"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 음성: 메뉴 밖 코드가 카탈로그에 없으면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 메뉴 밖 코드가 카탈로그에 없으면 위반이다"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 음성: 메뉴 밖 코드가 칸 표와 겹치면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 메뉴 밖 코드가 칸 표와 겹치면 위반이다"},{"ancestorTitles":["메뉴 권한 표 CI 검사 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 권한 표 CI 검사 (E5) 음성: 칸 표에서 코드 하나를 빼고 메뉴 밖에도 없으면 위반이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"음성: 칸 표에서 코드 하나를 빼고 메뉴 밖에도 없으면 위반이다"},{"ancestorTitles":["카탈로그 응답과 파생 입력 (E5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"카탈로그 응답과 파생 입력 (E5) 카탈로그는 칸 코드 키 구조이고 이름을 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"카탈로그는 칸 코드 키 구조이고 이름을 싣지 않는다"},{"ancestorTitles":["카탈로그 응답과 파생 입력 (E5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"카탈로그 응답과 파생 입력 (E5) 파생 입력은 같은 표에서 나온다 (URL → 보기 + 변경 코드)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"파생 입력은 같은 표에서 나온다 (URL → 보기 + 변경 코드)"},{"ancestorTitles":["첫 버전 적재 규칙 (E6)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"첫 버전 적재 규칙 (E6) 칸 코드는 칸을 가진 역할만 받는다 (칸 밖 코드는 모두 받는다)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"칸 코드는 칸을 가진 역할만 받는다 (칸 밖 코드는 모두 받는다)"},{"ancestorTitles":["첫 버전 적재 규칙 (E6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"첫 버전 적재 규칙 (E6) 최고관리자 전용 코드는 주지 않는다 (칸을 가져도)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"최고관리자 전용 코드는 주지 않는다 (칸을 가져도)"},{"ancestorTitles":["첫 버전 적재 규칙 (E6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"첫 버전 적재 규칙 (E6) 칸 밖 고위험 코드 treat-test.vendor-raw 는 주지 않는다 (칸을 다 가져도)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"칸 밖 고위험 코드 treat-test.vendor-raw 는 주지 않는다 (칸을 다 가져도)"},{"ancestorTitles":["첫 버전 적재 규칙 (E6)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"첫 버전 적재 규칙 (E6) 칸 전체 + 칸 밖 전부 = 최고관리자 전용 · vendor-raw 를 뺀 카탈로그 (빠짐 · 중복 없음)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"칸 전체 + 칸 밖 전부 = 최고관리자 전용 · vendor-raw 를 뺀 카탈로그 (빠짐 · 중복 없음)"}],"endTime":1793868745580,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/menu-permission-map.spec.ts","startTime":1793868745558,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 판정 불가 ≠ 거부 — 표가 없으면 deny 가 아니라 unknown 이다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"판정 불가 ≠ 거부 — 표가 없으면 deny 가 아니라 unknown 이다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 표 부재 1146 은 unknown (table-absent)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"표 부재 1146 은 unknown (table-absent)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 칸 없음 1054 는 unknown (column-absent)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"칸 없음 1054 는 unknown (column-absent)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 오류 사슬의 cause 를 본다 (드라이버 래퍼)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"오류 사슬의 cause 를 본다 (드라이버 래퍼)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate granted 코드는 allow 이고 최고관리자를 부르지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"granted 코드는 allow 이고 최고관리자를 부르지 않는다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate NULL 신원의 최고관리자는 allow","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"NULL 신원의 최고관리자는 allow"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate NULL 신원 비최고관리자는 deny (null-athid)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"NULL 신원 비최고관리자는 deny (null-athid)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 최고관리자 판정 불가 시 일반 코드도 unknown","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"최고관리자 판정 불가 시 일반 코드도 unknown"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 최고관리자 판정 불가 시 최고관리자 전용 코드는 unknown","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"최고관리자 판정 불가 시 최고관리자 전용 코드는 unknown"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 미등록 코드는 역할과 무관하게 unknown (unknown-code)","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"미등록 코드는 역할과 무관하게 unknown (unknown-code)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 비최고관리자는 최고관리자 전용 코드를 집합에 있어도 거부된다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"비최고관리자는 최고관리자 전용 코드를 집합에 있어도 거부된다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 관리자가 아닌 신원의 미등록 코드는 unknown-code 다 (호출자 오타가 unmapped 에 숨지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자가 아닌 신원의 미등록 코드는 unknown-code 다 (호출자 오타가 unmapped 에 숨지 않는다)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 관리자가 아닌 신원은 unmapped 다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자가 아닌 신원은 unmapped 다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 최고관리자 조회는 거부일 때만 한 번 불린다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자 조회는 거부일 때만 한 번 불린다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 행이 없으면 거부 (no-binding), 집합에 없는 코드는 거부 (not-granted)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"행이 없으면 거부 (no-binding), 집합에 없는 코드는 거부 (not-granted)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 카탈로그에 rbac.manage 가 있고 최고관리자 전용 집합에도 든다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"카탈로그에 rbac.manage 가 있고 최고관리자 전용 집합에도 든다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 칸 부재 (1054) 에서 최고관리자는 통과한다 (칸 부재 · 최고관리자 통과)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"칸 부재 (1054) 에서 최고관리자는 통과한다 (칸 부재 · 최고관리자 통과)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 표 부재 (1146) 에서 내부 관리자는 판정 불가이고 거부로 접힌다 (표 부재 · 내부 관리자 거부)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"표 부재 (1146) 에서 내부 관리자는 판정 불가이고 거부로 접힌다 (표 부재 · 내부 관리자 거부)"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate db 오류 중단 — 최고관리자여도 행 조회 오류는 판정 불가로 멈춘다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"db 오류 중단 — 최고관리자여도 행 조회 오류는 판정 불가로 멈춘다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 최고관리자 판정 불가 중단 — 표 부재여도 최고관리자 조회가 실패하면 멈춘다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"최고관리자 판정 불가 중단 — 표 부재여도 최고관리자 조회가 실패하면 멈춘다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 칸 부재 전용 코드 거부 — 최고관리자 전용 코드는 칸 부재에서 비최고관리자에게 닫힌다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"칸 부재 전용 코드 거부 — 최고관리자 전용 코드는 칸 부재에서 비최고관리자에게 닫힌다"},{"ancestorTitles":["권한 평가기 evaluate"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 평가기 evaluate 행 조회가 부재로 실패해도 행 없음 거부 (no-binding) 를 내지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"행 조회가 부재로 실패해도 행 없음 거부 (no-binding) 를 내지 않는다"}],"endTime":1793868745583,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/evaluate.spec.ts","startTime":1793868745548,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["AUDIT_SECURITY_ACTION"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SECURITY_ACTION 로그인 두 결과가 서로 다른 식별자를 갖는다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"로그인 두 결과가 서로 다른 식별자를 갖는다"},{"ancestorTitles":["AUDIT_SECURITY_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SECURITY_ACTION 식별자가 전건 유일하다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"식별자가 전건 유일하다"},{"ancestorTitles":["AUDIT_SECURITY_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SECURITY_ACTION 모든 식별자가 `<도메인>.<동작>` 형태다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"모든 식별자가 `<도메인>.<동작>` 형태다"},{"ancestorTitles":["AUDIT_SECURITY_ACTION"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SECURITY_ACTION 금전 어휘와 값이 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"금전 어휘와 값이 겹치지 않는다"},{"ancestorTitles":["AUDIT_SECURITY_ACTION"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"AUDIT_SECURITY_ACTION 금전 어휘와 키가 겹치지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"금전 어휘와 키가 겹치지 않는다"}],"endTime":1793868745594,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-security.spec.ts","startTime":1793868745582,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["권한 영역 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 영역 표 접두 기준으로 영역 1 · 2 · 3 과 영역 0 을 나눈다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"접두 기준으로 영역 1 · 2 · 3 과 영역 0 을 나눈다"},{"ancestorTitles":["권한 영역 표"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"권한 영역 표 rbac.manage 는 영역 1 이다 (카탈로그 코드와 접두 둘 다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"rbac.manage 는 영역 1 이다 (카탈로그 코드와 접두 둘 다)"},{"ancestorTitles":["권한 영역 표"],"duration":3,"failureDetails":[],"failureMessages":[],"fullName":"권한 영역 표 최고관리자 전용 코드는 영역 1 · 2 · 3 중 하나다 (영역 0 이면 스위치를 켜도 강제되지 않는다)","invocations":1,"location":null,"numPassingAsserts":10,"retryReasons":[],"status":"passed","title":"최고관리자 전용 코드는 영역 1 · 2 · 3 중 하나다 (영역 0 이면 스위치를 켜도 강제되지 않는다)"},{"ancestorTitles":["권한 영역 표"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 영역 표 표의 각 접두는 카탈로그 코드를 한 개 이상 물린다 (죽은 접두 0)","invocations":1,"location":null,"numPassingAsserts":29,"retryReasons":[],"status":"passed","title":"표의 각 접두는 카탈로그 코드를 한 개 이상 물린다 (죽은 접두 0)"},{"ancestorTitles":["권한 영역 표"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 영역 표 한 접두는 표에 한 번만 들고 영역 0 열거와도 겹치지 않는다 (중복 0)","invocations":1,"location":null,"numPassingAsserts":30,"retryReasons":[],"status":"passed","title":"한 접두는 표에 한 번만 들고 영역 0 열거와도 겹치지 않는다 (중복 0)"},{"ancestorTitles":["권한 영역 표"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"권한 영역 표 카탈로그 코드의 모든 접두가 표 또는 영역 0 열거 중 하나에 있다 (미분류 0)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"카탈로그 코드의 모든 접두가 표 또는 영역 0 열거 중 하나에 있다 (미분류 0)"}],"endTime":1793868745605,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/permission/permission-area.spec.ts","startTime":1793868745585,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["toInsightReportV2 — revision7-v1 (중요도 · 고정 순서)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — revision7-v1 (중요도 · 고정 순서) revision7 — 점수는 소수 그대로, importance 는 다섯 키 그대로, 순서는 받은 대로 선다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"revision7 — 점수는 소수 그대로, importance 는 다섯 키 그대로, 순서는 받은 대로 선다"},{"ancestorTitles":["toInsightReportV2 — revision7-v1 (중요도 · 고정 순서)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — revision7-v1 (중요도 · 고정 순서) revision7 — CRM · 이전 판 · 형이 틀린 값은 null 이고 importance 에 모르는 키는 싣지 않는다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"revision7 — CRM · 이전 판 · 형이 틀린 값은 null 이고 importance 에 모르는 키는 싣지 않는다"},{"ancestorTitles":["toInsightReportV2 — revision7-v1 (중요도 · 고정 순서)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"toInsightReportV2 — revision7-v1 (중요도 · 고정 순서) revision7 — 점수 근거(priority)는 질병 부분 · 신뢰도 · 이력 항목만 싣고, 없으면 null","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"revision7 — 점수 근거(priority)는 질병 부분 · 신뢰도 · 이력 항목만 싣고, 없으면 null"}],"endTime":1793868745609,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-report-v2.revision7.spec.ts","startTime":1793868745595,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["schedule isolation"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"schedule isolation (a) 전부 성공이면 mark 는 실패 0 으로 한 번 불리고 0 을 반환한다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(a) 전부 성공이면 mark 는 실패 0 으로 한 번 불리고 0 을 반환한다"},{"ancestorTitles":["schedule isolation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"schedule isolation (b) 첫 격리 호출이 throw 해도 나머지가 실행되고 mark 는 실패 1 로 불린다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"(b) 첫 격리 호출이 throw 해도 나머지가 실행되고 mark 는 실패 1 로 불린다"},{"ancestorTitles":["schedule isolation"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"schedule isolation (c) 보류 호출이 throw 하면 mark 가 불리지 않고 reject 한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(c) 보류 호출이 throw 하면 mark 가 불리지 않고 reject 한다"},{"ancestorTitles":["schedule isolation"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"schedule isolation (d) 격리 호출이 실패해도 보류 호출은 실행된다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"(d) 격리 호출이 실패해도 보류 호출은 실행된다"},{"ancestorTitles":["schedule isolation"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"schedule isolation (e) 격리 실패와 mark 의 reject 가 겹치면 reject 하고 둘째·셋째 격리 호출은 실행된다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"(e) 격리 실패와 mark 의 reject 가 겹치면 reject 하고 둘째·셋째 격리 호출은 실행된다"}],"endTime":1793868745622,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/schedules/schedule-isolation.spec.ts","startTime":1793868745606,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["감시용 신원 해석"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 관리자 쿠키가 검증되면 관리자 신원과 admId 를 준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 쿠키가 검증되면 관리자 신원과 admId 를 준다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 관리자 쿠키가 검증에 실패해도 던지지 않고 신원 없음을 준다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 쿠키가 검증에 실패해도 던지지 않고 신원 없음을 준다"},{"ancestorTitles":["감시용 신원 해석"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 영업 형상의 관리자 쿠키는 관리자 종류를 그대로 준다 (판정 대상은 admin 뿐이다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영업 형상의 관리자 쿠키는 관리자 종류를 그대로 준다 (판정 대상은 admin 뿐이다)"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 회원 쿠키는 회원 신원이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"회원 쿠키는 회원 신원이다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 옛 열람 토큰 헤더는 신원이 아니다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"옛 열람 토큰 헤더는 신원이 아니다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 외부 Basic 은 PrincipalKind 가 아닌 표지다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"외부 Basic 은 PrincipalKind 가 아닌 표지다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 중복 제시: 관리자 쿠키와 회원 쿠키가 같이 오면 관리자가 이긴다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"중복 제시: 관리자 쿠키와 회원 쿠키가 같이 오면 관리자가 이긴다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 검증된 회원 후보가 없는 refresh 형상만 있으면 형상 불일치 표지다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"검증된 회원 후보가 없는 refresh 형상만 있으면 형상 불일치 표지다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 아무 신원도 없으면 none 이다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"아무 신원도 없으면 none 이다"},{"ancestorTitles":["감시용 신원 해석"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"감시용 신원 해석 관리자 형상이 정수가 아닌 admId 를 주면 admId 를 비우고 판정 대상에서 뺀다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"관리자 형상이 정수가 아닌 admId 를 주면 admId 를 비우고 판정 대상에서 뺀다"}],"endTime":1793868745631,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/access-identity.spec.ts","startTime":1793868745611,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["메뉴 파생 (역할 fixture 대조)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 (역할 fixture 대조) 세 역할의 파생 · 미매핑 · 현행 차이가 골든과 같다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"세 역할의 파생 · 미매핑 · 현행 차이가 골든과 같다"},{"ancestorTitles":["메뉴 파생 (역할 fixture 대조)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 (역할 fixture 대조) 음성: 권한 코드 하나를 더하면 파생이 넓어진다 (칸 표가 파생 규칙을 실제로 잡는다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"음성: 권한 코드 하나를 더하면 파생이 넓어진다 (칸 표가 파생 규칙을 실제로 잡는다)"},{"ancestorTitles":["메뉴 파생 (역할 fixture 대조)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 (역할 fixture 대조) 스위치 상수는 OFF 로 커밋되었고 OFF 면 응답 menus 는 현행 집합과 같다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스위치 상수는 OFF 로 커밋되었고 OFF 면 응답 menus 는 현행 집합과 같다"},{"ancestorTitles":["메뉴 파생 (역할 fixture 대조)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 (역할 fixture 대조) 스위치 ON 분기는 파생 ∩ 현행이다 (jest.mock 으로만 켠다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스위치 ON 분기는 파생 ∩ 현행이다 (jest.mock 으로만 켠다)"},{"ancestorTitles":["메뉴 파생 (역할 fixture 대조)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 파생 (역할 fixture 대조) 스위치 ON 이어도 매핑이 없는 메뉴는 현행 그대로 남는다 (숨기지 않는다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"스위치 ON 이어도 매핑이 없는 메뉴는 현행 그대로 남는다 (숨기지 않는다)"},{"ancestorTitles":["메뉴 가지치기 (M7b · 스위치 ON 에서만 부른다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 가지치기 (M7b · 스위치 ON 에서만 부른다) 가지치기 골든: 부모 URL 이 keep 에 있으면 살아남은 자손도 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가지치기 골든: 부모 URL 이 keep 에 있으면 살아남은 자손도 남는다"},{"ancestorTitles":["메뉴 가지치기 (M7b · 스위치 ON 에서만 부른다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 가지치기 (M7b · 스위치 ON 에서만 부른다) 가지치기 음성: 부모 URL 이 keep 밖이면 keep 안의 자손도 빠진다 (음성)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가지치기 음성: 부모 URL 이 keep 밖이면 keep 안의 자손도 빠진다 (음성)"},{"ancestorTitles":["메뉴 가지치기 (M7b · 스위치 ON 에서만 부른다)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"메뉴 가지치기 (M7b · 스위치 ON 에서만 부른다) 가지치기 그룹: 살아남은 자손이 없는 그룹 노드는 빠지고 살아남은 자손이 있으면 남는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"가지치기 그룹: 살아남은 자손이 없는 그룹 노드는 빠지고 살아남은 자손이 있으면 남는다"}],"endTime":1793868745638,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/menu/menu-derivation.spec.ts","startTime":1793868745624,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["개발 인증 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"개발 인증 우회 스위치 (K10) 스위치 미설정이면 개발 인증 우회가 꺼져 있다","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"스위치 미설정이면 개발 인증 우회가 꺼져 있다"},{"ancestorTitles":["개발 인증 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"개발 인증 우회 스위치 (K10) 스위치는 정확히 true 일 때만 켜진다 — 1 · TRUE · false 는 꺼짐","invocations":1,"location":null,"numPassingAsserts":7,"retryReasons":[],"status":"passed","title":"스위치는 정확히 true 일 때만 켜진다 — 1 · TRUE · false 는 꺼짐"},{"ancestorTitles":["개발 인증 우회 스위치 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"개발 인증 우회 스위치 (K10) 스위치가 꺼지면 NODE_ENV 가 dev 여도 swagger 조건은 false 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스위치가 꺼지면 NODE_ENV 가 dev 여도 swagger 조건은 false 다"},{"ancestorTitles":["개발 인증 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"개발 인증 우회 스위치 (K10) 스위치가 켜지면 swagger 조건은 Referer 와 출발 IP 가 맞을 때만 true 다","invocations":1,"location":null,"numPassingAsserts":8,"retryReasons":[],"status":"passed","title":"스위치가 켜지면 swagger 조건은 Referer 와 출발 IP 가 맞을 때만 true 다"},{"ancestorTitles":["개발 인증 우회 스위치 (K10)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"개발 인증 우회 스위치 (K10) 스위치가 꺼지면 로컬 요청 조건도 false 다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"스위치가 꺼지면 로컬 요청 조건도 false 다"},{"ancestorTitles":["개발 인증 우회 스위치 (K10)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"개발 인증 우회 스위치 (K10) 스위치가 켜지면 로컬 요청 조건은 Referer 와 출발 IP 가 맞을 때만 true 다","invocations":1,"location":null,"numPassingAsserts":6,"retryReasons":[],"status":"passed","title":"스위치가 켜지면 로컬 요청 조건은 Referer 와 출발 IP 가 맞을 때만 true 다"}],"endTime":1793868745647,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/request.helper.spec.ts","startTime":1793868745635,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["authCookieOptions (인증쿠키 옵션 통일)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"authCookieOptions (인증쿠키 옵션 통일) https(prod/stg) → secure + sameSite none","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"https(prod/stg) → secure + sameSite none"},{"ancestorTitles":["authCookieOptions (인증쿠키 옵션 통일)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"authCookieOptions (인증쿠키 옵션 통일) http(로컬) → secure false + sameSite lax","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"http(로컬) → secure false + sameSite lax"},{"ancestorTitles":["authCookieOptions (인증쿠키 옵션 통일)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"authCookieOptions (인증쿠키 옵션 통일) withMaxAge → 12시간","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"withMaxAge → 12시간"},{"ancestorTitles":["authCookieOptions (인증쿠키 옵션 통일)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"authCookieOptions (인증쿠키 옵션 통일) clear용(maxAge 없음)과 set용 옵션의 path/secure/sameSite 동일 → 삭제 정상","invocations":1,"location":null,"numPassingAsserts":3,"retryReasons":[],"status":"passed","title":"clear용(maxAge 없음)과 set용 옵션의 path/secure/sameSite 동일 → 삭제 정상"},{"ancestorTitles":["getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보) _aT 2개(옛 만료 + 새 유효) → 둘 다 후보로 반환","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"_aT 2개(옛 만료 + 새 유효) → 둘 다 후보로 반환"},{"ancestorTitles":["getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보) 쿠키 + Authorization 헤더 토큰 모두 후보에 포함","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쿠키 + Authorization 헤더 토큰 모두 후보에 포함"},{"ancestorTitles":["getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보) 쿠키 없고 헤더만 있어도 후보 반환 (cross-site 쿠키 미전송 대응)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쿠키 없고 헤더만 있어도 후보 반환 (cross-site 쿠키 미전송 대응)"},{"ancestorTitles":["getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보) 쿠키와 헤더 토큰이 같으면 중복 제거","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쿠키와 헤더 토큰이 같으면 중복 제거"},{"ancestorTitles":["getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"getAuthTokenCandidates (중복 _aT + 헤더 토큰 후보) 토큰 없으면 빈 배열","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"토큰 없으면 빈 배열"},{"ancestorTitles":["isMemberAccessPayload (회원 access 형상, E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isMemberAccessPayload (회원 access 형상, E4) predicate: 회원 access 형상만 참이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"predicate: 회원 access 형상만 참이다"},{"ancestorTitles":["isMemberAccessPayload (회원 access 형상, E4)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isMemberAccessPayload (회원 access 형상, E4) predicate: refresh · 관리자 · 조직관리자 · 송장 열람 형상은 거짓이다","invocations":1,"location":null,"numPassingAsserts":5,"retryReasons":[],"status":"passed","title":"predicate: refresh · 관리자 · 조직관리자 · 송장 열람 형상은 거짓이다"},{"ancestorTitles":["isMemberAccessPayload (회원 access 형상, E4)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"isMemberAccessPayload (회원 access 형상, E4) predicate: 객체가 아니면 거짓이다","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"predicate: 객체가 아니면 거짓이다"}],"endTime":1793868745653,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/cookie.helper.spec.ts","startTime":1793868745639,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["isAdminViewerAllowed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 판정 번호 일치","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"판정 번호 일치"},{"ancestorTitles":["isAdminViewerAllowed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 판정 번호 다름","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"판정 번호 다름"},{"ancestorTitles":["isAdminViewerAllowed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 역할만 있는 영업","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할만 있는 영업"},{"ancestorTitles":["isAdminViewerAllowed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 역할만 있는 내부 관리자","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할만 있는 내부 관리자"},{"ancestorTitles":["isAdminViewerAllowed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 역할만 있는 기업 관리자","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"역할만 있는 기업 관리자"},{"ancestorTitles":["isAdminViewerAllowed"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 신원 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"신원 없음"},{"ancestorTitles":["isAdminViewerAllowed"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"isAdminViewerAllowed 분석 번호 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"분석 번호 없음"}],"endTime":1793868745663,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/admin-viewer.helper.spec.ts","startTime":1793868745648,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 자동차 ON이면 inhouse에 건강 다음 자동차를 정확히 한 번 전달한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 ON이면 inhouse에 건강 다음 자동차를 정확히 한 번 전달한다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 자동차 ON이면 coocon에 건강 다음 자동차를 정확히 한 번 전달한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 ON이면 coocon에 건강 다음 자동차를 정확히 한 번 전달한다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 자동차 ON이면 octover에 건강 다음 자동차를 정확히 한 번 전달한다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 ON이면 octover에 건강 다음 자동차를 정확히 한 번 전달한다"},{"ancestorTitles":["scopeCarItems"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 자동차 ON이어도 hyphen에는 자동차 요청을 전달하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 ON이어도 hyphen에는 자동차 요청을 전달하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 자동차 ON이어도 codef에는 자동차 요청을 전달하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 ON이어도 codef에는 자동차 요청을 전달하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 카나리 OFF면 inhouse에 자동차 요청을 전달하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"카나리 OFF면 inhouse에 자동차 요청을 전달하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 카나리 OFF면 coocon에 자동차 요청을 전달하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"카나리 OFF면 coocon에 자동차 요청을 전달하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 카나리 OFF면 octover에 자동차 요청을 전달하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"카나리 OFF면 octover에 자동차 요청을 전달하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 원본 요청과 twoWayInfo를 변경하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"원본 요청과 twoWayInfo를 변경하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 자동차 ON이어도 요청에 없던 자동차 항목을 합성하지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"자동차 ON이어도 요청에 없던 자동차 항목을 합성하지 않는다"},{"ancestorTitles":["scopeCarItems"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"scopeCarItems 정책 조회 장애(off)는 기존 요청에 자동차가 있어도 모든 공급자에서 제거한다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"정책 조회 장애(off)는 기존 요청에 자동차가 있어도 모든 공급자에서 제거한다"}],"endTime":1793868745668,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/treat/dispatch/treat-car-canary.util.spec.ts","startTime":1793868745654,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["parseAgcIds — 선택 기업ID 문자열 파싱"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseAgcIds — 선택 기업ID 문자열 파싱 쉼표구분 정상 파싱","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쉼표구분 정상 파싱"},{"ancestorTitles":["parseAgcIds — 선택 기업ID 문자열 파싱"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseAgcIds — 선택 기업ID 문자열 파싱 공백 trim + 숫자아님 제거","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"공백 trim + 숫자아님 제거"},{"ancestorTitles":["parseAgcIds — 선택 기업ID 문자열 파싱"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"parseAgcIds — 선택 기업ID 문자열 파싱 빈값/undefined/null → 빈 배열","invocations":1,"location":null,"numPassingAsserts":4,"retryReasons":[],"status":"passed","title":"빈값/undefined/null → 빈 배열"},{"ancestorTitles":["parseAgcIds — 선택 기업ID 문자열 파싱"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"parseAgcIds — 선택 기업ID 문자열 파싱 단건","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"단건"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","일반회원(fc/mem001)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 일반회원(fc/mem001) fc → MEM001 전체","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"fc → MEM001 전체"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","일반회원(fc/mem001)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 일반회원(fc/mem001) mem001 → MEM001 전체","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mem001 → MEM001 전체"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","일반회원(fc/mem001)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 일반회원(fc/mem001) fc는 agcId를 무시(일반회원엔 기업개념 없음)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"fc는 agcId를 무시(일반회원엔 기업개념 없음)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","기업회원(agency/mem002) — 특정 기업 선택"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 기업회원(agency/mem002) — 특정 기업 선택 agcId 있으면 그 기업만 (push 14 정상 케이스)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"agcId 있으면 그 기업만 (push 14 정상 케이스)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","기업회원(agency/mem002) — 특정 기업 선택"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 기업회원(agency/mem002) — 특정 기업 선택 agency 별칭도 동일","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"agency 별칭도 동일"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","기업회원(agency/mem002) — 특정 기업 선택"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 기업회원(agency/mem002) — 특정 기업 선택 잡값 섞여도 유효 agcId만","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"잡값 섞여도 유효 agcId만"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 ★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점) mem002 + undefined → 전체 기업회원(agcIds null)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mem002 + undefined → 전체 기업회원(agcIds null)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 ★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점) mem002 + 빈문자 → 전체 기업회원(agcIds null)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mem002 + 빈문자 → 전체 기업회원(agcIds null)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 ★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점) mem002 + 공백 → 전체 기업회원(agcIds null)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mem002 + 공백 → 전체 기업회원(agcIds null)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 ★ 안전 임계 — 기업회원인데 선택이 비면 전체발송 (push 13 사고 지점) mem002 + 숫자없는 잡값 → 전체 기업회원(agcIds null)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"mem002 + 숫자없는 잡값 → 전체 기업회원(agcIds null)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","전체(all)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 전체(all) all → 조건 없음(전 회원)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"all → 조건 없음(전 회원)"},{"ancestorTitles":["resolvePushTarget — 발송 대상(누가 받는가) 결정","전체(all)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"resolvePushTarget — 발송 대상(누가 받는가) 결정 전체(all) 미지정/알수없는 타입 → 조건 없음","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"미지정/알수없는 타입 → 조건 없음"}],"endTime":1793868745679,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/push/push-target.util.spec.ts","startTime":1793868745665,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 주민번호 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민번호 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 주민번호 공백 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주민번호 공백 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 휴대전화 하이픈 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"휴대전화 하이픈 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 휴대전화 붙여씀 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"휴대전화 붙여씀 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 휴대전화 10자리 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"휴대전화 10자리 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 이메일 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"이메일 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 짧은 이메일 을 가린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"짧은 이메일 을 가린다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 주문·거래 ID 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"주문·거래 ID 은 건드리지 않는다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 하이픈 없는 13자리 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"하이픈 없는 13자리 은 건드리지 않는다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 금액·건수·비율 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"금액·건수·비율 은 건드리지 않는다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 날짜·시각 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"날짜·시각 은 건드리지 않는다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 영숫자 덩어리 안 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"영숫자 덩어리 안 은 건드리지 않는다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 코드·라벨 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"코드·라벨 은 건드리지 않는다"},{"ancestorTitles":["maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"maskPiiInText — 알림 본문의 개인정보 꼴 가림 (SD-5) 빈 값 은 건드리지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"빈 값 은 건드리지 않는다"}],"endTime":1793868745684,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/helpers/mask.helper.spec.ts","startTime":1793868745671,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["확정 principal 기록 (admin-principal)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 principal 기록 (admin-principal) 확정 기록을 쓰고 읽으면 같은 객체다 (원 토큰 payload 를 덮어쓰지 않도록 기록을 참조로 넘긴다)","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"확정 기록을 쓰고 읽으면 같은 객체다 (원 토큰 payload 를 덮어쓰지 않도록 기록을 참조로 넘긴다)"},{"ancestorTitles":["확정 principal 기록 (admin-principal)"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"확정 principal 기록 (admin-principal) 기록이 없으면 읽기는 undefined 다 (현행 경로)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"기록이 없으면 읽기는 undefined 다 (현행 경로)"},{"ancestorTitles":["확정 principal 기록 (admin-principal)"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"확정 principal 기록 (admin-principal) 복원 결과의 pv 와 재발급 판단은 기록에 그대로 남고 pv 는 요청 객체에 실린다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"복원 결과의 pv 와 재발급 판단은 기록에 그대로 남고 pv 는 요청 객체에 실린다"}],"endTime":1793868745696,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/auth/access-control/admin-principal.spec.ts","startTime":1793868745684,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다 admin 접두를 벗기고 점으로 잇는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin 접두를 벗기고 점으로 잇는다"},{"ancestorTitles":["routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다 숫자 세그먼트를 :id 로 접는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"숫자 세그먼트를 :id 로 접는다"},{"ancestorTitles":["routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다"],"duration":2,"failureDetails":[],"failureMessages":[],"fullName":"routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다 쿼리스트링을 버린다 — 같은 행위가 파라미터로 갈리지 않게","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"쿼리스트링을 버린다 — 같은 행위가 파라미터로 갈리지 않게"},{"ancestorTitles":["routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다 admin 밖 경로도 형태를 유지한다(필터는 접두 검사를 따로 한다)","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"admin 밖 경로도 형태를 유지한다(필터는 접두 검사를 따로 한다)"},{"ancestorTitles":["routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"routeAction — 인터셉터와 예외 필터가 같은 어휘를 쓰게 한다 64자를 넘지 않는다 — 컬럼 상한과 같은 값","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"64자를 넘지 않는다 — 컬럼 상한과 같은 값"}],"endTime":1793868745701,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/audit/audit-route.spec.ts","startTime":1793868745687,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["app.module — 손해사정 API 등록 해제"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"app.module — 손해사정 API 등록 해제 LossAdjustmentCategoryModule 은 app.module 에 등록되지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"LossAdjustmentCategoryModule 은 app.module 에 등록되지 않는다"},{"ancestorTitles":["app.module — 손해사정 API 등록 해제"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"app.module — 손해사정 API 등록 해제 LossAdjustmentModule 은 app.module 에 등록되지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"LossAdjustmentModule 은 app.module 에 등록되지 않는다"},{"ancestorTitles":["app.module — 손해사정 API 등록 해제"],"duration":0,"failureDetails":[],"failureMessages":[],"fullName":"app.module — 손해사정 API 등록 해제 LossAdjustmentCommentModule 은 app.module 에 등록되지 않는다","invocations":1,"location":null,"numPassingAsserts":1,"retryReasons":[],"status":"passed","title":"LossAdjustmentCommentModule 은 app.module 에 등록되지 않는다"}],"endTime":1793868745709,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/app.module.loss-adjustment.spec.ts","startTime":1793868745698,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["pinoHttpOptions"],"duration":1,"failureDetails":[],"failureMessages":[],"fullName":"pinoHttpOptions 요청과 오류에서 인증정보와 개인정보를 직렬화하지 않는다","invocations":1,"location":null,"numPassingAsserts":2,"retryReasons":[],"status":"passed","title":"요청과 오류에서 인증정보와 개인정보를 직렬화하지 않는다"}],"endTime":1793868745713,"message":"","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/pino.spec.ts","startTime":1793868745702,"status":"passed","summary":""},{"assertionResults":[],"coverage":{},"endTime":1793868745936,"message":"  ● Test suite failed to run\n\n    ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-report-v2-m1.report-fixture.json'\n\n      20 | const ROOT = path.resolve(SERVER_ROOT, '..');\n      21 | const fixture = JSON.parse(\n    > 22 |   fs.readFileSync(\n         |      ^\n      23 |     path.join(\n      24 |       ROOT,\n      25 |       '.claude',\n\n      at Object.<anonymous> (apps/api/src/modules/ddx/insight-report-v2.spec.ts:22:6)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-report-v2.spec.ts","startTime":1793868745936,"status":"failed","summary":""},{"assertionResults":[],"coverage":{},"endTime":1793868745936,"message":"  ● Test suite failed to run\n\n    ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-cr2-visit-ids.request-fixture.json'\n\n      361 |   };\n      362 |   const fixture = JSON.parse(\n    > 363 |     fs.readFileSync(\n          |        ^\n      364 |       path.join(\n      365 |         REPO_ROOT,\n      366 |         '.claude',\n\n      at apps/api/src/modules/ddx/insight-payload.spec.ts:363:8\n      at Object.<anonymous> (apps/api/src/modules/ddx/insight-payload.spec.ts:339:1)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/insight-payload.spec.ts","startTime":1793868745936,"status":"failed","summary":""},{"assertionResults":[],"coverage":{},"endTime":1793868745936,"message":"  ● Test suite failed to run\n\n    ENOENT: no such file or directory, open '/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/.claude/plans/ai-insight-cr2-projection.openapi.json'\n\n      527 | //* 제공자 openapi 동결 사본(부모 `.claude/plans/`, sha256 은 계획 게이트 `#4` 가 본다). 서버 루트 다섯 단계 · superproject 여섯 단계.\n      528 | const OPENAPI = JSON.parse(\n    > 529 |   fs.readFileSync(\n          |      ^\n      530 |     path.join(\n      531 |       __dirname,\n      532 |       '..',\n\n      at Object.<anonymous> (apps/api/src/modules/ddx/ddx-verdict.service.spec.ts:529:6)\n","name":"/home/madsc/work/insuniverse-temp/.worktrees/admin-rbac/insuniverse-server/apps/api/src/modules/ddx/ddx-verdict.service.spec.ts","startTime":1793868745936,"status":"failed","summary":""}],"wasInterrupted":false}
