Skip to content

Add granular table store updates and fix cross-block selection bugs#96

Merged
hackerwins merged 17 commits into
mainfrom
feat/table-granular-store-updates
Mar 29, 2026
Merged

Add granular table store updates and fix cross-block selection bugs#96
hackerwins merged 17 commits into
mainfrom
feat/table-granular-store-updates

Conversation

@hackerwins

@hackerwins hackerwins commented Mar 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Phase C granular store updates: Decompose whole-block updateBlock() for table blocks into fine-grained Yorkie Tree editByPath operations so concurrent cell edits merge instead of last-writer-wins
  • DocStore interface: Add 6 granular methods (insertTableRow, deleteTableRow, insertTableColumn, deleteTableColumn, updateTableCell, updateTableAttrs)
  • Bug fixes: Bold toggle not rendering in table cells, cross-block italic not applied to table cells, indent/outdent only applying to first paragraph in multi-block selection
  • Code quality: Extract forEachBlockInSelection helper to eliminate ~120 lines of duplicated block-level selection iteration in editor.ts and text-editor.ts
  • Docs cleanup: Remove implementation details from design doc (keep final design only), archive completed task, mark Table (Phase 3.2) complete in roadmap

Test plan

  • pnpm verify:fast passes
  • pnpm verify:self passes (builds + tests)
  • All existing table tests pass unchanged
  • New YorkieDocStore granular method tests (7 test suites)
  • New cross-block italic + table test
  • New multi-block applyBlockStyle test
  • Manual: select text across paragraphs spanning a table, apply Bold/Italic
  • Manual: select multiple paragraphs, toggle indent/outdent
  • Manual: type in table cell, apply Bold via toolbar

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added granular table editing operations for inserting/deleting rows and columns with targeted cell updates
    • Extended text styling to apply across table cell selections
    • Enabled block-level formatting (indentation, lists, margins) to work across table cell selections and multiple table cells
    • Improved table cell-level concurrent editing support
  • Tests

    • Added comprehensive test coverage for table row/column operations and multi-block style application across tables
  • Documentation

    • Updated design documentation with Phase C table architecture and concurrent editing behavior specifications

hackerwins and others added 14 commits March 29, 2026 23:16
Phase C decomposes whole-block updateBlock() into fine-grained
Yorkie Tree editByPath operations for concurrent cell-level editing.
Extends DocStore interface with six table-specific methods
(insertTableRow, deleteTableRow, insertTableColumn, deleteTableColumn,
updateTableCell, updateTableAttrs) so Doc class can express operation
intent directly. Also marks Phase B as complete.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
7 tasks covering: helper extraction, interface extension, MemDocStore,
YorkieDocStore, Doc class migration, tests, and final verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Prepare for Phase C granular table updates by extracting row and cell
node builders into standalone functions.
Phase C: insertTableRow, deleteTableRow, insertTableColumn,
deleteTableColumn, updateTableCell, updateTableAttrs.
Direct in-memory mutations with deep cloning for consistency
with existing MemDocStore patterns.
Each method uses targeted editByPath with nested paths instead of
whole-block replacement. Column operations iterate rows within a
single doc.update() for atomicity.
Each table operation now calls the appropriate DocStore method
(insertTableRow, updateTableCell, etc.) instead of replacing the
entire table block. This enables concurrent cell-level editing
when backed by YorkieDocStore.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Fix mergeBlocks (cell branch) and applyInlineStyle (cross-block
same-cell branch) to use updateTableCell instead of updateBlock
on the parent table block.
Tests verify each of the 6 methods (insertTableRow, deleteTableRow,
insertTableColumn, deleteTableColumn, updateTableCell, updateTableAttrs)
preserves other cells and surrounding blocks.
toggleStyle calls getBlockIndex which returns -1 for cell-internal
blocks, causing early return without markDirty. Now falls back to
markDirty on the parent table block via getCellInfo.
When selecting across paragraphs that span a table block,
applyInlineStyle skipped table blocks because it only iterated
top-level block.inlines (empty for tables). Now detects table
blocks and applies style to every cell block within them.
handleIndent and handleOutdent only operated on the cursor block.
Now iterate all blocks in the selection range via a new
getBlocksInSelectionRange helper. Same fix applied in both
TextEditor (keyboard shortcut) and EditorAPI (toolbar button).
applyBlockStyle and toggleList had a 3-case selection pattern
(cell-range, same-cell cross-block, top-level with table traversal)
that was duplicated and missing from indent/outdent. Extract
forEachBlockInSelection helper in both editor.ts and text-editor.ts
to eliminate duplication and fix indent/outdent for cross-table
selections.
@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@hackerwins has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 26 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 4 minutes and 26 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f22c5938-da46-4117-93e3-e8e403af23f0

📥 Commits

Reviewing files that changed from the base of the PR and between d714a9b and 597e29a.

📒 Files selected for processing (2)
  • packages/docs/src/model/document.ts
  • packages/docs/src/view/editor.ts
📝 Walkthrough

Walkthrough

This PR implements Phase C of the table CRDT design by introducing six granular table-specific DocStore methods (insertTableRow, deleteTableRow, insertTableColumn, deleteTableColumn, updateTableCell, updateTableAttrs) and refactoring document and editor code to use these operations instead of whole-block table replacements.

Changes

Cohort / File(s) Summary
Design Documentation
docs/design/docs-table-crdt.md, docs/design/docs-wordprocessor-roadmap.md
Updated Phase C table design with finalized granular editByPath operations, atomic control-flow constraints, concurrent-editing matrix, and revised TableCell structure from inlines: Inline[] to blocks: Block[].
DocStore Interface
packages/docs/src/store/store.ts
Added six new public method signatures to DocStore: insertTableRow, deleteTableRow, insertTableColumn, deleteTableColumn, updateTableCell, and updateTableAttrs.
Memory Store Implementation
packages/docs/src/store/memory.ts
Implemented all six table operations in MemDocStore using array splices and JSON deep-cloning; added private findBlock helper for block lookup.
Document Model
packages/docs/src/model/document.ts
Refactored table editing to call granular DocStore methods instead of updateBlock; updated row/column insertion/deletion, cell styling, inline style application within tables, and span-adjusted operations to persist via cell-specific updateTableCell calls.
Editor & View
packages/docs/src/view/editor.ts, packages/docs/src/view/text-editor.ts
Added shared forEachBlockInSelection helper for iterating leaf blocks across selections including table cells; updated applyBlockStyle, toggleList, indent, outdent, and toggleStyle to operate over all affected blocks; improved dirty-marking for table parent blocks.
Yorkie Store Implementation
packages/frontend/src/app/docs/yorkie-doc-store.ts
Implemented six table operations in YorkieDocStore using targeted Yorkie Tree editByPath mutations; added buildRowNode and buildCellNode helpers; added private findTableIndex() lookup.
Tests
packages/docs/test/model/document.test.ts, packages/docs/test/model/table.test.ts, packages/frontend/tests/app/docs/yorkie-doc-store.test.ts
Added unit tests for per-block marginLeft styling, cross-selection italic application spanning table cells, and new YorkieDocStore table methods; added makeTableDoc() helper for test setup.
Task Documentation
docs/tasks/README.md, docs/tasks/archive/README.md, docs/tasks/archive/2026/03/20260329-table-granular-updates-todo.md
Added archived task document detailing Phase C implementation plan; updated task counts from 111 to 112.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hop, hop, the tables now know their fate—
No more whole blocks to ruin the state!
Cell by cell, row by row, we tiptoe through,
Granular edits make conflicts disappear—true! ✨🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the two main themes of the PR: adding granular table store updates (Phase C) and fixing cross-block selection bugs. Both are prominent aspects of the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/table-granular-store-updates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 104.3s

Lane Status Duration
sheets:build ✅ pass 13.3s
docs:build ✅ pass 6.5s
verify:fast ✅ pass 49.1s
frontend:build ✅ pass 15.4s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.4s
cli:build ✅ pass 1.8s
verify:entropy ✅ pass 13.4s

Verification: verify:integration

Result: ✅ PASS

Remove implementation details (code snippets, implementation order,
test strategy) from docs-table-crdt.md, keeping only final design.
Mark Phase C as Complete. Archive the Phase C task to docs/tasks/archive.
Update TableCell type to reflect Block[] containers and add
references to detailed design docs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/frontend/src/app/docs/yorkie-doc-store.ts (1)

482-487: Minor inefficiency: getDocument() called twice per granular method.

Each granular method calls findTableIndex() (which calls getDocument()), then calls getDocument() again after doc.update(). This results in two document clones per operation.

Consider caching the document from findTableIndex() or having it return both the index and the document:

♻️ Optional refactor
-  private findTableIndex(tableBlockId: string): number {
+  private findTableIndex(tableBlockId: string): { index: number; currentDoc: Document } {
     const currentDoc = this.getDocument();
     const index = currentDoc.blocks.findIndex((b) => b.id === tableBlockId);
     if (index === -1) throw new Error(`Table block not found: ${tableBlockId}`);
-    return index;
+    return { index, currentDoc };
   }

Then callers can reuse the returned currentDoc instead of calling getDocument() again.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/docs/yorkie-doc-store.ts` around lines 482 - 487,
findTableIndex currently calls getDocument() internally and callers also call
getDocument() again after doc.update, causing duplicate document clones; change
findTableIndex to return both the found index and the document snapshot (e.g.,
return { index, currentDoc }) or provide a cachedDocument along with the index
so callers (methods that call findTableIndex and then doc.update) can reuse the
returned currentDoc instead of calling getDocument() a second time; update
callers of findTableIndex to destructure the returned { index, currentDoc } and
use that currentDoc for reads, only calling this.getDocument() again when a
fresh post-update snapshot is actually required.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/docs/src/model/document.ts`:
- Around line 363-379: Selection endpoints can mix top-level paragraph blocks
and table cell blocks causing getBlockIndex(cellBlockId) to return -1 and lead
to dereferencing this._document.blocks[-1]; before the top-level block walk
normalize any endpoint that is a cell block to its parent table block id (use
the cell's tableBlockId) or add an explicit mixed-endpoint branch so the later
loop sees valid top-level indices. Update the selection-normalization logic
(where getBlockIndex is called) to detect cell blocks (via block.tableData
presence or cell lookup), replace the cell endpoint id with its parent
tableBlockId, then proceed to call getBlockIndex and run the existing table
handling (applyStyleToBlock, store.updateTableCell) safely.
- Around line 582-591: The persistence pass is re-checking cell.rowSpan/colSpan
after you've already decremented them, causing merged cells that went from 2->1
to be skipped and not written back; fix by capturing the original span values
before any mutation (e.g., store originalRowSpan = cell.rowSpan ?? 1 and
originalColSpan = cell.colSpan ?? 1) and use those originals when evaluating the
predicate in the loops that call this.store.updateTableCell(blockId, r, c,
cell); apply the same change to the analogous column loop referenced (the
646-655 block) so decisions are based on pre-decrement spans rather than the
mutated values.

In `@packages/docs/src/view/editor.ts`:
- Around line 293-296: In the cursor-only fallback, we're dirtying the leaf cell
block (doc.getBlock(cursor.position.blockId)) instead of the owning table, so
replace the markDirty(block.id) call with a markDirty of the owning table block
id (e.g., use block.tableBlockId or traverse parents from doc.getBlock to find
the enclosing table block id) so toolbar/API calls (applyBlockStyle, toggleList,
indent, outdent) trigger table re-layout; still call fn(block) with the leaf
block before marking the table dirty.

---

Nitpick comments:
In `@packages/frontend/src/app/docs/yorkie-doc-store.ts`:
- Around line 482-487: findTableIndex currently calls getDocument() internally
and callers also call getDocument() again after doc.update, causing duplicate
document clones; change findTableIndex to return both the found index and the
document snapshot (e.g., return { index, currentDoc }) or provide a
cachedDocument along with the index so callers (methods that call findTableIndex
and then doc.update) can reuse the returned currentDoc instead of calling
getDocument() a second time; update callers of findTableIndex to destructure the
returned { index, currentDoc } and use that currentDoc for reads, only calling
this.getDocument() again when a fresh post-update snapshot is actually required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0de26c0e-4821-426a-b2c1-da9856c1c0b2

📥 Commits

Reviewing files that changed from the base of the PR and between 63fc17c and 61f7465.

📒 Files selected for processing (11)
  • docs/design/docs-table-crdt.md
  • docs/tasks/active/20260329-table-granular-updates-todo.md
  • packages/docs/src/model/document.ts
  • packages/docs/src/store/memory.ts
  • packages/docs/src/store/store.ts
  • packages/docs/src/view/editor.ts
  • packages/docs/src/view/text-editor.ts
  • packages/docs/test/model/document.test.ts
  • packages/docs/test/model/table.test.ts
  • packages/frontend/src/app/docs/yorkie-doc-store.ts
  • packages/frontend/tests/app/docs/yorkie-doc-store.test.ts

Comment thread packages/docs/src/model/document.ts
Comment thread packages/docs/src/model/document.ts Outdated
Comment on lines +582 to +591
// Update cells with adjusted rowSpan
for (let r = 0; r < rowIndex; r++) {
for (let c = 0; c < td.rows[r].cells.length; c++) {
const cell = td.rows[r].cells[c];
const rs = cell.rowSpan ?? 1;
if (r + rs > rowIndex) {
this.store.updateTableCell(blockId, r, c, cell);
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Don't re-check decremented spans in the persistence pass.

Both follow-up loops inspect rowSpan/colSpan after you've already decremented it. A merge that ends exactly on the deleted edge goes 2 -> 1, no longer satisfies the predicate, and never gets written back to the store. After refresh(), the row/column is gone but the neighboring merged cell still has stale span metadata.

Also applies to: 646-655

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/docs/src/model/document.ts` around lines 582 - 591, The persistence
pass is re-checking cell.rowSpan/colSpan after you've already decremented them,
causing merged cells that went from 2->1 to be skipped and not written back; fix
by capturing the original span values before any mutation (e.g., store
originalRowSpan = cell.rowSpan ?? 1 and originalColSpan = cell.colSpan ?? 1) and
use those originals when evaluating the predicate in the loops that call
this.store.updateTableCell(blockId, r, c, cell); apply the same change to the
analogous column loop referenced (the 646-655 block) so decisions are based on
pre-decrement spans rather than the mutated values.

Comment thread packages/docs/src/view/editor.ts Outdated
@hackerwins hackerwins changed the title Add granular table store updates (Phase C) and fix cross-block selection bugs Add granular table store updates and fix cross-block selection bugs Mar 29, 2026
Address CodeRabbit review findings:
- Merge rowSpan/colSpan adjust and store persist into one loop
  so decremented spans (2->1) are written back correctly
- Normalize cell endpoints to parent tableBlockId in cross-block
  applyInlineStyle for mixed paragraph-cell selections
- Use tableBlockId for markDirty in cursor-only fallback of
  forEachBlockInSelection

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/tasks/archive/2026/03/20260329-table-granular-updates-todo.md`:
- Around line 733-757: Update "Task 7: Final verification and cleanup" to add an
explicit final step that runs the archive/index commands before closing the
task: append a new checklist item under Step 4 (or as Step 5) that instructs to
run `pnpm tasks:archive && pnpm tasks:index` and confirm completion; also ensure
the checklist bullet explicitly reminds to update docs/design/ when architecture
changed and to run `pnpm verify:fast` prior to archiving so the final flow in
"Task 7: Final verification and cleanup" is fully reproducible and includes the
archive/index step.
- Around line 126-129: Remove the conflicting typecheck line and keep only the
canonical command: delete the initial "pnpm sheets typecheck 2>&1 | head -5"
entry and leave the canonical "cd packages/docs && npx tsc --noEmit 2>&1 | head
-20" command in the Task 2 section so there is a single authoritative
instruction; update surrounding text if needed to reference only the retained
command.
- Around line 344-351: The current updateTableAttrs implementation replaces the
whole table node via doc.update(... editByPath([tIdx], [tIdx + 1],
buildBlockNode(block))) which violates the Phase C granular-update goal;
instead, change updateTableAttrs (used with findTableIndex and getDocument) to
perform a scoped attrs-only mutation by updating only the tableData.columnWidths
path (e.g., call doc.update with a targeted edit that mutates
root.content[tIdx].tableData.columnWidths) rather than rebuilding the entire
block with buildBlockNode, so concurrent cell edits are not overwritten.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3882203b-7db6-4081-892b-4a2b9491148e

📥 Commits

Reviewing files that changed from the base of the PR and between 61f7465 and d714a9b.

📒 Files selected for processing (5)
  • docs/design/docs-table-crdt.md
  • docs/design/docs-wordprocessor-roadmap.md
  • docs/tasks/README.md
  • docs/tasks/archive/2026/03/20260329-table-granular-updates-todo.md
  • docs/tasks/archive/README.md
✅ Files skipped from review due to trivial changes (2)
  • docs/tasks/archive/README.md
  • docs/tasks/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/design/docs-table-crdt.md

Comment on lines +126 to +129
Run: `pnpm sheets typecheck 2>&1 | head -5` (docs package uses the same typecheck)

Actually, run: `cd packages/docs && npx tsc --noEmit 2>&1 | head -20`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove conflicting typecheck command in Task 2

This section lists a command and then immediately overrides it with “Actually, run...”. Keep only the canonical command to avoid accidental execution drift in scripted workflows.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/tasks/archive/2026/03/20260329-table-granular-updates-todo.md` around
lines 126 - 129, Remove the conflicting typecheck line and keep only the
canonical command: delete the initial "pnpm sheets typecheck 2>&1 | head -5"
entry and leave the canonical "cd packages/docs && npx tsc --noEmit 2>&1 | head
-20" command in the Task 2 section so there is a single authoritative
instruction; update surrounding text if needed to reference only the retained
command.

Comment on lines +344 to +351
updateTableAttrs(tableBlockId: string, attrs: { cols: number[] }): void {
const tIdx = this.findTableIndex(tableBlockId);
const currentDoc = this.getDocument();
const block = currentDoc.blocks[tIdx];
block.tableData!.columnWidths = attrs.cols;
this.doc.update((root) => {
root.content.editByPath([tIdx], [tIdx + 1], buildBlockNode(block));
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid whole-table replacement in updateTableAttrs instructions

This step reintroduces broad block replacement (editByPath([tIdx], [tIdx + 1], buildBlockNode(block))), which conflicts with the Phase C granular-update goal and risks overwriting concurrent cell edits. Keep updateTableAttrs scoped to attrs-only mutation (or a truly targeted path) instead of replacing the full table node.

Suggested doc correction
-  updateTableAttrs(tableBlockId: string, attrs: { cols: number[] }): void {
-    const tIdx = this.findTableIndex(tableBlockId);
-    const currentDoc = this.getDocument();
-    const block = currentDoc.blocks[tIdx];
-    block.tableData!.columnWidths = attrs.cols;
-    this.doc.update((root) => {
-      root.content.editByPath([tIdx], [tIdx + 1], buildBlockNode(block));
-    });
-    this.cachedDoc = currentDoc;
-    this.dirty = false;
-  }
+  updateTableAttrs(tableBlockId: string, attrs: { cols: number[] }): void {
+    const tIdx = this.findTableIndex(tableBlockId);
+    const currentDoc = this.getDocument();
+    currentDoc.blocks[tIdx].tableData!.columnWidths = [...attrs.cols];
+    this.cachedDoc = currentDoc;
+    this.dirty = false;
+    // Keep this attrs-scoped; do not replace the entire table node.
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/tasks/archive/2026/03/20260329-table-granular-updates-todo.md` around
lines 344 - 351, The current updateTableAttrs implementation replaces the whole
table node via doc.update(... editByPath([tIdx], [tIdx + 1],
buildBlockNode(block))) which violates the Phase C granular-update goal;
instead, change updateTableAttrs (used with findTableIndex and getDocument) to
perform a scoped attrs-only mutation by updating only the tableData.columnWidths
path (e.g., call doc.update with a targeted edit that mutates
root.content[tIdx].tableData.columnWidths) rather than rebuilding the entire
block with buildBlockNode, so concurrent cell edits are not overwritten.

Comment on lines +733 to +757
### Task 7: Final verification and cleanup

- [ ] **Step 1: Run full verify**

Run: `pnpm verify:fast`
Expected: All tests pass.

- [ ] **Step 2: Verify existing Doc table tests**

Run: `cd packages/docs && npx vitest run test/model/table.test.ts --reporter verbose`
Expected: All tests pass — confirms `MemDocStore` granular methods work correctly through `Doc`.

- [ ] **Step 3: Verify no remaining whole-block updateBlock calls for tables**

Search for any remaining `store.updateBlock` calls in table methods of `document.ts`:

```bash
grep -n 'store.updateBlock' packages/docs/src/model/document.ts
```

Expected: Only non-table usages remain (e.g., `updateBlockInStore`'s else branch for top-level blocks, `insertText`, `deleteText`, etc.). No calls within `insertRow`, `deleteRow`, `insertColumn`, `deleteColumn`, `mergeCells`, `splitCell`, `applyCellStyle`, `setColumnWidth`.

- [ ] **Step 4: Update design doc Phase C status**

If all verifications pass, no further changes needed — the design doc was already updated at the start of this session.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Final checklist should explicitly include archive/index command

Please add an explicit final step to run pnpm tasks:archive && pnpm tasks:index before closure, so the completion flow is fully reproducible in the task doc itself.

Based on learnings: Before marking a task done: (1) Update docs/design/ if architecture changed, (2) Run pnpm verify:fast and confirm pass, (3) Archive with pnpm tasks:archive && pnpm tasks:index.

🧰 Tools
🪛 LanguageTool

[style] ~757-~757: Consider an alternative to strengthen your wording.
Context: ...status** If all verifications pass, no further changes needed — the design doc was already upd...

(CHANGES_ADJUSTMENTS)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/tasks/archive/2026/03/20260329-table-granular-updates-todo.md` around
lines 733 - 757, Update "Task 7: Final verification and cleanup" to add an
explicit final step that runs the archive/index commands before closing the
task: append a new checklist item under Step 4 (or as Step 5) that instructs to
run `pnpm tasks:archive && pnpm tasks:index` and confirm completion; also ensure
the checklist bullet explicitly reminds to update docs/design/ when architecture
changed and to run `pnpm verify:fast` prior to archiving so the final flow in
"Task 7: Final verification and cleanup" is fully reproducible and includes the
archive/index step.

@hackerwins
hackerwins merged commit faeacad into main Mar 29, 2026
1 check passed
@hackerwins
hackerwins deleted the feat/table-granular-store-updates branch March 29, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant