Skip to content

fix: validate presentation preset runtime profiles - #1014

Merged
kang-heewon merged 1 commit into
trunkfrom
fix/949-presentation-profile-contracts
Jun 19, 2026
Merged

fix: validate presentation preset runtime profiles#1014
kang-heewon merged 1 commit into
trunkfrom
fix/949-presentation-profile-contracts

Conversation

@kang-heewon

@kang-heewon kang-heewon commented Jun 19, 2026

Copy link
Copy Markdown
Member

Fixes #949.

Summary

  • @croco/presentation-preset now has a generated runtime profile catalog backing the package catalog claims for node, lambda, cloudflare-workers, and browser.
  • Runtime profile validation now checks deploy target metadata, output contract artifacts, entry descriptors, smoke-case evidence, unsupported runtime claims, and missing catalog evidence.
  • docs:catalog:check now fails when docs/package-catalog.json claims a presentation-preset runtime without generated profile evidence.
  • The profile catalog is documented, exported as ./runtime-profiles.json, copied into the published dist, reflected in README/docs/catalog outputs, and released with a patch changeset.
  • Package entrypoint smoke now handles JSON subpath exports with ESM import attributes and skips JSON-only subpaths for declaration-entry smoke.

Verification

  • pnpm --filter @croco/presentation-preset test - passed, 30 tests.
  • pnpm --filter @croco/presentation-preset typecheck - passed.
  • pnpm --filter @croco/presentation-preset build - passed.
  • pnpm --filter @croco/presentation-preset pack --pack-destination /tmp/croco-presentation-pack-check - passed; tarball contains dist/runtime-profiles.json.
  • pnpm package-entrypoints:smoke - passed; CJS and ESM consumers resolved @croco/presentation-preset/runtime-profiles.json.
  • pnpm exec vitest run scripts/tests/package-docs-check.spec.ts - passed, 11 tests.
  • pnpm docs:catalog:check - passed.
  • pnpm check - passed.
  • pnpm create-croco-app:smoke - passed; all generated app smoke cases passed on the rebased commit.
  • pnpm changeset-required:check -- --base origin/trunk --head HEAD - passed.
  • git diff --check HEAD - passed.
  • Pre-commit hook passed: staged oxlint and oxfmt where applicable.
  • Pre-push hook passed after the amended push: existing changeset detected, full pnpm test passed with 209/209 Turbo tasks, and full pnpm typecheck passed with 208/208 Turbo tasks.

Self-review gates

  • Correctness/regression: PASS. Package tests cover all four supported profiles, catalog runtime coverage, smoke-case references, unsupported claims, missing evidence, target/runtime mismatch, malformed env/runtime metadata, unsupported artifact formats, and missing artifact entries. Docs-check tests cover catalog drift when claimed runtimes lack generated profile evidence. Entrypoint smoke now covers the published JSON subpath in both CJS and ESM.
  • API/security/compatibility/release: PASS. Public exports are additive, public API snapshots and generated catalog outputs are updated, package manifests remain normalized, the published package includes the runtime profile JSON, and a patch changeset is present. No secrets, lockfile changes, external services, or new dependencies are introduced.
  • Maintainability/minimality: PASS. The diff is scoped to presentation-preset contracts/validator/tests, docs catalog validation, entrypoint smoke JSON handling, documentation/catalog snapshots, and release metadata. The docs-check script keeps a local schema gate so catalog validation does not depend on importing package source during strip-types execution.

Independent review

An independent review found two actionable issues before PR creation: the published package would not include the runtime profile JSON, and the package validator was less strict than the docs catalog gate for malformed target metadata. The final patch copies runtime-profiles.json into dist, exposes ./runtime-profiles.json, verifies the tarball contents, hardens package validation, and adds regression coverage for malformed env/runtime metadata.

Risk

Low-medium. This introduces stricter runtime-claim validation for presentation-preset catalog metadata and extends the repository entrypoint smoke harness for JSON subpath exports. Existing generated app flows continue to pass, while unsupported or unevidenced runtime claims now fail deterministically.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • Presentation runtime에 대한 프로필 기반 검증 시스템 추가
    • runtime-profiles.json을 공개 경로로 확장
    • 런타임 프로필 관련 타입 내보내기 추가
  • 문서

    • Presentation Preset README 작성
    • 런타임 프로필 증거 및 검증 문서 추가
    • 패키지 카탈로그 런타임 지원 정보 업데이트
  • 테스트

    • 출력 계약 및 런타임 프로필 검증 테스트 강화

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kang-heewon, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 33 minutes and 47 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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 credits.

🚦 How do rate limits work?

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

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, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 15e14049-bfe1-4a38-abd2-a5e24c7d447d

📥 Commits

Reviewing files that changed from the base of the PR and between 42613a4 and bec2758.

📒 Files selected for processing (18)
  • .changeset/presentation-preset-runtime-profiles.md
  • README.md
  • docs/package-docs-baseline.json
  • docs/package-docs-report.md
  • packages/docs/src/content/docs/en/reference/presentation-runtime-support.md
  • packages/presentation-preset/README.md
  • packages/presentation-preset/package.json
  • packages/presentation-preset/runtime-profiles.json
  • packages/presentation-preset/src/__tests__/output-contract-validator.spec.ts
  • packages/presentation-preset/src/index.ts
  • packages/presentation-preset/src/output-contract-validator.ts
  • packages/presentation-preset/src/output-contract.ts
  • packages/presentation-preset/tsup.config.ts
  • packages/presentation-preset/vitest.config.ts
  • public-api-surface.snapshot.json
  • scripts/package-docs-check.mts
  • scripts/package-entrypoint-smoke.mts
  • scripts/tests/package-docs-check.spec.ts
📝 Walkthrough

Walkthrough

@croco/presentation-preset에 4개 런타임 프로필(node-server, lambda-function, cloudflare-worker, browser-vite-spa)을 기술하는 runtime-profiles.json을 추가하고, OutputContractValidator에 프로필·카탈로그·디플로이 타겟 검증 메서드를 신규 구현한다. package-docs-check 스크립트에 런타임 증거 교차 검증 파이프라인을 연동하고, smoke 스크립트에 JSON import 지원을 추가하며, 패키지 README와 문서를 신규 작성한다.

Changes

presentation-preset 런타임 프로필 계약 및 카탈로그 검증

Layer / File(s) Summary
출력 계약 타입 정의 및 런타임 프로필 데이터
packages/presentation-preset/src/output-contract.ts, packages/presentation-preset/runtime-profiles.json, packages/presentation-preset/package.json, packages/presentation-preset/tsup.config.ts, packages/presentation-preset/src/index.ts, public-api-surface.snapshot.json
ArtifactFormat"neutral" 추가, PresentationRuntime/GeneratedRuntimeProfile/GeneratedRuntimeProfileCatalog 타입 신규 추가. 4개 런타임 프로필을 runtime-profiles.json으로 정의하고 publishConfig.exports에 서브패스를 추가하며 tsup onSuccessdist에 복사. 공개 API 스냅샷과 index.ts 재내보내기를 갱신.
OutputContractValidator 확장 및 헬퍼 가드
packages/presentation-preset/src/output-contract-validator.ts
RuntimeClaimValidationOptions 타입과 허용 집합을 추가하고, validateDeployTarget/validateGeneratedRuntimeProfile/validateGeneratedRuntimeProfileCatalog 공개 메서드를 구현. isRecord/isNonEmptyString/isPositiveNumber 기반 타입 가드로 기존 검증 로직을 강화.
OutputContractValidator 테스트 및 vitest 설정
packages/presentation-preset/src/__tests__/output-contract-validator.spec.ts, packages/presentation-preset/vitest.config.ts
실제 runtime-profiles.json·package-catalog.json을 읽어 프로필 통과, 클레임 커버리지, smoke case 포함 여부, 근거 누락/지원 불가 런타임/타겟 불일치/제약 값 오류/artifact 교차 참조 등 10개 이상 시나리오를 검증하는 테스트를 추가. vitest.config.ts@croco/* alias 설정 추가.
package-docs-check 런타임 증거 검증 파이프라인
scripts/package-docs-check.mts
RuntimeProfileCatalog 타입, 경로 상수, 허용 format/type 목록을 추가하고, run() 흐름에 validatePresentationPresetRuntimeEvidence를 연결. 카탈로그 스키마, 프로필 필드, 디플로이 타겟, 출력 계약, artifact/entry 내부 일관성까지 전체 파이프라인을 구현.
package-docs-check 통합 테스트
scripts/tests/package-docs-check.spec.ts
writeCatalogMetadataextensionRuntimesByPackage 옵션을 추가하고, writePresentationRuntimeProfileCatalog 헬퍼로 픽스처를 생성. 런타임 증거 불일치 시 실패, 일치 시 "in sync" 메시지를 출력하는 2개 통합 테스트 추가.
smoke 스크립트 JSON import 지원
scripts/package-entrypoint-smoke.mts
SmokeTargetkind 필드를 추가하고 isJsonTargetPath로 JSON/module을 구분. JSON 타겟은 import(..., { with: { type: "json" } }) 구문으로 로드하고, types 조건의 JSON 경로는 스킵.
문서, README, 베이스라인 갱신
packages/presentation-preset/README.md, packages/docs/src/content/docs/en/reference/presentation-runtime-support.md, docs/package-docs-baseline.json, docs/package-docs-report.md, README.md, .changeset/presentation-preset-runtime-profiles.md
presentation-preset README를 신규 작성해 런타임 프로필 매핑 표와 contract check 명령을 문서화. presentation-runtime-support.md에 Preset Evidence 섹션 추가. allowedMissingReadme에서 presentation-preset 제거 및 관련 카운트/목록 갱신.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 '런타임 프로필 검증 수정(fix: validate presentation preset runtime profiles)'으로 변경 집합의 핵심을 정확하게 반영합니다.
Linked Issues check ✅ Passed PR이 #949의 모든 주요 요구사항을 충족합니다: 4개 런타임 프로필 정의, 생성 출력 계약 검증, 미증명 주장 제거, CI 통합, README 업데이트, 검증 명령어 통과가 모두 구현됨.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #949의 범위 내에서 런타임 프로필 검증 구현과 직접 관련되어 있으며, 범위를 벗어나는 변경은 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/949-presentation-profile-contracts

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.

❤️ Share

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

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

📊 Benchmark Results

❌ Some benchmarks failed

Gate failures

  • CrocoApp constructor: p75 5.3μs exceeds baseline 3.4μs by more than 20%
  • CrocoApp lambdaHandler (10 controllers): p75 190.7μs exceeds baseline 33.3μs by more than 20%
  • Lambda cold-start simulation: p75 336.0μs exceeds baseline 70.2μs by more than 20%
  • Lambda cold-start with headers: p75 300.4μs exceeds baseline 66.7μs by more than 20%
  • Lambda cold-start with binary body: p75 261.6μs exceeds baseline 63.2μs by more than 20%
  • Lambda cold-start with query params: p75 235.4μs exceeds baseline 63.9μs by more than 20%
  • Lambda cold-start with authorizer context: p75 237.8μs exceeds baseline 59.8μs by more than 20%
  • Lambda cold-start realistic scenario: p75 238.3μs exceeds baseline 60.2μs by more than 20%
  • EventBusConfig.start (10 handlers): p75 1.3μs exceeds baseline 0.9μs by more than 20%
  • EventPublisher.publishNow single event: p75 1.5μs exceeds baseline 1.1μs by more than 20%
  • DefaultHandlerResolver.resolve × 10: p75 0.1μs exceeds baseline 0.0μs by more than 20%
  • Container.get singleton (cold): p75 2.0μs exceeds baseline 0.6μs by more than 20%
  • Container.get singleton (warm): p75 1.5μs exceeds baseline 0.3μs by more than 20%
  • lambdaPreset config creation: p75 1.5μs exceeds baseline 1.0μs by more than 20%
Benchmark p75 Threshold Baseline vs Baseline Status Notes
CrocoApp constructor 5.3μs 30.0ms 3.4μs +56.1% -
CrocoApp lambdaHandler (10 controllers) 190.7μs 50.0ms 33.3μs +472.9% -
Lambda cold-start simulation 336.0μs 80.0ms 70.2μs +378.9% -
Lambda cold-start with headers 300.4μs 80.0ms 66.7μs +350.1% -
Lambda cold-start with binary body 261.6μs 80.0ms 63.2μs +314.1% -
Lambda cold-start with query params 235.4μs 80.0ms 63.9μs +268.6% -
Lambda cold-start with authorizer context 237.8μs 80.0ms 59.8μs +297.7% -
Lambda cold-start realistic scenario 238.3μs 80.0ms 60.2μs +296.1% -
EventBusConfig.start (10 handlers) 1.3μs 10.0ms 0.9μs +43.2% -
EventPublisher.publishNow single event 1.5μs 2.0ms 1.1μs +41.5% -
DefaultHandlerResolver.resolve × 10 0.1μs 5.0ms 0.0μs +90.5% -
Container.get singleton (cold) 2.0μs 5.0ms 0.6μs +217.4% -
Container.register × 50 components 11.5μs 10.0ms 12.1μs -5.6% -
Container.validate (50 components) 29.0μs 20.0ms 29.7μs -2.2% -
Container.get singleton (warm) 1.5μs 500.0μs 0.3μs +397.6% -
TelemetryRuntime.init (lambda preset) 1.1ms 200.0ms 69.3ms -98.4% -
lambdaPreset config creation 1.5μs 2.0ms 1.0μs +46.3% -

Updated: 2026-06-19T19:04:24.514Z · Commit: 142868d

@kang-heewon
kang-heewon force-pushed the fix/949-presentation-profile-contracts branch from 60a8b82 to 42613a4 Compare June 19, 2026 18:33

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

Caution

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

⚠️ Outside diff range comments (1)
packages/presentation-preset/src/output-contract-validator.ts (1)

287-299: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

교차 검증에서 null artifact/entry를 만나면 런타임 예외가 발생합니다.

Line 287의 artifact.path와 Line 291~298의 entry.* 접근이 레코드 검증 없이 실행됩니다. 앞단에서 shape 에러를 수집해도 여기서 TypeError로 중단될 수 있습니다.

제안 수정안
-    const artifactPaths = new Set(contract.artifacts.map((artifact) => artifact.path));
+    const artifactPaths = new Set<string>();
+    for (const artifact of contract.artifacts) {
+      if (isRecord(artifact) && isNonEmptyString(artifact.path)) {
+        artifactPaths.add(artifact.path);
+      }
+    }
     const referencedPaths = new Set<string>();

     for (const entry of contract.entries) {
+      if (!isRecord(entry)) {
+        continue;
+      }
       if (isNonEmptyString(entry.main)) {
         referencedPaths.add(entry.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 `@packages/presentation-preset/src/output-contract-validator.ts` around lines
287 - 299, The code in output-contract-validator.ts directly accesses
artifact.path and entry properties (main, cjs, types) without null or undefined
checks, which can cause runtime TypeErrors during cross-validation. Add
defensive guards or optional chaining operators before accessing artifact.path
in the artifactPaths Set construction and before accessing entry.main,
entry.cjs, and entry.types in the referencedPaths Set construction loop. This
ensures the validator gracefully handles cases where these objects or properties
might be null or undefined rather than throwing TypeErrors.
🤖 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/presentation-preset/src/__tests__/output-contract-validator.spec.ts`:
- Around line 124-324: Add regression test cases to the "Generated runtime
profile catalog" describe block to ensure the OutputContractValidator handles
non-object and null inputs gracefully without throwing exceptions. Specifically,
add test cases that verify when validateGeneratedRuntimeProfile is called with
null values mixed into the profiles array, or null values in the entries or
artifacts arrays, the report.passed should be false and appropriate error
messages should be present in the results. These tests should verify the
validator returns a failed report rather than throwing an exception, ensuring
stability when handling invalid inputs.

In `@packages/presentation-preset/src/output-contract-validator.ts`:
- Around line 29-31: The constants artifactFormats, artifactTypes, and
presentationRuntimes on lines 29-31 are using camelCase naming convention but
should follow SCREAMING_SNAKE_CASE as per the coding guidelines for constant
names. Rename these three constants to ARTIFACT_FORMATS, ARTIFACT_TYPES, and
PRESENTATION_RUNTIMES respectively, and update all references to these constants
throughout the file. Additionally, check lines 469-479 for similar naming
convention violations and apply the same SCREAMING_SNAKE_CASE fix to any other
constants found in that range.
- Around line 89-115: The validator may crash with a TypeError if the profiles
array contains null or primitive values instead of valid objects. When iterating
through profiles in the loop, add a guard check before accessing profile.name
and profile.runtime to ensure the profile is a valid object. Specifically,
before the checks at the profile.name conditional and the
isPresentationRuntime() call, verify that profile is actually an object (not
null or a primitive value) and skip processing that element or push an
appropriate error result if it is invalid.

In `@packages/presentation-preset/tsup.config.ts`:
- Around line 5-16: The constant runtimeProfilesOutputPath on line 5 does not
follow the SCREAMING_SNAKE_CASE naming convention required for constant values.
Rename runtimeProfilesOutputPath to RUNTIME_PROFILES_OUTPUT_PATH and update all
references to this constant throughout the file, specifically in the
copyFileSync call within the onSuccess callback where it is currently used.

In `@scripts/package-docs-check.mts`:
- Around line 924-949: Add validation to check that if target.runtime is
defined, it must be an object. Currently, the code only validates internal
fields when target.runtime is already a record, but it doesn't catch cases where
target.runtime is defined but not a record (e.g., string, number). Before the
existing isRecord(target.runtime) check, add a validation block that calls
addRuntimeProfileViolation if target.runtime is defined but not a record, using
a message like "Generated runtime profile '${profileName}' runtime must be an
object when provided". This ensures consistency with the upstream
OutputContractValidator behavior.

In `@scripts/package-entrypoint-smoke.mts`:
- Around line 540-542: The JSON skip condition for types (checking if condition
equals "types" and isJsonTargetPath returns true) is currently only applied to
the string value case. When value is an object with a types property, the target
is extracted around lines 555-560 but the same JSON skip check is not applied to
the extracted target. Add the same condition check (condition === "types" &&
isJsonTargetPath) after extracting the target from the object to ensure JSON
paths are skipped for types targets in both the string and object cases.

---

Outside diff comments:
In `@packages/presentation-preset/src/output-contract-validator.ts`:
- Around line 287-299: The code in output-contract-validator.ts directly
accesses artifact.path and entry properties (main, cjs, types) without null or
undefined checks, which can cause runtime TypeErrors during cross-validation.
Add defensive guards or optional chaining operators before accessing
artifact.path in the artifactPaths Set construction and before accessing
entry.main, entry.cjs, and entry.types in the referencedPaths Set construction
loop. This ensures the validator gracefully handles cases where these objects or
properties might be null or undefined rather than throwing TypeErrors.
🪄 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

Run ID: d3888092-047a-4cb8-b424-425f36f706b9

📥 Commits

Reviewing files that changed from the base of the PR and between ac40099 and 42613a4.

📒 Files selected for processing (18)
  • .changeset/presentation-preset-runtime-profiles.md
  • README.md
  • docs/package-docs-baseline.json
  • docs/package-docs-report.md
  • packages/docs/src/content/docs/en/reference/presentation-runtime-support.md
  • packages/presentation-preset/README.md
  • packages/presentation-preset/package.json
  • packages/presentation-preset/runtime-profiles.json
  • packages/presentation-preset/src/__tests__/output-contract-validator.spec.ts
  • packages/presentation-preset/src/index.ts
  • packages/presentation-preset/src/output-contract-validator.ts
  • packages/presentation-preset/src/output-contract.ts
  • packages/presentation-preset/tsup.config.ts
  • packages/presentation-preset/vitest.config.ts
  • public-api-surface.snapshot.json
  • scripts/package-docs-check.mts
  • scripts/package-entrypoint-smoke.mts
  • scripts/tests/package-docs-check.spec.ts
💤 Files with no reviewable changes (1)
  • docs/package-docs-baseline.json

Comment thread packages/presentation-preset/src/output-contract-validator.ts Outdated
Comment thread packages/presentation-preset/src/output-contract-validator.ts
Comment thread packages/presentation-preset/tsup.config.ts Outdated
Comment thread scripts/package-docs-check.mts
Comment thread scripts/package-entrypoint-smoke.mts
@kang-heewon
kang-heewon force-pushed the fix/949-presentation-profile-contracts branch from 42613a4 to bec2758 Compare June 19, 2026 18:59
@kang-heewon
kang-heewon merged commit 0ab39c6 into trunk Jun 19, 2026
8 checks passed
@kang-heewon
kang-heewon deleted the fix/949-presentation-profile-contracts branch June 19, 2026 19:20
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.

[presentation-preset] generated output contract를 모든 지원 runtime profile에서 검증한다

1 participant