[Habits] Add Habit Strength Decay & Half-Life Calculator in src/lib/habits/habit-decay.ts

Open Beginner friendly
#758 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
88/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, typescript
Domain
backend, testing

Research direction

Create src/lib/habits/habit-decay.ts and tests/habit-decay.test.ts as specified. Start by checking the project’s TypeScript configuration and existing node:test tests, then run the requested test suite and npx tsc --noEmit. Done means the specified decay, floor, status, and validation cases pass with no external dependencies.

Written by the indexing model from the issue text.

Description

area:habits difficulty:easy enhancement good first issue
🎯 Feature Overview & Context

In PACT OS, users build habit strength through consistent streaks. When check-ins are missed, habits do not instantly reset to zero in human psychology; instead, neurological pathways experience gradual decay modeled by an exponential half-life ($S(t) = S_0 \cdot 2^{-t / t_{1/2}}$). This utility calculates residual habit strength, retention percentage, and status tier to combat the demoralizing "all-or-nothing" psychological pitfall.


🧩 Scope & Deliverables
  1. Module Implementation: Create src/lib/habits/habit-decay.ts
  2. Unit Test Suite: Create tests/habit-decay.test.ts using native node:test and node:assert/strict.

📐 Specification & Interface Contracts
export interface HabitDecayOptions {
  /** Half-life in days before strength decays by 50% (default: 7) */
  halfLifeDays?: number;
  /** Minimum residual strength floor between 0 and 100 (default: 0) */
  minStrengthFloor?: number;
}

export type HabitDecayStatus = 'solid' | 'fading' | 'at_risk' | 'dormant';

export interface HabitDecayAssessment {
  /** Current calculated strength score (0.0 to 100.0, rounded to 1 decimal) */
  currentStrength: number;
  /** Ratio of original strength retained (0.0 to 1.0, 4 decimals) */
  retentionFraction: number;
  /** Categorized retention status tier */
  status: HabitDecayStatus;
  /** Guidance recommendation */
  recommendation: string;
}

export function calculateHabitStrengthDecay(
  initialStrength: number,
  daysSinceLastCheckIn: number,
  options?: HabitDecayOptions
): HabitDecayAssessment;
Calculation & Decay Rules:
  1. Decay Formula:
    $$\text{rawStrength} = \text{initialStrength} \times 2^{-\frac{\text{daysSinceLastCheckIn}}{\text{halfLifeDays}}}$$
  2. Floor Clamping:
    $$\text{currentStrength} = \text{roundTo1Decimal}(\max(\text{minStrengthFloor}, \min(\text{initialStrength}, \text{rawStrength})))$$
  3. Retention Fraction:
    $$\text{retentionFraction} = \text{initialStrength} === 0 ? 0.0 : \text{roundTo4Decimals}(\text{currentStrength} / \text{initialStrength})$$
  4. Status Tiers:
    • currentStrength >= 80: 'solid' (e.g. "Habit neural pathway is well-preserved.")
    • 50 <= currentStrength < 80: 'fading' (e.g. "Strength is fading. A quick check-in will restore momentum.")
    • 20 <= currentStrength < 50: 'at_risk' (e.g. "High risk of habit drop-off. Initiate a two-minute comeback.")
    • currentStrength < 20: 'dormant' (e.g. "Habit has become dormant. Re-anchor with a tiny trigger.")
  5. Validation:
    • Throws TypeError if initialStrength or daysSinceLastCheckIn is not a finite number.
    • Throws RangeError if initialStrength < 0 or > 100, daysSinceLastCheckIn < 0, halfLifeDays <= 0, or minStrengthFloor < 0 or > 100.

🧪 Acceptance Criteria
  • TypeScript strict mode passes with 0 errors (npx tsc --noEmit).
  • Uses extensionless import in test file (import { calculateHabitStrengthDecay } from '../src/lib/habits/habit-decay').
  • Unit tests cover 0 days elapsed (100% retention), exact half-life boundary (50% retention), long periods, min strength floor, and boundary errors.
  • Zero external dependencies added.
Dominant language
TypeScript
Stars
5
Forks
7
Avg merge
1d 16h
Merged PRs (30d)
79

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from TheVicky1/Pact_OS

All issues in TheVicky1/Pact_OS

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.