Skip to content

Fix completed habits consuming the free cap (ORB-185) - #455

Open
thomasluizon wants to merge 4 commits into
mainfrom
fix/orb-185-free-cap-completed
Open

Fix completed habits consuming the free cap (ORB-185)#455
thomasluizon wants to merge 4 commits into
mainfrom
fix/orb-185-free-cap-completed

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Aug 7, 2026

Copy link
Copy Markdown
Owner

DEGRADED: same-vendor review

Implements ORB-185.

Summary

  • Excludes completed top-level habits from the free habit allowance in direct creation and onboarding.
  • Rechecks that allowance before unlogging a completed top-level task or clearing or extending an end date that reactivates a habit.
  • Rejects capped reactivation before mutating the tracked habit or its log.
  • Preserves the configured cap and exact refusal message for users with ten live habits.
  • Updates Astra's paygate explanation to name completed habits as excluded.

Scope choice

The allowance remains defined by PayGateService and is applied only when a completed top-level habit would become active. Sub-habits do not consume the top-level allowance. No IsDeleted clause was added because the repository's global query filter already excludes soft deleted habits.

Verification

  • Focused allowance and habit command tests: 76 passed
  • Orbit.Application.Tests: 2,980 passed
  • Orbit.Analyzers.Tests: 32 passed
  • Architecture map drift: clean locally and passing in CI
  • dotnet build Orbit.slnx: 0 errors
  • dotnet test: 5,599 passed

@thomasluizon

Copy link
Copy Markdown
Owner Author

Approach:

  1. Update the top level habit predicates in PayGateService and ApplyOnboardingCommand to exclude completed habits while relying on the existing global soft delete filter.
  2. Add focused PayGateService coverage using domain completion paths for finished one time tasks and recurring habits past their end date, while preserving the live cap, sub habit, soft delete, and Pro behavior.
  3. Extend onboarding coverage for completed existing habits so requested live habits are not trimmed incorrectly.
  4. Update the Astra paygate explanation to state that completed habits are excluded.

This keeps the fix at the two count sites instead of changing the entity or global query filter because completion is relevant to this allowance, while completed habits remain valid persisted records elsewhere.

@thomasluizon

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c65f70cd6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Orbit.Application/Common/PayGateService.cs
@thomasluizon

Copy link
Copy Markdown
Owner Author

DEGRADED: same-vendor review

Review verdict: clean after round 1. No Blocking or Non-blocking findings against the frozen rubric. This used a fresh Sol xhigh session; same-family bias is not eliminated and its magnitude is unmeasured.

@thomasluizon

Copy link
Copy Markdown
Owner Author

Current-head fix approach:

  • In LogHabitCommandHandler, call the existing CanCreateHabits allowance gate before mutating a completed top-level habit when an unlog would reactivate it.
  • In UpdateHabitCommandHandler, detect completed top-level habits whose cleared or extended end date would make them active, then run the same gate before Habit.Update.
  • Add one focused cross-command regression suite covering unlog and end-date reactivation at the cap, including assertions that the habit and log state remain unchanged after rejection.

This keeps the allowance definition in PayGateService, avoids duplicating cap logic, and stays within the existing file cap.

@thomasluizon

Copy link
Copy Markdown
Owner Author

CI drift plan update:

The direct IPayGateService constructor parameter changed the generated handler architecture map. I will move that dependency into the existing LogHabitServices group, wire it in ServiceCollectionExtensions.AiServices.cs, and keep the handler behavior and focused regressions unchanged. This restores the existing architecture shape and uses the eighth and final allowed file.

@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

@thomasluizon

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: eaec4b0845

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@thomasluizon

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eaec4b0845

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ClearEndDate: request.ClearEndDate,
ScheduledReminders: opts.ScheduledReminders,
Emoji: request.Emoji));
var result = await HabitReactivationAllowance.ExecuteAsync(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate reactivation in the registered update_habit tool

When a free user already has 10 active root habits and asks Astra or MCP to clear or extend the end date of a completed recurring root, this gate is never reached: UpdateHabitTool.ExecuteAsync calls habit.Update(updateParams) directly, and chat persistence subsequently saves the reopened habit, leaving 11 active roots. Fresh evidence after the earlier fix is this separate registered update_habit mutation path; route it through the same allowance check or command.

Useful? React with 👍 / 👎.

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.

1 participant