diff --git a/.pql/changelog/ticket_history/2026-07.sql b/.pql/changelog/ticket_history/2026-07.sql index 8dcf76b0..1bc75528 100644 --- a/.pql/changelog/ticket_history/2026-07.sql +++ b/.pql/changelog/ticket_history/2026-07.sql @@ -63,3 +63,18 @@ SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch intera PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk. PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).', NULL, '2026-07-02 21:22:59', '2026-07-02 21:22:59.395', '2026-07-02 21:22:59.395', NULL, '6b17245b0d3d39a0d61bc90a2a0a034b', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'description', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget. + +SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin). + +PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk. + +PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget. + +SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin). + +PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk. + +PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists). + +Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.', NULL, '2026-07-03 20:20:00', '2026-07-03 20:20:00.827', '2026-07-03 20:20:00.827', NULL, '541312e6b1f559f60934ad1a1b784d76', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-07.sql b/.pql/changelog/tickets/2026-07.sql index 8b3b1803..2d34c75e 100644 --- a/.pql/changelog/tickets/2026-07.sql +++ b/.pql/changelog/tickets/2026-07.sql @@ -58,3 +58,12 @@ SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch intera PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk. PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists).', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-02 21:22:59.395', NULL, '6ba2a2c1892dbf56c582f83bd9753314', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB2G1WD1839Z90AQ5C0BHNV4', 'story', '06FHAX7FV5KWGZQ31617R63W94', 'Tier-5 canvas pane (builtin.canvas)', 'Tier-5 canvas PANE, absorbed from the former T-7 into the unified canvas epic (T-317, decision D-91). A full workspace pane that renders .canvas files by CONVERTING them into the drawing-card JSON (per D-91: .canvas is an import format, not a native schema) and painting via the shared canvas renderer (T-318). Scope: nodes (note, text, group, image) + edges + layout state; pan/zoom; node selection, drag, resize; edit affordances (add note from file picker, add text node, draw edge between nodes); persist layout back to the .canvas file on disk. Uses MultitabPane (T-83) for tabs and its own slot per D-47; panels are extension-shaped (D-17). Depends on the core renderer (T-318). NOTE: unlike the conversation drawing card (display-only, D-78), this pane is interactive/editable — it is a pane, not a conversation widget. + +SCOPE NOTE (2026-06-29): currently a 17-line stub. This is a from-scratch interactive Tier-5 pane (parse .canvas -> drawing-card JSON, CustomPaint render, pan/zoom, node select/drag/resize, edit affordances, persist .canvas) — a multi-session feature, NOT template-class work. The drawing-card TEMPLATE half of epic T-317 is now complete (svg/d2/image/icon/compare/graph + stdin). + +PROGRESS (2026-07-02): two foundation slices built + tested (from the 17-line stub). (1) JSONCanvas parser/model — lib/src/canvas/json_canvas.dart (2eb5d0f1): typed CanvasDoc (text/file/link/group nodes + edges with sides/ends/color/label), parse + toJson round-trip, skips unknown/malformed; pure Dart, 8 dart-test cases. (2) CustomPaint renderer — lib/builtin/canvas/src/canvas_painter.dart (035a37a1): CanvasBounds + pan/zoom CanvasViewport, group frames + edges (arrowheads) + node cards; node colours from the file (Obsidian presets/hex, NOT clide tokens per arbitrary-content rule), chrome themed; 7 tests (pixel-probe + viewport + colour). DECISION NOTE: the interactive pane paints the CanvasDoc model directly via CustomPaint (hit-testable, cheap re-paint) rather than re-lowering to SVG each frame — the ticket''s ''convert to drawing-card JSON'' path (D-91 SVG substrate) is for the display-only viewer; an editable pane needs direct model painting. Mirrors the graph pane. REMAINING (multi-session): interactive CanvasView (hit-test nodes + pan/zoom + click-select), pane shell (load .canvas from disk, workspace slot D-47, MultitabPane), CanvasExtension registration + open-.canvas routing, then edit affordances (add node/edge, drag, resize) + persist back to disk. + +PROGRESS (2026-07-02, cont.): third foundation slice landed — interactive CanvasView (lib/builtin/canvas/src/canvas_view.dart, 7700fc7a): hitTestCanvasNode (topmost node under a point; cards beat the group frames behind, via the painter''s own viewport) + scroll-zoom + drag-pan + click-select with a focus ring; 6 tests. The canvas rendering + interaction FOUNDATION is now complete + tested (parser 2eb5d0f1, renderer 035a37a1, view 7700fc7a — 21 canvas tests), mirroring where T-323''s foundation was before its integration phase. NOT yet reachable. REACHABLE-INTEGRATION PHASE (next, fresh session): (a) pane shell — a StatefulWidget that loads a .canvas from disk (files.read/editor.open path), holds the CanvasDoc, embeds CanvasView; (b) CanvasExtension registration as a workspace pane (own slot D-47, MultitabPane T-83); (c) FILE-OPEN ROUTING — how opening a .canvas lands in this pane instead of the text editor: NOTE the TabContribution.fileGlobs field is DECLARED but has ZERO consumers in lib/, so this routing must be built (wire fileGlobs, or have the editor delegate by extension, or a command + workspace tab); (d) i18n + tests. THEN the edit phase: add node/text/edge affordances, node drag + resize, and persist the CanvasDoc back to the .canvas file (encode() already exists). + +Refinement (2026-07-03, user-confirmed): (1) SLOT: Slots.workspace — diff/editor recipe, center column; coexists with Claude the way diff does (D-47). (2) TABS: real MultitabPane — N .canvas files open as tabs (user explicitly chose over the single-TabContribution graph/diff precedent; needs MultitabController plumbing like Claude sessions). (3) FILE-OPEN ROUTING resolved by inspection: TabContribution.fileGlobs is dead (zero consumers) — do NOT wire it. Add a .canvas branch in lib/kernel/src/file_open.dart openWorkspaceFile() publishing to ''builtin.canvas''/''selection'' (mirror of the .md branch), and D-6 CLI parity via a ''canvas'' entry in the _readers map at lib/src/daemon/ui_command.dart:34 → clide ui open canvas (diff precedent). (4) Fix stale doc header lib/src/canvas/json_canvas.dart:5-7 (claims SVG-lowering; actual architecture paints CanvasDoc directly per the ticket''s DECISION NOTE) in the same pass. (5) Edit phase later needs a mutation path (CanvasView has no onChanged; CanvasDoc is immutable-construction only) — deferred, flagged now.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-10 11:17:17', '2026-07-03 20:20:00.827', NULL, '34eeab12879a55e77e6c9841a442cf27', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);