[Analytics] Add Composite Daily Focus Score & Distraction Ratio Evaluator in src/lib/analytics/focus-score.ts

Open Beginner friendly
#759 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
85/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, typescript
Domain
analytics

Research direction

Create src/lib/analytics/focus-score.ts and tests/focus-score.test.ts; start by checking the project's TypeScript configuration and existing test conventions. Implement the specified interface, scoring, tiers, and validation, then cover the listed edge cases with node:test and node:assert/strict. Done when strict TypeScript checking passes and the tests cover the acceptance criteria.

Written by the indexing model from the issue text.

Description

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

In PACT OS, end-of-day reflection debriefs provide users with a holistic view of their productivity. Rather than looking only at total raw hours, users benefit from a single weighted Focus Score (0–100) that balances deep work volume, shallow work volume, and context-switching interruption penalties.


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

📐 Specification & Interface Contracts
export interface DailyFocusMetrics {
  deepWorkMinutes: number;
  shallowWorkMinutes: number;
  interruptionCount: number;
  targetDeepWorkMinutes?: number; // default: 240 (4 hours)
}

export type FocusTier = 'optimal' | 'productive' | 'fragmented' | 'unfocused';

export interface DailyFocusAssessment {
  /** Composite score from 0 to 100 (integer) */
  score: number;
  /** Percentage of total work time spent in deep work (0.0 to 1.0, 2 decimals) */
  deepWorkRatio: number;
  /** Penalty points deducted due to interruptions */
  interruptionPenalty: number;
  /** Qualitative performance tier */
  tier: FocusTier;
  /** Brief takeaway summary */
  summary: string;
}

export function calculateDailyFocusScore(
  metrics: DailyFocusMetrics
): DailyFocusAssessment;
Scoring Rules & Formulas:
  1. Total Minutes & Deep Ratio:
    $$\text{totalMinutes} = \text{deepWorkMinutes} + \text{shallowWorkMinutes}$$
    $$\text{deepWorkRatio} = \text{totalMinutes} === 0 ? 0.0 : \text{roundTo2Decimals}(\text{deepWorkMinutes} / \text{totalMinutes})$$
  2. Component Weights:
    • Volume Score (max 70 pts):
      $$\text{volumeScore} = \min(70, (\text{deepWorkMinutes} / \text{targetDeepWorkMinutes}) \times 70)$$
    • Quality Bonus (max 30 pts):
      $$\text{qualityBonus} = \text{deepWorkRatio} \times 30$$
    • Interruption Penalty (capped at 25 pts):
      $$\text{interruptionPenalty} = \min(25, \text{interruptionCount} \times 3)$$
  3. Composite Score:
    $$\text{score} = \max(0, \min(100, \text{Math.round}(\text{volumeScore} + \text{qualityBonus} - \text{interruptionPenalty})))$$
  4. Tiers:
    • score >= 85: 'optimal'
    • 70 <= score < 85: 'productive'
    • 50 <= score < 70: 'fragmented'
    • score < 50: 'unfocused'
  5. Validation: Throws TypeError if any field is not a finite number, and RangeError if any metric is negative or targetDeepWorkMinutes <= 0.

🧪 Acceptance Criteria
  • TypeScript strict mode passes with 0 errors (npx tsc --noEmit).
  • Uses extensionless import in test file (import { calculateDailyFocusScore } from '../src/lib/analytics/focus-score').
  • Unit tests cover 0 minutes, hitting exact target, excessive interruptions penalty clamp, all 4 performance tiers, and invalid parameters.
  • 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.