Skip to content

feat(ai): expose durable proposal audit and decision API - #105

Merged
seonghobae merged 28 commits into
mainfrom
feat/ai-proposal-audit-api
Aug 4, 2026
Merged

feat(ai): expose durable proposal audit and decision API#105
seonghobae merged 28 commits into
mainfrom
feat/ai-proposal-audit-api

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the next reviewable ai.auditable-proposals slice as a production PostgreSQL-backed boundary.

  • persists every generated inert proposal before returning it
  • adds bounded AI_DATABASE_URL pool configuration with a dedicated application name and exactly-once NestJS shutdown
  • exposes tenant-scoped list/get proposal evidence and deterministic decision history
  • appends explicit accept/reject events bound to workspace, actor, immutable content digest, UUIDv4 idempotency key, and decision timestamp
  • rejects hidden ownership fields, stale revisions, conflicting replays, malformed identifiers, and unbounded input with fixed credential-free problem details
  • preserves the dependency-free no-silent-mutation module while bootstrapping the production module with one shared audit runtime
  • adds unit and PostgreSQL HTTP integration evidence for restart durability, tenant isolation, exact replay, stale/conflicting decisions, shutdown, and absence of apply/execute routes
  • documents runtime variables, internal header trust assumptions, migration privileges, rollback, and deferred gateway/model/execution work

Capability boundary

The production AI module receives no planning, calendar, habit, identity, notification, event-bus, command-bus, or generic user-data mutation dependency. Proposal operations remain inert evidence. Workspace and actor headers must be derived and authorized by a private authenticated gateway before external exposure.

Verification gate

Merge only when formatting, lint, type checking, complete tests, build, Compose validation, AppGuardrail, SAST Semgrep, Security Scan, Commercial Readiness, CodeRabbit, and every human/security review finding pass on the exact current head.

Closes #56.
Refs #46 and #21.

Summary by CodeRabbit

  • 새 기능

    • AI 제안 생성 및 불변 감사 기록을 지원합니다.
    • 테넌트 범위의 제안·결정 조회와 승인·거부 이력 확인이 가능합니다.
    • 멱등성 키를 사용한 결정 재처리와 입력 검증을 지원합니다.
    • PostgreSQL 기반 영속 저장 및 서비스 종료 처리를 추가했습니다.
  • 문서

    • 운영 설정, API 범위, 보안 경계와 제한 사항을 문서화했습니다.
  • 테스트

    • 제안 감사, 테넌트 격리, 영속성, 오류 처리 및 멱등성 검증을 추가했습니다.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 375c025f-830d-482f-b060-4ab5802291dd

📥 Commits

Reviewing files that changed from the base of the PR and between 8c5e034 and 85b3f56.

📒 Files selected for processing (8)
  • .env.example
  • .github/workflows/ci.yml
  • apps/ai-service/migrations/README.md
  • apps/ai-service/src/ai-runtime.test.ts
  • apps/ai-service/src/ai-runtime.ts
  • apps/ai-service/src/main.ts
  • apps/ai-service/src/proposal-audit-application.ts
  • apps/ai-service/src/proposal-audit-http.integration.test.ts
📝 Walkthrough

Walkthrough

AI 제안 감사 기능을 추가했습니다. 제안을 PostgreSQL에 저장하고 테넌트 범위로 조회합니다. 승인·거부 결정을 멱등적으로 기록합니다. Production 런타임, HTTP 오류 매핑, 통합 테스트와 운영 문서를 추가했습니다.

Changes

AI 제안 감사 API

Layer / File(s) Summary
제안 감사 애플리케이션과 결정 계약
apps/ai-service/src/proposal-audit-application.ts, apps/ai-service/src/proposal-audit-application.test.ts
제안 생성·조회와 결정 이력 조회를 추가했습니다. 결정 요청의 UUID v4 키, SHA-256 digest, RFC 3339 시각, 결정 값, reason을 검증하고 정규화합니다. 테넌트 범위, stale digest, 미존재 오류와 입력 검증을 테스트합니다.
PostgreSQL 런타임과 종료 수명주기
apps/ai-service/src/ai-runtime.ts, apps/ai-service/src/ai-runtime.test.ts, .env.example, apps/ai-service/migrations/README.md
AI 전용 PostgreSQL 풀과 감사 저장소를 구성합니다. URL과 풀 설정의 범위를 검증합니다. close와 NestJS 종료 훅에서 풀을 정확히 한 번 종료합니다.
Production 모듈과 감사 HTTP 경계
apps/ai-service/src/main.ts, apps/ai-service/src/proposal-audit-http.integration.test.ts, docs/superpowers/plans/2026-08-04-ai-proposal-audit-api-slice.md, CHANGELOG.md, package.json
Production 모듈에 공유 런타임을 주입합니다. 제안·결정 조회와 결정 기록 라우트를 추가하고 오류를 구조화된 응답으로 변환합니다. 테넌트 격리, 재시작 내구성, 결정 replay, stale digest, 멱등성 충돌과 apply 라우트 부재를 통합 테스트로 검증합니다.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AiProposalAuditController
  participant ProposalAuditApplication
  participant PostgresProposalAuditRepository
  Client->>AiProposalAuditController: 제안 생성 또는 결정 요청
  AiProposalAuditController->>ProposalAuditApplication: workspace/actor 범위와 요청 전달
  ProposalAuditApplication->>PostgresProposalAuditRepository: 제안 또는 결정 감사 레코드 저장
  PostgresProposalAuditRepository-->>ProposalAuditApplication: 저장 결과 반환
  ProposalAuditApplication-->>AiProposalAuditController: 감사된 제안 또는 결정 반환
  AiProposalAuditController-->>Client: JSON 응답 반환
Loading

Possibly related issues

  • ContextualWisdomLab/life-os 이슈 46: 테넌트 범위의 불변 AI 제안 감사와 결정 API라는 목표가 이번 변경과 직접 연결됩니다.

Possibly related PRs

  • ContextualWisdomLab/life-os#54: 기존 제안 감사 도메인과 PostgreSQL 저장소를 이번 런타임, 애플리케이션 서비스, HTTP 경계가 확장합니다.
  • ContextualWisdomLab/life-os#104: PostgreSQL 기반 테넌트 감사 저장, 런타임 설정, 정확히 한 번의 종료 처리를 별도 서비스 구현에서 다룹니다.
  • ContextualWisdomLab/life-os#37: 다른 도메인 서비스에서 테넌트 범위 append-only 감사 이력과 멱등 이벤트 기록을 구현합니다.
🚥 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 제목이 PostgreSQL 기반 제안 감사 및 결정 API 공개라는 주요 변경을 정확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed 구현이 이슈 #56의 영속성, 테넌트 범위 조회, 결정 기록, 멱등성, 종료 처리 및 실행 경로 제외 요구를 충족합니다.
Out of Scope Changes check ✅ Passed 변경 사항이 이슈 #56의 구현, 테스트, 운영 문서 및 형식 검사 범위에 포함되며 관련 없는 코드 변경은 확인되지 않습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feat/ai-proposal-audit-api

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

Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed
Comment thread apps/ai-service/src/ai-runtime.test.ts Fixed

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/ai-service/src/main.ts (1)

118-134: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

생성 경로에서 감사 검증 오류가 503으로 매핑됩니다.

createProposal의 catch는 ProposalValidationErrorProposalAuditPersistenceError만 구분합니다. ProposalAuditApplication.generateProposalcreateProposalAuditRecordnow(this.clock)을 통해 ProposalAuditValidationError를 던질 수 있습니다. 그 오류는 라인 129의 기본 분기로 떨어져 503 proposal_unavailable이 됩니다.

docs/superpowers/plans/2026-08-04-ai-proposal-audit-api-slice.md 라인 54는 "malformed headers, identifiers, bodies, or model/audit evidence"를 400 invalid_request로 문서화합니다. 따라서 현재 매핑은 문서화된 실패 계약과 어긋납니다. mapAuditError가 이미 모든 분기를 처리하므로 재사용하면 두 경로의 매핑이 일치합니다.

🐛 제안 수정: 감사 오류 매퍼를 재사용합니다
     } catch (error) {
       if (error instanceof ProposalValidationError) {
         throw problem(400, 'Proposal request is invalid', 'invalid_request');
       }
-      if (error instanceof ProposalAuditPersistenceError) {
-        throw problem(
-          503,
-          'Proposal audit is unavailable',
-          'audit_unavailable',
-        );
-      }
+      if (
+        error instanceof ProposalAuditValidationError ||
+        error instanceof ProposalAuditPersistenceError
+      ) {
+        return mapAuditError(error);
+      }
       throw problem(
         503,
         'Proposal generation is unavailable',
         'proposal_unavailable',
       );
     }
🤖 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/main.ts` around lines 118 - 134, Update the
createProposal catch path to route ProposalAuditValidationError through the
existing mapAuditError helper before the generic 503 proposal_unavailable
fallback. Preserve the current ProposalValidationError and
ProposalAuditPersistenceError handling, and ensure audit validation failures map
to the same 400 invalid_request contract as the other audit path.
🧹 Nitpick comments (7)
apps/ai-service/src/main.ts (2)

228-245: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

두 토큰이 같은 인스턴스를 제공합니다.

PROPOSAL_SERVICEPROPOSAL_AUDIT_APPLICATION은 모두 runtime.application을 반환합니다. 팩토리 두 개가 동일한 객체를 노출합니다. AiProposalControllerProposalGenerator 계약만 필요하므로 토큰 분리는 의도된 계약 축소로 보입니다. 그 의도를 남기려면 한 줄 주석을 추가하십시오. 그렇지 않으면 토큰 하나로 통합하는 편이 배선이 단순합니다.

또한 PROPOSAL_SERVICE 팩토리의 반환 타입은 ProposalAuditApplication으로 선언되어 있습니다. 좁힌 계약을 드러내려면 ProposalGenerator로 선언하십시오.

🤖 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/main.ts` around lines 228 - 245, Clarify the intentional
shared instance in the provider configuration by adding a brief comment
explaining that PROPOSAL_SERVICE exposes the narrowed ProposalGenerator contract
while both tokens reuse runtime.application. Update the PROPOSAL_SERVICE factory
return type from ProposalAuditApplication to ProposalGenerator, leaving
PROPOSAL_AUDIT_APPLICATION unchanged.

67-91: 🩺 Stability & Availability | 🔵 Trivial

알 수 없는 오류가 관측 가능성 없이 소실됩니다.

라인 90은 분류되지 않은 모든 오류를 503 audit_unavailable로 변환합니다. 자격 증명 없는 응답 본문은 올바른 설계입니다. 그러나 원래 오류는 어디에도 기록되지 않습니다. 프로그래밍 결함과 실제 데이터베이스 장애가 운영자에게 동일하게 보입니다.

기본 분기에서 구조화된 로그를 남기고 code 라벨별 카운터를 노출하십시오. 그러면 감사 원장 장애를 경보로 연결할 수 있습니다.

🤖 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/main.ts` around lines 67 - 91, Update the fallback branch
of mapAuditError to record the original unknown error through the existing
structured logging mechanism and increment/expose a counter labeled with the
relevant error code, while preserving the current sanitized 503 response. Use
the project’s established logger and metrics symbols rather than introducing ad
hoc observability APIs.
package.json (1)

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

format:check가 명시적 파일 목록으로 계속 커집니다.

새 AI 파일 경로는 정확히 추가되었습니다. 그러나 이 스크립트는 모든 대상 파일을 하나의 인수 목록으로 열거합니다. 목록은 PR마다 늘어나고, 경로를 빠뜨리면 포맷 검사가 조용히 건너뜁니다. 글롭과 .prettierignore로 바꾸면 새 파일이 자동으로 포함됩니다.

예: prettier --single-quote --check "**/*.{ts,tsx,mjs,cjs,json,yaml,yml,md}".prettierignorenode_modules, dist, .turbo 등록.

🤖 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 `@package.json` at line 16, Update the format:check script in package.json to
use Prettier glob patterns for supported file extensions instead of maintaining
a manually enumerated file list. Add or update .prettierignore to exclude
generated and dependency directories such as node_modules, dist, and .turbo,
ensuring newly added files are included automatically.
apps/ai-service/src/proposal-audit-application.ts (2)

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

애플리케이션 계층이 PostgreSQL 모듈에 의존합니다.

ProposalDigestMismatchErrorpostgres-proposal-audit-repository에서 가져옵니다. 그 결과 애플리케이션 계층이 저장소 구현 모듈에 의존합니다. 이 오류는 저장 기술과 무관한 도메인 규칙입니다. proposal-audit-domain으로 옮기고 저장소가 도메인에서 재수출하도록 하면 의존 방향이 정리됩니다.

main.ts도 같은 모듈에서 이 오류를 가져오므로, 이동 시 두 임포트를 함께 수정해야 합니다.

🤖 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/proposal-audit-application.ts` at line 17, Move
ProposalDigestMismatchError from postgres-proposal-audit-repository into
proposal-audit-domain, then update proposal-audit-application.ts and main.ts to
import it from the domain module. Re-export the error from the repository module
to preserve its existing public surface while keeping application dependencies
independent of the PostgreSQL implementation.

218-244: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

결정 요청을 두 번 검증합니다.

HTTP 경계(main.ts 라인 204)가 이미 validateProposalDecisionRequest로 본문을 정규화합니다. 라인 224는 같은 검증을 다시 수행합니다. 현재 검증은 멱등이므로 동작은 정확합니다. 방어적 재검증을 유지하려면 그대로 두어도 됩니다. 단일 검증 지점을 원한다면 경계에서만 검증하고 애플리케이션은 이미 검증된 타입만 받도록 계약을 좁히십시오.

🤖 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/proposal-audit-application.ts` around lines 218 - 244,
Remove the duplicate validateProposalDecisionRequest call from appendDecision
and narrow its request contract to the already-validated request type produced
by the HTTP boundary, preserving all subsequent field usage and decision-event
creation.
apps/ai-service/src/proposal-audit-http.integration.test.ts (1)

191-200: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

존재 확인이 단정 뒤에 있습니다.

라인 197은 audit를 사용하고, 라인 198의 if (!audit) 보호 구문은 그 뒤에 옵니다. 옵셔널 체이닝 때문에 런타임 오류는 발생하지 않습니다. 그러나 audit가 없을 때 실패 메시지가 명확하지 않습니다. 보호 구문을 단정보다 앞으로 옮기십시오.

♻️ 제안 리팩터: 보호 구문을 먼저 실행합니다
-      expect(audit?.proposal.proposalId).toBe(proposalId);
       if (!audit) {
         throw new Error('Expected persisted proposal audit evidence');
       }
+      expect(audit.proposal.proposalId).toBe(proposalId);
🤖 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/proposal-audit-http.integration.test.ts` around lines 191
- 200, Move the audit existence guard before the proposalId assertion in the
integration test, so the missing-audit error is reported first. Keep the
existing “Expected persisted proposal audit evidence” failure and the
audit.proposal.proposalId assertion unchanged after the guard.
apps/ai-service/src/ai-runtime.ts (1)

140-146: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

end() 실패 후 재시도가 불가능합니다.

라인 144는 await this.pool.end() 전에 closedtrue로 설정합니다. end()가 거부되면 플래그는 이미 설정되어 있습니다. 이후 onApplicationShutdown이 다시 호출되어도 정리는 시도되지 않고 조용히 반환됩니다. 정확히 한 번 종료를 유지하면서 실패를 표면화하려면 진행 중인 종료 프로미스를 저장해 재사용하십시오.

♻️ 제안 리팩터: 종료 프로미스를 재사용합니다
-  private closed = false;
+  private closing?: Promise<void>;
 
   constructor(
     private readonly pool: AiPool,
     readonly application: ProposalAuditApplication,
   ) {}
 
   async close(): Promise<void> {
-    if (this.closed) {
-      return;
-    }
-    this.closed = true;
-    await this.pool.end();
+    this.closing ??= this.pool.end();
+    await this.closing;
   }
🤖 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/ai-runtime.ts` around lines 140 - 146, Update the close()
method to store and reuse the in-progress pool.end() promise instead of setting
closed before awaiting it. Return the existing promise for repeated calls,
ensure a rejected end() remains observable and can be retried on a later
shutdown attempt, and preserve exactly-once successful cleanup.
🤖 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/ai-runtime.ts`:
- Around line 127-129: Update defaultPoolFactory to store the new Pool instance,
register a pool.on('error', ...) listener that records the error without
terminating the process, then pass that configured pool to NodePostgresAiPool.

In `@apps/ai-service/src/proposal-audit-http.integration.test.ts`:
- Around line 109-122: Update the database setup in beforeAll and afterAll to
use a dedicated disposable test database connection, such as
AI_TEST_DATABASE_URL, instead of the configured application database URL.
Require that variable for this integration test and ensure both Pool creation
and schema cleanup use it, preventing DROP SCHEMA from running against a shared
or production database.

---

Outside diff comments:
In `@apps/ai-service/src/main.ts`:
- Around line 118-134: Update the createProposal catch path to route
ProposalAuditValidationError through the existing mapAuditError helper before
the generic 503 proposal_unavailable fallback. Preserve the current
ProposalValidationError and ProposalAuditPersistenceError handling, and ensure
audit validation failures map to the same 400 invalid_request contract as the
other audit path.

---

Nitpick comments:
In `@apps/ai-service/src/ai-runtime.ts`:
- Around line 140-146: Update the close() method to store and reuse the
in-progress pool.end() promise instead of setting closed before awaiting it.
Return the existing promise for repeated calls, ensure a rejected end() remains
observable and can be retried on a later shutdown attempt, and preserve
exactly-once successful cleanup.

In `@apps/ai-service/src/main.ts`:
- Around line 228-245: Clarify the intentional shared instance in the provider
configuration by adding a brief comment explaining that PROPOSAL_SERVICE exposes
the narrowed ProposalGenerator contract while both tokens reuse
runtime.application. Update the PROPOSAL_SERVICE factory return type from
ProposalAuditApplication to ProposalGenerator, leaving
PROPOSAL_AUDIT_APPLICATION unchanged.
- Around line 67-91: Update the fallback branch of mapAuditError to record the
original unknown error through the existing structured logging mechanism and
increment/expose a counter labeled with the relevant error code, while
preserving the current sanitized 503 response. Use the project’s established
logger and metrics symbols rather than introducing ad hoc observability APIs.

In `@apps/ai-service/src/proposal-audit-application.ts`:
- Line 17: Move ProposalDigestMismatchError from
postgres-proposal-audit-repository into proposal-audit-domain, then update
proposal-audit-application.ts and main.ts to import it from the domain module.
Re-export the error from the repository module to preserve its existing public
surface while keeping application dependencies independent of the PostgreSQL
implementation.
- Around line 218-244: Remove the duplicate validateProposalDecisionRequest call
from appendDecision and narrow its request contract to the already-validated
request type produced by the HTTP boundary, preserving all subsequent field
usage and decision-event creation.

In `@apps/ai-service/src/proposal-audit-http.integration.test.ts`:
- Around line 191-200: Move the audit existence guard before the proposalId
assertion in the integration test, so the missing-audit error is reported first.
Keep the existing “Expected persisted proposal audit evidence” failure and the
audit.proposal.proposalId assertion unchanged after the guard.

In `@package.json`:
- Line 16: Update the format:check script in package.json to use Prettier glob
patterns for supported file extensions instead of maintaining a manually
enumerated file list. Add or update .prettierignore to exclude generated and
dependency directories such as node_modules, dist, and .turbo, ensuring newly
added files are included automatically.
🪄 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: fbbbaa59-4040-4857-b92e-36adf0a59fab

📥 Commits

Reviewing files that changed from the base of the PR and between f99e598 and 8c5e034.

📒 Files selected for processing (11)
  • .env.example
  • CHANGELOG.md
  • apps/ai-service/migrations/README.md
  • apps/ai-service/src/ai-runtime.test.ts
  • apps/ai-service/src/ai-runtime.ts
  • apps/ai-service/src/main.ts
  • apps/ai-service/src/proposal-audit-application.test.ts
  • apps/ai-service/src/proposal-audit-application.ts
  • apps/ai-service/src/proposal-audit-http.integration.test.ts
  • docs/superpowers/plans/2026-08-04-ai-proposal-audit-api-slice.md
  • package.json

Comment thread apps/ai-service/src/ai-runtime.ts
Comment thread apps/ai-service/src/proposal-audit-http.integration.test.ts

Copy link
Copy Markdown
Contributor Author

Review disposition for the exact head 85b3f563dcc038e99ef2b93a9b50bb2d767db517:

  • Addressed the pool idle-client error listener, disposable AI_TEST_DATABASE_URL safety boundary, proposal-generation audit error mapping, retryable/concurrent-safe pool shutdown, narrowed shared provider contract, sanitized unknown-error logging, single decision-validation boundary, and guard ordering.
  • All inline CodeRabbit and security threads are resolved, and the exact head passes CI, AppGuardrail, Security Scan, SAST Semgrep, Commercial Readiness, and CodeRabbit.
  • The suggested repository-wide Prettier glob migration is deliberately excluded from this feature slice because it changes the formatting scope for the entire monorepo; the explicit list includes every file introduced here and the formatting gate passes.
  • The suggested digest-error module relocation is a non-functional public-surface refactor and is deferred to a dedicated layering cleanup rather than mixed into the audited persistence/API slice.
  • A sanitized structured log was added for unclassified failures. A labeled metric is deferred until the AI service adopts the shared observability registry; adding an ad hoc counter here would conflict with the review’s requirement to reuse established metrics symbols.

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.

Expose durable AI proposal audit and decision API

2 participants