bd sync: close checkvist-api-4bz (Task.tasks field bug already fixed)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Oliver Jakoubek 2026-01-23 08:20:25 +01:00
commit 7c0839c831
2 changed files with 6 additions and 0 deletions

5
.beads/.gitignore vendored
View file

@ -32,6 +32,11 @@ beads.left.meta.json
beads.right.jsonl beads.right.jsonl
beads.right.meta.json beads.right.meta.json
# Sync state (local-only, per-machine)
# These files are machine-specific and should not be shared across clones
.sync.lock
sync_base.jsonl
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here. # NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
# They would override fork protection in .git/info/exclude, allowing # They would override fork protection in .git/info/exclude, allowing
# contributors to accidentally commit upstream issue databases. # contributors to accidentally commit upstream issue databases.

View file

@ -6,6 +6,7 @@
{"id":"checkvist-api-2zr","title":"Fix Close/Invalidate/Reopen to handle array response","description":"## Description\n\nThe `Close()`, `Invalidate()`, and `Reopen()` methods on `TaskService` fail with a JSON decoding error because the Checkvist API returns an array of tasks, not a single task object.\n\n## Error\n\n```go\ntask, err := client.Tasks(945445).Close(ctx, taskID)\nif err != nil {\n panic(err)\n}\n```\n\nResults in:\n```\npanic: decoding response: json: cannot unmarshal array into Go value of type checkvist.Task\n```\n\n## Root Cause\n\nIn `tasks.go` (lines 204-240), all three methods decode the API response into a single `Task`:\n\n```go\nvar task Task\nif err := s.client.doPost(ctx, path, nil, \u0026task); err != nil {\n return nil, err\n}\n```\n\nBut the Checkvist API returns an array containing the modified task and potentially its subtasks.\n\n## Affected Methods\n\n- `TaskService.Close()` (tasks.go:204)\n- `TaskService.Reopen()` (tasks.go:217)\n- `TaskService.Invalidate()` (tasks.go:230)\n\n## Acceptance Criteria\n\n- [ ] All three methods correctly decode the array response\n- [ ] Return the first element (the modified task) as `*Task`\n- [ ] Update tests to use array response fixtures\n- [ ] Add integration test notes in code comments","status":"closed","priority":2,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-15T10:26:22.308158727+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-15T10:48:33.012621346+01:00","closed_at":"2026-01-15T10:48:33.012621346+01:00","close_reason":"Closed"} {"id":"checkvist-api-2zr","title":"Fix Close/Invalidate/Reopen to handle array response","description":"## Description\n\nThe `Close()`, `Invalidate()`, and `Reopen()` methods on `TaskService` fail with a JSON decoding error because the Checkvist API returns an array of tasks, not a single task object.\n\n## Error\n\n```go\ntask, err := client.Tasks(945445).Close(ctx, taskID)\nif err != nil {\n panic(err)\n}\n```\n\nResults in:\n```\npanic: decoding response: json: cannot unmarshal array into Go value of type checkvist.Task\n```\n\n## Root Cause\n\nIn `tasks.go` (lines 204-240), all three methods decode the API response into a single `Task`:\n\n```go\nvar task Task\nif err := s.client.doPost(ctx, path, nil, \u0026task); err != nil {\n return nil, err\n}\n```\n\nBut the Checkvist API returns an array containing the modified task and potentially its subtasks.\n\n## Affected Methods\n\n- `TaskService.Close()` (tasks.go:204)\n- `TaskService.Reopen()` (tasks.go:217)\n- `TaskService.Invalidate()` (tasks.go:230)\n\n## Acceptance Criteria\n\n- [ ] All three methods correctly decode the array response\n- [ ] Return the first element (the modified task) as `*Task`\n- [ ] Update tests to use array response fixtures\n- [ ] Add integration test notes in code comments","status":"closed","priority":2,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-15T10:26:22.308158727+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-15T10:48:33.012621346+01:00","closed_at":"2026-01-15T10:48:33.012621346+01:00","close_reason":"Closed"}
{"id":"checkvist-api-347","title":"Write unit tests for Checklists","description":"Create checklists_test.go with tests:\n- TestChecklists_List\n- TestChecklists_ListArchived\n- TestChecklists_Get\n- TestChecklists_Get_NotFound\n- TestChecklists_Create\n- TestChecklists_Update\n- TestChecklists_Delete\nUse table-driven tests. Create testdata/checklists/ fixtures.","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:37.243525209+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:41:58.076714398+01:00","closed_at":"2026-01-14T13:41:58.076714398+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-347","depends_on_id":"checkvist-api-c2k","type":"blocks","created_at":"2026-01-14T12:33:13.512887479+01:00","created_by":"Oliver Jakoubek"}]} {"id":"checkvist-api-347","title":"Write unit tests for Checklists","description":"Create checklists_test.go with tests:\n- TestChecklists_List\n- TestChecklists_ListArchived\n- TestChecklists_Get\n- TestChecklists_Get_NotFound\n- TestChecklists_Create\n- TestChecklists_Update\n- TestChecklists_Delete\nUse table-driven tests. Create testdata/checklists/ fixtures.","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:37.243525209+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:41:58.076714398+01:00","closed_at":"2026-01-14T13:41:58.076714398+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-347","depends_on_id":"checkvist-api-c2k","type":"blocks","created_at":"2026-01-14T12:33:13.512887479+01:00","created_by":"Oliver Jakoubek"}]}
{"id":"checkvist-api-47y","title":"Quality \u0026 Documentation","description":"Phase 4: Complete unit tests, GoDoc examples, README, and CHANGELOG. Target \u003e80% test coverage. All public functions documented with examples.","status":"closed","priority":0,"issue_type":"epic","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:36.655509387+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T14:37:52.12671299+01:00","closed_at":"2026-01-14T14:37:52.12671299+01:00","close_reason":"Alle zugehörigen Features und Tasks abgeschlossen"} {"id":"checkvist-api-47y","title":"Quality \u0026 Documentation","description":"Phase 4: Complete unit tests, GoDoc examples, README, and CHANGELOG. Target \u003e80% test coverage. All public functions documented with examples.","status":"closed","priority":0,"issue_type":"epic","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:36.655509387+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T14:37:52.12671299+01:00","closed_at":"2026-01-14T14:37:52.12671299+01:00","close_reason":"Alle zugehörigen Features und Tasks abgeschlossen"}
{"id":"checkvist-api-4bz","title":"Fix Task.tasks field type: API returns []int (child IDs), not []Task","description":"## Problem\n\nDie Go-Bibliothek kann keine hierarchischen Checklisten parsen. Beim Abrufen von Listen mit verschachtelten Items schlägt das JSON-Unmarshaling fehl.\n\n### Fehlermeldung\n```\njson: cannot unmarshal number into Go struct field Task.tasks of type checkvist.Task\n```\n\n### Ursache\n\nLaut [Checkvist API Dokumentation](https://checkvist.com/auth/api) liefert das `tasks`-Feld eines Tasks ein **Array von Kind-Task-IDs** (Integer), nicht die tatsächlichen Task-Objekte:\n\n\u003e `tasks` - [JSON] Javascript array of children task IDs\n\nDie aktuelle Implementierung erwartet jedoch einen anderen Typ (vermutlich `[]Task` oder `*Task`), was zum Unmarshaling-Fehler führt.\n\n### Betroffene Listen\n\nAlle Checklisten mit Hierarchie, z.B.:\n- Einkaufsliste → ALDI → Milch, Butter\n- VORRÄTE → Sprudel → 4 Flaschen\n\nFlache Listen (ohne Parent/Child-Beziehungen) funktionieren weiterhin.\n\n## Lösungsvorschlag\n\n### 1. Task-Struct anpassen\n\nDas `tasks`-Feld im Task-Struct auf `[]int` ändern:\n\n```go\ntype Task struct {\n // ... andere Felder ...\n Tasks []int \\`json:\"tasks,omitempty\"\\` // Array of child task IDs\n // ...\n}\n```\n\n### 2. Optional: Hilfsmethode für Hierarchie-Aufbau\n\nDa die API alle Tasks flach zurückliefert (sortiert nach parent_id, position), könnte eine Hilfsmethode die Hierarchie rekonstruieren:\n\n```go\n// BuildHierarchy rekonstruiert die Baumstruktur aus der flachen Task-Liste\nfunc BuildHierarchy(tasks []Task) []*TaskNode {\n // 1. Map von ID -\u003e Task erstellen\n // 2. Anhand von ParentID und Tasks[] die Baumstruktur aufbauen\n // 3. Root-Tasks (ParentID == 0) zurückgeben\n}\n\ntype TaskNode struct {\n Task Task\n Children []*TaskNode\n}\n```\n\n### 3. Tests\n\n- Unit-Test mit hierarchischer JSON-Response (aus testdata/)\n- Sicherstellen, dass ParentID und Tasks korrekt geparst werden\n\n## Referenzen\n\n- API-Doku: https://checkvist.com/auth/api (Abschnitt task fields)\n- Relevantes Feld: parent_id (Parent task ID, 0 für Root-Tasks)\n- Relevantes Feld: tasks (Array of children task IDs)","status":"closed","priority":2,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-23T07:44:54.135665375+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-23T08:19:28.943046075+01:00","closed_at":"2026-01-23T08:19:28.943046075+01:00","close_reason":"Already fixed in commit d92a1b9 - ChildIDs []int field correctly unmarshals task ID arrays"}
{"id":"checkvist-api-4pz","title":"Fix DueDate not applied when creating tasks with WithDueDate()","description":"## Problem\n\nWhen creating tasks with `WithDueDate()`, the due date is not set on the created task, even though other parameters (position, priority, tags) work correctly.\n\n## Example Code\n\n```go\ntask, err := client.Tasks(945445).Create(ctx,\n checkvist.NewTask(\"Buy milk\").\n WithPosition(1).\n WithDueDate(checkvist.DueTomorrow).\n WithPriority(2).\n WithTags(\"Shopping\"),\n)\n// Result: task has position=1, priority=2, tags=\"Shopping\", but DueDate is nil\n```\n\n## Analysis\n\nThe JSON being sent to the API looks correct:\n```json\n{\n \"task\": {\n \"content\": \"Buy milk\",\n \"position\": 1,\n \"due_date\": \"^Tomorrow\",\n \"priority\": 2,\n \"tags\": \"Shopping\"\n }\n}\n```\n\nThe task wrapper format is correct (other fields work). The issue is likely with the due_date format:\n- Current format: `\"^Tomorrow\"` (with caret prefix)\n- API might expect: `\"tomorrow\"` (without caret) or different syntax\n\n## Investigation Needed\n\n1. Check Checkvist API documentation for exact `due_date` format\n2. Test with different formats:\n - `\"tomorrow\"` (without ^)\n - `\"Tomorrow\"` (capitalized, without ^)\n - `\"2026-01-16\"` (ISO date)\n3. Check if the `^` prefix is only used in task content, not in API parameters\n\n## Affected Code\n\n- `models.go:178-188` - DueDate constants with `^` prefix\n- `models.go:190-205` - DueAt(), DueString(), DueInDays() functions\n\n## Acceptance Criteria\n\n- [ ] `WithDueDate(DueTomorrow)` creates task with correct due date\n- [ ] `WithDueDate(DueAt(time))` creates task with correct due date\n- [ ] All DueDate constants work correctly","status":"closed","priority":2,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-15T10:11:00.062239196+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-15T10:17:38.380280674+01:00","closed_at":"2026-01-15T10:17:38.380280674+01:00","close_reason":"Closed"} {"id":"checkvist-api-4pz","title":"Fix DueDate not applied when creating tasks with WithDueDate()","description":"## Problem\n\nWhen creating tasks with `WithDueDate()`, the due date is not set on the created task, even though other parameters (position, priority, tags) work correctly.\n\n## Example Code\n\n```go\ntask, err := client.Tasks(945445).Create(ctx,\n checkvist.NewTask(\"Buy milk\").\n WithPosition(1).\n WithDueDate(checkvist.DueTomorrow).\n WithPriority(2).\n WithTags(\"Shopping\"),\n)\n// Result: task has position=1, priority=2, tags=\"Shopping\", but DueDate is nil\n```\n\n## Analysis\n\nThe JSON being sent to the API looks correct:\n```json\n{\n \"task\": {\n \"content\": \"Buy milk\",\n \"position\": 1,\n \"due_date\": \"^Tomorrow\",\n \"priority\": 2,\n \"tags\": \"Shopping\"\n }\n}\n```\n\nThe task wrapper format is correct (other fields work). The issue is likely with the due_date format:\n- Current format: `\"^Tomorrow\"` (with caret prefix)\n- API might expect: `\"tomorrow\"` (without caret) or different syntax\n\n## Investigation Needed\n\n1. Check Checkvist API documentation for exact `due_date` format\n2. Test with different formats:\n - `\"tomorrow\"` (without ^)\n - `\"Tomorrow\"` (capitalized, without ^)\n - `\"2026-01-16\"` (ISO date)\n3. Check if the `^` prefix is only used in task content, not in API parameters\n\n## Affected Code\n\n- `models.go:178-188` - DueDate constants with `^` prefix\n- `models.go:190-205` - DueAt(), DueString(), DueInDays() functions\n\n## Acceptance Criteria\n\n- [ ] `WithDueDate(DueTomorrow)` creates task with correct due date\n- [ ] `WithDueDate(DueAt(time))` creates task with correct due date\n- [ ] All DueDate constants work correctly","status":"closed","priority":2,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-15T10:11:00.062239196+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-15T10:17:38.380280674+01:00","closed_at":"2026-01-15T10:17:38.380280674+01:00","close_reason":"Closed"}
{"id":"checkvist-api-4qn","title":"Fix date parsing for Checkvist API format","description":"## Problem\n\nThe Checkvist API returns timestamps in a non-standard format that Go's `time.Time` cannot parse with default JSON unmarshaling.\n\n**API returns:** `\"2026/01/14 16:07:31 +0000\"`\n**Go expects:** `\"2006-01-02T15:04:05Z07:00\"` (RFC3339/ISO8601)\n\nThis causes errors like:\n```\nparsing time \"2026/01/14 16:07:31 +0000\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"/01/14 16:07:31 +0000\" as \"-\"\n```\n\n## Affected Fields\n\n- `Checklist.UpdatedAt`\n- `Task.UpdatedAt`\n- `Task.CreatedAt`\n- `Note.UpdatedAt`\n- `Note.CreatedAt`\n\n## Solution\n\nCreate a custom `APITime` type that implements `json.Unmarshaler` to handle the Checkvist date format:\n\n```go\ntype APITime struct {\n time.Time\n}\n\nfunc (t *APITime) UnmarshalJSON(data []byte) error {\n // Try multiple formats:\n // 1. Checkvist format: \"2006/01/02 15:04:05 -0700\"\n // 2. ISO8601/RFC3339: \"2006-01-02T15:04:05Z07:00\"\n}\n```\n\nReplace `time.Time` with `APITime` in all model structs.\n\n## Test\n\nA test has been added that documents this bug:\n`TestChecklists_List_RealAPIDateFormat` in `checklists_test.go`\n\nCurrently skips with message showing the parsing error. Should pass after fix.","status":"closed","priority":1,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T17:55:53.54028308+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T18:09:52.876804767+01:00","closed_at":"2026-01-14T18:09:52.876804767+01:00","close_reason":"APITime type with custom UnmarshalJSON implemented, all tests passing"} {"id":"checkvist-api-4qn","title":"Fix date parsing for Checkvist API format","description":"## Problem\n\nThe Checkvist API returns timestamps in a non-standard format that Go's `time.Time` cannot parse with default JSON unmarshaling.\n\n**API returns:** `\"2026/01/14 16:07:31 +0000\"`\n**Go expects:** `\"2006-01-02T15:04:05Z07:00\"` (RFC3339/ISO8601)\n\nThis causes errors like:\n```\nparsing time \"2026/01/14 16:07:31 +0000\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"/01/14 16:07:31 +0000\" as \"-\"\n```\n\n## Affected Fields\n\n- `Checklist.UpdatedAt`\n- `Task.UpdatedAt`\n- `Task.CreatedAt`\n- `Note.UpdatedAt`\n- `Note.CreatedAt`\n\n## Solution\n\nCreate a custom `APITime` type that implements `json.Unmarshaler` to handle the Checkvist date format:\n\n```go\ntype APITime struct {\n time.Time\n}\n\nfunc (t *APITime) UnmarshalJSON(data []byte) error {\n // Try multiple formats:\n // 1. Checkvist format: \"2006/01/02 15:04:05 -0700\"\n // 2. ISO8601/RFC3339: \"2006-01-02T15:04:05Z07:00\"\n}\n```\n\nReplace `time.Time` with `APITime` in all model structs.\n\n## Test\n\nA test has been added that documents this bug:\n`TestChecklists_List_RealAPIDateFormat` in `checklists_test.go`\n\nCurrently skips with message showing the parsing error. Should pass after fix.","status":"closed","priority":1,"issue_type":"bug","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T17:55:53.54028308+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T18:09:52.876804767+01:00","closed_at":"2026-01-14T18:09:52.876804767+01:00","close_reason":"APITime type with custom UnmarshalJSON implemented, all tests passing"}
{"id":"checkvist-api-5ab","title":"Implement Note operations","description":"Create notes.go with NoteService:\n- client.Notes(checklistID, taskID) returns NoteService\n- List(ctx) ([]Note, error) - GET /checklists/{id}/tasks/{task_id}/comments.json\n- Create(ctx, comment string) (*Note, error) - POST /checklists/{id}/tasks/{task_id}/comments.json\n- Update(ctx, noteID, comment string) (*Note, error) - PUT /checklists/{id}/tasks/{task_id}/comments/{note_id}.json\n- Delete(ctx, noteID) error - DELETE /checklists/{id}/tasks/{task_id}/comments/{note_id}.json\nContext support for all methods.","status":"closed","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:30:54.268124634+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:40:31.06124818+01:00","closed_at":"2026-01-14T13:40:31.06124818+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-5ab","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:32:55.843507717+01:00","created_by":"Oliver Jakoubek"}]} {"id":"checkvist-api-5ab","title":"Implement Note operations","description":"Create notes.go with NoteService:\n- client.Notes(checklistID, taskID) returns NoteService\n- List(ctx) ([]Note, error) - GET /checklists/{id}/tasks/{task_id}/comments.json\n- Create(ctx, comment string) (*Note, error) - POST /checklists/{id}/tasks/{task_id}/comments.json\n- Update(ctx, noteID, comment string) (*Note, error) - PUT /checklists/{id}/tasks/{task_id}/comments/{note_id}.json\n- Delete(ctx, noteID) error - DELETE /checklists/{id}/tasks/{task_id}/comments/{note_id}.json\nContext support for all methods.","status":"closed","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:30:54.268124634+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:40:31.06124818+01:00","closed_at":"2026-01-14T13:40:31.06124818+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-5ab","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:32:55.843507717+01:00","created_by":"Oliver Jakoubek"}]}