feat: release immutable plan versions through reviewed drafts - #1725
Conversation
|
Warning Review limit reached
Next review available in: 14 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 ignored due to path filters (2)
📒 Files selected for processing (92)
📝 WalkthroughWalkthroughbilling-core에 draft, in_review, scheduled, published, superseded, abandoned 상태를 가진 Plan Release 수명 주기를 추가했다. PlanRelease 도메인 모델, PlanReleaseService, InMemoryPlanReleaseStore, 관련 Problem 클래스와 전환 이벤트를 신설하고, 공개 API export, 문서, problem registry, changeset을 갱신했다. 별도로 create-croco-app 템플릿의 DI 가드 테스트를 수정하고, 다수 API 문서의 구분선 표기를 정리했다. ChangesPlan Release 수명 주기 기능
Estimated code review effort: 4 (Complex) | ~75 minutes create-croco-app DI 가드 테스트 수정
Estimated code review effort: 2 (Simple) | ~10 minutes 문서 마크다운 구분선 표기 정리
Estimated code review effort: 1 (Trivial) | ~5 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 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-08-01T21:19:41.360Z · Commit: 5a54f42 |
a1ae54d to
dca0a93
Compare
There was a problem hiding this comment.
Actionable comments posted: 24
🤖 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/billing-core/src/index.ts`:
- Around line 127-167: Reorder the Plan Release exports in index.ts so all value
exports, including PlanReleaseTransitionedEvent and the
PlanRelease/PlanReleaseService symbols, appear before the type-only export
block. Keep every existing export unchanged and place the complete Plan Release
type export last within this category.
In `@packages/billing-core/src/libs/events/PlanReleaseTransitionedEvent.ts`:
- Around line 9-19: Update the PlanReleaseTransitionedEvent constructor to
accept one typed object containing planVersionRef, from, to, revision, actorId,
reason, and optional eventId instead of positional arguments. Update
PlanReleaseService.createEvent and every constructor call to pass these values
by property name, preserving existing behavior and eliminating actorId/reason
ordering errors.
In `@packages/billing-core/src/libs/InMemoryPlanReleaseStore.ts`:
- Around line 93-108: 중복된 effectivePeriodsConflict 구현을 공유 함수로 통합하십시오.
packages/billing-core/src/libs/InMemoryPlanReleaseStore.ts의 93-108행에서는 지역 함수를
제거하고 ./PlanRelease의 export 함수를 import하며 매개변수 타입을 PlanVersionDefinition으로 맞추십시오.
packages/billing-core/src/libs/PlanReleaseService.ts의 656-671행에서도 지역 함수를 제거하고
동일한 함수를 import하십시오. 구현 본문은 packages/billing-core/src/libs/PlanRelease.ts로 이동해
export하여 사전 검사와 최종 검사가 항상 같은 판정 로직을 사용하게 하십시오.
In `@packages/billing-core/src/libs/PlanRelease.ts`:
- Around line 314-326: Update stableStringify’s object serialization to omit
keys whose values are undefined before sorting and joining entries, so objects
with explicitly undefined optional fields produce the same fingerprint as
objects without those fields. Preserve serialization of all defined values and
array elements.
- Around line 282-288: Update the usage_tiers comparator in PlanRelease so tiers
sharing the same meterKey and upTo rank are deterministically ordered by
unitAmount as the secondary key. Preserve the existing meterKey and upTo
ordering, including treating null upTo as the highest rank, and ensure this
tie-break applies when upTo values are both null.
- Around line 252-259: Update planReleaseCommandFingerprint to return a sha256:
digest of the stableStringify payload, matching
planVersionDefinitionFingerprint, so actor and reason are not persisted in
plaintext or unbounded form. Locate every idempotency comparison in
PlanReleaseService that compares stored
PlanReleasePublicationEvidence.commandFingerprint or
PlanReleasePublicationFailure.commandFingerprint and make it use the same digest
format, including any required handling for existing stored records.
In `@packages/billing-core/src/libs/PlanReleaseService.ts`:
- Around line 357-375: Update cancelPublish’s cancellation path to create the
cancelled record through the existing transition/saveTransition flow instead of
directly calling store.save. Preserve the current state changes, add the
corresponding history entry and PlanReleaseLifecycleEvent to the save options,
and invoke deliverPendingEvents after persistence so the revision remains
traceable and the cancellation is audited.
- Around line 105-116: Update the validation failure branch in
PlanReleaseService to collect a distinct diagnostic code for each failed
evidence check: planVersionRef, definitionFingerprint, draftRevision, empty
graphVersion, empty snapshotId, and invalid checkedAt. Pass the collected codes
in deterministic sorted order to PlanReleaseValidationFailedProblem instead of
using the single validation-snapshot-definition-mismatch code.
- Around line 198-200: Update the empty idempotencyKey validation in the command
handling flow to throw the established validation-related Problem instead of
PlanReleasePublishConflictProblem; keep PlanReleasePublishConflictProblem
reserved for actual competing publish requests.
- Around line 537-548: Update the pending-event loop in the release publication
flow to stop publishing further events for a planVersionRef after one event
fails, while continuing to process later events belonging to other releases.
Preserve the failed event as a failure and leave skipped events unmarked so they
remain pending; ensure the pending aggregate only reflects attempted publication
failures, not skipped events.
- Around line 487-514: Update publishNow and
recordDeterministicPublicationFailure so compensation-save failures are absorbed
and the original InvalidPlanVersionDefinitionProblem or
PlanVersionConflictProblem remains the propagated error. Ensure the helper
records the failure without creating history entries or outbox events, and align
its cleanup behavior with cancelPublish. Model any recovery outcome using the
existing stable diagnostic mechanism rather than a generic catch-all or silent
fallback.
In `@packages/billing-core/src/libs/problems/PlanReleaseProblems.ts`:
- Around line 3-13: Update StalePlanReleaseRevisionProblem to expose expected
and actual through the Problem extensions, following the existing extensions
pattern used by PlanReleaseValidationFailedProblem and
PlanReleaseProviderCapabilityProblem while preserving the current diagnostic
code and message.
- Around line 15-25: Update the constructor signature of
InvalidPlanReleaseTransitionProblem so from uses PlanReleaseState | null and to
uses PlanReleaseState, reusing the existing PlanReleaseState union from the
package while leaving the error message behavior unchanged.
In `@packages/billing-core/src/tests/BillingProblems.spec.ts`:
- Around line 8-14: Update the PlanReleaseProblems tests by moving them from
BillingProblems.spec.ts to src/tests/PlanReleaseProblems.spec.ts, and extend
coverage to include InvalidPlanReleaseScheduleProblem and
PlanReleasePublishConflictProblem. Assert the stable problem-code strings for
all seven classes defined in PlanReleaseProblems.ts, preserving the existing
assertions for the five covered classes.
In `@packages/billing-core/src/tests/InMemoryPlanRegistry.spec.ts`:
- Around line 366-385: Update both asynchronous rejection assertions in the
InMemoryPlanRegistry tests to use rejects.toThrow with
InvalidPlanVersionDefinitionProblem, preserving the existing class-matching
validation for duplicate usage tiers and entitlements.
In `@packages/billing-core/src/tests/PlanReleaseService.spec.ts`:
- Around line 863-888: Extend the test “keeps failed lifecycle events in the
outbox and redelivers them idempotently” to call service.deliverPendingEvents
while shouldFail remains true and assert attempted: 1, published: 0, pending: 1,
with failures containing the event ID and detail “publisher unavailable”; then
retain the existing retry assertions after setting shouldFail to false.
- Around line 431-465: Update the rejection assertions in
PlanReleaseService.spec.ts for both structural.service.submitReview and
provider.service.submitReview to use rejects.toMatchObject, preserving the
expected Problem classes while also asserting the deterministic diagnostic code
lists: the structural case must include its validation diagnostic code, and the
provider case must include "polar/meter-missing".
- Around line 190-281: Split the combined “supports the explicit review, return,
schedule, abandon, publish, and supersede transitions” test into separate it
blocks, each covering one transition and retaining its existing assertions. Add
cases verifying every attempted transition from an abandoned release rejects
with InvalidPlanReleaseTransitionProblem, that abandon on a published release
has the expected result, and that updateDraft rejects with
PlanReleasePublishConflictProblem while publicationIntent is active; use the
existing abandon tests as context without duplicating unrelated setup.
In
`@packages/docs/src/content/docs/api/billing-core/src/classes/InMemoryPlanReleaseStore.md`:
- Line 28: Update the original TypeScript JSDoc for InMemoryPlanReleaseStore to
describe pendingEvents as in-memory and non-durable, removing the durable outbox
claim. Regenerate the API Markdown with pnpm docs:api:check, and do not edit the
generated Markdown directly.
In
`@packages/docs/src/content/docs/api/billing-core/src/classes/InvalidPlanReleaseScheduleProblem.md`:
- Line 8: packages/billing-core/src/libs/problems/PlanReleaseProblems.ts의
InvalidPlanReleaseScheduleProblem, InvalidPlanReleaseTransitionProblem,
OverlappingPlanEffectivePeriodProblem source JSDoc을 각 concrete Problem의 실제 역할에
맞게 수정하세요. 생성 문서는 직접 편집하지 말고 pnpm docs:api:check를 실행해 다음 문서를 갱신하세요:
packages/docs/src/content/docs/api/billing-core/src/classes/InvalidPlanReleaseScheduleProblem.md
(8-8),
packages/docs/src/content/docs/api/billing-core/src/classes/InvalidPlanReleaseTransitionProblem.md
(8-8),
packages/docs/src/content/docs/api/billing-core/src/classes/OverlappingPlanEffectivePeriodProblem.md
(8-8).
In
`@packages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseProviderCapabilityProblem.md`:
- Line 8: 공개 타입별 역할과 맞지 않는 공통 JSDoc 설명을 원본 TypeScript 선언에서 수정하세요.
PlanReleaseProviderCapabilityProblem은 provider capability preflight 실패 Problem,
PlanReleasePublishConflictProblem은 publication idempotency conflict Problem,
PlanReleaseTransitionedEvent는 구체적인 DomainEvent,
PlanReleaseValidationFailedProblem은 validation 실패 Problem으로 설명하고, 네 생성 문서 파일은 직접
수정하지 마세요. 변경 후
packages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseProviderCapabilityProblem.md:8,
packages/docs/src/content/docs/api/billing-core/src/classes/PlanReleasePublishConflictProblem.md:8,
packages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseTransitionedEvent.md:8,
packages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseValidationFailedProblem.md:8에
반영되도록 TypeDoc을 재생성하고 pnpm docs:api:check 및 문서 빌드로 검증하세요.
In
`@packages/docs/src/content/docs/api/billing-core/src/classes/StalePlanReleaseRevisionProblem.md`:
- Line 8: StalePlanReleaseRevisionProblem과 PlanEntitlementDefinition의 원본
TypeScript JSDoc을 API 정의에 맞게 갱신하세요. StalePlanReleaseRevisionProblem은
billing/stale-plan-release-revision revision 충돌 Problem으로,
PlanEntitlementDefinition은 plan id/version 참조와 entitlement discriminated union
체계를 설명하도록 수정하고, 생성 문서
packages/docs/src/content/docs/api/billing-core/src/classes/StalePlanReleaseRevisionProblem.md:8
및
packages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanEntitlementDefinition.md:10은
재생성으로 반영하세요. 이후 pnpm docs:api:check를 실행해 생성 문서 drift가 없는지 확인하세요.
In
`@packages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseValidationEvidence.md`:
- Line 10: The PlanReleaseService.submitReview documentation must distinguish
skipping ContractGraph re-validation from verifying snapshot binding. Update the
original TypeScript JSDoc for the relevant PlanRelease validation evidence type
to state that validation is not re-run but planVersionRef,
definitionFingerprint, draftRevision, graphVersion, snapshotId, and checkedAt
bindings are checked; regenerate the TypeDoc output, then validate with pnpm
docs:api:check and the documentation build.
In
`@packages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanTrialDefinition.md`:
- Line 10: PlanTrialDefinition과 PlanUsageTier의 공통 generic 설명을 각 타입의 실제 계약에 맞는 원본
TypeScript JSDoc으로 교체하세요. PlanTrialDefinition에는 trial 기간과 결제 수단 요구 여부를,
PlanUsageTier에는 meter key·단위 금액·사용량 상한을 설명하고 TypeDoc을 재생성하세요. 생성물인
packages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanTrialDefinition.md:10과
packages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanUsageTier.md:10은
직접 수정하지 말고, 변경 후 pnpm docs:api:check와 문서 빌드로 검증하세요.
🪄 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: f0efb578-4677-4099-8b97-f3becf25f55e
⛔ Files ignored due to path filters (2)
packages/problems-core/src/generated/problem-code-registry.tsis excluded by!**/generated/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (92)
.changeset/plan-release-lifecycle.mddocs/problem-code-registry.jsonpackages/billing-core/README.mdpackages/billing-core/package.jsonpackages/billing-core/src/index.tspackages/billing-core/src/libs/InMemoryPlanRegistry.tspackages/billing-core/src/libs/InMemoryPlanReleaseStore.tspackages/billing-core/src/libs/PlanRelease.tspackages/billing-core/src/libs/PlanReleaseService.tspackages/billing-core/src/libs/events/PlanReleaseTransitionedEvent.tspackages/billing-core/src/libs/problems/PlanReleaseProblems.tspackages/billing-core/src/tests/BillingProblems.spec.tspackages/billing-core/src/tests/InMemoryPlanRegistry.spec.tspackages/billing-core/src/tests/PlanReleaseService.spec.tspackages/billing-core/src/types.tspackages/create-croco-app/templates/spa-be-split/apps/api-server/src/tests/app.spec.tspackages/docs/src/content/docs/api/admin-core/src/classes/CreditOperationsValidationProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/DeterministicPlanReleaseImpactAnalyzer.mdpackages/docs/src/content/docs/api/billing-core/src/classes/InMemoryPlanReleaseStore.mdpackages/docs/src/content/docs/api/billing-core/src/classes/InvalidPlanReleaseScheduleProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/InvalidPlanReleaseTransitionProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/OverlappingPlanEffectivePeriodProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseProviderCapabilityProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/PlanReleasePublishConflictProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseService.mdpackages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseTransitionedEvent.mdpackages/docs/src/content/docs/api/billing-core/src/classes/PlanReleaseValidationFailedProblem.mdpackages/docs/src/content/docs/api/billing-core/src/classes/StalePlanReleaseRevisionProblem.mdpackages/docs/src/content/docs/api/billing-core/src/functions/createPlanVersionSemanticDiff.mdpackages/docs/src/content/docs/api/billing-core/src/functions/planReleaseCommandFingerprint.mdpackages/docs/src/content/docs/api/billing-core/src/functions/planVersionDefinitionFingerprint.mdpackages/docs/src/content/docs/api/billing-core/src/interfaces/PlanReleaseEventPublisher.mdpackages/docs/src/content/docs/api/billing-core/src/interfaces/PlanReleaseImpactAnalyzer.mdpackages/docs/src/content/docs/api/billing-core/src/interfaces/PlanReleaseStore.mdpackages/docs/src/content/docs/api/billing-core/src/interfaces/PlanReleaseValidator.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/CreatePlanDraftCommand.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanEntitlementDefinition.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanRelease.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseActor.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseEventDeliveryResult.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseImpactEstimate.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseImpactFact.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseImpactPreview.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseLifecycleEvent.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleasePublicationEvidence.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleasePublicationFailure.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleasePublicationIntent.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseReviewEvidence.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseServiceDependencies.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseState.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseStoreSaveOptions.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseTransitionCommand.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseTransitionRecord.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseValidationDiagnostic.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanReleaseValidationEvidence.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanTrialDefinition.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanUsageTier.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanVersionDefinition.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanVersionSemanticDiffField.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PlanVersionSemanticDiffRecord.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/PublishPlanReleaseCommand.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/SubmitPlanReviewCommand.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/SupersedePlanReleaseCommand.mdpackages/docs/src/content/docs/api/billing-core/src/type-aliases/UpdatePlanDraftCommand.mdpackages/docs/src/content/docs/api/events-core/src/classes/DomainEvent.mdpackages/docs/src/content/docs/api/metering-core/src/classes/BillableUsageJournalRequiredProblem.mdpackages/docs/src/content/docs/api/metering-core/src/classes/InMemoryBillableUsageJournal.mdpackages/docs/src/content/docs/api/metering-core/src/classes/MeterRegistry.mdpackages/docs/src/content/docs/api/metering-core/src/classes/MeteringService.mdpackages/docs/src/content/docs/api/metering-core/src/classes/RedisBillableUsageJournal.mdpackages/docs/src/content/docs/api/metering-core/src/interfaces/BillableUsageJournal.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/BillableUsageAppendResult.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/BillableUsageClaimOptions.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/BillableUsageEvent.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/BillableUsageFailure.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/BillableUsageJournalDiagnostics.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/BillableUsageJournalEntry.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/MeterDefinition.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredMetadata.mdpackages/docs/src/content/docs/api/metering-core/src/type-aliases/MeteredOptions.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/protocols-desktop/src/classes/DesktopWireSchemaProblem.mdpackages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopWireEnumDescriptor.mdpackages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopWireLiteralDescriptor.mdpackages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopWireObjectDescriptor.mdpackages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopWireSchemaContext.mdpackages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopWireSchemaDiagnostic.mdpackages/docs/src/content/docs/api/protocols-desktop/src/type-aliases/DesktopWireSourceLocation.mdpackages/docs/src/content/docs/api/protocols-rest/src/interfaces/ControllerMetadata.mdpackages/docs/src/content/docs/en/reference/problem-recovery-cookbook.mdpublic-api-surface.snapshot.json
dca0a93 to
b5fdf3a
Compare
Outcome
Plan versions now move through optimistic drafts, review, scheduling, publication, supersession, and abandonment while published definitions remain immutable. Review evidence is bound to the exact draft revision and
ContractGraphfingerprint, with deterministic structural/provider diagnostics, semantic diffs, impact facts, and estimates.Publication records intent before registry effects, reconciles ambiguous failures idempotently, prevents overlapping plan-family periods atomically, and emits durable transition events through an idempotent outbox. Open-ended versions derive a successor boundary so an older version cannot become effective again after a finite successor expires.
The publish-profile generated-app canary now models an actually unregistered route guard instead of a self-registering controller, preserving fail-closed DI bootstrap evidence after controllers became automatic providers.
Fixes #1539
Verification
pnpm --dir=packages/billing-core test— 152 tests passed.pnpm --filter @croco/billing-core typecheck,lint, andbuild— passed.pnpm --filter create-croco-app test— 136 tests passed; package typecheck and lint passed.pnpm create-croco-app:smoke production-app-starter— generated tests, typecheck, build, browser journeys, contracts, codegen, and DI graph verification passed.pnpm problem-registry:check— 560 discovered codes matched.pnpm public-api:checkandpnpm docs:api:check— passed.pnpm changeset-required:check -- --base origin/trunk --head HEAD— all affected publishable packages covered.pnpm check— 24/25 gates passed, 1 not applicable, 0 failed.Review gates
Residual risk
The included store and registry are in-memory reference implementations. Durable production adapters must preserve the documented compare-and-swap, atomic family-overlap, publication-intent, and idempotent outbox contracts.
Summary by CodeRabbit