fix(vv): resolve all 6 V&V issues — field trial unblocked
All findings from the inaugural LeadValidator audit resolved and confirmed. Release gate: PASS. VV_ISSUE_002 (BLOCKER): 15 OpenAPI specs verified present covering all 20 route groups (46 endpoints documented in docs/openapi/) VV_ISSUE_003 (MAJOR): Remove any types from src/db/pool.ts — replaced pool.query shim with unknown[] + Object.defineProperty, zero any types, eslint-disable suppressions removed VV_ISSUE_004 (MAJOR): Remove raw Pool from ScaffoldController and HealthDetailedController — injected AgentRepository/CredentialRepository and DbProbe interface respectively; added CredentialRepository.findActiveClientId() VV_ISSUE_005 (MAJOR): Add unit tests for 5 untested services — ComplianceStatusStore, EventPublisher, MarketplaceService, OIDCTrustPolicyService, UsageService VV_ISSUE_006 (MAJOR): Add integration tests for 7 missing route groups — analytics, billing, tiers, webhooks, marketplace, oidc-trust-policies, oidc-token-exchange VV_ISSUE_001 (MINOR): Create missing design.md and tasks.md in 4 OpenSpec archives — all archives now complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
70
openspec/vv_audit/VV_ISSUE_003.md
Normal file
70
openspec/vv_audit/VV_ISSUE_003.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# VV_ISSUE_003 — `any` type usage in src/db/pool.ts
|
||||
|
||||
**Status:** RESOLVED
|
||||
**Severity:** MAJOR
|
||||
**Category:** TYPE_VIOLATION
|
||||
**Logged by:** LeadValidator
|
||||
**Date:** 2026-04-07
|
||||
**Audit phase:** Phase C — TypeScript Standards Audit
|
||||
|
||||
## Finding
|
||||
|
||||
The PRD (Sections 6.4 and 4.5) states: "No `any` types — ever." and "TypeScript strict mode:
|
||||
zero `any` types." The `tsconfig.json` correctly enables `noImplicitAny: true` and all strict
|
||||
flags.
|
||||
|
||||
Despite this, `src/db/pool.ts` contains explicit `any` type casts on two lines (lines 89 and
|
||||
91), with ESLint suppression comments (`eslint-disable-next-line @typescript-eslint/no-explicit-any`)
|
||||
added to bypass the linting rule. While the developer included a comment explaining the
|
||||
technical reason (wrapping the pg query method in a shim that is difficult to type precisely),
|
||||
the PRD standard is absolute: zero `any` types, with no exceptions granted.
|
||||
|
||||
The intent of the standard is to eliminate unsafe escape hatches that weaken TypeScript's
|
||||
type safety guarantees. Using `any` in the database pool layer — a critical path component —
|
||||
is particularly concerning since this wraps every database query in the application.
|
||||
|
||||
## Evidence
|
||||
|
||||
**File:** `src/db/pool.ts`, lines 88–91:
|
||||
|
||||
```typescript
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const originalQuery = pool.query.bind(pool) as (...args: any[]) => Promise<any>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(pool as any).query = async (...args: any[]): Promise<any> => {
|
||||
```
|
||||
|
||||
There are 5 `any` occurrences on these two lines:
|
||||
- `(...args: any[]) => Promise<any>` — line 89
|
||||
- `(pool as any)` — line 91
|
||||
- `(...args: any[]): Promise<any>` — line 91
|
||||
|
||||
The surrounding comment (lines 84–87) acknowledges the issue and explains the rationale, but
|
||||
does not resolve it per PRD standards.
|
||||
|
||||
## Required Action
|
||||
|
||||
Replace the `any` types in `src/db/pool.ts` with properly typed alternatives. Options:
|
||||
|
||||
1. Use the `pg` library's exported `QueryConfig`, `QueryResultRow`, and overload signatures
|
||||
to type the query wrapper correctly without resorting to `any`.
|
||||
2. Use generic types: `<T extends QueryResultRow>(...args: Parameters<Pool['query']>) => Promise<QueryResult<T>>`
|
||||
3. If the shim cannot be typed without `any` due to pg's type definitions, document the
|
||||
specific technical constraint and seek CEO approval for a formal exemption. An exemption
|
||||
does NOT mean leaving it as-is — it means a tracked, acknowledged deviation.
|
||||
|
||||
Remove the `eslint-disable-next-line` suppression comments once the `any` types are resolved.
|
||||
|
||||
## CTO Response
|
||||
|
||||
Agreed. The `any` types in pool.ts were a sanctioned workaround for pg's overloaded `Pool.query` signature. The correct solution is to use `unknown[]` rest parameters and `Object.defineProperty` to replace the method without widening the pool reference to `any`. The pool's typed interface is preserved at the type level for all callers; only the internal shim uses `unknown` as the safe alternative to `any`.
|
||||
|
||||
## Resolution
|
||||
|
||||
**Fixed in:** `src/db/pool.ts`
|
||||
|
||||
Replaced the two `any`-typed lines and two `eslint-disable-next-line` suppressions with a clean `Object.defineProperty` shim:
|
||||
- `originalQuery` is typed via `pool.query.bind(pool)` — no cast needed
|
||||
- The replacement function uses `unknown[]` rest params and `Promise<unknown>` — zero `any` types
|
||||
- TypeScript compiles clean (`npx tsc --noEmit` — 0 errors)
|
||||
- Pool's typed interface (`Pool['query']`) unchanged for all callers
|
||||
Reference in New Issue
Block a user