Run 5: Entity-data-grid Evolution — Project Plan
Date: 2026-03-19 Status: Pending Risk: Highest complexity — core of the project Effort: Large
User Request
Section titled “User Request”Promote general-purpose capabilities from the callil item-grid organism into entity-data-grid, making it the single canonical grid component for all entity types. Run 5 has five sequential sub-runs, each adding one capability with its own stories, tests, and verification gate. Sub-runs are ordered by risk (highest first).
Repository and Branch Context
Section titled “Repository and Branch Context”| Property | Value |
|---|---|
| Repository | ux-prototype |
| Branch | jmpicnic/component-consolidation |
| Working directory | /Users/jmp/code/arda/ux-prototype/ |
| Read-only reference | /Users/jmp/code/arda/callil-consolidation-worktree/ (callil branch) |
| Base component | src/components/canary/organisms/shared/entity-data-grid/ |
| Reference implementation | callil-consolidation-worktree/src/components/canary/organisms/item-grid/ |
Worktree Strategy
Section titled “Worktree Strategy”Not needed. All tasks write to a single repository (ux-prototype) on a single branch (jmpicnic/component-consolidation). Sub-runs are strictly sequential — only one writer at a time. The callil worktree is read-only reference material, not a write target.
Entry Criteria
Section titled “Entry Criteria”- Run 4 exit gate passed (SelectCellEditor promoted to
atoms/grid/select/, EnumCellEditor replaced, all grid stories with enum columns still work) - Branch
jmpicnic/component-consolidationclean, all checks passing:npm run lint— passnpx tsc --noEmit— passnpm run test— passnpm run build-storybook— pass
Artifact Specifications
Section titled “Artifact Specifications”Source Files Modified/Created
Section titled “Source Files Modified/Created”All source paths are relative to ux-prototype/src/components/canary/organisms/shared/entity-data-grid/.
| Sub-run | Files Created/Modified | Purpose |
|---|---|---|
| 5a | create-entity-data-grid.tsx, use-row-auto-publish.ts (new), use-row-auto-publish.test.ts (new), create-entity-data-grid.test.tsx (modified), create-entity-data-grid.stories.tsx (modified), index.ts (modified) | Row auto-publish lifecycle, pending changes, visual states, ref API |
| 5b | create-entity-data-grid.tsx (modified), create-entity-data-grid.test.tsx (modified), create-entity-data-grid.stories.tsx (modified) | Actions column injection |
| 5c | use-grid-search.ts (new), use-grid-search.test.ts (new), create-entity-data-grid.tsx (modified), create-entity-data-grid.test.tsx (modified), create-entity-data-grid.stories.tsx (modified) | Search/filter UI |
| 5d | create-entity-data-grid.tsx (modified), create-entity-data-grid.test.tsx (modified), create-entity-data-grid.stories.tsx (modified) | Client-side pagination mode |
| 5e | use-drag-to-scroll.ts (new), use-drag-to-scroll.test.ts (new), create-entity-data-grid.tsx (modified), create-entity-data-grid.stories.tsx (modified) | Toolbar slot, auto-height, drag-to-scroll |
CSS Classes (Sub-run 5a)
Section titled “CSS Classes (Sub-run 5a)”| Class | Purpose | Style |
|---|---|---|
.ag-row-saving | Row publish in progress | background-color: color-mix(in srgb, var(--base-primary) 6%, var(--base-background)) |
.ag-row-error | Row publish failed | background-color: color-mix(in srgb, var(--destructive) 8%, var(--base-background)) |
Injected via <style> tag scoped to the grid container, matching the pattern in the callil item-grid.
Task List
Section titled “Task List”Sub-run 5a: Row Auto-Publish Lifecycle (Highest Risk)
Section titled “Sub-run 5a: Row Auto-Publish Lifecycle (Highest Risk)”| # | Task | Persona | Depends On | Status | Acceptance Criteria |
|---|---|---|---|---|---|
| 5a.1 | Implement row-auto-publish as the only editing mode | front-end-engineer | Entry gate | Pending | onEntityUpdated callback removed from EntityDataGridModelProps. New onRowPublish(rowId, changes, entity?) async callback added. Cell changes accumulate per row instead of firing individually. |
| 5a.2 | Add onRowPublish async callback | front-end-engineer | 5a.1 | Pending | onRowPublish: (rowId: string, changes: Record<string, unknown>, entity?: T) => Promise<void> added to model props. Callback fires with batched changes for a row. |
| 5a.3 | Implement pending changes accumulation per row | front-end-engineer | 5a.2 | Pending | New useRowAutoPublish hook extracted. Pending changes tracked per row via Record<string, Record<string, unknown>>. Multiple cell edits in the same row accumulate into a single change set. |
| 5a.4 | Implement 50ms debounce on row blur before publish | front-end-engineer | 5a.3 | Pending | When onCellEditingStopped fires and no more cells are editing in that row, a 50ms setTimeout defers the publish call. If editing resumes in the same row within 50ms, the publish is cancelled. |
| 5a.5 | Add row visual states: idle, saving, success/error | front-end-engineer | 5a.4 | Pending | RowEditState type ('idle' | 'saving' | 'error') added. CSS classes .ag-row-saving and .ag-row-error injected via getRowClass callback. Styles match callil implementation (color-mix). <style> tag injected in grid container. |
| 5a.6 | Implement imperative ref API | front-end-engineer | 5a.5 | Pending | EntityDataGridRef updated: saveAll(): Promise<void> (publishes all dirty rows sequentially), discardAll(): void (restores original values, clears pending), getDirtyRowIds(): string[] (returns IDs of rows with pending changes). Old saveAllDrafts/discardAllDrafts/getHasUnsavedChanges removed or aliased. |
| 5a.7 | Add stories: RowAutoPublish, RowAutoPublishError, SaveAllDrafts, DiscardAllDrafts | front-end-engineer | 5a.6 | Pending | Four stories in create-entity-data-grid.stories.tsx with step DSL play functions. RowAutoPublish: edit cell, edit another in same row, click different row, verify saving callback. RowAutoPublishError: edit, blur, verify error visual persists. SaveAllDrafts/DiscardAllDrafts: toolbar button triggers ref API. |
| 5a.8 | Add unit tests for pending changes, publish lifecycle, ref API, CSS class injection | front-end-engineer | 5a.6 | Pending | Tests in use-row-auto-publish.test.ts and create-entity-data-grid.test.tsx. Cover: pending changes accumulate per row, onRowPublish fires with batched changes, dirty state tracking, saveAll/discardAll/getDirtyRowIds ref API, .ag-row-saving/.ag-row-error CSS class injection. |
| 5a.9 | Playwright MCP visual verification | front-end-engineer | 5a.7 | Pending | Navigate to RowAutoPublish story; edit cell, edit another in same row, click different row. Verify saving row background appears briefly then clears. Navigate to RowAutoPublishError; verify error row background persists. Check SaveAllDrafts/DiscardAllDrafts via toolbar button interactions. |
| 5a.10 | VRT baselines for row visual states | front-end-engineer | 5a.9 | Pending | Generate VRT baselines for RowAutoPublish, RowAutoPublishError stories. Capture: idle state, saving state (light orange tint), error state (light red tint). |
Sub-run 5a Gate: npm run test pass + all 4 stories render + play functions pass + VRT baselines captured.
Sub-run 5b: Actions Column (Medium Risk)
Section titled “Sub-run 5b: Actions Column (Medium Risk)”| # | Task | Persona | Depends On | Status | Acceptance Criteria |
|---|---|---|---|---|---|
| 5b.1 | Add actionsColumn as InitConfig property | front-end-engineer | 5a gate | Pending | New actionsColumn?: ColDef<T> & { actionCount?: number } in EntityDataGridConfig. Treated as mount-time (InitConfig) — value read once during factory creation, not reactive to prop changes. |
| 5b.2 | Inject as pinned-right column with auto-width calculation | front-end-engineer | 5b.1 | Pending | Actions column appended to column defs with pinned: 'right', lockPinned: true, suppressHeaderMenuButton: true. Width calculation: actionCount * 28 + (actionCount - 1) * 4 + 16 (28px per button, 4px gap, 16px padding). Falls back to explicit width or 200px default. |
| 5b.3 | Add WithActionsColumn story with step DSL play function | front-end-engineer | 5b.2 | Pending | Story in create-entity-data-grid.stories.tsx. Shows 2-3 action buttons per row. Play function: click action button, verify callback receives correct row data. |
| 5b.4 | Add unit tests: column injection, width calc, action callbacks | front-end-engineer | 5b.2 | Pending | Tests in create-entity-data-grid.test.tsx. Verify: actions column injected as last column with pinned: 'right', width calculated from actionCount, action callbacks receive correct entity. |
| 5b.5 | Playwright MCP visual verification | front-end-engineer | 5b.3 | Pending | Navigate to WithActionsColumn story. Click action buttons in rows. Verify pinned-right column appearance and button layout. |
Sub-run 5b Gate: npm run test pass + WithActionsColumn story renders + play function passes.
Sub-run 5c: Search/Filter UI (Medium Risk)
Section titled “Sub-run 5c: Search/Filter UI (Medium Risk)”| # | Task | Persona | Depends On | Status | Acceptance Criteria |
|---|---|---|---|---|---|
| 5c.1 | Add searchConfig to factory config | front-end-engineer | 5b gate | Pending | New searchConfig?: { fields: string[], placeholder?: string } in EntityDataGridConfig. When provided, search bar renders above the grid. When absent, no search UI. |
| 5c.2 | Implement search bar with 150ms debounce | front-end-engineer | 5c.1 | Pending | New useGridSearch hook. Search input with type="search", debounced via 150ms setTimeout. Quick filter applied via AG Grid’s quickFilterText or client-side rowData filtering on configured fields. Search icon from lucide-react. |
| 5c.3 | Implement filtered count display | front-end-engineer | 5c.2 | Pending | Count label shows "N items" when no search/selection, "N of M items" when filtered, "N of M selected" when rows selected. Updates reactively as search input changes and selection changes. |
| 5c.4 | Add WithSearch and WithSearchAndSelection stories with step DSL play functions | front-end-engineer | 5c.3 | Pending | Two stories. WithSearch: type search term, verify row count changes after debounce, verify count display text. WithSearchAndSelection: select rows, verify count switches to selected format. |
| 5c.5 | Add unit tests: debounce timing, filter predicate, count updates | front-end-engineer | 5c.3 | Pending | Tests in use-grid-search.test.ts and create-entity-data-grid.test.tsx. Cover: 150ms debounce (vi.useFakeTimers), filter applies to configured fields only, count text formats correctly for all states. |
| 5c.6 | Playwright MCP visual verification | front-end-engineer | 5c.4 | Pending | Navigate to WithSearch story. Type a search term. Verify row count updates after debounce. Verify count display text. Check WithSearchAndSelection: select rows, verify count switches. |
Sub-run 5c Gate: npm run test pass + both stories render + play functions pass.
Sub-run 5d: Pagination Modes (Low-Medium Risk)
Section titled “Sub-run 5d: Pagination Modes (Low-Medium Risk)”| # | Task | Persona | Depends On | Status | Acceptance Criteria |
|---|---|---|---|---|---|
| 5d.1 | Add pagination mode as StaticConfig property | front-end-engineer | 5c gate | Pending | New paginationMode in EntityDataGridConfig (factory config, design-time). Two modes: 'server' (existing PaginationData + callbacks) and 'client' (AG Grid built-in pageSize). Modes are mutually exclusive. When 'client', new pageSize: number in config. When 'server', existing paginationData/onNextPage/etc. props used. Default: none (no pagination). |
| 5d.2 | Implement client-side pagination | front-end-engineer | 5d.1 | Pending | When paginationMode: 'client', pass pagination: true and paginationPageSize to AG Grid. paginationPageSizeSelector: false (no size selector). |
| 5d.3 | Verify existing server-driven pagination still works | front-end-engineer | 5d.2 | Pending | Existing ServerPagination story still renders. Existing pagination tests still pass. No changes to server pagination code path. |
| 5d.4 | Add ClientPagination story | front-end-engineer | 5d.2 | Pending | Story in create-entity-data-grid.stories.tsx. Shows 50 rows with pageSize: 10. AG Grid’s built-in pagination controls visible. |
| 5d.5 | Add unit tests: both modes correct, mutually exclusive | front-end-engineer | 5d.2 | Pending | Tests verify: client mode passes correct AG Grid props, server mode uses PaginationData, specifying both modes produces a warning or the factory-time mode wins. |
Sub-run 5d Gate: npm run test pass + ClientPagination story renders + existing ServerPagination story still works.
Sub-run 5e: Toolbar, Auto-Height, Drag-to-Scroll (Low Risk)
Section titled “Sub-run 5e: Toolbar, Auto-Height, Drag-to-Scroll (Low Risk)”| # | Task | Persona | Depends On | Status | Acceptance Criteria |
|---|---|---|---|---|---|
| 5e.1 | Add toolbar prop (ReactNode slot above grid) | front-end-engineer | 5d gate | Pending | New toolbar?: ReactNode in EntityDataGridViewProps. Rendered in a container div above the grid (between search bar and grid, or at the top if no search). Flex layout with ml-auto for right-alignment. |
| 5e.2 | Add autoHeight StaticConfig property | front-end-engineer | 5e.1 | Pending | New autoHeight?: boolean in EntityDataGridConfig (design-time). When true, passes domLayout: 'autoHeight' to DataGrid/AG Grid. Disables explicit height. |
| 5e.3 | Add enableDragToScroll opt-in with useDragToScroll hook | front-end-engineer | 5e.2 | Pending | New enableDragToScroll?: boolean in EntityDataGridConfig. New useDragToScroll(containerRef) hook extracted from callil item-grid. ~80 lines pointer-event logic: 5px threshold, cursor change, cell focus clear, click suppression (100ms timeout), header/popup/input/button ignore. |
| 5e.4 | Add WithToolbar, AutoHeight, DragToScroll stories | front-end-engineer | 5e.3 | Pending | Three stories. WithToolbar: buttons/dropdown above grid. AutoHeight: grid with 3 rows growing to fit. DragToScroll: wide grid with many columns demonstrating horizontal drag. |
| 5e.5 | Add unit tests: toolbar render, autoHeight pass-through | front-end-engineer | 5e.3 | Pending | Tests verify: toolbar ReactNode renders in correct position, domLayout: 'autoHeight' passed when autoHeight: true, useDragToScroll hook attaches/detaches event listeners. DragToScroll play function optional (fragile in CI). |
Sub-run 5e Gate: npm run test pass + all 3 stories render.
Quality Review (Spans Full Run)
Section titled “Quality Review (Spans Full Run)”| # | Task | Persona | Depends On | Status | Acceptance Criteria |
|---|---|---|---|---|---|
| 5.qr | Quality review of sub-run 5a | quality-reviewer | 5a gate | Pending | Review useRowAutoPublish hook for: race conditions in debounce/publish, memory leaks (timer cleanup), correct useCallback/useMemo dependencies, TypeScript strictness, consistent error handling. Review API surface for breaking changes against existing consumers. |
Dependency Graph
Section titled “Dependency Graph”Entry Gate (Run 4 passed) | vSub-run 5a: Row Auto-Publish Lifecycle (highest risk) 5a.1 -> 5a.2 -> 5a.3 -> 5a.4 -> 5a.5 -> 5a.6 -> 5a.7 ---------> 5a.9 -> 5a.10 \-> 5a.8 ---/ [5a Gate: tests + stories + play functions + VRT] | +-- 5.qr (quality review, parallel with 5b start) | vSub-run 5b: Actions Column (medium risk) 5b.1 -> 5b.2 -> 5b.3 -> 5b.5 \-> 5b.4 [5b Gate: tests + story + play function] | vSub-run 5c: Search/Filter UI (medium risk) 5c.1 -> 5c.2 -> 5c.3 -> 5c.4 -> 5c.6 \-> 5c.5 [5c Gate: tests + stories + play functions] | vSub-run 5d: Pagination Modes (low-medium risk) 5d.1 -> 5d.2 -> 5d.3 \-> 5d.4 \-> 5d.5 [5d Gate: tests + stories] | vSub-run 5e: Toolbar, Auto-Height, Drag-to-Scroll (low risk) 5e.1 -> 5e.2 -> 5e.3 -> 5e.4 \-> 5e.5 [5e Gate: tests + stories] | vExit GateSub-runs are strictly sequential. Within each sub-run, implementation tasks are sequential, while stories and tests can begin as soon as the implementation they test is complete. The quality review (5.qr) for sub-run 5a can overlap with the start of sub-run 5b since it is read-only.
Personas Required
Section titled “Personas Required”| Persona | Tasks Assigned | Working Directory | Agent Name Pattern | Spawn Order |
|---|---|---|---|---|
| front-end-engineer | 5a.1-5a.10, 5b.1-5b.5, 5c.1-5c.6, 5d.1-5d.5, 5e.1-5e.5 | /Users/jmp/code/arda/ux-prototype/ | fe-entity-grid-5x | 1st |
| quality-reviewer | 5.qr | /Users/jmp/code/arda/ux-prototype/ (read-only) | qr-auto-publish | After 5a gate |
All spawned agents use mode: "bypassPermissions".
In Scope
Section titled “In Scope”- New
useRowAutoPublishhook replacing bothuseDirtyTracking(entity-data-grid) anduseItemGridEditing(item-grid) for the auto-publish lifecycle - Removal of cell-granular
onEntityUpdatedcallback from entity-data-grid - New
onRowPublishasync callback with batched per-row changes - Row visual states (saving/error) via CSS class injection
- Updated imperative ref API:
saveAll(),discardAll(),getDirtyRowIds() - Actions column as InitConfig property with auto-width calculation
- Search/filter UI with configurable fields, 150ms debounce, filtered count display
- Client-side pagination mode alongside existing server-driven mode
- Toolbar ReactNode slot above the grid
- Auto-height
domLayoutpass-through - Drag-to-scroll horizontal scrolling with
useDragToScrollhook - 10+ new stories with step DSL play functions
- Unit tests for every new capability
- VRT baselines for row visual states
- Playwright MCP visual verification for all stories
Out of Scope
Section titled “Out of Scope”- Item-grid refactoring to use entity-data-grid (Run 6)
- TypeaheadCellEditor extraction (already handled as a molecule in Run 3)
- entity-data-grid-shim changes (deprecated, kept as-is)
- Barrel export changes (Run 7)
- Composition/acceptance stories (Run 8)
- Changes to the DataGrid molecule (theme already migrated in Run 2)
- Any changes to the callil worktree (read-only reference)
Key Design Decisions
Section titled “Key Design Decisions”These decisions are recorded in analysis/grid-integration.md and govern this run:
| # | Decision | Rationale |
|---|---|---|
| 1 | Row-auto-publish is the ONLY editing mode | Cell-granular onEntityUpdated does not match the product’s UX pattern. All entity grids auto-publish on row blur. No need to support both modes. |
| 2 | Actions column is InitConfig (mount-time) | Contents may be determined by user/tenant settings in the future. Mount-time evaluation allows the factory to bake in the column definition once. |
| 3 | Pagination modes are StaticConfig (design-time), mutually exclusive | The pagination approach is a structural choice made when creating the factory — server-driven (external data source) vs client-side (full dataset in memory). Cannot be switched at runtime. |
| 4 | entity-data-grid-shim is deprecated but kept in place | New code uses entity-data-grid directly. The shim remains for any migration needs during Run 6+. |
| 5 | useDirtyTracking is replaced by useRowAutoPublish | The existing hook tracks dirty state but has no publish lifecycle. The new hook subsumes its functionality and adds pending changes accumulation, debounced publish, and row visual state management. |
Acceptance Criteria
Section titled “Acceptance Criteria”-
onEntityUpdatedcallback removed fromEntityDataGridModelProps -
onRowPublishasync callback fires with batched per-row changes on row blur - Pending changes accumulate across multiple cell edits in the same row
- 50ms debounce on row blur before publish fires
-
.ag-row-savingand.ag-row-errorCSS classes injected during publish lifecycle -
saveAll(),discardAll(),getDirtyRowIds()ref API works correctly - Actions column injected as pinned-right with correct auto-width calculation
- Search bar renders when
searchConfigprovided, with 150ms debounce - Filtered count displays correctly in all states (no filter, filtered, selected)
- Client-side pagination works via AG Grid built-in
pageSize - Server-driven pagination (existing) still works — no regressions
- Toolbar ReactNode renders above the grid
-
autoHeightpassesdomLayout: 'autoHeight'to AG Grid -
useDragToScrollhook provides horizontal drag-scroll with proper threshold and cleanup - All new stories (10+) render in Storybook
- All play functions use step DSL and pass in
npm run test:storybook - All unit tests pass
- VRT baselines captured for row visual states
- All existing entity-data-grid stories still pass (no regressions)
-
npm run lint+npx tsc --noEmit+npm run test+npm run build-storybookall pass
Risks and Blockers
Section titled “Risks and Blockers”| # | Risk/Blocker | Likelihood | Impact | Mitigation |
|---|---|---|---|---|
| R1 | Removing onEntityUpdated breaks existing consumers | Medium | High | Search for all usages of onEntityUpdated before removal. If external consumers exist, provide a migration path or deprecation period. The entity-data-grid-shim may need adjustment. |
| R2 | Race condition in debounce + async publish | Medium | High | Quality review (5.qr) specifically targets this. Use timer cleanup in useEffect return. Cancel pending publishes if component unmounts. |
| R3 | AG Grid getRowClass callback timing with React state | Low | Medium | The callil useItemGridEditing already proves this pattern works. Follow the same useCallback + state-driven approach. |
| R4 | Search debounce conflicts with cell editing | Low | Medium | Search input is outside the grid — AG Grid’s editing state is independent. Test this interaction in the WithSearch story. |
| R5 | useDragToScroll interferes with cell selection | Low | Low | Hook ignores drags on header, popups, inputs, buttons. The callil implementation is battle-tested. Copy it directly. |
| R6 | Client-side pagination conflicts with server-driven props | Low | Medium | Modes are mutually exclusive at factory creation time. TypeScript union type prevents passing both. Unit test enforces exclusivity. |
Open Questions and Decisions
Section titled “Open Questions and Decisions”| # | Question | Options | Recommendation | Decision |
|---|---|---|---|---|
| 1 | Should useDirtyTracking be removed or kept alongside useRowAutoPublish? | (a) Remove — single hook, (b) Keep both — backward compat | (a) Remove. The new hook subsumes all functionality. useDirtyTracking has no external consumers beyond entity-data-grid. | Accepted (2026-03-19): Remove |
| 2 | Should the search bar use AG Grid’s quickFilterText or client-side rowData filtering? | (a) quickFilterText — simpler but less control, (b) Client-side filter — matches item-grid approach | (b) Client-side. Gives control over which fields are searched and allows the filtered count display. Server-side search via Query DSL is a future enhancement (tracked as GitHub ticket). | Accepted (2026-03-19): Client-side |
| 3 | Should the toolbar prop coexist with the search bar in the same row or be a separate row? | (a) Same row — toolbar right-aligned after search, (b) Separate row above search | (a) Same row. Matches item-grid layout. Toolbar right-aligned with ml-auto. | Accepted (2026-03-19): Same row |
Agent Prompt Templates
Section titled “Agent Prompt Templates”front-end-engineer (Sub-run 5a)
Section titled “front-end-engineer (Sub-run 5a)”You are implementing the row-auto-publish lifecycle for entity-data-grid.
Working directory: /Users/jmp/code/arda/ux-prototype/Branch: jmpicnic/component-consolidationEntity-data-grid source: src/components/canary/organisms/shared/entity-data-grid/
Reference implementation:- /Users/jmp/code/arda/callil-consolidation-worktree/src/components/canary/organisms/item-grid/use-item-grid-editing.ts- /Users/jmp/code/arda/callil-consolidation-worktree/src/components/canary/organisms/item-grid/item-grid.tsx (row state styles, getRowClass usage)
Key decisions:- Row-auto-publish is the ONLY editing mode. Remove onEntityUpdated.- New onRowPublish(rowId, changes, entity?) async callback.- 50ms debounce on row blur before publish.- Row visual states via CSS classes: .ag-row-saving, .ag-row-error- Ref API: saveAll(), discardAll(), getDirtyRowIds()
Conventions:- All play functions use the step DSL (see analysis/test-coverage.md)- Use storyStepDelay() between major interaction steps- Follow existing test patterns in create-entity-data-grid.test.tsx- TypeScript strict mode (exactOptionalPropertyTypes: true)front-end-engineer (Sub-runs 5b-5e)
Section titled “front-end-engineer (Sub-runs 5b-5e)”You are adding capabilities to entity-data-grid. Each sub-run adds one feature.
Working directory: /Users/jmp/code/arda/ux-prototype/Branch: jmpicnic/component-consolidationEntity-data-grid source: src/components/canary/organisms/shared/entity-data-grid/
Reference implementation for each feature:- Actions column: callil-consolidation-worktree/.../item-grid.tsx (actionsColumn prop, width calc)- Search/filter: callil-consolidation-worktree/.../item-grid.tsx (search state, debounce, count display)- Pagination: callil-consolidation-worktree/.../item-grid.tsx (pageSize prop, AG Grid pagination)- Toolbar: callil-consolidation-worktree/.../item-grid.tsx (toolbar prop, flex layout)- Auto-height: callil-consolidation-worktree/.../item-grid.tsx (autoHeight prop, domLayout)- Drag-to-scroll: callil-consolidation-worktree/.../item-grid.tsx (useEffect with pointer events)
Config tiers:- StaticConfig (design-time, in EntityDataGridConfig): paginationMode, autoHeight, enableDragToScroll- InitConfig (mount-time, in EntityDataGridConfig): actionsColumn, searchConfig- RuntimeConfig (render-time, in EntityDataGridViewProps): toolbar
Conventions:- All play functions use the step DSL- All new hooks get their own test file- Follow existing patterns in create-entity-data-grid.stories.tsxquality-reviewer (Sub-run 5a)
Section titled “quality-reviewer (Sub-run 5a)”You are reviewing the row-auto-publish implementation for correctness and safety.
Files to review:- src/components/canary/organisms/shared/entity-data-grid/use-row-auto-publish.ts- src/components/canary/organisms/shared/entity-data-grid/create-entity-data-grid.tsx (changes only)- src/components/canary/organisms/shared/entity-data-grid/use-row-auto-publish.test.ts- src/components/canary/organisms/shared/entity-data-grid/create-entity-data-grid.test.tsx (changes only)
Focus areas:1. Race conditions: debounce timer vs async publish vs component unmount2. Memory leaks: timer cleanup in useEffect return, abort on unmount3. useCallback/useMemo dependency arrays — correctness and exhaustiveness4. TypeScript strictness: no implicit any, exactOptionalPropertyTypes compliance5. Error handling: what happens when onRowPublish rejects? Does the row stay in error state?6. API surface: breaking changes to EntityDataGridRef, EntityDataGridProps7. Test coverage: are edge cases covered (rapid edits, concurrent publishes, empty changes)?
This is a read-only review. Do not modify files.Implementation Output
Section titled “Implementation Output”At run completion, write the following to implementation/run-5-entity-grid-evolution/:
| Artifact | File | Description |
|---|---|---|
| Run summary | summary.md | What was done, decisions made during implementation, deviations from plan |
| Byproducts log | byproducts.md | Discovered issues, TODOs, observations for later runs |
| Validation output | validation-output.txt | Stdout from validate-exit.sh execution |
| Session log | session-log.md | Agent session IDs, timestamps, notable events |
Path: documentation/src/content/docs/roadmap/backlog/requested/callil-consolidation/implementation/run-5-entity-grid-evolution/
Handoff
Section titled “Handoff”To Run 6 (Item-grid Integration)
Section titled “To Run 6 (Item-grid Integration)”Exit artifacts from Run 5:
- Entity-data-grid with full API:
createEntityDataGrid<T>(config)supporting auto-publish, actions, search, pagination, toolbar, auto-height, drag-to-scroll - Updated
EntityDataGridConfigtype with all new properties - Updated
EntityDataGridReftype withsaveAll(),discardAll(),getDirtyRowIds() - 10+ stories demonstrating each capability
- Unit tests proving each capability
Context for Run 6:
- Item-grid can now be refactored to call
createEntityDataGrid<Item>(itemGridConfig)instead of building on the DataGrid molecule directly - Domain-specific code (curated columns, typeahead lookups, notes icon, image renderer) stays in item-grid config
- The
useItemGridEditinghook should be removable — entity-data-grid’s built-in auto-publish replaces it - Evaluate whether item-grid becomes a pure factory config call or needs a thin wrapper for domain-specific rendering
Exit Criteria
Section titled “Exit Criteria”All sub-run gates passed:
- 5a gate: Row auto-publish stories + tests + play functions + VRT pass
- 5b gate: Actions column story + tests + play function pass
- 5c gate: Search/filter stories + tests + play functions pass
- 5d gate: Pagination stories + tests pass
- 5e gate: Toolbar/auto-height/drag-to-scroll stories + tests pass
Overall:
-
npm run lint— pass -
npx tsc --noEmit— pass -
npm run test— pass (all tests, including all new tests) -
npm run build-storybook— pass -
npm run test:storybook— all play functions pass - VRT:
npx playwright test --project=vrt— pass (row visual state baselines captured) - All existing entity-data-grid stories still pass (no regressions)
- Entity-data-grid API supports all capabilities needed for item-grid to use it as a base (Run 6 entry criterion)
- Quality review (5.qr) completed for sub-run 5a with no blocking findings
Progress Log
Section titled “Progress Log”| Date | Event |
|---|---|
| 2026-03-19 | Project plan created |
Copyright: © Arda Systems 2025-2026, All rights reserved