Add safe individual-block actions for Content databases - #2781
Conversation
…ntent-feedback-block-actions-base
…ntent-feedback-block-actions-base # Conflicts: # templates/content/server/plugins/db.ts
|
Here's a visual recap of what changed: Open the full interactive recap |
…ent-feedback-block-actions-base
…ent-feedback-block-actions-base
…ontent-feedback-block-actions # Conflicts: # templates/content/actions/delete-document.test.ts
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Builder reviewed your changes and found 5 potential issues 🔴
Review Details
Code Review Summary
PR #2781 adds a substantial, well-scoped action surface for listing and mutating individual Blocks in an exact Content database row/property. The implementation has good foundations: typed operation discrimination, field/row/schema revisions, durable receipt storage, scope checks, stable identity reconciliation, and extensive SQLite/PostgreSQL-oriented tests. I classified this as standard risk because it introduces shared data-mutation and concurrency behavior, though it does not change authentication or payment paths.
Key Findings
- 🔴 HIGH — Primary document-body mutations bypass the live collaboration document, allowing an open editor to remain stale and later overwrite the agent's committed change.
- 🔴 HIGH — Mutating one document-backed primary Blocks property can leave sibling primary-field identity sidecars stale when the same document belongs to multiple databases.
- 🟡 MEDIUM — Leaf blocks are accepted as insertion parents even though serialization cannot retain nested block children.
- 🟡 MEDIUM — The advertised row revision check is only a pre-write read and is not protected by a CAS shared with other row writers.
- 🟡 MEDIUM — Idempotent receipt replay bypasses current-state verification and can return stale data marked as verified.
- 🟡 MEDIUM — Replacing a container can recreate unchanged descendant IDs, breaking stable references.
The overall action contract is thoughtfully explicit and the test coverage is unusually broad; the findings are concentrated at the boundary between SQL persistence, collaborative editor state, and identity/revision bookkeeping.
🧪 Browser testing: Will run after this review (PR touches UI code)
| markdown: string, | ||
| now: string, | ||
| ) { | ||
| if (loaded.storageTarget === "document_body") { |
There was a problem hiding this comment.
🟡 Synchronize primary Blocks mutations with the live collaboration document
writeMarkdown updates documents.content directly for the primary Blocks field, but the Content editor uses a live Yjs document and does not observe raw SQL writes. An open editor can remain stale and later persist its old state over this successful, verified mutation; route the write through the collaboration-aware path or publish an equivalent post-commit synchronization update.
Additional Info
Found by 4/4 review agents; two classified this high and two medium, so severity normalized to medium per majority voting.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…k-block-actions # Conflicts: # templates/content/parity/matrix.md # templates/content/server/agent-card.test.ts
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Builder reviewed your changes — no new findings
Review Details
Incremental Code Review Summary
The latest PR head expands the test coverage and repairs the previously reported existing-upsert positioning behavior. The new implementation also adds direct editor-race coverage, leaf-parent rejection coverage, and PostgreSQL title-write concurrency coverage. I reviewed the complete shuffled diff with four independent agents and found no new confirmed regressions beyond the already-open primary document-body collaboration issue, which was intentionally not reposted.
The earlier upsert-position comment was verified fixed and has been resolved. Focused mutation and identity suites report 38 passing tests with one PostgreSQL-only case skipped in some environments; one agent also noted that broader typecheck is environment-blocked by production configuration validation rather than a code diagnostic.
Risk remains standard because this is shared Content data-mutation and concurrency logic. Existing concerns around live collaboration synchronization remain visible to the author and are not duplicated here.
🧪 Browser testing: Will run after this review (PR touches UI code)

Problem
Content could replace a whole Blocks field, but an agent could not safely address one stable block without risking sibling content, losing concurrent UI edits, or replaying a retry.
What changes
This PR adds two actions for one exact database membership row, row document, and Blocks property:
list-content-database-blocksreturns stable block IDs, canonical values, order, supported operations, and schema, row, and field revisions.mutate-content-database-blockperforms one typedinsert,update,upsert,delete, or same-parentreorderwhere the live block-kind capability matrix permits it.Sparse mutations preserve sibling blocks and other fields. Field and row compare-and-swap checks reject concurrent edits without clobbering them. Durable idempotency receipts replay the original result for an exact retry and reject reuse of a key with a different payload. Accepted mutations refresh the UI and return the row link, revisions, affected/deleted IDs, resulting order, and verified read-back. Unsupported kinds and structural operations fail explicitly.
The mutation schema remains object-shaped at the action boundary so both Content actions register as agent tools, while operation-specific validation stays discriminated and strict.
Dependency and base refresh
PRs #2778 and #2779 are merged on
main. This branch was rebuilt fromd916772e506b713c6f425bccc86d95bac13da5cc, with both merge commits present, and PR #2781 now targetsmaindirectly. Its independently reviewable artifact is 18 Content-only files.Three dependency overlaps were reconciled without changing the frozen contract:
_database-row-mutation.tskeeps merged row-mutation semantics and exports the substrate used here.shared/blocks-field-identity.tskeeps merged field-scoped collision and tombstone behavior while accepting caller-supplied preferred IDs for block actions.parity/matrix.mdwas regenerated from the reconciled source matrix.Current
mainthrough429ae6c416d99ffa0c1c012cf9bfa5f806647843is merged. The later Content intake work overlapped only the generated parity matrix and agent-card registration test: the resolution preserves both action sets, combines both registration assertions, and regenerates the matrix from its merged typed source. The resulting prospective merge tree is conflict-free.Verification
At exact head
ed6faff33f4a336c025672cb4fab748030acf5cd:git diff --check, Content product records 14/14, and product-impact tests 30/30 pass.An authenticated local real-interface fixture exercised exact list, insert, update, existing/new upsert, delete, and reorder; retry/dedupe and key-reuse rejection; field/row CAS and no-clobber; sibling and other-field preservation; receipts/link/read-back; unsupported-kind and outside-scope denial; and UI visibility after reload. The task-owned database
QpCpr3bVGzE2, pagel75u94Wlxx3v, row documentFE17mvlCyLm4, and both block fields were action-deleted, independently read back as absent, verified at zero rows across all relevant SQL tables, and the isolated database directory and browser session were removed.A bounded independent review found one cross-field preferred-ID race: persistence could remap a raced caller ID while the receipt retained the requested ID. The repair rejects cross-field remapping, maps database uniqueness races to
BLOCK_ID_ALREADY_USED, and asserts the inserted ID survives verified read-back. A later forge review identified five additional in-contract gaps: multi-database primary sidecars, leaf insertion parents, direct title-write row CAS, replay receipts after later drift, and ignored positioning on an existing-block upsert. The exact-head repair synchronizes every primary sidecar, rejects leaf parents before serialization, locks the row document before revision validation, re-verifies every replay, and atomically applies existing-upsert content and position while preserving its stable ID. Focused tests cover each path; the Yjs and container-descendant claims were independently rejected against the established action refresh/reconcile and identity algorithms, with an added descendant-ID regression test. No frozen-contract drift was required.A broad Content sweep also exposed two pre-existing unrelated failures outside this 18-file artifact: an obsolete row-upsert fixture shape and a Node 26
localStoragetest assumption. They are not counted as green and are not repaired here; all official branch-owned suites above pass.Boundaries
This PR does not add PR 4 routing/actor-history work, Slack or A2A behavior, provider calls, deployment, or production/canonical-data mutation.
Review focus