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.
This commit is contained in:
parent
f94c2d8424
commit
9897d2cd09
@ -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<string | null> {
|
||||
// Only attempt if extraction service URL is configured
|
||||
const extractionUrl = config.EXTRACTION_SERVICE_URL;
|
||||
|
||||
@ -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 ───────────────────────────────────────────────────────
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 `<MaintenanceBanner />`, 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
|
||||
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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 <MaintenanceBanner /> 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)
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
@ -192,8 +192,13 @@ export async function fetchEnrichedMessage(params: {
|
||||
timeOfDay?: string;
|
||||
recentTimerLabels?: string[];
|
||||
}): Promise<EnrichedMessageResult> {
|
||||
// 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`, {
|
||||
|
||||
@ -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 ───────────────────────────────────────────────────────
|
||||
|
||||
Loading…
Reference in New Issue
Block a user