feat: boot production apps in isolated test kernels - #1559
Conversation
|
Warning Review limit reached
Next review available in: 59 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthrough프로덕션 부트스트랩을 격리된 스코프에서 실행하는 Changes프로덕션 패리티 테스트 커널
문서 및 레지스트리 갱신
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
📊 Benchmark Results✅ All benchmarks passed
Updated: 2026-07-27T07:48:32.967Z · Commit: 7c8eaf6 |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/framework-context/src/libs/Container.ts (1)
334-359: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift스코프 내
register()가 여전히 전역 상태를 변조합니다.
activeScope.components에만 메타데이터를 넣지만componentRegistrationOrder,componentSourceLocations,clearConstructorLabelTokenIdentities()는 전역 맵을 수정합니다. 동시에 실행되는 두 커널이 동일 이름 컴포넌트를 등록하면 토큰 identity/등록 순서가 서로 간섭하고, 스코프 dispose 후에도 전역에 잔존합니다. PR 목표인 "커널 간 DI 격리"와 어긋납니다.스코프 활성 시 등록 순서·소스 로케이션·token identity도 스코프 상태에 저장하도록 분리하는 것을 검토하세요.
🤖 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 `@packages/framework-context/src/libs/Container.ts` around lines 334 - 359, Update Container.register so that when activeScope exists, registration order, source location, and constructor-label token identities are stored and resolved through that scope’s state rather than mutating global componentRegistrationOrder, componentSourceLocations, or clearConstructorLabelTokenIdentities. Preserve the existing global behavior only when no scope is active, and ensure scoped data is discarded with the scope.
🤖 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
`@packages/create-croco-app/templates/saas/apps/api-server/src/tests/SaasDemo.spec.ts`:
- Around line 26-44: Update the test around createTestKernel and createCrocoApp
to guarantee kernel disposal when any assertion fails, using await using or a
try/finally block. Add a concise comment explaining that validation: { di: "off"
} reflects the template’s createCrocoApp configuration and therefore produces
overridden validation fidelity.
In `@packages/docs/src/content/docs/api/testing/src/classes/TestKernel.md`:
- Around line 48-50: TestKernel 문서의 cleanupOperations 타입 표기를 단일 함수 반환 타입이 아닌
cleanup callback 배열로 명확히 수정하세요. 실제 구현에 맞춰 각 콜백이 void 또는 Promise<void>를 반환하고 전체
컬렉션이 readonly가 되도록 `readonly (() => Promise<void> | void)[]` 또는 동등한
ReadonlyArray 표기를 생성하게 하세요.
- Around line 160-184: Update the generated documentation for TestKernel.run so
its asynchronous and synchronous overloads use distinct headings instead of both
being titled “Call Signature.” Prefer configuring the documentation generator to
distinguish overload signatures; otherwise assign clear async and sync titles
while preserving both overload descriptions.
In `@packages/framework-context/src/libs/ShutdownManager.ts`:
- Around line 117-135: Update shutdown’s timeout handling around hookExecution
and Promise.race so failures collected before a timeout are not discarded when
options.throwOnHookError is true. When the timeout wins, preserve the
ShutdownTimeoutProblem while incorporating the recorded hook failures into the
propagated error or aggregate; keep existing behavior unchanged when no hook
failures were collected.
In `@packages/testing/src/index.ts`:
- Around line 30-43: Export the TestKernelBootstrapResult type declaration in
TestKernel.ts and re-export it from the package index alongside
TestKernelOptions and the other public TestKernel symbols. Update the public API
snapshot to include this newly exposed type.
In `@packages/testing/src/libs/TestKernel.ts`:
- Around line 256-260: Update assertActive in TestKernel to throw a dedicated
problem for accessing a disposed kernel instead of reusing
TestKernelDisposalProblem. Register the new testing/test-kernel-disposed problem
and synchronize its snapshots and documentation so the rendered message
describes reuse after disposal rather than failed cleanup.
- Around line 340-385: Extract the duplicated shutdown and disposal sequence
from disposeOnce and the bootstrap-failure catch path into a shared helper such
as runCleanupSequence(scope, cleanups), returning collected cleanup errors.
Preserve the existing order—shutdown, registered cleanup operations, EventBus
scope disposal, ShutdownManager scope disposal, then scope disposal—and update
both callers to use the helper while retaining their current error propagation
behavior.
- Line 274: Update the options type used by TestKernel so fidelity and adapter
form a discriminated union: application fidelity must not accept an adapter,
while adapter fidelity may accept the supported adapter values. Ensure the
runtime selection around the fidelity/adapter logic cannot silently ignore an
adapter and that invalid combinations fail at compile time.
- Around line 394-434: Update toRequest so Request inputs receive the same
query, JSON/body, and header handling as string or URL inputs, or explicitly
reject unsupported options; do not pass TestingRequestOptions directly to new
Request as RequestInit. Reuse the existing request-construction logic or extract
a shared helper used by both this implementation and the matching testing.ts
helper to keep Request-instance behavior consistent.
In `@packages/testing/src/tests/TestKernel.spec.ts`:
- Around line 326-351: Add a regression test in TestKernel.spec.ts covering both
post-disposal access and the await using cleanup path. Use Symbol.asyncDispose
through await using, then assert kernelRef.get and kernelRef.http.get reject
with TestKernelDisposalProblem after the scope exits.
---
Outside diff comments:
In `@packages/framework-context/src/libs/Container.ts`:
- Around line 334-359: Update Container.register so that when activeScope
exists, registration order, source location, and constructor-label token
identities are stored and resolved through that scope’s state rather than
mutating global componentRegistrationOrder, componentSourceLocations, or
clearConstructorLabelTokenIdentities. Preserve the existing global behavior only
when no scope is active, and ensure scoped data is discarded with the scope.
🪄 Autofix (Beta)
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: ASSERTIVE
Plan: Pro Plus
Run ID: 3af8f9e0-969c-4bd2-9287-ffbc986b692b
⛔ Files ignored due to path filters (1)
packages/problems-core/src/generated/problem-code-registry.tsis excluded by!**/generated/**
📒 Files selected for processing (72)
.changeset/production-parity-test-kernel.mddocs/problem-code-registry.jsonpackages/create-croco-app/templates/saas/apps/api-server/src/tests/SaasDemo.spec.tspackages/docs/src/content/docs/api/cache-core/src/classes/Cache.mdpackages/docs/src/content/docs/api/cache-core/src/classes/CacheStore.mdpackages/docs/src/content/docs/api/cache-core/src/classes/DistributedCacheStore.mdpackages/docs/src/content/docs/api/cache-core/src/classes/InMemoryCacheStore.mdpackages/docs/src/content/docs/api/cache-core/src/classes/InvalidCacheTtlProblem.mdpackages/docs/src/content/docs/api/cache-core/src/type-aliases/CacheWarmupEntry.mdpackages/docs/src/content/docs/api/events-core/src/classes/EventBusConfig.mdpackages/docs/src/content/docs/api/framework-context/src/classes/Container.mdpackages/docs/src/content/docs/api/framework-context/src/classes/ContainerScope.mdpackages/docs/src/content/docs/api/framework-context/src/classes/ShutdownHookExecutionProblem.mdpackages/docs/src/content/docs/api/framework-context/src/classes/ShutdownManager.mdpackages/docs/src/content/docs/api/framework-context/src/type-aliases/ShutdownOptions.mdpackages/docs/src/content/docs/api/membership-core/src/classes/InMemoryMembershipStore.mdpackages/docs/src/content/docs/api/membership-core/src/classes/MembershipOwnerGuard.mdpackages/docs/src/content/docs/api/membership-core/src/classes/MembershipService.mdpackages/docs/src/content/docs/api/membership-core/src/classes/MembershipStore.mdpackages/docs/src/content/docs/api/membership-core/src/type-aliases/MembershipOwnershipTransferInput.mdpackages/docs/src/content/docs/api/membership-drizzle/src/classes/DrizzleMembershipStore.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/CarryingCapacitySimulationProblem.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/CarryingCapacityTenantRequiredProblem.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/GrossMarginRequiredProblem.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/InvalidRetentionMovementProblem.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/MetricsEngine.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/MixedCurrencyMRRProblem.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/RetentionCalculator.mdpackages/docs/src/content/docs/api/metrics-core/src/classes/RetentionMetricsUnavailableProblem.mdpackages/docs/src/content/docs/api/metrics-core/src/type-aliases/RetentionMetrics.mdpackages/docs/src/content/docs/api/pagination-core/src/classes/InvalidPaginationDirectionProblem.mdpackages/docs/src/content/docs/api/problems-core/src/classes/Problem.mdpackages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.mdpackages/docs/src/content/docs/api/testing/src/classes/CrocoTestingApp.mdpackages/docs/src/content/docs/api/testing/src/classes/TestKernel.mdpackages/docs/src/content/docs/api/testing/src/classes/TestKernelDisposalProblem.mdpackages/docs/src/content/docs/api/testing/src/classes/TestKernelHttp.mdpackages/docs/src/content/docs/api/testing/src/classes/TestKernelValidationProblem.mdpackages/docs/src/content/docs/api/testing/src/functions/createTestKernel.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/IsolatedTestingFidelity.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelBootFidelity.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelBootstrapContext.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelEvidence.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelFidelity.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelOptions.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelRuntime.mdpackages/docs/src/content/docs/api/testing/src/type-aliases/TestKernelValidationFidelity.mdpackages/docs/src/content/docs/api/transports-http/src/classes/CrocoApp.mdpackages/docs/src/content/docs/api/transports-http/src/type-aliases/BootstrapValidationPolicy.mdpackages/docs/src/content/docs/api/transports-http/src/type-aliases/NodeRequestHandler.mdpackages/docs/src/content/docs/en/reference/problem-recovery-cookbook.mdpackages/events-core/src/libs/EventBusConfig.tspackages/framework-context/README.mdpackages/framework-context/src/index.tspackages/framework-context/src/libs/Container.test.tspackages/framework-context/src/libs/Container.tspackages/framework-context/src/libs/ShutdownManager.tspackages/framework-context/src/libs/problems/ShutdownProblems.tspackages/testing/README.mdpackages/testing/src/index.tspackages/testing/src/libs/TestKernel.tspackages/testing/src/libs/testing.tspackages/testing/src/tests/TestKernel.spec.tspackages/testing/src/tests/testing.spec.tspackages/transports-http/src/index.tspackages/transports-http/src/libs/CrocoApp.tspackages/transports-http/src/libs/types.tspublic-api-surface.snapshot.jsonscripts/public-api-surface.mtsscripts/static-misuse-empty-catch-allowlist.jsonscripts/static-misuse-raw-error-allowlist.jsontsconfig/contract-strict.baseline.json
|
The outside-diff Container isolation finding is fixed in ca1a211. Scope state now owns component registration order, source locations, explicit source locations, and token identity maps; reset/dispose clears them without mutating root state. The concurrent-scope regression registers same-named services in two scopes and proves independent deterministic IDs and source evidence. |
|
@coderabbitai resolve |
✅ Action performedComments resolved and changes approved. |
dc1e4c4 to
03ef264
Compare
03ef264 to
2641fee
Compare
Outcome
@croco/testingcan now boot the exact production application definition in a runner-neutralTestKernel, exercise real Node or Lambda handler paths without opening a public port, and report machine-readable application, adapter, and validation fidelity.Each kernel owns isolated DI instances, event configuration, request state, behavioral evidence, scoped shutdown hooks, and test transaction evidence. Production validation remains enabled unless a caller explicitly records an override, production transaction providers are not replaced, and concurrent disposal coalesces into one in-flight-aware cleanup with stable Problem aggregation.
The existing
createTestingApp()path remains compatible and now reports isolated fidelity. The generated SaaS application verifies its exact production bootstrap through the kernel. Public contracts, generated API docs, Problem registry, snapshots, and changesets are synchronized.Fixes #1482
Verification
@croco/framework-context,@croco/events-core,@croco/transports-http, and@croco/testing— 38/38 focused test tasks and 38/38 focused typecheck tasks@croco/testing— 102 tests, including 14 TestKernel acceptance testspnpm public-api:check— 111 package snapshots matchpnpm problem-registry:check— 459 codes from 459 discoveriespnpm static-misuse:check— all rules passedpnpm package-manifests:check— 111 manifests normalizedpnpm changeset-required:check -- --base origin/trunk --head HEAD— all affected packages coveredpnpm check— 21/22 applicable repository gates passed; one not applicablepnpm docs:api:check— 112/112 tasks; 3,662 pages; generated docs matchReview gates
listen(), isolation is scoped through framework primitives, and generated application coverage uses the same public kernel contract.Residual risk
Applications that deliberately skip production bootstrap validation must opt into that behavior explicitly in the kernel; the resulting reduced validation fidelity remains visible in the kernel contract.
Summary by CodeRabbit
새 기능
문서
테스트