January 3rd, 2026
Today wasn’t about writing UI or backend code. It was about finally locking the mental model of how CommitT should actually enforce things in the real world. We started from a simple question: “How do we integrate this task schema with the frontend without breaking enforcement?” And from there, everything unfolded.1. The Starting Point: The Task Schema
At the center of everything was this realization: A task is not an idea, not a habit, not a rule. A task is:“During this exact time window, these exact conditions must hold.”That’s it.
- Time is stored as absolute timestamps (
start_at,due_at). - Conditions are metrics like location, steps, proofs, etc.
2. The Big Confusion: Time Slots vs. Tasks
At first, it felt natural to say: “Why not store multiple time slots inside one task?” But the backend reality killed that idea quickly. If a task has multiple days and multiple time slots, then at runtime, the backend has to:- Loop days
- Loop slots
- Compare weekdays
- Check overlaps
- Scan logs
The Unlock
The moment we reframed it as: One time slot = One task Everything snapped into place. Now the backend can simply ask: What tasks exist right now? And answer it with one query:3. Frontend vs. Backend Optimization (The “Ah-Ha” Moment)
This led to a deeper understanding: Backend logic should never be exactly replicated in the frontend, and frontend presentation should never dictate backend storage. Why? Because they optimize for different things:- Frontend optimizes for human abstraction and usability.
- Backend optimizes for indexing, querying, and absolute truth.
The Example: Time Slots
In our app, we allow the user to add multiple time slots for a given task because that makes sense to a human (“I do usage blocking in the morning and evening”).
- Frontend sees “One Rule with Many Slots”.
- Zustand translates that intent.
- Backend receives “Many Atomic Tasks”.
4. Where “Days” Actually Live
Days like Monday, Tuesday, or Wednesday do not live inside tasks. They live:- In the UI
- In the recurring rule
- During task generation
5. The Minutes-Since-Day-Start Idea
Instead of storing times as strings, we store time slots as constants:- 2:00 PM →
840 - 10:00 PM →
1320
“Every Monday, from minute 840 to 1320”Then Convex combines:
Today’s Date + Slot Minutes + User Timezone → Real Timestamp.
6. Planning vs. Enforcement
We also separated the Planner from the Enforcer.App Blocking (Android Implementation)
For Android app blocking, we do not need a Convex server or cron jobs running continuously. It happens completely event-driven at the client side:- App Launch: When the user launches an app, the local service checks the condition.
- Instant Check: “Is this app allowed right now?”
- Action: Block or Allow immediately. Backend is only queried if local state needs synchronization, but the blocking mechanism is lightweight and instant.
Verification & Penalties (Server-Driven)
- Must be time-based.
- Must happen even if the app is closed.
- Convex handles the schedule.
7. The Execution Flow: Planner, Verifier, and Penalty
This is the exact flow that makes the system consistent, scalable, and secure.Daily Lifecycle (Per User)
1. Start of Day (The Planner)
At the beginning of each day (or via a rolling window), Convex runs a Daily Planner for the user.- It senses: What day is it? (e.g., Monday).
- It checks: What recurring rules apply today?
- It sees: How many verification-based tasks does this user have?
2. User Perspective (During the Slot)
From the user’s POV:- They know that in these specific time slots (e.g., 2 PM - 4 PM), they are “on the hook”.
- They need to provide proof (GPS location, photo, etc.) via the client side.
- The client collects this raw data throughout the slot.
3. At Slot End (The Verifier)
At the end of the time slot, our Convex function wakes up.- It gathers those raw data/proofs submitted by the client.
- It calculates a confidence score based on the quality of proofs.
- It decides whether to apply a penalty or mark the task as complete.
Proof Verification & Penalty Logic
This part is critical. We don’t just “fail” a user. We follow a strict accountability ladder. The Flow:- Collect Proofs: During the slot, the user uploads proofs (e.g., gym selfies, screen time screenshots). These are stored but not fully judged yet.
- Validate: At the end of the slot, the backend aggregates these proofs.
- Decide:
- High Confidence Score: Task marked Complete.
- Low/No Confidence: Task marked Failed.
- Mercy (Penalty Waiver): If failed, check if a “Penalty Waiver” is available.
- If Yes: Give a lifeline (e.g., “Submit explanation within 1 hour”).
- If No: BOOM. Apply Penalty.
Important Refinements
- Refinement 1: We use a rolling planner (Today + Tomorrow) rather than just “Midnight” to handle server restarts or timezone shifts safely.
- Refinement 2: We schedule verification, not “failure”. The penalty is a result of the verification logic, not a scheduled event.
One Line Summary: Convex plans the day, wakes up at the right moments, evaluates proofs collected from the client, offers mercy once, then enforces consequences.
Refined System in Action
After considering critique and suggestions from various users, we refined the UI to match this mental model while keeping it simple.Final Division of Labor
This clarified how me and Atheeq work together: Maajith (Me)- UI & Flow
- State (Zustand)
- Bending messy user input into clean payloads
- Backend Truth
- Enforcement
- Scheduling & Penalties
Final Takeaway: Tasks are atomic. Rules generate tasks. Convex owns time. Runtime only queries truth.