Skip to content

test(ai): enforce complete audit assurance gates - #111

Merged
seonghobae merged 38 commits into
mainfrom
chore/ai-service-quality-gates
Aug 4, 2026
Merged

test(ai): enforce complete audit assurance gates#111
seonghobae merged 38 commits into
mainfrom
chore/ai-service-quality-gates

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Buyer-visible outcome

Makes the production AI proposal-audit bounded context independently verifiable: every production declaration is documented, every executable production path is covered, and the operator assurance boundary is grounded in current AI-governance and HTTP standards.

Implemented outcome

  • exact 100% statement, branch, function, and line coverage for all production TypeScript under apps/ai-service/src
  • executable TypeScript-AST JSDoc contract for production top-level declarations and class/interface members
  • realistic deterministic, PostgreSQL, HTTP, lifecycle, tenant-isolation, malformed-row, stale-revision, and idempotent/conflicting replay evidence
  • a branchless, directly testable AI process bootstrap and production server.ts entrypoint
  • technology-independent ownership of stale immutable proposal-revision semantics, with a compatibility re-export from the PostgreSQL adapter
  • append-only AI audit assurance documentation, human-authorization separation, trusted-header assumptions, RFC 9457 error boundaries, limitations, and continuous risk-review triggers
  • APA 7th references to NIST AI 600-1, ISO/IEC 42001:2023, ISO/IEC 23894:2023, and RFC 9457
  • a quality.ai-audit-assurance commercial-readiness capability and matching CHANGELOG.md evidence
  • Turborepo propagation of AI_TEST_DATABASE_URL, so the full monorepo gate executes rather than silently skipping the real AI PostgreSQL/HTTP suite
  • a fixed-instant expired-lease notification fixture that preserves real recovery semantics without wall-clock drift
  • generated TypeScript build state excluded from version control
  • a repository lockfile for reproducible pnpm dependency resolution

Architecture boundary

The AI service remains independently deployable and receives no planning, calendar, habit, identity, notification, generic mutation repository, command bus, or execution dependency. An accepted proposal decision remains append-only audit evidence only; it cannot apply or execute an operation.

No NVIDIA NIM or external model call is introduced in this slice because the assurance gate is deterministic and provider-independent. External-model integration remains subject to separate accuracy, robustness, privacy, prompt-injection, latency, and cost evidence using the configured secret boundary.

Fresh verification before PR

The complete repository gate passed before the temporary repair automation removed itself:

  • formatting
  • lint
  • type checking
  • complete tests, including real disposable PostgreSQL integration
  • build
  • Compose validation
  • AI production coverage: 100% statements / 100% branches / 100% functions / 100% lines

Exact-head merge gate

CI, AppGuardrail, SAST Semgrep, Security Scan, Commercial Readiness, CodeRabbit, and every actionable review thread must pass on the exact current head before squash merge.

Closes #107.

Summary by CodeRabbit

  • 새 기능

    • AI 제안 감사·보증 기능을 추가했습니다.
    • 제안과 결정 기록의 무결성, 멱등성, 테넌트 격리 및 안전한 오류 응답을 강화했습니다.
    • AI 서비스가 검증된 포트와 네트워크 설정으로 안정적으로 시작됩니다.
  • 품질 개선

    • AI 서비스에 100% 코드 커버리지와 문서화 검증을 도입했습니다.
    • 입력·데이터베이스·HTTP 경계 조건과 오류 처리를 폭넓게 검증합니다.
  • 문서

    • AI 감사 운영 경계, 보안 원칙, 테스트 및 운영 절차를 문서화했습니다.
  • 빌드 및 테스트

    • 잠금 파일 기반의 재현 가능한 의존성 설치를 적용했습니다.
    • 테스트 환경의 시간 의존성을 제거해 결과를 안정화했습니다.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AI 서비스의 감사 오류 소유권과 PostgreSQL 검증을 정리했다. 공개 부트스트랩 API와 서버 진입점을 추가했다. JSDoc·100% 커버리지 게이트, 운영 보증 문서, capability manifest와 CI 검증을 갱신했다.

Changes

AI 서비스 품질 및 감사 경계

Layer / File(s) Summary
감사 도메인과 저장소 오류 경계
apps/ai-service/src/proposal-audit-domain.ts, apps/ai-service/src/postgres-proposal-audit-repository.ts, apps/ai-service/src/proposal-audit-application.ts, apps/ai-service/src/main.ts, apps/ai-service/src/proposal-service.ts, apps/ai-service/src/proposal-audit-domain.test.ts
ProposalDigestMismatchError를 도메인 오류로 추가했다. PostgreSQL 입력·행 검증 실패를 ProposalAuditPersistenceError로 통합했다. 테넌트 범위 검증과 감사 도메인 JSDoc을 보강했다.
부트스트랩과 서버 실행 경로
apps/ai-service/src/main.ts, apps/ai-service/src/server.ts, apps/ai-service/src/server.test.ts, apps/ai-service/src/quality-coverage.test.ts
애플리케이션 팩토리, 포트 검증, 환경 주입형 bootstrapAiServiceserver 진입점을 추가했다. 포트 범위, shutdown hooks, 0.0.0.0 바인딩을 검증했다.
JSDoc·커버리지 게이트와 경계 테스트
apps/ai-service/src/docstring-coverage.test.ts, apps/ai-service/src/quality-coverage.test.ts, apps/ai-service/src/ai-runtime.ts, apps/ai-service/src/proposal-service.ts, apps/ai-service/vitest.config.ts, apps/ai-service/package.json
production TypeScript 선언의 JSDoc 누락을 AST로 검사한다. V8 기반 statements·branches·functions·lines 커버리지를 모두 100%로 설정했다. 서비스, 저장소, HTTP와 오류 경계를 테스트했다.
운영 보증과 capability 증거
docs/operations/ai-proposal-audit-assurance.md, docs/superpowers/plans/..., docs/superpowers/specs/..., product/capabilities.json, CHANGELOG.md
AI 제안의 비실행 경계, append-only 감사, 테넌트 격리, 오류 정제와 표준 참고문헌을 문서화했다. quality.ai-audit-assurance capability와 변경 이력을 추가했다.
CI와 저장소 검증 지원
.github/workflows/ci.yml, .gitignore, package.json, turbo.json, apps/notification-service/src/postgres-reminder-repository.integration.test.ts
CI에서 --frozen-lockfile 설치를 사용한다. 포맷 대상과 의존성 override를 갱신했다. AI_TEST_DATABASE_URL을 전역 환경 변수로 등록했다. 만료 lease 테스트의 시간을 고정했다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목 'test(ai): enforce complete audit assurance gates'는 AI 서비스 감사 보증 게이트 강제 설정이라는 주요 변경 사항을 명확하고 정확하게 나타냅니다.
Linked Issues check ✅ Passed 연결된 #107 이슈의 모든 요구사항이 충족되었습니다. 100% 커버리지, 실행 가능한 JSDoc 검증, 포괄적 테스트, 감사 도메인으로의 오류 이동, 표준 문서화, 스크립트 업데이트, 의존성 관리가 모두 구현되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경은 #107 이슈의 범위 내에서 감사 경계 강제, 테스트 및 문서화 추가를 목표로 합니다. 범위를 벗어난 변경은 없습니다.
Docstring Coverage ✅ Passed Docstring coverage is 80.85% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/ai-service-quality-gates

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
apps/ai-service/package.json (1)

8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

패키지 lint가 리포지터리 루트 문서를 포맷 검사합니다.

lint../../docs/... 경로의 문서 3개를 검사합니다. 이 방식은 패키지 스크립트를 리포지터리 배치에 결합합니다. 문서 경로가 바뀌거나 파일이 삭제되면 apps/ai-servicelint가 실패합니다. 또한 Turborepo 캐시 입력이 패키지 외부 파일 변경을 추적하지 못하면 결과가 신뢰할 수 없게 됩니다. 문서 포맷 검사는 루트 format/lint 스크립트로 옮기고, 이 스크립트는 패키지 내부 파일만 검사하도록 유지하십시오.

♻️ 제안 변경
-    "lint": "tsc --noEmit && prettier --single-quote --check package.json tsconfig.json vitest.config.ts \"src/**/*.ts\" ../../docs/operations/ai-proposal-audit-assurance.md ../../docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md ../../docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md",
+    "lint": "tsc --noEmit && prettier --single-quote --check package.json tsconfig.json vitest.config.ts \"src/**/*.ts\"",

문서 파일은 루트 package.json의 포맷 대상에 추가하십시오.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ai-service/package.json` at line 8, Update the ai-service lint script to
remove the three ../../docs document paths, keeping it limited to package-owned
files and existing TypeScript checks. Add those documents to the repository-root
package.json format/lint target so their formatting is validated centrally.
apps/ai-service/src/postgres-proposal-audit-repository.ts (1)

303-316: 🚀 Performance & Scalability | 🔵 Trivial

listProposals는 워크스페이스의 전체 행을 한 번에 반환한다.

ai.proposal_audit_records는 append-only 감사 테이블이다. 행 수는 계속 증가한다. listProposals에는 LIMIT이나 커서가 없다. 도메인 검증은 레코드 하나의 크기만 제한하고 행 개수는 제한하지 않는다. 워크스페이스 하나의 제안 수가 커지면 이 조회는 요청 스레드에서 대용량 결과를 파싱한다.

운영 관점의 후속 작업으로 두 가지를 권한다.

  • created_at, proposal_id 기준 키셋 페이지네이션을 추가한다. 현재 ORDER BY와 정렬 순서가 같으므로 커서 도입이 단순하다.
  • (workspace_id, created_at, proposal_id) 복합 인덱스를 확인한다. 이 인덱스는 현재 정렬과 필터를 함께 처리한다.

이번 변경은 JSDoc 추가이므로 이 PR에서 반드시 수정할 항목은 아니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ai-service/src/postgres-proposal-audit-repository.ts` around lines 303 -
316, Review the listProposals implementation for unbounded result handling, but
no code change is required for this JSDoc-only PR. Track keyset pagination using
the existing created_at, proposal_id ordering and verify a composite index on
workspace_id, created_at, proposal_id as follow-up work.
apps/ai-service/src/quality-coverage.test.ts (1)

165-184: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

SequencedSqlClient가 큐 소진 시 조용히 빈 행을 반환한다. 호출 수를 확정하기 바란다.

line 178의 this.responses.shift() ?? []는 스크립트한 응답이 모두 소비된 뒤에도 빈 결과를 반환한다. line 629-633과 line 664-669의 테스트는 이 동작에 의존하므로 의도된 설계다.

부작용이 하나 있다. 대상 코드가 스크립트한 개수보다 많은 질의를 보내도 테스트는 실패하지 않는다. 추가 질의는 빈 행을 받고, 테스트는 다른 이유로 통과할 수 있다. 이 클래스는 calls를 기록하지만 calls.length를 확인하는 assertion이 보이지 않는다.

이 PR의 목표는 정확한 보증 증거다. 최소한 appendDecision의 insert-후-replay 경로처럼 질의 순서가 계약인 테스트에서는 client.calls.length를 확정하기를 권한다. 이렇게 하면 질의 횟수 변화가 회귀로 드러난다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ai-service/src/quality-coverage.test.ts` around lines 165 - 184, Update
the tests covering appendDecision’s insert-then-replay path to assert the
expected client.calls.length, using SequencedSqlClient’s recorded calls to
enforce the scripted query count and order. Keep the existing empty-response
fallback unchanged because the tests at the referenced scenarios intentionally
depend on it.
apps/ai-service/src/server.test.ts (1)

4-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

모듈 mock 정리를 afterEach로 옮기기 바란다.

vi.doUnmock('./main')이 테스트 본문 마지막 줄에 있다. line 11의 assertion이 실패하면 이 줄은 실행되지 않는다. 그러면 './main' mock이 파일의 남은 실행 구간에 계속 등록된 상태로 남는다.

현재 이 파일에는 테스트가 하나뿐이므로 실제 영향은 없다. 다만 누구든 두 번째 테스트를 추가하면 그 테스트가 mock된 './main'을 받게 된다. afterEach는 assertion 결과와 무관하게 정리를 보장한다. vi.resetModules()도 함께 호출하면 모듈 레지스트리 캐시까지 정리된다.

♻️ 테스트 격리 보장 제안
-import { describe, expect, it, vi } from 'vitest';
+import { afterEach, describe, expect, it, vi } from 'vitest';
 
 describe('AI process entrypoint', () => {
+  afterEach(() => {
+    vi.doUnmock('./main');
+    vi.resetModules();
+  });
+
   it('delegates process startup to the tested bootstrap boundary', async () => {
     vi.resetModules();
     const bootstrapAiService = vi.fn().mockResolvedValue(undefined);
     vi.doMock('./main', () => ({ bootstrapAiService }));
 
     await import('./server');
 
     expect(bootstrapAiService).toHaveBeenCalledOnce();
-    vi.doUnmock('./main');
   });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ai-service/src/server.test.ts` around lines 4 - 13, Move the ./main mock
cleanup from the test body into an afterEach hook, and call vi.resetModules()
there as well so cleanup runs even when assertions fail and clears the module
registry for subsequent tests. Remove the now-redundant inline
vi.doUnmock('./main') while preserving the existing bootstrapAiService test
behavior.
apps/ai-service/src/server.ts (1)

4-4: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

명시적 시작 실패 처리 추가

void bootstrapAiService()는 반환된 Promise를 버린다. resolveAiServicePort()가 유효하지 않은 포트 값으로 오류를 던지거나 app.listen()이 EADDRINUSE로 거부되면, 미처리 거부(unhandled rejection)가 발생한다.

Node.js 22.0.0 이상은 기본값 --unhandled-rejections=throw로 미처리 거부 시 프로세스를 0이 아닌 코드로 종료한다. 이 경우 프로세스는 종료되지만 운영자는 미처리 거부 스택 추적만 본다. 명시적 .catch() 핸들러를 추가하면 실패 원인을 구조화된 로그로 기록하고 종료 코드를 명확히 설정한다.

제안된 수정
 import 'reflect-metadata';
+import { Logger } from '`@nestjs/common`';
 import { bootstrapAiService } from './main';
 
-void bootstrapAiService();
+void bootstrapAiService().catch((error: unknown) => {
+  new Logger('AiServiceEntrypoint').error(
+    'AI service failed to start',
+    error instanceof Error ? error.stack : undefined,
+  );
+  process.exitCode = 1;
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ai-service/src/server.ts` at line 4, Update the bootstrapAiService
invocation to attach an explicit catch handler for startup failures, including
errors from resolveAiServicePort and app.listen. Log the failure through the
service’s established structured logger and terminate the process with a
non-zero exit code after recording the error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ai-service/src/quality-coverage.test.ts`:
- Around line 870-895: Update the logging redaction assertion in the audit
failure test around logger.mock.calls so it inspects each logged argument,
including Error.message and Error.stack, rather than relying only on
JSON.stringify(logger.mock.calls). Ensure the assertion rejects password=secret
in both ordinary logged values and Error details, while preserving the existing
test cases and logger cleanup.

---

Nitpick comments:
In `@apps/ai-service/package.json`:
- Line 8: Update the ai-service lint script to remove the three ../../docs
document paths, keeping it limited to package-owned files and existing
TypeScript checks. Add those documents to the repository-root package.json
format/lint target so their formatting is validated centrally.

In `@apps/ai-service/src/postgres-proposal-audit-repository.ts`:
- Around line 303-316: Review the listProposals implementation for unbounded
result handling, but no code change is required for this JSDoc-only PR. Track
keyset pagination using the existing created_at, proposal_id ordering and verify
a composite index on workspace_id, created_at, proposal_id as follow-up work.

In `@apps/ai-service/src/quality-coverage.test.ts`:
- Around line 165-184: Update the tests covering appendDecision’s
insert-then-replay path to assert the expected client.calls.length, using
SequencedSqlClient’s recorded calls to enforce the scripted query count and
order. Keep the existing empty-response fallback unchanged because the tests at
the referenced scenarios intentionally depend on it.

In `@apps/ai-service/src/server.test.ts`:
- Around line 4-13: Move the ./main mock cleanup from the test body into an
afterEach hook, and call vi.resetModules() there as well so cleanup runs even
when assertions fail and clears the module registry for subsequent tests. Remove
the now-redundant inline vi.doUnmock('./main') while preserving the existing
bootstrapAiService test behavior.

In `@apps/ai-service/src/server.ts`:
- Line 4: Update the bootstrapAiService invocation to attach an explicit catch
handler for startup failures, including errors from resolveAiServicePort and
app.listen. Log the failure through the service’s established structured logger
and terminate the process with a non-zero exit code after recording the error.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ea08fed1-ded8-4070-89a6-219923c8bc33

📥 Commits

Reviewing files that changed from the base of the PR and between f477ce8 and 5d9e30f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • .github/workflows/ci.yml
  • .gitignore
  • CHANGELOG.md
  • apps/ai-service/package.json
  • apps/ai-service/src/ai-runtime.ts
  • apps/ai-service/src/docstring-coverage.test.ts
  • apps/ai-service/src/main.ts
  • apps/ai-service/src/postgres-proposal-audit-repository.ts
  • apps/ai-service/src/proposal-audit-application.ts
  • apps/ai-service/src/proposal-audit-domain.test.ts
  • apps/ai-service/src/proposal-audit-domain.ts
  • apps/ai-service/src/proposal-service.ts
  • apps/ai-service/src/quality-coverage.test.ts
  • apps/ai-service/src/server.test.ts
  • apps/ai-service/src/server.ts
  • apps/ai-service/vitest.config.ts
  • apps/notification-service/src/postgres-reminder-repository.integration.test.ts
  • docs/operations/ai-proposal-audit-assurance.md
  • docs/superpowers/plans/2026-08-04-ai-service-quality-gates.md
  • docs/superpowers/specs/2026-08-04-ai-service-quality-gates-design.md
  • package.json
  • product/capabilities.json
  • turbo.json

Comment on lines +870 to +895
it('maps every audit application failure without credential details', async () => {
const logger = vi
.spyOn(Logger.prototype, 'error')
.mockImplementation(() => undefined);
const cases: Array<[unknown, number, string]> = [
[new ProposalValidationError(), 400, 'invalid_request'],
[new ProposalAuditValidationError(), 400, 'invalid_request'],
[new ProposalAuditNotFoundError(), 404, 'proposal_not_found'],
[new ProposalDigestMismatchError(), 409, 'stale_proposal'],
[new ProposalDecisionConflictError(), 409, 'idempotency_conflict'],
[new ProposalAuditPersistenceError(), 503, 'audit_unavailable'],
[new Error('password=secret'), 503, 'audit_unavailable'],
['password=secret', 503, 'audit_unavailable'],
];
for (const [error, status, code] of cases) {
await expectProblem(
new AiProposalAuditController(throwingApplication(error)).listProposals(
WORKSPACE_ID,
),
status,
code,
);
}
expect(JSON.stringify(logger.mock.calls)).not.toContain('password=secret');
logger.mockRestore();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- Logger.error usage and test assertion context ---'
rg -n -A8 -B8 "JSON\.stringify\(logger\.mock\.calls\)|Logger\.prototype\.error|password=secret" apps/ai-service/src

printf '%s\n' '--- Standalone Error serialization probe ---'
node - <<'JS'
const error = new Error('password=secret');
console.log(JSON.stringify([error]));
console.log(Object.prototype.propertyIsEnumerable.call(error, 'message'));
console.log(Object.prototype.propertyIsEnumerable.call(error, 'stack'));
console.log(JSON.stringify(error, ['name', 'message', 'stack']));
JS

Repository: ContextualWisdomLab/life-os

Length of output: 6494


Sensitive Data Exposure (CWE-532): Insertion of Sensitive Information into Log File

Reachability: Internal · Exploitability: Theoretical

Reachability path
● Entry
  apps/ai-service/src/server.test.ts
│
▼
● Hop
  apps/ai-service/src/server.ts
│
▼
● Hop
  apps/ai-service/src/main.ts
│
▼
● Hop
  apps/ai-service/src/proposal-audit-domain.ts
│
▼
● Hop
  apps/ai-service/src/proposal-service.ts:282
  ProposalService: Creates the generator with explicit model, clock, and identifier seams.
│
▼
● Sink
  apps/ai-service/src/quality-coverage.test.ts

Errormessagestack도 redaction assertion에 포함하세요.

JSON.stringify(logger.mock.calls)Error{}로 직렬화합니다. 따라서 new Error('password=secret')가 raw 객체로 로깅되어도 assertion이 통과합니다. 로깅 인자를 펼쳐 Error.messageError.stack을 검사해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ai-service/src/quality-coverage.test.ts` around lines 870 - 895, Update
the logging redaction assertion in the audit failure test around
logger.mock.calls so it inspects each logged argument, including Error.message
and Error.stack, rather than relying only on JSON.stringify(logger.mock.calls).
Ensure the assertion rejects password=secret in both ordinary logged values and
Error details, while preserving the existing test cases and logger cleanup.

@seonghobae
seonghobae merged commit 41ed8d7 into main Aug 4, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enforce AI service documentation and 100% coverage gates

1 participant