Skip to content

feat: standardize monetization lifecycle signals - #1633

Merged
kang-heewon merged 1 commit into
trunkfrom
feat/1571-monetization-lifecycle-signals
Jul 31, 2026
Merged

feat: standardize monetization lifecycle signals#1633
kang-heewon merged 1 commit into
trunkfrom
feat/1571-monetization-lifecycle-signals

Conversation

@kang-heewon

@kang-heewon kang-heewon commented Jul 30, 2026

Copy link
Copy Markdown
Member

Outcome

  • Adds nine provider-neutral monetization signal contracts with deterministic identities, safe diagnostic evidence, recovery correlation, and explicit source timestamps.
  • Provides atomic one-shot usage-threshold tracking scoped by tenant, meter, plan version, and billing period, including ordered levels, lease acknowledgement, retries, rollover, and plan migration.
  • Publishes eight opt-in versioned reference recipes with declared source/action capabilities, dry-run compatibility, stable lifecycle artifacts, and explicit capability failures.
  • Extends lifecycle diagnostics with recent monetization counts, suppressed crossings, failed actions, recovery state, and generated Problem/API documentation.

Fixes #1571

Verification

  • pnpm --filter @croco/lifecycle-core test — 51/51 passed.
  • lifecycle-core lint, typecheck, and build — passed.
  • pnpm saas-billing-golden-path:smoke — 4/4 passed.
  • pnpm public-api:check — 114 snapshots matched.
  • pnpm problem-registry:check — 535 codes and discoveries matched.
  • pnpm dependency-boundaries:check — passed.
  • pnpm docs:api:check — 115 build tasks passed; generated API docs match.
  • pnpm changeset-required:check -- --base origin/trunk --head HEAD — all affected packages covered.
  • pnpm check — 24/25 passed, 1 not applicable, 0 failed.
  • Pre-push workspace tests — 232/232 tasks passed.
  • Pre-push workspace typecheck — 231/231 tasks passed.

Review gates

  • Correctness and concurrency: PASS — duplicate and out-of-order conditions, atomic threshold races, lease expiry/release/acknowledgement, higher thresholds, period rollover, plan migration, and recovery correlation are covered.
  • API, privacy, and release: PASS — signal payloads exclude provider/customer payment details by contract; typed Problems, public snapshots, generated docs, registry metadata, and changesets are synchronized.
  • Maintainability and boundaries: PASS — lifecycle-core consumes provider-neutral normalized state, keeps enforcement in entitlements, and requires recipes to declare capabilities before installation.
  • Independent adversarial review: APPROVED after correcting retry-stable duplicate transitions, pending threshold ordering, credit condition identity, and distributive signal narrowing; final review reported no actionable findings.

Residual risk

The included stores are in-memory reference implementations. Distributed deployments must provide durable MonetizationThresholdStore and MonetizationConditionStore adapters with equivalent atomic claim and ordering semantics.

Summary by CodeRabbit

  • 새 기능

    • 청구·사용량·크레딧·좌석 관련 수익화 신호와 참조 레시피를 지원합니다.
    • 사용량 임계값의 중복·순서 역전 제어와 구독 상태 전이를 제공합니다.
    • 레시피 capability 검증, 설치, dry-run 및 상세 진단을 지원합니다.
    • 수익화 관련 오류와 진단 정보가 공개 API에 추가되었습니다.
  • 문서

    • 수익화 신호, 레시피, 추적기, 저장소 및 진단 API 문서를 추가했습니다.
    • 문제 코드 레지스트리에 3개 항목을 추가했습니다.
  • 버그 수정

    • CLI 테스트에서 통합 테스트가 의도치 않게 실행되지 않도록 개선했습니다.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 37 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: ASSERTIVE

Plan: Pro Plus

Run ID: 600c915f-7d56-45c4-b35d-19dfe904f448

📥 Commits

Reviewing files that changed from the base of the PR and between 26b9c8b and d5a994c.

⛔ Files ignored due to path filters (2)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (87)
  • .changeset/calm-pandas-observe.md
  • .changeset/steady-cli-tests.md
  • docs/problem-code-registry.json
  • packages/cli/package.json
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/LifecycleDiagnosticsProvider.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSignalDefinitionProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSubscriptionConditionTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationThresholdClaimProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationThresholdTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditBalanceLowSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditExhaustedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createDeliveryBacklogEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createLowCreditWarningRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationReferenceRecipes.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createPastDueGraceFollowUpRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createQuotaReachedNotificationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatQuantityDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionPastDueSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionRecoveredSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingReminderRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDeliveryLaggingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageSyncDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageThresholdCrossedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageUpgradePromptRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/installMonetizationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/validateMonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationCapabilitySource.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditBalanceLowSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditExhaustedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/InMemoryMonetizationThresholdStoreOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDryRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsProviderOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleMonetizationOperationalDiagnostic.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransitionResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilityDiagnostic.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDefinition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeId.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSafeEvidence.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalData.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalEvidenceByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalMetadataByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalReason.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaim.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaimResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdDiagnostics.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdScope.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SeatQuantityDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionPastDueSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionRecoveredSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/TrialEndingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageDeliveryLaggingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageSyncDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageThresholdCrossedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/variables/MONETIZATION_SIGNAL_DESCRIPTORS.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/lifecycle-core/README.md
  • packages/lifecycle-core/package.json
  • packages/lifecycle-core/src/index.ts
  • packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts
  • packages/lifecycle-core/src/libs/monetization.ts
  • packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts
  • packages/lifecycle-core/src/libs/types.ts
  • packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts
  • public-api-surface.snapshot.json
📝 Walkthrough

Walkthrough

@croco/lifecycle-core에 provider-neutral monetization signal, threshold 및 condition tracker, opt-in reference recipe, capability 검증, diagnostics, Problem 유형과 공개 API 문서가 추가되었습니다. 통합 테스트와 릴리스 메타데이터도 갱신되었습니다.

Changes

Monetization lifecycle

Layer / File(s) Summary
Signal 계약과 생성기
packages/lifecycle-core/src/libs/monetization.ts, packages/lifecycle-core/src/libs/types.ts, packages/lifecycle-core/src/index.ts
9개 monetization signal의 입력 타입, descriptor, evidence, metadata, 검증, 결정적 ID 및 factory를 추가했습니다.
Condition 및 threshold 추적
packages/lifecycle-core/src/libs/monetization.ts, packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts
구독 전이와 usage threshold crossing을 scope별로 관리합니다. 중복, 순서 오류, 기간·플랜 변경, lease 만료 및 원자적 claim을 처리합니다.
Recipe와 capability 설치
packages/lifecycle-core/src/libs/monetization.ts, packages/lifecycle-core/README.md
8개 reference recipe, 안전한 evidence, idempotency key, capability 진단, recipe 설치 및 croco.lifecycle.monetization/v1 artifact 생성을 추가했습니다.
Diagnostics와 Problem 유형
packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts, packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts, docs/problem-code-registry.json
signal 집계, recovery 상태, suppressed crossing, capability drift를 진단 결과에 추가했습니다. 세 monetization Problem 코드를 등록했습니다.
검증과 공개 surface
packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts, public-api-surface.snapshot.json, packages/docs/src/content/docs/api/lifecycle-core/src/*
신호, 추적, recipe, dry-run, cooldown, recovery, 오류 및 capability drift를 검증하는 테스트를 추가했습니다. 공개 export와 API 문서를 갱신했습니다.
패키지 및 릴리스 wiring
packages/lifecycle-core/package.json, packages/cli/package.json, .changeset/*
@croco/billing-core 의존성을 추가했습니다. CLI 테스트 제외 패턴과 package release changeset을 갱신했습니다.

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

Possibly related issues

  • #1511 — monetization signal, threshold tracking, recipe 및 capability diagnostic 목표가 직접 겹칩니다.

Possibly related PRs

  • croco-dev/framework#1637 — licensed quantity capability 처리와 monetization capability diagnostics가 연결됩니다.

Sequence Diagram(s)

sequenceDiagram
  participant BillingOrMeteringAdapter
  participant MonetizationSignalFactory
  participant MonetizationThresholdTracker
  participant LifecycleRuleRegistry
  participant LifecycleDiagnosticsProvider

  BillingOrMeteringAdapter->>MonetizationSignalFactory: normalized monetization input
  MonetizationSignalFactory-->>MonetizationThresholdTracker: lifecycle signal
  MonetizationThresholdTracker->>LifecycleRuleRegistry: accepted threshold crossing
  LifecycleRuleRegistry-->>LifecycleDiagnosticsProvider: monetization run data
  LifecycleDiagnosticsProvider-->>BillingOrMeteringAdapter: signal counts and capability diagnostics
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning CLI 테스트 스크립트 변경과 전용 CLI changeset은 수익화 라이프사이클 요구사항과 직접 관련되지 않습니다. packages/cli/package.json 및 .changeset/steady-cli-tests.md 변경을 별도 PR로 분리하거나, 이 PR에서 필요한 근거를 추가하십시오.
Linked Issues check ❓ Inconclusive 대부분의 요구사항을 구현하고 검증했지만, 생성 문제 레지스트리 파일은 리뷰 필터로 제외되어 갱신 여부를 확인할 수 없습니다. 제외된 packages/problems-core/src/generated/problem-code-registry.ts 파일을 포함하여 새 문제 코드 등록 상태를 확인하십시오. 제외 규칙은 !**/generated/**입니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 수익화 라이프사이클 신호 표준화라는 주요 변경을 간결하고 명확하게 설명합니다.
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/1571-monetization-lifecycle-signals

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.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

📊 Benchmark Results

✅ All benchmarks passed

Benchmark p75 Threshold Baseline vs Baseline Status Notes
CrocoApp constructor 8.4μs 30.0ms 8.2μs +2.7% -
CrocoApp lambdaHandler (10 controllers) 287.9μs 50.0ms 258.4μs +11.4% -
Lambda cold-start simulation 430.6μs 80.0ms 418.1μs +3.0% -
Lambda cold-start with headers 389.2μs 80.0ms 369.7μs +5.3% -
Lambda cold-start with binary body 381.6μs 80.0ms 339.1μs +12.5% -
Lambda cold-start with query params 317.9μs 80.0ms 301.3μs +5.5% -
Lambda cold-start with authorizer context 318.4μs 80.0ms 299.8μs +6.2% -
Lambda cold-start realistic scenario 316.9μs 80.0ms 299.2μs +5.9% -
EventBusConfig.start (10 handlers) 1.6μs 10.0ms 1.4μs +9.8% -
EventPublisher.publishNow single event 1.8μs 2.0ms 1.7μs +7.8% -
DefaultHandlerResolver.resolve × 10 0.1μs 5.0ms 0.1μs +0.0% -
Container.get singleton (cold) 78.4μs 5.0ms 70.3μs +11.7% -
Container.register × 50 components 3.4ms 10.0ms 3.2ms +4.2% -
Container.validate (50 components) 3.9ms 20.0ms 3.4ms +15.5% -
Container.get singleton (warm) 1.7μs 500.0μs 1.6μs +1.2% -
TelemetryRuntime.init (lambda preset) 2.3μs 200.0ms 1.1ms -99.8% -
lambdaPreset config creation 1.5μs 2.0ms 1.4μs +4.3% -

Updated: 2026-07-31T15:16:24.726Z · Commit: ddaf420

@kang-heewon
kang-heewon force-pushed the feat/1571-monetization-lifecycle-signals branch 4 times, most recently from 512f58a to ae784dd Compare July 31, 2026 07:48

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

🤖 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/cli/package.json`:
- Line 40: Update the package.json test script to wrap the Vitest integration
exclusion glob in escaped double quotes instead of single quotes, ensuring
Windows cmd.exe passes the pattern correctly while preserving the existing
test:e2e scope and exclusion behavior.

In
`@packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md`:
- Line 8: Update the JSDoc for MonetizationSignalDefinitionProblem and
MonetizationRecipeCapabilityProblem in
packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts to describe their
specific problem details instead of the generic Problem class. Document signal
input definition issues for MonetizationSignalDefinitionProblem, and describe
missing unavailable recipe capabilities using recipeId and missingCapabilities
for MonetizationRecipeCapabilityProblem; then regenerate the TypeDoc pages
packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSignalDefinitionProblem.md:8-8
and
packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md:8-8.

In
`@packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md`:
- Around line 8-18: Restore the API documentation generation path behind
CROCO_PROBLEM_CODE_REGISTRY and reconcile its source Problem metadata before
updating this generated Markdown. Run the canonical regeneration flow, verify
the regenerated registry matches the source metadata, and ensure pnpm
docs:api:check passes before committing the document.

In
`@packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts`:
- Around line 173-184: Update the getHealth flow around
monetizationThresholdStore.getDiagnostics and
monetizationCapabilitySource.getCapabilities to handle each Promise
independently with an appropriate timeout; convert failures into degraded health
results and detailed diagnostics containing traceable diagnostic codes and
underlying causes instead of allowing getHealth to throw. Also emit a diagnostic
when monetizationRecipes is configured but no monetizationCapabilitySource
exists, rather than silently skipping capability validation.
- Around line 59-66: Update the monetizationSignalsByType property in
LifecycleDiagnosticsProvider to use MonetizationSignalType as the Record key
instead of string, and add MonetizationSignalType to the existing type import
from ../monetization.

In `@packages/lifecycle-core/src/libs/monetization.ts`:
- Around line 1211-1226: Update the when callback to access the threshold
through optional chaining from data.evidence, returning false when evidence is
absent while preserving the existing threshold-range checks. Anchor the change
in the when callback and its threshold evaluation; do not assume data.evidence
is always present.
- Around line 435-438: Update the trial-ending signal construction in the
function containing createMonetizationSignal so daysRemaining is included in the
signal identity material, ensuring D-7, D-3, and D-1 reminders receive distinct
IDs and are not deduplicated by createRecipe’s context.signal.idempotencyKey.
- Around line 977-991: Update acknowledgeCrossings and the
reservation-expiration flow so claims removed by pruneExpiredReservations are
surfaced rather than silently ignored. Add expiredClaimCount to
MonetizationThresholdDiagnostics, increment it when reservations expire, and
expose it through the existing diagnostics path; ensure acknowledgeCrossings
does not falsely treat an expired claim as successfully acknowledged.

In `@packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts`:
- Line 171: LifecycleProblems의 생성자에서 signalType을 MonetizationSignalType으로 좁히고,
관련 recipeId 파라미터와 MonetizationRecipeCapabilityDiagnostic.recipeId도
MonetizationRecipeId를 사용하도록 변경하십시오. 두 도메인 타입은 순환 import가 발생하지 않는 공용 타입 모듈에 선언하거나
재사용하여 Problem extensions 계약이 컴파일 시점에 검증되도록 하십시오.
- Around line 170-184: Update the category used by
MonetizationSignalDefinitionProblem from ProblemCategory.InternalServerError to
the input-validation category, ProblemCategory.ValidationError, while preserving
the existing error code, message, and extensions.

In `@packages/lifecycle-core/src/libs/types.ts`:
- Around line 6-14: Remove the duplicated monetization signal literals from
LifecycleSignalType and reuse MonetizationSignalType from monetization.ts as the
single source of truth. If direct reuse is not possible, add a compile-time
compatibility assertion between LifecycleSignalType and MonetizationSignalType
so future divergence fails type checking.

In `@packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts`:
- Around line 180-184: Update the test around the
billing.usage.threshold_crossed signal to assert signal.type equals the expected
event type before checking reason, status, and evidence. Remove the conditional
guard so the test always validates the event type and payload.
- Around line 63-69: Update allCapabilities() to derive signalSources from each
recipe descriptor’s requiredSignalSources field instead of signalTypes, while
keeping requiredActionTypes unchanged. Ensure the helper matches the capability
fields checked by missingCapabilities so the diagnostics and installation tests
validate the actual contract.
- Around line 319-331: Update the asynchronous rejection assertion for
installMonetizationRecipe to include rejects.toThrow alongside the existing
toMatchObject checks, preserving the current error code and recipeId assertions.
Since MonetizationRecipeCapabilityProblem is currently type-only imported,
change it to a value import if using it for a class assertion.
- Line 152: The assertion at line 152 uses toHaveLength on a Set object, but Set
instances use the .size property instead of .length. Update the expect assertion
for the Set created from signals.map to use the toHaveSize matcher instead,
which correctly validates that the unique signal types collection contains
exactly 8 distinct entries.
🪄 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: 03bf0e79-56bb-47a4-a595-ae7061a4f431

📥 Commits

Reviewing files that changed from the base of the PR and between 88c6ce1 and ae784dd.

⛔ Files ignored due to path filters (2)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (85)
  • .changeset/calm-pandas-observe.md
  • .changeset/steady-cli-tests.md
  • docs/problem-code-registry.json
  • packages/cli/package.json
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/LifecycleDiagnosticsProvider.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSignalDefinitionProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSubscriptionConditionTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationThresholdTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditBalanceLowSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditExhaustedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createDeliveryBacklogEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createLowCreditWarningRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationReferenceRecipes.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createPastDueGraceFollowUpRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createQuotaReachedNotificationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatQuantityDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionPastDueSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionRecoveredSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingReminderRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDeliveryLaggingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageSyncDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageThresholdCrossedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageUpgradePromptRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/installMonetizationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/validateMonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationCapabilitySource.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditBalanceLowSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditExhaustedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/InMemoryMonetizationThresholdStoreOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDryRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsProviderOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransitionResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilityDiagnostic.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDefinition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeId.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSafeEvidence.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalData.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalEvidenceByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalMetadataByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalReason.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaim.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaimResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdDiagnostics.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdScope.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SeatQuantityDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionPastDueSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionRecoveredSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/TrialEndingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageDeliveryLaggingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageSyncDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageThresholdCrossedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/variables/MONETIZATION_SIGNAL_DESCRIPTORS.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/lifecycle-core/README.md
  • packages/lifecycle-core/package.json
  • packages/lifecycle-core/src/index.ts
  • packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts
  • packages/lifecycle-core/src/libs/monetization.ts
  • packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts
  • packages/lifecycle-core/src/libs/types.ts
  • packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/cli/package.json Outdated
Comment thread packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts Outdated
Comment thread packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts Outdated
Comment thread packages/lifecycle-core/src/libs/monetization.ts
Comment thread packages/lifecycle-core/src/libs/types.ts Outdated
Comment thread packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts
Comment thread packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts Outdated
Comment thread packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts Outdated
Comment thread packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts Outdated

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 15

🤖 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/cli/package.json`:
- Line 40: Update the package.json test script to wrap the Vitest integration
exclusion glob in escaped double quotes instead of single quotes, ensuring
Windows cmd.exe passes the pattern correctly while preserving the existing
test:e2e scope and exclusion behavior.

In
`@packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md`:
- Line 8: Update the JSDoc for MonetizationSignalDefinitionProblem and
MonetizationRecipeCapabilityProblem in
packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts to describe their
specific problem details instead of the generic Problem class. Document signal
input definition issues for MonetizationSignalDefinitionProblem, and describe
missing unavailable recipe capabilities using recipeId and missingCapabilities
for MonetizationRecipeCapabilityProblem; then regenerate the TypeDoc pages
packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSignalDefinitionProblem.md:8-8
and
packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md:8-8.

In
`@packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md`:
- Around line 8-18: Restore the API documentation generation path behind
CROCO_PROBLEM_CODE_REGISTRY and reconcile its source Problem metadata before
updating this generated Markdown. Run the canonical regeneration flow, verify
the regenerated registry matches the source metadata, and ensure pnpm
docs:api:check passes before committing the document.

In
`@packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts`:
- Around line 173-184: Update the getHealth flow around
monetizationThresholdStore.getDiagnostics and
monetizationCapabilitySource.getCapabilities to handle each Promise
independently with an appropriate timeout; convert failures into degraded health
results and detailed diagnostics containing traceable diagnostic codes and
underlying causes instead of allowing getHealth to throw. Also emit a diagnostic
when monetizationRecipes is configured but no monetizationCapabilitySource
exists, rather than silently skipping capability validation.
- Around line 59-66: Update the monetizationSignalsByType property in
LifecycleDiagnosticsProvider to use MonetizationSignalType as the Record key
instead of string, and add MonetizationSignalType to the existing type import
from ../monetization.

In `@packages/lifecycle-core/src/libs/monetization.ts`:
- Around line 1211-1226: Update the when callback to access the threshold
through optional chaining from data.evidence, returning false when evidence is
absent while preserving the existing threshold-range checks. Anchor the change
in the when callback and its threshold evaluation; do not assume data.evidence
is always present.
- Around line 435-438: Update the trial-ending signal construction in the
function containing createMonetizationSignal so daysRemaining is included in the
signal identity material, ensuring D-7, D-3, and D-1 reminders receive distinct
IDs and are not deduplicated by createRecipe’s context.signal.idempotencyKey.
- Around line 977-991: Update acknowledgeCrossings and the
reservation-expiration flow so claims removed by pruneExpiredReservations are
surfaced rather than silently ignored. Add expiredClaimCount to
MonetizationThresholdDiagnostics, increment it when reservations expire, and
expose it through the existing diagnostics path; ensure acknowledgeCrossings
does not falsely treat an expired claim as successfully acknowledged.

In `@packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts`:
- Line 171: LifecycleProblems의 생성자에서 signalType을 MonetizationSignalType으로 좁히고,
관련 recipeId 파라미터와 MonetizationRecipeCapabilityDiagnostic.recipeId도
MonetizationRecipeId를 사용하도록 변경하십시오. 두 도메인 타입은 순환 import가 발생하지 않는 공용 타입 모듈에 선언하거나
재사용하여 Problem extensions 계약이 컴파일 시점에 검증되도록 하십시오.
- Around line 170-184: Update the category used by
MonetizationSignalDefinitionProblem from ProblemCategory.InternalServerError to
the input-validation category, ProblemCategory.ValidationError, while preserving
the existing error code, message, and extensions.

In `@packages/lifecycle-core/src/libs/types.ts`:
- Around line 6-14: Remove the duplicated monetization signal literals from
LifecycleSignalType and reuse MonetizationSignalType from monetization.ts as the
single source of truth. If direct reuse is not possible, add a compile-time
compatibility assertion between LifecycleSignalType and MonetizationSignalType
so future divergence fails type checking.

In `@packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts`:
- Around line 180-184: Update the test around the
billing.usage.threshold_crossed signal to assert signal.type equals the expected
event type before checking reason, status, and evidence. Remove the conditional
guard so the test always validates the event type and payload.
- Around line 63-69: Update allCapabilities() to derive signalSources from each
recipe descriptor’s requiredSignalSources field instead of signalTypes, while
keeping requiredActionTypes unchanged. Ensure the helper matches the capability
fields checked by missingCapabilities so the diagnostics and installation tests
validate the actual contract.
- Around line 319-331: Update the asynchronous rejection assertion for
installMonetizationRecipe to include rejects.toThrow alongside the existing
toMatchObject checks, preserving the current error code and recipeId assertions.
Since MonetizationRecipeCapabilityProblem is currently type-only imported,
change it to a value import if using it for a class assertion.
- Line 152: The assertion at line 152 uses toHaveLength on a Set object, but Set
instances use the .size property instead of .length. Update the expect assertion
for the Set created from signals.map to use the toHaveSize matcher instead,
which correctly validates that the unique signal types collection contains
exactly 8 distinct entries.
🪄 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: 03bf0e79-56bb-47a4-a595-ae7061a4f431

📥 Commits

Reviewing files that changed from the base of the PR and between 88c6ce1 and ae784dd.

⛔ Files ignored due to path filters (2)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (85)
  • .changeset/calm-pandas-observe.md
  • .changeset/steady-cli-tests.md
  • docs/problem-code-registry.json
  • packages/cli/package.json
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/LifecycleDiagnosticsProvider.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSignalDefinitionProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSubscriptionConditionTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationThresholdTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditBalanceLowSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditExhaustedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createDeliveryBacklogEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createLowCreditWarningRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationReferenceRecipes.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createPastDueGraceFollowUpRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createQuotaReachedNotificationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatQuantityDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionPastDueSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionRecoveredSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingReminderRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDeliveryLaggingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageSyncDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageThresholdCrossedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageUpgradePromptRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/installMonetizationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/validateMonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationCapabilitySource.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditBalanceLowSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditExhaustedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/InMemoryMonetizationThresholdStoreOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDryRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsProviderOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransitionResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilityDiagnostic.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDefinition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeId.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSafeEvidence.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalData.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalEvidenceByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalMetadataByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalReason.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaim.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaimResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdDiagnostics.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdScope.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SeatQuantityDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionPastDueSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionRecoveredSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/TrialEndingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageDeliveryLaggingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageSyncDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageThresholdCrossedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/variables/MONETIZATION_SIGNAL_DESCRIPTORS.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/lifecycle-core/README.md
  • packages/lifecycle-core/package.json
  • packages/lifecycle-core/src/index.ts
  • packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts
  • packages/lifecycle-core/src/libs/monetization.ts
  • packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts
  • packages/lifecycle-core/src/libs/types.ts
  • packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts
  • public-api-surface.snapshot.json
🛑 Comments failed to post (1)
packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md (1)

8-18: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

registry='packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md'
source='packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts'

expected="$(sed -nE 's/.*problemCount.*: `([0-9]+)`.*/\1/p' "$registry")"
actual="$(rg -o '`code`:' "$registry" | wc -l | tr -d ' ')"

test "$expected" = "$actual"

rg -n -C 6 \
  'monetization-recipe-capability-missing|monetization-signal-invalid' \
  "$source" "$registry"

pnpm docs:api:check

Repository: croco-dev/framework

Length of output: 50376


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

registry='packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md'
lifecycle='packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts'

printf 'registry line count: '
wc -l < "$registry"

printf '\nproblemCount in registry: '
sed -nE 's/.*problemCount.*?:.*?`([0-9]+)`.*/\1/p' "$registry"

printf '\nnested code declarations in registry: '
rg -o '(`code`|code:)' "$registry" | wc -l | tr -d ' '

printf '\nmatches in registry and lifecycle for monetization codes:\n'
rg -n -C 3 'monetization-(recipe-capability-missing|signal-invalid)' "$registry" "$lifecycle" || true

printf '\npackage/scripts entries for docs APIs:\n'
node - <<'JS'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json','utf8'));
for (const [k,v] of Object.entries(pkg?.scripts||{})) {
  if (/docs|typedoc|api/.test(k)) console.log(k, '=', v);
}
JS

printf '\nTypeDoc config files:\n'
git ls-files | rg '(^|/)typedoc\.[cm]?[jt]s?$|(^|/)typedoc-config|packages/doc|docs:api' || true

Repository: croco-dev/framework

Length of output: 50376


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

registry='packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md'
lifecycle='packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts'

printf '%s: problemCount line\n' "$registry"
rg -n -E '^\s*problemCount\s*:.*?`([0-9]+)`.+' "$registry"

printf '\n%s: occurrences of `code` declarations and nested code references (no failures expected)\n' "$registry"
python3 - <<'PY'
import re
from pathlib import Path
p=Path('packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md')
s=p.read_text()
codes=re.findall(r'`code`:\s*"(.*?)"', s)
print('declared codes:', len(codes))
print('first 20 codes:', codes[:20])
print('\ntotal nested code matches:', len(re.findall(r'`code`:', s)))
PY

printf '\n%s: metadata for monetization-recipe-capability-missing\n' "$lifecycle"
rg -n -C 4 'monetization-recipe-capability-missing' "$lifecycle"

printf '\n%s: metadata for monetization-signal-invalid\n' "$lifecycle"
rg -n -C 4 'monetization-signal-invalid' "$lifecycle"

Repository: croco-dev/framework

Length of output: 370


API 문서 생성 경로를 복구하세요.

pnpm docs:api:check가 실패했습니다.
이 Markdown은 생성물이라도 불일치를 원본 Problem 메타데이터 검사와 함께 확인해야 합니다. 결과로 API 문서 생성 경로가 실패하면 이 커밋 전에 원본 수정/재생성 경로를 먼저 복구하세요.

🤖 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/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md`
around lines 8 - 18, Restore the API documentation generation path behind
CROCO_PROBLEM_CODE_REGISTRY and reconcile its source Problem metadata before
updating this generated Markdown. Run the canonical regeneration flow, verify
the regenerated registry matches the source metadata, and ensure pnpm
docs:api:check passes before committing the document.

Source: Learnings

@kang-heewon
kang-heewon force-pushed the feat/1571-monetization-lifecycle-signals branch from ae784dd to 26b9c8b Compare July 31, 2026 10:50

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

🤖 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/lifecycle-core/README.md`:
- Around line 157-160: Update the README example’s loop to use the previously
defined evaluator instead of the undefined lifecycle identifier, and ensure
createLifecycleContext is imported if the example is intended to stand alone.
Keep the crossing.signals evaluation and tracker.acknowledge flow unchanged.
- Line 195: Update the README description of
createMonetizationLifecycleArtifact() to remove the claim that fingerprints
cover versioned activation and dry-run paths, since executableFingerprint
currently includes only descriptor, executionModelVersion, actionDescriptors,
signal action IDs, cooldown, and thresholdRange. Keep the documented fingerprint
scope aligned with the implementation in executableFingerprint and
registerVersion().

In `@packages/lifecycle-core/src/libs/monetization.ts`:
- Around line 929-941: Update the latestSourceAt advancement guard near
crossedThresholds to also require that no unresolved reservation remains for the
same scope key. Use the existing reservations collection and key filtering, so
observations with pending claims—including those with an empty eligible
set—cannot advance latestSourceAt; preserve the current advancement behavior
when no matching reservation exists.

In `@packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts`:
- Around line 206-221: Update the extensions in
MonetizationThresholdClaimProblem so this permanently unavailable claim is
marked retryable: false, matching MonetizationSignalDefinitionProblem and
MonetizationRecipeCapabilityProblem. Preserve the existing claimId and error
message behavior.
🪄 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: 16407e24-a1ec-46f5-b5c8-3185473bd003

📥 Commits

Reviewing files that changed from the base of the PR and between ae784dd and 26b9c8b.

⛔ Files ignored due to path filters (2)
  • packages/problems-core/src/generated/problem-code-registry.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (87)
  • .changeset/calm-pandas-observe.md
  • .changeset/steady-cli-tests.md
  • docs/problem-code-registry.json
  • packages/cli/package.json
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/InMemoryMonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/LifecycleDiagnosticsProvider.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationRecipeCapabilityProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSignalDefinitionProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationSubscriptionConditionTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationThresholdClaimProblem.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/classes/MonetizationThresholdTracker.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditBalanceLowSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createCreditExhaustedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createDeliveryBacklogEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createLowCreditWarningRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createMonetizationReferenceRecipes.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createPastDueGraceFollowUpRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createQuotaReachedNotificationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSeatQuantityDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionPastDueSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createSubscriptionRecoveredSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingReminderRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createTrialEndingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDeliveryLaggingSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageDriftEscalationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageSyncDriftedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageThresholdCrossedSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/createUsageUpgradePromptRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/installMonetizationRecipe.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/functions/validateMonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationCapabilitySource.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationConditionStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/interfaces/MonetizationThresholdStore.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditBalanceLowSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/CreditExhaustedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/InMemoryMonetizationThresholdStoreOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsDryRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsProviderOptions.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleDiagnosticsRunDetails.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleMonetizationOperationalDiagnostic.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/LifecycleSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationConditionTransitionResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleArtifact.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationLifecycleSignal.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilities.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeCapabilityDiagnostic.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDefinition.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationRecipeId.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSafeEvidence.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalData.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalDescriptor.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalEvidenceByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalMetadataByType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalReason.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationSignalType.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaim.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdClaimResult.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdDiagnostics.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdEvaluation.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/MonetizationThresholdScope.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SeatQuantityDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionPastDueSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/SubscriptionRecoveredSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/TrialEndingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageDeliveryLaggingSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageSyncDriftedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/type-aliases/UsageThresholdCrossedSignalInput.md
  • packages/docs/src/content/docs/api/lifecycle-core/src/variables/MONETIZATION_SIGNAL_DESCRIPTORS.md
  • packages/docs/src/content/docs/api/problems-core/src/classes/Problem.md
  • packages/docs/src/content/docs/api/problems-core/src/variables/CROCO_PROBLEM_CODE_REGISTRY.md
  • packages/docs/src/content/docs/en/reference/problem-recovery-cookbook.md
  • packages/lifecycle-core/README.md
  • packages/lifecycle-core/package.json
  • packages/lifecycle-core/src/index.ts
  • packages/lifecycle-core/src/libs/diagnostics/LifecycleDiagnosticsProvider.ts
  • packages/lifecycle-core/src/libs/monetization.ts
  • packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts
  • packages/lifecycle-core/src/libs/types.ts
  • packages/lifecycle-core/src/tests/MonetizationLifecycle.spec.ts
  • public-api-surface.snapshot.json

Comment thread packages/lifecycle-core/README.md
Comment thread packages/lifecycle-core/README.md Outdated
Comment thread packages/lifecycle-core/src/libs/monetization.ts
Comment thread packages/lifecycle-core/src/libs/problems/LifecycleProblems.ts
@kang-heewon
kang-heewon force-pushed the feat/1571-monetization-lifecycle-signals branch from 26b9c8b to d5a994c Compare July 31, 2026 15:11
@kang-heewon

Copy link
Copy Markdown
Member Author

@coderabbitai resolve

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

@kang-heewon
kang-heewon merged commit 772a244 into trunk Jul 31, 2026
12 checks passed
@kang-heewon
kang-heewon deleted the feat/1571-monetization-lifecycle-signals branch July 31, 2026 15:45
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.

[lifecycle-core] Standardize monetization lifecycle signals and retention recipes

1 participant