Skip to content

Updating SharedTree's public transaction docs#26564

Open
jumyhre wants to merge 3 commits intomainfrom
jumyhre/docUpdate
Open

Updating SharedTree's public transaction docs#26564
jumyhre wants to merge 3 commits intomainfrom
jumyhre/docUpdate

Conversation

@jumyhre
Copy link
Contributor

@jumyhre jumyhre commented Feb 26, 2026

This PR updates the docs for SharedTree's transaction API. It adds:

  • A brief explanation of the new TreeAlpha runTransaction API, and what benefits it provides over the old API
  • Snippets for new API use, including async forms and transaction nesting
  • A section on Constraints and their usage

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the documentation for SharedTree's transaction API, removing the old TODO and adding comprehensive documentation for the new alpha-level transaction APIs. The changes introduce examples and explanations for the TreeBranchAlpha.runTransaction and TreeViewAlpha.runTransaction methods, which provide more control over error handling compared to the legacy Tree.runTransaction API.

Changes:

  • Removed the TODO comment about updating the transaction API documentation
  • Added detailed documentation for the new alpha transaction APIs including synchronous and asynchronous forms
  • Documented transaction nesting behavior and constraints functionality


The APIs described in this section are currently `@alpha` and may change in future releases.

Unlike `Tree.runTransaction`, the Alpha `runTransaction` does **not** automatically roll back the transaction if the callback throws an error. If your callback may throw, you should handle errors explicitly and return { rollback: true } when required
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Missing period at the end of the sentence. The sentence should end with a period for consistency with documentation style.

Suggested change
Unlike `Tree.runTransaction`, the Alpha `runTransaction` does **not** automatically roll back the transaction if the callback throws an error. If your callback may throw, you should handle errors explicitly and return { rollback: true } when required
Unlike `Tree.runTransaction`, the Alpha `runTransaction` does **not** automatically roll back the transaction if the callback throws an error. If your callback may throw, you should handle errors explicitly and return { rollback: true } when required.

Copilot uses AI. Check for mistakes.
```

### The `transaction` Callback Function
The callback function passed to runTransaction is the actual implementation of the transaction to apply. It can optionally return a status object indicating success or failure and include a user-defined value.
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The sentence is grammatically awkward. Consider rephrasing to: "The callback function passed to runTransaction implements the transaction logic. It can optionally return a status object indicating success or failure, and include a user-defined value."

Suggested change
The callback function passed to runTransaction is the actual implementation of the transaction to apply. It can optionally return a status object indicating success or failure and include a user-defined value.
The callback function passed to runTransaction implements the transaction logic. It can optionally return a status object indicating success or failure, and include a user-defined value.

Copilot uses AI. Check for mistakes.

## Constraints

Constraints let you opt in to stricter validation when your application needs it. A violated constraint causes the **entire transaction** to be dropped. Constraints can be applied as preconditions to a transaction (or as preconditions on revert, to be applied if the transaction is reverted), thereby ensuring that its effect will only apply if some specific conditions are met.
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The phrase "its effect will only apply" could be clearer. Consider rephrasing to "the transaction will only be applied" or "the transaction's changes will only be applied" for better clarity.

Suggested change
Constraints let you opt in to stricter validation when your application needs it. A violated constraint causes the **entire transaction** to be dropped. Constraints can be applied as preconditions to a transaction (or as preconditions on revert, to be applied if the transaction is reverted), thereby ensuring that its effect will only apply if some specific conditions are met.
Constraints let you opt in to stricter validation when your application needs it. A violated constraint causes the **entire transaction** to be dropped. Constraints can be applied as preconditions to a transaction (or as preconditions on revert, to be applied if the transaction is reverted), thereby ensuring that the transaction's changes will only be applied if some specific conditions are met.

Copilot uses AI. Check for mistakes.

:::

The TreeBranchAlpha API introduces `TreeBranchAlpha.runTransaction` as a replacement for `Tree.runTransaction`. This new API exists to solve correctness issues where errors being thrown in runTransaction could result in an undefined state. This new API enables developers to customize how their application handles this error case.
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The phrasing "TreeBranchAlpha API introduces" is technically imprecise. TreeBranchAlpha is an interface type, not an API namespace. The APIs are introduced on both the TreeBranchAlpha interface (obtained via TreeAlpha.branch(node)) and the TreeViewAlpha interface. Consider rephrasing to: "The alpha APIs introduce runTransaction methods on TreeBranchAlpha and TreeViewAlpha as a replacement for Tree.runTransaction." This would more accurately describe where the APIs are available.

Suggested change
The TreeBranchAlpha API introduces `TreeBranchAlpha.runTransaction` as a replacement for `Tree.runTransaction`. This new API exists to solve correctness issues where errors being thrown in runTransaction could result in an undefined state. This new API enables developers to customize how their application handles this error case.
The alpha APIs introduce `runTransaction` methods on `TreeBranchAlpha` and `TreeViewAlpha` as a replacement for `Tree.runTransaction`. This new API exists to solve correctness issues where errors being thrown in `runTransaction` could result in an undefined state. This new API enables developers to customize how their application handles this error case.

Copilot uses AI. Check for mistakes.

### Supported Constraint Types

// TODO:#59981: Document new constraint types as they are implemented. Consider breaking this section into its own page when we have enough constraint types to warrant it.
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The TODO comment is visible in the published documentation. Consider moving this TODO to a code comment in the relevant source file, or converting it to a note/admonition if users need to be aware that more constraint types are coming. If this is meant for maintainers only, it should not appear in user-facing documentation.

Suggested change
// TODO:#59981: Document new constraint types as they are implemented. Consider breaking this section into its own page when we have enough constraint types to warrant it.
:::note
Additional constraint types may be added in future versions of `SharedTree`. This section will be updated as new constraint types become available.
:::

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, we'll want to use mdx comment syntax here to avoid this appearing in the user-facing docs.

Suggested change
// TODO:#59981: Document new constraint types as they are implemented. Consider breaking this section into its own page when we have enough constraint types to warrant it.
{/* TODO:#59981: Document new constraint types as they are implemented. Consider breaking this section into its own page when we have enough constraint types to warrant it. */}


#### `noChange` (Alpha)

Requires that the document is in the exact same state when the transaction is applied as it was when the transaction was authored. If _any_ concurrent edit is sequenced before the transaction, the constraint is violated and the transaction is rolled back.
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The phrase "when the transaction is authored" might be unclear to readers. Consider using more precise terminology like "when the transaction is created/started" or "when the transaction callback begins executing" to clarify what "authored" means in this context.

Suggested change
Requires that the document is in the exact same state when the transaction is applied as it was when the transaction was authored. If _any_ concurrent edit is sequenced before the transaction, the constraint is violated and the transaction is rolled back.
Requires that the document is in the exact same state when the transaction is applied as it was when the transaction callback begins executing. If _any_ concurrent edit is sequenced before the transaction, the constraint is violated and the transaction is rolled back.

Copilot uses AI. Check for mistakes.
Comment on lines +180 to +191
#### `nodeInDocument`

Requires that a specific node exists in the document.

```typescript
const importantNode = view.root;

view.runTransaction(
() => {
view.root.value = 42;
},
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Question for reviewers: In theory, the old transaction API supports constraints, but in practice the old transaction API only supports nodeInDocument. I didn't document it because by my understanding we're not planning to invest in the old API due to its correctness issues and want to replace it. Should I add documentation on the old API specifically for nodeInDocument?

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, it would probably still be worth at least a quick note. I'm not sure how quickly we will stabilize these new APIs (we have not really been bumping many things to public recently, so I fear it might be a while). But I'm curious how others feel.

@github-actions
Copy link
Contributor

🔗 No broken links found! ✅

Your attention to detail is admirable.

linkcheck output


> [email protected] ci:check-links /home/runner/work/FluidFramework/FluidFramework/docs
> start-server-and-test "npm run serve -- --no-open" 3000 check-links

1: starting server using command "npm run serve -- --no-open"
and when url "[ 'http://127.0.0.1:3000' ]" is responding with HTTP status code 200
running tests using command "npm run check-links"


> [email protected] serve
> docusaurus serve --no-open

[SUCCESS] Serving "build" directory at: http://localhost:3000/

> [email protected] check-links
> linkcheck http://localhost:3000 --skip-file skipped-urls.txt

Crawling...

Stats:
  257812 links
    1822 destination URLs
    2063 URLs ignored
       0 warnings
       0 errors


sidebar_position: 6
---

TODO:#27374: update this page to describe the new transaction API
Copy link
Contributor

Choose a reason for hiding this comment

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

Oof. We should avoid comments like this in our website docs. Users would see this. Glad to see it removed.


The APIs described in this section are currently `@alpha` and may change in future releases.

Unlike `Tree.runTransaction`, the Alpha `runTransaction` does **not** automatically roll back the transaction if the callback throws an error. If your callback may throw, you should handle errors explicitly and return `{ rollback: true }` when required
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Our Markdown best practices generally recommend line breaking along sentence boundaries. This helps make future changes a bit easier to review / reason about.


:::

The TreeBranchAlpha API introduces `TreeBranchAlpha.runTransaction` as a replacement for `Tree.runTransaction`. This new API exists to solve correctness issues where errors being thrown in runTransaction could result in an undefined state. This new API enables developers to customize how their application handles this error case.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I would recommend linking to the API docs for the referenced APIs here (assuming they've been published).

);
```

If transactions are nested, only the outermost transaction's label is used.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: this makes sense, but it took me a minute to reason out why. I wonder if it would be worth noting the why.

`runTransaction` and `runTransactionAsync` can be called from within the callback of another transaction, with some limitations. Nested transactions have the following behavior:

- If the inner transaction rolls back, only the inner transaction's changes are discarded. The outer transaction continues.
- Constraints are applied to the outermost transaction. A single commit is generated for the outermost transaction, encompassing all inner transactions.
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this mean for constraints applied to inner transactions? Are they ignored? Or does this just mean that any constraints within the transaction (including nested transactions) are applied to the entire outer-most transaction?


:::warning

An asynchronous transaction cannot be started inside a synchronous transaction. The other three nesting combinations (sync-in-sync, sync-in-async, async-in-async) are all supported.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the error mode that a user will see if they try to do async in sync?

},
{
preconditions: [
{ type: "nodeInDocument", node: someNode },
Copy link
Contributor

Choose a reason for hiding this comment

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

This could probably use an inline comment explaining what the precondition does.

const result = view.runTransaction(() => {
const oldName = view.root.name;
view.root.name = "Bob";
return { rollback: false, value: oldName };
Copy link
Contributor

Choose a reason for hiding this comment

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

Does rollback have a default? Or are users required to return something?

() => {
view.root.name = "Dave";
},
{ label: "rename-user" },
Copy link
Contributor

Choose a reason for hiding this comment

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

An example of how this will affect the change metadata (either as an inline comment, or as notes following the codeblock) would probably be useful.


### Nested Transactions

`runTransaction` and `runTransactionAsync` can be called from within the callback of another transaction, with some limitations. Nested transactions have the following behavior:
Copy link
Contributor

Choose a reason for hiding this comment

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

These are obviously existing APIs, so this isn't feedback for this PR or anything, but I'm curious: would it be possible to make the async variation of this be an overload of runTransaction? Do we actually need 2 different function names?

view.root.content = "new value";
},
{
preconditions: [
Copy link
Contributor

@Josmithr Josmithr Feb 26, 2026

Choose a reason for hiding this comment

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

Nit: A quick comment above this indicating that preconditions applies to the application of the transaction itself might be useful (to help identify how this example is different from the next one).

view.root.content = "updated";
return {
rollback: false,
preconditionsOnRevert: [
Copy link
Contributor

@Josmithr Josmithr Feb 26, 2026

Choose a reason for hiding this comment

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

Nit: A quick comment above this line indicating that the preconditionsOnRevert apply to if/when the associated transaction is reverted might be useful (to help identify how this example is different from the previous one).

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.

3 participants