Repository navigation
Make sub-habits free across every creation path (ORB-231) - #824
Conversation
There was a problem hiding this comment.
Important
Free sub-habit creation also exposes Pro-only slip alerts through the dedicated endpoint. Preserve that independent entitlement check before merging.
Reviewed changes Reviewed all five creation paths, entitlement removal, feature configuration, migration artifacts, and regression coverage.
- Creation access: Removes the sub-habit paywall from dedicated, inline, bulk, duplicate, and Astra creation while retaining existing root-ceiling and depth behavior.
- Feature migration: Makes
sub_habitsplan-independent and removes the obsolete gate configuration, with rollback operations and matching model snapshots. - Regression coverage: Adds Free/Pro creation and configuration tests; 165 focused Application tests and 19 focused Infrastructure tests passed. A temporary unit test reproduced the slip-alert bypass and was removed afterward.
- Consumer compatibility: Checked the sibling config schema, which already accepts nullable plan requirements and does not require the removed configuration key.
gpt-6.1-sol | 𝕏
There was a problem hiding this comment.
No new issues found.
Reviewed changes Reviewed 6bd8f346 since the prior Pullfrog review at dfe0dcbe, with the complete PR diff as context; the resolved slip-alert finding is fixed, and no new Critical or High issues remain.
- Preserved paid alerts: Added a shared constructed-habit check before persistence in dedicated child, root/inline, and Astra creation, enforcing
CanUseSlipAlertswithout restoring the sub-habit paywall. - Expanded regression coverage: Added Free/Pro cases for dedicated, inline, and explicit/default Astra alerts, asserting free failures persist nothing and Pro requests retain alerts. Confirmed ordinary creation remains available across all five paths, while bulk and duplicated habits keep alerts disabled.
- Verified focused suites: Passed 173 Application tests and 19 Infrastructure tests with no failures or skips. The full test suite and live deployment checks were not rerun in this review.
gpt-6.1-sol | 𝕏
|
…e sub-habits and referral Pro days (#746) (#829) * fix: preserve yearly streak gap repairs through recalculation (#818) * fix: preserve yearly streak gap repairs through recalculation * fix: isolate yearly streak repair history window (cherry picked from commit 90c5320) * fix: expose discounted Stripe billed amount per period (#819) * fix: expose discounted Stripe billed amount per period * fix: isolate optional recurring Stripe billing preview (cherry picked from commit 0460a54) * Make sub-habits free across every creation path (ORB-231) (#824) * feat: make sub-habits available to every plan (ORB-231) * test: track free sub-habits in migration model expectations * fix: preserve Pro slip alerts when creating free sub-habits (cherry picked from commit c9d22a6) * Grant atomic referral Pro days (ORB-22) (#823) * feat: grant atomic referral Pro days (ORB-22) * fix: preserve referral transaction and billing context * fix: preserve bonus Pro access across provider changes (cherry picked from commit 7b4e9af) * test: retain combined migration assertions after main carry * fix: include one-time coupons in billed amount preview (#830) (cherry picked from commit 377eca5)
* feat: make sub-habits available to every plan (ORB-231) * test: track free sub-habits in migration model expectations * fix: preserve Pro slip alerts when creating free sub-habits (cherry picked from commit c9d22a6)




Free users could not create sub-habits through the dedicated endpoint, inline creation, bulk creation, duplication, or Astra. Remove the server gate from all five paths so both plans can create sub-habits while retaining the existing depth validation and root-habit ceiling.
Closes thomasluizon/orbit-tickets#237. Implements ORB-231.
Intended approach
CanCreateSubHabitsfromPayGateServiceandIPayGateService, removeAppConfigKeys.SubHabitsProOnly, and remove each call and failure branch in the four habit commands andCreateHabitTool. Delete the dedicated command's unused pay-gate dependency.sub_habits.PlanRequirementinOrbitDbContextseed data. ScaffoldMakeSubHabitsFreethroughOrbitDbContextFactory, keep its Designer and snapshot, and add the non-model-seeded config deletion and matching rollback. Deleting enforcement prevents the old default from restricting environments without a config row.SubHabitPlanAccessTests, which uses the realPayGateServicefor all five paths and both plans. Check child ownership and parent links, copied descendants, saved output, depth-six rejection, the root ceiling, and the interface surface. ExtendConfigControllerTestsover the real seeded model and feature resolver; test both migration directions inMakeSubHabitsFreeMigrationTests. ExtendFeatureFlagAccountsMigrationTeststo include the new migration and assert its exact seed update in the current model.Assumptions
thomasluizon/ticket-237-subhabits-freebranch, rather than creating a branch with the repository's usual prefix, as the work order explicitly requires.Placed the shared check in
Habits/Servicesrather than expandingIPayGateService; it evaluates constructed habits using the existing entitlement.Test evidence
Before changing implementation, the five existing success tests passed with the restriction present:
Observed: 5 passed, 0 failed, 0 skipped. They substituted a successful sub-habit gate and therefore did not exercise the free-plan restriction.
Before removing the gate:
dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~SubHabitPlanAccessTestsObserved: 8 failed, 6 passed, 0 skipped. All five free-plan creation cases failed with
This is a Pro feature.; the free depth and child-at-ceiling cases were blocked by the same gate, and the interface assertion found the old member. All five Pro creation cases and Pro depth rejection passed. These new tests exercise the real service with its compiled defaults.Before changing the feature seed:
dotnet test tests/Orbit.Infrastructure.Tests --filter FullyQualifiedName~GetConfig_SubHabitsAreFree_PreservesLimitsObserved: 2 failed, 0 passed, 0 skipped. The free account received
enabled: false; the Pro account received a string plan requirement rather than null.After gate deletion and seed change, before adding the hand-written migration operations:
Observed: 9 passed, 2 failed, 0 skipped. Both migration tests found only one operation, catching the missing config deletion and rollback insertion. After completing the migration, the same filter with
--no-buildpassed all 11 tests. The application handler/tool/service filter passed all 165 focused tests after gate deletion.The first full Infrastructure run (
dotnet test tests/Orbit.Infrastructure.Tests) found one required model-expectation update:FeatureFlagAccountsMigrationTests.TargetModel_PreservesRedesignexpected 12 operations and eight recent migrations. The new feature seed adds a thirteenth operation and a ninth migration. Updated the test to assert exactly oneUpdateDataOperationforAppFeatureFlags.sub_habits.PlanRequirement = null, and list the new migration. No production changes were needed. The focused command below then passed 14 tests with no failures or skips:Final verification, each command exited 0:
dotnet build Orbit.slnxdotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~SubHabitPlanAccessTestsdotnet test tests/Orbit.Domain.Testsdotnet test tests/Orbit.Application.Testsdotnet test tests/Orbit.Infrastructure.TestsThe final build and full Infrastructure run were repeated after the model-expectation-only follow-up commit. Domain and Application results are from the same production code. Both commits passed the normal formatting, dash, timeless prose, root-allowlist, and suppression hooks. Source searches leave
CanCreateSubHabits/SubHabitsProOnlyonly in migration history; the removed paywall message is absent fromsrc/. No new warning suppressions or narration comments were added.Before implementation, ran:
dfe0dcbe: 14 passed.dedicated,astra-explicit, andastra-defaultrequests incorrectly succeeded.Broader verification:
dotnet build Orbit.slnxdotnet test tests/Orbit.Domain.Testsdotnet test tests/Orbit.Application.Testsdotnet test tests/Orbit.Infrastructure.TestsNo skipped tests. OpenAPI regenerated without changes. All commit hooks passed.
External interface evidence
The new migration tests obtain
UpOperationsandDownOperationsfrom the realMakeSubHabitsFreemigration through EF Core 10.0.13; there are no operation fixtures. The incomplete scaffold's actual failed assertion printed anUpdateDataOperationwithTable = AppFeatureFlags,KeyColumns = {Key},KeyValues = {{sub_habits}},Columns = {PlanRequirement}, andValues = {{null}}for Up or{{Pro}}for Down. The completed migration tests exercise the actual deletion and insertion operations and their key/column/value arrays. Re-derive these observations with the migration test filter above. No production code begins reading an external response field.Migration
20261020030817_MakeSubHabitsFree:Scaffold command, run from
src/Orbit.Api:dotnet ef migrations add MakeSubHabitsFree --project ../Orbit.Infrastructure --startup-project . --context OrbitDbContext --verboseThe tool reported
Using DbContext factory 'OrbitDbContextFactory'. No live database was contacted or migrated. Removed the new Designer's generated warning pragma to meet the ticket's zero-new-suppression requirement.Manual steps
Release API(.github/workflows/release.yml) frommainwithenvironment=productionandbranch=main. Startup applies the migration; no manual SQL, environment key, or backfill is required.GET /api/configand confirmfeatures.sub_habitshasenabled: trueandplanRequirement: null, with the existing limits retained apart from the deleted obsolete gate key. From a free account, create a child through the REST endpoint and Astra and confirm both requests succeed and persist it. These live checks belong to release verification and were not run by this worker.None for the owner. The run carries this change to api
redesign/mainthrough the#746carry; it reaches production in the go-live runbook's production API release. After that release the run verifies ordinary free sub-habit creation succeeds, free creation with alerts returnsPAY_GATEwithout creating habits, and Pro creation saves alerts. No new configuration keys, secrets, manual migrations, or backfills are required.