From 0e3815ac3cadc93959924d16a22004733418676c Mon Sep 17 00:00:00 2001 From: zenchantlive Date: Wed, 11 Feb 2026 19:38:19 -0800 Subject: [PATCH] docs: add project context model design --- .beads/issues.jsonl | 4 +- ...2026-02-12-project-context-model-design.md | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 docs/plans/2026-02-12-project-context-model-design.md diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 22955f5..a1b22ff 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -8,7 +8,7 @@ {"id":"bb-6aj.2","title":"Implement registry API for add/remove/list operations","description":"Expose robust API endpoints with path validation and normalized identity checks to prevent duplicates.","acceptance_criteria":"API supports add, remove, list and returns clear validation errors.","status":"closed","priority":0,"issue_type":"task","assignee":"agent-a","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:49.3542564-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:53:23.9298353-08:00","closed_at":"2026-02-11T17:53:23.9298353-08:00","close_reason":"Implemented /api/projects GET/POST/DELETE with validation, normalization, and registry integration.","labels":["api","registry"],"dependencies":[{"issue_id":"bb-6aj.2","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:49.3558158-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.2","depends_on_id":"bb-6aj.1","type":"blocks","created_at":"2026-02-11T17:12:26.7117348-08:00","created_by":"zenchantlive"}]} {"id":"bb-6aj.3","title":"Build scanner with profile-root default and depth/ignore controls","description":"Scan %USERPROFILE% and user-defined roots for .beads directories with bounded recursion and ignore patterns to protect performance.","acceptance_criteria":"Scanner discovers projects without traversing entire drives by default.","status":"open","priority":0,"issue_type":"task","assignee":"agent-c","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:50.1925005-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:43:32.4095636-08:00","labels":["performance","scanner"],"dependencies":[{"issue_id":"bb-6aj.3","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:50.1940841-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.3","depends_on_id":"bb-6aj.1","type":"blocks","created_at":"2026-02-11T17:12:27.2225981-08:00","created_by":"zenchantlive"}]} {"id":"bb-6aj.3.1","title":"Add explicit full-drive scan mode for C:/D: by user action","description":"Provide an opt-in scan mode for full drive enumeration while retaining safe defaults and progress reporting expectations.","acceptance_criteria":"Full-drive scan is only activated explicitly, never by default startup logic.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:51.0244174-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:51.0244174-08:00","labels":["optional","scanner"],"dependencies":[{"issue_id":"bb-6aj.3.1","depends_on_id":"bb-6aj.3","type":"parent-child","created_at":"2026-02-11T17:11:51.0259617-08:00","created_by":"zenchantlive"}]} -{"id":"bb-6aj.4","title":"Implement aggregate project issue context model","description":"Define normalized project identity payload attached to every issue for cross-project Kanban, timeline, and session views.","acceptance_criteria":"Aggregated read output always includes stable project metadata.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:51.8518922-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:51.8518922-08:00","labels":["aggregation","data-model"],"dependencies":[{"issue_id":"bb-6aj.4","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:51.8534893-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.4","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:27.7270195-08:00","created_by":"zenchantlive"}]} +{"id":"bb-6aj.4","title":"Implement aggregate project issue context model","description":"Define normalized project identity payload attached to every issue for cross-project Kanban, timeline, and session views.","acceptance_criteria":"Aggregated read output always includes stable project metadata.","status":"in_progress","priority":1,"issue_type":"task","assignee":"zenchantlive","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:51.8518922-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T19:31:12.4614879-08:00","labels":["aggregation","data-model"],"dependencies":[{"issue_id":"bb-6aj.4","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:51.8534893-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.4","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:27.7270195-08:00","created_by":"zenchantlive"}]} {"id":"bb-92d","title":"Foundation and Read/Write Boundary","description":"Establish the Windows-native Next.js foundation, canonical Beads schema handling, and strict data boundaries: read from JSONL, write only via bd.exe. This epic defines the non-negotiable invariants that all later work must preserve.","acceptance_criteria":"App boots on Windows, schema/parser contracts exist, and no direct issues.jsonl write path exists in code.","status":"closed","priority":0,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:41.0756295-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:28:27.8108066-08:00","closed_at":"2026-02-11T17:28:27.8108066-08:00","close_reason":"Completed foundation milestone: bootstrap, licensing/docs, schema contracts, parser, windows path normalization, and write-boundary guardrails.","labels":["beadboard","foundation","windows"]} {"id":"bb-92d.1","title":"Bootstrap Next.js 15 + React 19 + TypeScript strict","description":"Initialize project scaffold with strict TypeScript, App Router baseline, and repeatable scripts for lint/typecheck/test in PowerShell.","acceptance_criteria":"npm install and dev startup work on Windows; strict type checking enabled.","status":"closed","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:41.9363647-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:23:14.0089901-08:00","closed_at":"2026-02-11T17:23:14.0089901-08:00","close_reason":"Bootstrapped Next.js 15 + React 19 + strict TypeScript; install/typecheck/dev startup verified on Windows.","labels":["foundation","nextjs"],"dependencies":[{"issue_id":"bb-92d.1","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:41.9379355-08:00","created_by":"zenchantlive"}]} {"id":"bb-92d.2","title":"Add MIT license and baseline repository docs","description":"Add LICENSE and baseline docs that state Windows-native support, read/write boundaries, and required runtime dependencies.","acceptance_criteria":"MIT license present and docs describe core architecture constraints.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:42.7699961-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:23:50.7519159-08:00","closed_at":"2026-02-11T17:23:50.7519159-08:00","close_reason":"Added MIT license and baseline repository documentation with architecture boundary rules.","labels":["docs","license"],"dependencies":[{"issue_id":"bb-92d.2","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:42.7715653-08:00","created_by":"zenchantlive"}]} @@ -47,7 +47,7 @@ {"id":"bb-xhm.2","title":"Implement snapshot diffing for derived timeline events","description":"Compare periodic snapshots and watcher updates to infer meaningful change events without requiring write interception.","acceptance_criteria":"Diff engine emits deterministic event records for relevant field changes.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:07.5007059-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:07.5007059-08:00","labels":["diff","timeline"],"dependencies":[{"issue_id":"bb-xhm.2","depends_on_id":"bb-xhm","type":"parent-child","created_at":"2026-02-11T17:12:07.501756-08:00","created_by":"zenchantlive"},{"issue_id":"bb-xhm.2","depends_on_id":"bb-xhm.1","type":"blocks","created_at":"2026-02-11T17:12:35.3430513-08:00","created_by":"zenchantlive"},{"issue_id":"bb-xhm.2","depends_on_id":"bb-tpc.2","type":"blocks","created_at":"2026-02-11T17:12:35.8495336-08:00","created_by":"zenchantlive"}]} {"id":"bb-xhm.3","title":"Build timeline UI with date grouping and project/assignee/event filters","description":"Render reverse-chronological feed suitable for morning review workflows with practical filter controls.","acceptance_criteria":"Timeline view supports grouping and filter combinations with acceptable performance.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:08.3834905-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:08.3834905-08:00","labels":["timeline","ui"],"dependencies":[{"issue_id":"bb-xhm.3","depends_on_id":"bb-xhm","type":"parent-child","created_at":"2026-02-11T17:12:08.3851144-08:00","created_by":"zenchantlive"},{"issue_id":"bb-xhm.3","depends_on_id":"bb-xhm.2","type":"blocks","created_at":"2026-02-11T17:12:36.3627477-08:00","created_by":"zenchantlive"}]} {"id":"bb-ymg","title":"CLI Write-Back via bd.exe","description":"Enable safe issue mutations from UI by routing all write operations through bd.exe and reflecting results through realtime reconciliation.","acceptance_criteria":"No direct JSONL writes exist; all mutations use bd commands and recover cleanly from failures.","status":"open","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:00.9164956-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:00.9164956-08:00","labels":["bd-cli","mutation"],"dependencies":[{"issue_id":"bb-ymg","depends_on_id":"bb-trz","type":"blocks","created_at":"2026-02-11T17:12:21.1512868-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg","depends_on_id":"bb-tpc","type":"blocks","created_at":"2026-02-11T17:12:21.6536312-08:00","created_by":"zenchantlive"}]} -{"id":"bb-ymg.1","title":"Implement bd bridge using child_process.execFile with project-scoped cwd","description":"Wrap bd execution with command argument safety, Windows path compatibility, stdout/stderr parsing, and project-specific current working directory.","acceptance_criteria":"Bridge executes supported bd commands and returns structured result/error payloads.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:01.7327732-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:01.7327732-08:00","labels":["bridge","execfile"],"dependencies":[{"issue_id":"bb-ymg.1","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:01.7343468-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.1","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:32.3039711-08:00","created_by":"zenchantlive"}]} +{"id":"bb-ymg.1","title":"Implement bd bridge using child_process.execFile with project-scoped cwd","description":"Wrap bd execution with command argument safety, Windows path compatibility, stdout/stderr parsing, and project-specific current working directory.","acceptance_criteria":"Bridge executes supported bd commands and returns structured result/error payloads.","status":"in_progress","priority":0,"issue_type":"task","assignee":"zenchantlive","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:01.7327732-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T19:35:15.8003769-08:00","labels":["bridge","execfile"],"dependencies":[{"issue_id":"bb-ymg.1","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:01.7343468-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.1","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:32.3039711-08:00","created_by":"zenchantlive"}]} {"id":"bb-ymg.1.1","title":"Resolve bd.exe location from PATH and configuration fallback","description":"Add detection logic for bd executable and actionable errors when not found, including setup guidance.","acceptance_criteria":"Missing bd path returns clear setup instructions and diagnostics.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:02.5593205-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:02.5593205-08:00","labels":["bridge","setup"],"dependencies":[{"issue_id":"bb-ymg.1.1","depends_on_id":"bb-ymg.1","type":"parent-child","created_at":"2026-02-11T17:12:02.5603636-08:00","created_by":"zenchantlive"}]} {"id":"bb-ymg.2","title":"Implement mutation API for create/update/close/reopen/comment operations","description":"Expose strict server-side mutation endpoints translating UI actions to corresponding bd commands with validated arguments.","acceptance_criteria":"All required mutation operations execute via bd and return normalized responses.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:03.3757503-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:03.3757503-08:00","labels":["api","mutation"],"dependencies":[{"issue_id":"bb-ymg.2","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:03.377343-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.2","depends_on_id":"bb-ymg.1","type":"blocks","created_at":"2026-02-11T17:12:32.810993-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.2","depends_on_id":"bb-ymg.1.1","type":"blocks","created_at":"2026-02-11T17:12:33.313807-08:00","created_by":"zenchantlive"}]} {"id":"bb-ymg.3","title":"Add optimistic updates with rollback and SSE reconciliation","description":"Apply immediate UI updates for responsiveness, rollback on command failure, and reconcile with watcher-triggered authoritative state updates.","acceptance_criteria":"Failed mutations restore previous UI state and emit meaningful error feedback.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:04.1956393-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:04.1956393-08:00","labels":["optimistic","state"],"dependencies":[{"issue_id":"bb-ymg.3","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:04.1966728-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.3","depends_on_id":"bb-ymg.2","type":"blocks","created_at":"2026-02-11T17:12:33.8246167-08:00","created_by":"zenchantlive"}]} diff --git a/docs/plans/2026-02-12-project-context-model-design.md b/docs/plans/2026-02-12-project-context-model-design.md new file mode 100644 index 0000000..01f2e51 --- /dev/null +++ b/docs/plans/2026-02-12-project-context-model-design.md @@ -0,0 +1,52 @@ +# Project Context Model Design + +## Summary +Aggregate views need stable project identity attached to each issue so cross-project Kanban, timeline, and session views can filter and display project metadata consistently. This design adds a normalized `ProjectContext` payload to every issue returned from read flows while keeping the raw JSONL format untouched. + +## Requirements +- Use existing Windows-safe path normalization for stable identity. +- Attach project identity on every issue returned from read services. +- Include fields: `key`, `root`, `displayPath`, `name`, `source`, `addedAt`. +- Default single-project reads to `source="local"` and `addedAt=null`. + +## Data Model +```ts +export type ProjectSource = 'local' | 'registry' | 'scanner'; + +export interface ProjectContext { + key: string; // windowsPathKey(root) + root: string; // canonicalizeWindowsPath(root) + displayPath: string; // toDisplayPath(root) + name: string; // path.basename(root) + source: ProjectSource; + addedAt: string | null; +} + +export type BeadIssueWithProject = BeadIssue & { project: ProjectContext }; +``` + +## Construction +- Add a helper (e.g., `buildProjectContext`) that accepts `projectRoot`, `source`, and `addedAt`. +- Normalize the root with `canonicalizeWindowsPath`, compute the key with `windowsPathKey`, display path with `toDisplayPath`, and name from `path.basename`. +- No filesystem checks are required; this is identity metadata only. + +## Read Flow Integration +- Update `readIssuesFromDisk` to attach `project` to each parsed issue. +- Default `projectRoot` to `process.cwd()` when not provided. +- Keep the existing `BeadIssue` shape for raw parsing; project context is added in read services only. + +## Error Handling +- If `projectRoot` is empty, throw a clear error early in `buildProjectContext`. +- Otherwise, treat normalization as pure string ops and do not swallow exceptions. + +## Tests +- Add unit tests for `buildProjectContext` field derivation (key/root/displayPath/name/source/addedAt). +- Update `readIssuesFromDisk` tests to assert `project` is attached with expected fields. + +## Alternatives Considered +1. **Wrapper object `{ project, issue }`** + Pro: explicit separation; Con: more refactors across UI filtering and query shapes. +2. **`metadata.project` on issues** + Pro: zero type changes; Con: weak typing and harder discoverability. +3. **Chosen: `issue.project` field** + Clear typing, predictable access, and minimal friction for UI + aggregate queries.