From 9897d2cd09caab6686f80f9f72968fd3ca192361 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Wed, 1 Apr 2026 01:05:25 -0700 Subject: [PATCH] docs(todos): standardize all TODOs with running numbers and delegatable instructions Replace ad-hoc AGENTIC-N comments with standardized TODO-NNN format across the entire codebase. Each TODO has: - Running number (TODO-001 through TODO-011) - Priority level (high/medium/low) - Phase reference (0, A.1, A.4, B, cleanup) - Clear step-by-step instructions an AI agent can follow TODO index: TODO-001: Kill switch maintenance banner (providers.tsx) TODO-002: Feedback button in settings page TODO-003: Accessibility focus trap for modals TODO-004: Clone routine template instead of mutating in-place TODO-005: Wire real LLM enrichment for context messages TODO-006: Centralize backend URL configuration TODO-007: MCP tool integration tests (common-plat) TODO-008: Wire trackEvent() calls into routes + components TODO-009: Unit tests for AI context generation TODO-010: Import PRODUCT_ID from product-config (5 route files) TODO-011: Wire error boundary to telemetry Added consolidated TODO Index table at top of AGENTIC_AI_ROADMAP.md for agent scanning. 219 backend tests pass, no code changes. --- backend/src/lib/ai-context.ts | 13 ++++++-- backend/src/lib/telemetry-events.ts | 9 ++++++ backend/src/modules/households/routes.ts | 3 ++ backend/src/modules/routines/routes.ts | 14 ++++++-- backend/src/modules/shared-timers/routes.ts | 3 ++ backend/src/modules/timers/routes.ts | 4 +++ backend/src/modules/webhooks/routes.ts | 3 ++ docs/AGENTIC_AI_ROADMAP.md | 36 +++++++++++++++++---- web/src/app/error.tsx | 6 +++- web/src/app/providers.tsx | 13 +++++--- web/src/lib/context-messages.ts | 9 ++++-- web/src/lib/telemetry-events.ts | 7 ++++ 12 files changed, 101 insertions(+), 19 deletions(-) diff --git a/backend/src/lib/ai-context.ts b/backend/src/lib/ai-context.ts index ae7883a..0a4de95 100644 --- a/backend/src/lib/ai-context.ts +++ b/backend/src/lib/ai-context.ts @@ -58,9 +58,16 @@ export interface ContextMessageResult { // ── LLM enrichment (extraction-service or ollama-client) ── -// TODO(AGENTIC-6): Replace this stub with a real LLM call via -// @bytelyst/extraction client (timer-context task) or @bytelyst/ollama-client. -// For now we build the prompt and return a simulated enriched message. +// TODO-005: Wire real LLM enrichment for context messages +// Priority: high | Phase: A.4 +// Replace the stub below with a real LLM call. Two options: +// Option A: @bytelyst/extraction client — POST to extraction-service /api/extract +// with task='timer-context'. Requires creating a new extraction task type in +// learning_ai_common_plat/services/extraction-service/src/modules/extract/. +// Option B: @bytelyst/ollama-client — call Ollama directly with buildPrompt(). +// Simpler, no extraction-service dependency, but no task abstraction. +// The prompt is already built by buildPrompt() below. Just replace the fetch stub +// with a real client call. Keep the 5s timeout and null-return-on-error pattern. async function llmEnrich(input: ContextMessageInput): Promise { // Only attempt if extraction service URL is configured const extractionUrl = config.EXTRACTION_SERVICE_URL; diff --git a/backend/src/lib/telemetry-events.ts b/backend/src/lib/telemetry-events.ts index 2f871b2..ab07c45 100644 --- a/backend/src/lib/telemetry-events.ts +++ b/backend/src/lib/telemetry-events.ts @@ -3,6 +3,15 @@ * * Centralised here so backend routes and web components can reference * a single source of truth for event names (Phase 0.5). + * + * TODO-008: Wire trackEvent() calls into backend routes + * Priority: medium | Phase: B + * These constants are defined but not yet imported anywhere. Wire them in: + * - agent-actions/routes.ts: AGENT_INBOX_ACTION_APPROVED on approve, + * AGENT_INBOX_ACTION_REJECTED on reject, AGENT_INBOX_BATCH_APPROVED on batch + * - server.ts context-message route: AI_CONTEXT_ENRICHED when source='llm', + * AI_CONTEXT_FALLBACK_USED when source='keyword' or 'generic' + * - Use: import { bufferEvent } from './telemetry.js' then bufferEvent(EVENT_NAME, { ...metadata }) */ // ── MCP ─────────────────────────────────────────────────────── diff --git a/backend/src/modules/households/routes.ts b/backend/src/modules/households/routes.ts index cb95c82..b11253b 100644 --- a/backend/src/modules/households/routes.ts +++ b/backend/src/modules/households/routes.ts @@ -30,6 +30,9 @@ import { type HouseholdInvite, } from './types.js'; +// TODO-010: Import PRODUCT_ID from product-config instead of hardcoding +// Priority: low | Phase: cleanup +// Replace this line with: import { PRODUCT_ID } from '../../lib/product-config.js'; const PRODUCT_ID = 'chronomind'; function isAdmin(household: HouseholdDoc, userId: string): boolean { diff --git a/backend/src/modules/routines/routes.ts b/backend/src/modules/routines/routes.ts index 43f012f..ae27d4d 100644 --- a/backend/src/modules/routines/routes.ts +++ b/backend/src/modules/routines/routes.ts @@ -24,6 +24,9 @@ import { type RoutineDoc, } from './types.js'; +// TODO-010: Import PRODUCT_ID from product-config instead of hardcoding +// Priority: low | Phase: cleanup +// Replace this line with: import { PRODUCT_ID } from '../../lib/product-config.js'; const PRODUCT_ID = 'chronomind'; export async function routineRoutes(app: FastifyInstance) { @@ -154,8 +157,15 @@ export async function routineRoutes(app: FastifyInstance) { } const now = new Date().toISOString(); - // TODO(AGENTIC-5): When starting from a template, consider cloning instead of - // mutating the template directly. For now we transition in-place. + // TODO-004: Clone template instead of mutating in-place + // Priority: medium | Phase: A.1 + // When routine.isTemplate is true: + // 1. Create a NEW RoutineDoc (crypto.randomUUID() for id) with isTemplate=false + // 2. Copy all fields from the template into the clone + // 3. Set the clone's status to 'active', startedAt to now, first step to 'active' + // 4. Leave the original template unchanged (status stays 'template') + // 5. Return the new clone, not the template + // This lets users reuse templates multiple times without losing the original. const result = await repo.updateRoutine( id, auth.sub, diff --git a/backend/src/modules/shared-timers/routes.ts b/backend/src/modules/shared-timers/routes.ts index b75c056..fc6765f 100644 --- a/backend/src/modules/shared-timers/routes.ts +++ b/backend/src/modules/shared-timers/routes.ts @@ -25,6 +25,9 @@ import { type SharedTimerDoc, } from './types.js'; +// TODO-010: Import PRODUCT_ID from product-config instead of hardcoding +// Priority: low | Phase: cleanup +// Replace this line with: import { PRODUCT_ID } from '../../lib/product-config.js'; const PRODUCT_ID = 'chronomind'; async function requireMembership(householdId: string, userId: string) { diff --git a/backend/src/modules/timers/routes.ts b/backend/src/modules/timers/routes.ts index a070d60..0993bc2 100644 --- a/backend/src/modules/timers/routes.ts +++ b/backend/src/modules/timers/routes.ts @@ -27,6 +27,10 @@ import { type FreeSlot, } from './types.js'; +// TODO-010: Import PRODUCT_ID from product-config instead of hardcoding +// Priority: low | Phase: cleanup +// Replace this line with: import { PRODUCT_ID } from '../../lib/product-config.js'; +// Same fix needed in: routines/routes.ts, households/routes.ts, webhooks/routes.ts, shared-timers/routes.ts const PRODUCT_ID = 'chronomind'; export async function timerRoutes(app: FastifyInstance) { diff --git a/backend/src/modules/webhooks/routes.ts b/backend/src/modules/webhooks/routes.ts index 57677b3..7d5f82f 100644 --- a/backend/src/modules/webhooks/routes.ts +++ b/backend/src/modules/webhooks/routes.ts @@ -10,6 +10,9 @@ import { dispatchEvent } from './dispatcher.js'; import { extractAuth } from '../../lib/auth.js'; import { BadRequestError } from '@bytelyst/errors'; +// TODO-010: Import PRODUCT_ID from product-config instead of hardcoding +// Priority: low | Phase: cleanup +// Replace this line with: import { PRODUCT_ID } from '../../lib/product-config.js'; const PRODUCT_ID = 'chronomind'; export async function webhookRoutes(app: FastifyInstance) { diff --git a/docs/AGENTIC_AI_ROADMAP.md b/docs/AGENTIC_AI_ROADMAP.md index f88a10c..f1c21d3 100644 --- a/docs/AGENTIC_AI_ROADMAP.md +++ b/docs/AGENTIC_AI_ROADMAP.md @@ -8,6 +8,28 @@ --- +## Open TODO Index + +> **For AI agents:** Scan this table, pick the next unresolved TODO by priority, and address it. +> Search the codebase for `TODO-NNN` to find the in-code comment with full instructions. +> After completing a TODO, remove it from this table and mark the corresponding roadmap checkbox. + +| TODO | Priority | Phase | File(s) | Summary | +|------|----------|-------|---------|---------| +| **TODO-001** | medium | 0 | `web/src/app/providers.tsx` | Kill switch maintenance banner — create ``, set React state when `checkKillSwitch()` returns `disabled=true`, disable timer creation buttons | +| **TODO-002** | medium | 0 | `web/src/app/(app)/settings/page.tsx` (create) | Wire feedback button into settings page (or floating FAB) using `feedbackClient` from `web/src/lib/feedback.ts` | +| **TODO-003** | medium | 0 | `web/src/components/CreateTimerModal.tsx`, `web/src/components/AlarmOverlay.tsx` | Apply `@bytelyst/accessibility` focus trap + screen reader announcements. Ensure `--cm-*` color tokens meet WCAG AA contrast | +| **TODO-004** | medium | A.1 | `backend/src/modules/routines/routes.ts` | Clone template into new RoutineDoc instead of mutating in-place. Create new doc with `crypto.randomUUID()`, leave original template unchanged | +| **TODO-005** | high | A.4 | `backend/src/lib/ai-context.ts` | Replace extraction-service stub with real LLM call. Option A: `@bytelyst/extraction` client with `timer-context` task. Option B: `@bytelyst/ollama-client` directly | +| **TODO-006** | low | A.4 | `web/src/lib/context-messages.ts` | Centralize backend URL — create `getBackendUrl()` in `product-config.ts` instead of raw `NEXT_PUBLIC_CHRONOMIND_BACKEND_URL` env var | +| **TODO-007** | medium | A.3 | `learning_ai_common_plat/services/mcp-server/` | Add integration tests for 5 new ChronoMind MCP tools (reschedule, availability, routine start, agent-actions list, agent-actions approve) | +| **TODO-008** | medium | B | `backend/src/lib/telemetry-events.ts`, `web/src/lib/telemetry-events.ts` | Wire `trackEvent()` / `bufferEvent()` calls into routes and components using the defined telemetry constants. See in-code comments for specific call sites | +| **TODO-009** | medium | A.4 | `backend/src/lib/ai-context.ts`, `web/src/lib/context-messages.ts` | Add unit tests for `generateContextMessage()` (backend) and `fetchEnrichedMessage()` (web). Test keyword fallback, LLM enrichment, generic fallback, and error paths | +| **TODO-010** | low | cleanup | `backend/src/modules/timers/routes.ts`, `routines/routes.ts`, `households/routes.ts`, `webhooks/routes.ts`, `shared-timers/routes.ts` | Replace `const PRODUCT_ID = 'chronomind'` with `import { PRODUCT_ID } from '../../lib/product-config.js'` in all 5 files | +| **TODO-011** | low | cleanup | `web/src/app/error.tsx` | Wire error boundary to telemetry — `trackEvent('app.error_boundary', { message, digest })` and optionally `@bytelyst/diagnostics-client` | + +--- + ## Current State Summary | Layer | Status | Key Files | @@ -103,13 +125,13 @@ These proxy to `chronomind-backend` (port 4011) via `chronomind-client.ts`. - [x] `web/src/lib/feedback.ts` — integrate `@bytelyst/feedback-client` (commit: f3e14e2) - `createFeedbackClient({ baseUrl, productId, getAccessToken })` - [ ] Add feedback button to settings page (or floating FAB) (commit: ) - - TODO(AGENTIC-3): Wire feedback button into settings page UI + - TODO-002: Wire feedback button into settings page using `feedbackClient` from `web/src/lib/feedback.ts` ### 0.3 — Accessibility Package (Web) - [x] Add `@bytelyst/accessibility` to web/package.json (commit: f3e14e2) - [ ] Integrate helpers into existing modals (commit: ) - - TODO(AGENTIC-4): Apply focus trap + screen reader announcements to CreateTimerModal, AlarmOverlay + - TODO-003: Apply `@bytelyst/accessibility` focus trap + screen reader to CreateTimerModal, AlarmOverlay - Ensure all `--cm-*` color tokens meet WCAG AA contrast ### 0.4 — Feature Flags for New Features (Backend) @@ -141,8 +163,8 @@ These proxy to `chronomind-backend` (port 4011) via `chronomind-client.ts`. ### Phase 0 Exit Criteria - [x] Kill switch client initialized on web app startup (f3e14e2) -- [x] Feedback client created (f3e14e2) — UI entry point deferred to TODO(AGENTIC-3) -- [x] Accessibility package added (f3e14e2) — modal integration deferred to TODO(AGENTIC-4) +- [x] Feedback client created (f3e14e2) — UI entry point deferred to TODO-002 +- [x] Accessibility package added (f3e14e2) — modal integration deferred to TODO-003 - [x] 7 new feature flags registered (all default `false`) (f3e14e2) - [x] Telemetry event names defined (16 events, backend + web) (f3e14e2) - [x] All existing tests still pass (182 backend + 394 web) @@ -205,7 +227,7 @@ Extend `learning_ai_common_plat/services/mcp-server/src/modules/chronomind/`: - `chronomind.agentActions.approve` — approve a proposed action - Write tools (reschedule, routines.start) record agent action for audit trail (fail-open) - [ ] MCP tool tests (commit: ) - - TODO(AGENTIC-8): Add integration tests for the 5 new MCP tools + - TODO-007: Add integration tests for the 5 new ChronoMind MCP tools in common-plat ### A.4 — Context-Aware AI Messages (LLM upgrade) @@ -220,9 +242,9 @@ Upgrade `web/src/lib/context-messages.ts` with optional LLM enrichment: - [x] Backend route: `POST /api/context-message` (commit: c80c1e4) - [x] `web/src/lib/context-messages.ts` — add `fetchEnrichedMessage()` (commit: c80c1e4) - Graceful degradation: keyword rules remain primary, LLM messages shown as "AI suggestion" - - TODO(AGENTIC-9): Add trackEvent() calls for ai_context.enriched / ai_context.fallback_used + - TODO-008: Wire trackEvent() calls for ai_context.enriched / ai_context.fallback_used - [ ] Tests for AI context generation (commit: ) - - TODO(AGENTIC-10): Add unit tests for generateContextMessage() and fetchEnrichedMessage() + - TODO-009: Add unit tests for generateContextMessage() and fetchEnrichedMessage() ### Phase A Exit Criteria diff --git a/web/src/app/error.tsx b/web/src/app/error.tsx index 0eb831b..9a280f0 100644 --- a/web/src/app/error.tsx +++ b/web/src/app/error.tsx @@ -11,7 +11,11 @@ export default function GlobalError({ reset: () => void; }) { useEffect(() => { - // TODO: send to telemetry once wired + // TODO-011: Wire error boundary to telemetry + // Priority: low | Phase: cleanup + // Import { trackEvent } from '../lib/telemetry' and send error details: + // trackEvent('app.error_boundary', { message: error.message, digest: error.digest }) + // Also consider sending to @bytelyst/diagnostics-client if available. }, [error]); return ( diff --git a/web/src/app/providers.tsx b/web/src/app/providers.tsx index 850e235..d0ab2d2 100644 --- a/web/src/app/providers.tsx +++ b/web/src/app/providers.tsx @@ -17,12 +17,17 @@ export function Providers({ children }: { children: ReactNode }) { initTelemetry(); initFeatureFlags(); initDiagnostics(); - // TODO(AGENTIC-1): When kill switch returns disabled=true, show a maintenance - // banner and disable timer creation. For now we just log and check. + // TODO-001: Kill switch maintenance banner + // Priority: medium | Phase: 0 + // When checkKillSwitch() returns disabled=true: + // 1. Set a React state flag (e.g. `isMaintenanceMode`) + // 2. Render a component at the top of the app + // 3. Disable timer creation buttons (pass flag via context or prop) + // 4. Use --cm-warning-* design tokens for the banner styling + // File to create: web/src/components/MaintenanceBanner.tsx checkKillSwitch().then((disabled) => { if (disabled) { - // TODO(AGENTIC-2): Render a visible maintenance banner component here. - // For now, the kill switch result is available but not surfaced in UI. + // TODO-001: Surface this in the UI (see instructions above) } }); }, []); diff --git a/web/src/lib/context-messages.ts b/web/src/lib/context-messages.ts index 4c2b3ee..647a46d 100644 --- a/web/src/lib/context-messages.ts +++ b/web/src/lib/context-messages.ts @@ -192,8 +192,13 @@ export async function fetchEnrichedMessage(params: { timeOfDay?: string; recentTimerLabels?: string[]; }): Promise { - // TODO(AGENTIC-7): Use the backend URL from product-config or auth-api - // instead of relative path, once backend is always available. + // TODO-006: Centralize backend URL configuration + // Priority: low | Phase: A.4 + // Replace the raw env var with a centralized config helper. Options: + // 1. Create getBackendUrl() in web/src/lib/product-config.ts that reads + // NEXT_PUBLIC_CHRONOMIND_BACKEND_URL with a sensible default + // 2. Or use the same pattern as auth-api.ts getBaseUrl() but for the product backend + // This avoids scattering env var references across multiple files. try { const backendUrl = process.env.NEXT_PUBLIC_CHRONOMIND_BACKEND_URL ?? 'http://localhost:4011'; const res = await fetch(`${backendUrl}/api/context-message`, { diff --git a/web/src/lib/telemetry-events.ts b/web/src/lib/telemetry-events.ts index 77223b1..cd64ba9 100644 --- a/web/src/lib/telemetry-events.ts +++ b/web/src/lib/telemetry-events.ts @@ -3,6 +3,13 @@ * * Mirrors backend/src/lib/telemetry-events.ts — single source of truth * for event names used in React components and API clients (Phase 0.5). + * + * TODO-008: Wire trackEvent() calls into web components + * Priority: medium | Phase: B + * These constants are defined but not yet imported anywhere. Wire them in: + * - Dashboard.tsx or agent inbox component: AGENT_INBOX_ACTION_APPROVED / REJECTED + * - Context message display component: AI_CONTEXT_ENRICHED / AI_CONTEXT_FALLBACK_USED + * - Use: import { trackEvent } from './telemetry' then trackEvent(EVENT_NAME, { ...metadata }) */ // ── MCP ───────────────────────────────────────────────────────