From 0fe3737035959936cc53d8ac0fb7b091e7a56255 Mon Sep 17 00:00:00 2001 From: teernisse Date: Wed, 25 Feb 2026 10:02:45 -0500 Subject: [PATCH] docs(plan): add GitLab TODOs integration design document Captures design decisions and acceptance criteria for adding GitLab TODO support to lore. This plan was developed through user interview to ensure the feature aligns with actual workflows. Key design decisions: - Read-only scope (no mark-as-done operations) - Three integration points: --todos flag, activity enrichment, lore todos - Account-wide: --project does NOT filter todos (unlike issues/MRs) - Separate signal: todos don't affect attention state calculation - Snapshot sync: missing todos = marked done elsewhere = delete locally The plan covers: - Database schema (todos table + indexes) - GitLab API client extensions - Sync pipeline integration - Action type handling and grouping - CLI commands and robot mode schemas - Non-synced project handling with [external] indicator Implementation is organized into 5 rollout slices: A: Schema + Client, B: Sync, C: lore todos, D: lore me, E: Polish Co-Authored-By: Claude Opus 4.5 --- .../gitlab-todos-notifications-integration.md | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 plans/gitlab-todos-notifications-integration.md diff --git a/plans/gitlab-todos-notifications-integration.md b/plans/gitlab-todos-notifications-integration.md new file mode 100644 index 0000000..e873e3c --- /dev/null +++ b/plans/gitlab-todos-notifications-integration.md @@ -0,0 +1,278 @@ +--- +plan: true +title: "GitLab TODOs Integration" +status: proposed +iteration: 1 +target_iterations: 3 +beads_revision: 1 +related_plans: [] +created: 2026-02-23 +updated: 2026-02-23 +--- + +# GitLab TODOs Integration + +## Summary + +Add GitLab TODO support to lore. Todos are fetched during sync, stored locally, and surfaced through: +1. A new `--todos` section in `lore me` +2. Enrichment of the activity feed in `lore me` +3. A standalone `lore todos` command + +**Scope:** Read-only. No mark-as-done operations. + +--- + +## Design Decisions (from interview) + +| Decision | Choice | +|----------|--------| +| Write operations | **Read-only** — no mark-as-done | +| Storage | **Persist locally** in SQLite | +| Integration | Three-way: activity enrichment + `--todos` flag + `lore todos` | +| Action types | Core only: assigned, mentioned, directly_addressed, approval_required, build_failed, unmergeable | +| Niche actions | Skip display (but store): merge_train_removed, member_access_requested, marked | +| Project filter | **Always account-wide** — `--project` does NOT filter todos | +| Sync timing | During normal `lore sync` | +| Non-synced projects | Include with `[external]` indicator | +| Attention state | **Separate signal** — todos don't boost attention | +| Summary header | Include pending todo count | +| Grouping | By action type: Assignments \| Mentions \| Approvals \| Build Issues | +| History | **Pending only** — done todos not tracked | +| `lore todos` filters | **None** — show all pending, simple | +| Robot mode | Yes, standard envelope | +| Target types | All GitLab supports (Issue, MR, Epic, Commit, etc.) | + +--- + +## Out of Scope + +- Write operations (mark as done) +- Done todo history tracking +- Filters on `lore todos` command +- Todo-based attention state boosting +- Notification settings API integration (deferred to separate plan) + +--- + +## Acceptance Criteria + +### AC-1: Database Schema + +- [ ] **AC-1.1:** Create `todos` table with columns: + - `id` INTEGER PRIMARY KEY + - `gitlab_todo_id` INTEGER NOT NULL UNIQUE + - `project_id` INTEGER REFERENCES projects(id) ON DELETE SET NULL (nullable for non-synced) + - `target_type` TEXT NOT NULL (Issue, MergeRequest, Commit, Epic, etc.) + - `target_id` INTEGER (GitLab ID of target entity) + - `target_iid` INTEGER (IID for issues/MRs, nullable) + - `target_url` TEXT NOT NULL + - `target_title` TEXT + - `action_name` TEXT NOT NULL (assigned, mentioned, etc.) + - `author_id` INTEGER + - `author_username` TEXT + - `body` TEXT (the todo message/snippet) + - `state` TEXT NOT NULL (pending) + - `created_at` INTEGER NOT NULL (epoch ms) + - `updated_at` INTEGER NOT NULL (epoch ms) + - `synced_at` INTEGER NOT NULL (epoch ms) + - `project_path` TEXT (for display even if project not synced) +- [ ] **AC-1.2:** Create index `idx_todos_state_action` on `(state, action_name)` +- [ ] **AC-1.3:** Create index `idx_todos_target` on `(target_type, target_id)` +- [ ] **AC-1.4:** Create index `idx_todos_created` on `(created_at DESC)` +- [ ] **AC-1.5:** Migration increments schema version + +### AC-2: GitLab API Client + +- [ ] **AC-2.1:** Add `fetch_todos()` method to GitLab client +- [ ] **AC-2.2:** Fetch only `state=pending` todos +- [ ] **AC-2.3:** Handle pagination (use existing pagination pattern) +- [ ] **AC-2.4:** Parse all target types GitLab returns +- [ ] **AC-2.5:** Extract project path from `target_url` for non-synced projects + +### AC-3: Sync Pipeline + +- [ ] **AC-3.1:** Add todos sync step to `lore sync` pipeline +- [ ] **AC-3.2:** Sync todos AFTER issues/MRs (ordering consistency) +- [ ] **AC-3.3:** Snapshot semantics: fetch all pending, upsert, delete missing (= marked done elsewhere) +- [ ] **AC-3.4:** Track `synced_at` timestamp +- [ ] **AC-3.5:** Log todo sync stats: fetched, inserted, updated, deleted +- [ ] **AC-3.6:** Add `--no-todos` flag to skip todo sync + +### AC-4: Action Type Handling + +- [ ] **AC-4.1:** Store ALL action types from GitLab +- [ ] **AC-4.2:** Display only core actions: + - `assigned` — assigned to issue/MR + - `mentioned` — @mentioned in comment + - `directly_addressed` — @mentioned at start of comment + - `approval_required` — approval needed on MR + - `build_failed` — CI failed on your MR + - `unmergeable` — merge conflicts on your MR +- [ ] **AC-4.3:** Skip display (but store) niche actions: `merge_train_removed`, `member_access_requested`, `marked` + +### AC-5: `lore todos` Command + +- [ ] **AC-5.1:** New subcommand `lore todos` (alias: `todo`) +- [ ] **AC-5.2:** Display all pending todos, no filters +- [ ] **AC-5.3:** Group by action type: Assignments | Mentions | Approvals | Build Issues +- [ ] **AC-5.4:** Per-todo display: target title, project path, author, age, action +- [ ] **AC-5.5:** Flag non-synced project todos with `[external]` indicator +- [ ] **AC-5.6:** Human-readable output with colors/icons +- [ ] **AC-5.7:** Robot mode: standard `{ok, data, meta}` envelope + +### AC-6: `lore me --todos` Section + +- [ ] **AC-6.1:** Add `--todos` flag to `MeArgs` +- [ ] **AC-6.2:** When no section flags: show todos in full dashboard +- [ ] **AC-6.3:** When `--todos` flag only: show only todos section +- [ ] **AC-6.4:** Todos section grouped by action type +- [ ] **AC-6.5:** Todos NOT filtered by `--project` (always account-wide) +- [ ] **AC-6.6:** Robot mode includes `todos` array in dashboard response + +### AC-7: `lore me` Summary Header + +- [ ] **AC-7.1:** Add `pending_todo_count` to `MeSummary` struct +- [ ] **AC-7.2:** Display todo count in summary line (human mode) +- [ ] **AC-7.3:** Include `pending_todo_count` in robot mode summary + +### AC-8: Activity Feed Enrichment + +- [ ] **AC-8.1:** Todos with local issue/MR target appear in activity feed +- [ ] **AC-8.2:** New `ActivityEventType::Todo` variant +- [ ] **AC-8.3:** Todo events show: action type, author, target in summary +- [ ] **AC-8.4:** Sorted chronologically with other activity events +- [ ] **AC-8.5:** Respect `--since` filter on todo `created_at` + +### AC-9: Non-Synced Project Handling + +- [ ] **AC-9.1:** Store todos even if target project not in config +- [ ] **AC-9.2:** Display `[external]` indicator for non-synced project todos +- [ ] **AC-9.3:** Show project path (extracted from target URL) +- [ ] **AC-9.4:** Graceful fallback when target title unavailable + +### AC-10: Attention State + +- [ ] **AC-10.1:** Attention state calculation remains note-based (unchanged) +- [ ] **AC-10.2:** Todos are separate signal, do not affect attention state +- [ ] **AC-10.3:** Document this design decision in code comments + +### AC-11: Robot Mode Schema + +- [ ] **AC-11.1:** `lore todos --robot` returns: + ```json + { + "ok": true, + "data": { + "todos": [{ + "id": 123, + "gitlab_todo_id": 456, + "action": "mentioned", + "target_type": "Issue", + "target_iid": 42, + "target_title": "Fix login bug", + "target_url": "https://...", + "project_path": "group/repo", + "author_username": "jdoe", + "body": "Hey @you, can you look at this?", + "created_at_iso": "2026-02-20T10:00:00Z", + "is_external": false + }], + "counts": { + "total": 8, + "assigned": 2, + "mentioned": 5, + "approval_required": 1, + "build_failed": 0, + "unmergeable": 0 + } + }, + "meta": {"elapsed_ms": 42} + } + ``` +- [ ] **AC-11.2:** `lore me --robot` includes `todos` and `pending_todo_count` in response +- [ ] **AC-11.3:** Support `--fields minimal` for token efficiency + +### AC-12: Documentation + +- [ ] **AC-12.1:** Update CLAUDE.md with `lore todos` command reference +- [ ] **AC-12.2:** Update `lore robot-docs` manifest with todos schema +- [ ] **AC-12.3:** Add todos to CLI help output + +### AC-13: Quality Gates + +- [ ] **AC-13.1:** `cargo check --all-targets` passes +- [ ] **AC-13.2:** `cargo clippy --all-targets -- -D warnings` passes +- [ ] **AC-13.3:** `cargo fmt --check` passes +- [ ] **AC-13.4:** `cargo test` passes with new tests + +--- + +## Technical Notes + +### GitLab API Endpoint + +``` +GET /api/v4/todos?state=pending +``` + +Response fields: id, project, author, action_name, target_type, target, target_url, body, state, created_at, updated_at + +### Sync Deletion Strategy + +Snapshot semantics: a todo disappearing from API response means it was marked done elsewhere. Delete from local DB to stay in sync. + +### Project Path Extraction + +For non-synced projects, extract path from `target_url`: +``` +https://gitlab.com/group/subgroup/repo/-/issues/42 + ^^^^^^^^^^^^^^^^^ extract this +``` + +### Action Type Grouping + +| Group | Actions | +|-------|---------| +| Assignments | `assigned` | +| Mentions | `mentioned`, `directly_addressed` | +| Approvals | `approval_required` | +| Build Issues | `build_failed`, `unmergeable` | + +--- + +## Rollout Slices + +### Slice A: Schema + Client +- Migration 028 +- `GitLabTodo` type +- `fetch_todos()` client method +- Unit tests for deserialization + +### Slice B: Sync Integration +- `src/ingestion/todos.rs` +- Integrate into `lore sync` +- `--no-todos` flag +- Sync stats + +### Slice C: `lore todos` Command +- CLI args + dispatch +- Human + robot rendering +- Autocorrect aliases + +### Slice D: `lore me` Integration +- `--todos` flag +- Summary count +- Activity feed enrichment + +### Slice E: Polish +- Edge case tests +- Documentation updates +- `robot-docs` manifest + +--- + +## References + +- [GitLab To-Do List API](https://docs.gitlab.com/api/todos/) +- [GitLab User Todos](https://docs.gitlab.com/user/todos/)