Skip to content

feat(transaction): compound append + add-index via action transactions#7674

Draft
wjones127 wants to merge 6 commits into
will/unstable-action-transactions-skeletonfrom
will/action-transactions-vertical-slice
Draft

feat(transaction): compound append + add-index via action transactions#7674
wjones127 wants to merge 6 commits into
will/unstable-action-transactions-skeletonfrom
will/action-transactions-vertical-slice

Conversation

@wjones127

Copy link
Copy Markdown
Contributor

Stacked on #7671 (experimental action-transaction skeleton). Please review after it.

The first vertical slice of the "Action-based Transactions" milestone (#5960):
a caller can now construct and commit a UserOperation that both appends new
fragments and registers an index covering those fragments, in a single
atomic transaction — the compound-commit capability that motivates the milestone.

Everything stays behind the non-default unstable-action-transactions Cargo
feature (absent from released artifacts), and committing one declares the
action-transactions experimental writer feature, which sets FLAG_EXPERIMENTAL
so libraries that don't understand the format refuse to commit. The resulting
manifest and data are standard, so stock readers are unaffected.

What's here

  • Actions (lance-table): AddFragments now carries NewFragments, each
    with an operation-local local_id placeholder so a later action can reference
    a fragment before its real id is assigned. New AddIndex action registers an
    index segment; coverage is the union of already-committed fragment ids and
    same-operation placeholders.
  • Wire format: the action list rides the existing transaction file as an
    opaque experimental_user_operation payload in the canonical
    transaction.proto, keeping the PMC-voted schema free of the unstable action
    structure. The structured messages live in transaction_experimental.proto.
  • Apply + commit (lance): a feature-gated Operation::UserOperation
    variant flows through the existing CommitBuilder/commit-retry path. Apply
    mints fragment ids from the manifest counter (late binding), records
    local_id -> id, and resolves each AddIndex bitmap. Conflict resolution
    treats the op like an Append (commutes with concurrent appends); retries
    re-run apply against the latest manifest, so ids/placeholders are recomputed
    each attempt.
  • Python: gated LanceOperation.UserOperation / UserAction /
    AddFragments / AddIndex / NewFragment, committed through the existing
    LanceDataset.commit. A lance.lance._action_transactions_enabled flag lets
    callers detect whether the extension was built with the feature.

Testing

  • Rust integration tests: compound append+index (asserts ids, index bitmap,
    FLAG_EXPERIMENTAL, row count) and non-conflict-with-concurrent-append.
  • Python test (skips unless the extension was built with the feature): the
    pylance acceptance flow end-to-end.
  • Clippy clean with the feature both on and off; the default build is
    unaffected.

Notes

  • CI does not exercise the feature (it's non-default and pylance isn't built
    with it). The Rust feature-on tests are the real gate; the Python test
    documents/verifies the acceptance path only in a feature-enabled build.
  • Index registration is metadata-only in this slice (the index file is assumed
    written); a real index-build path is out of scope.

🤖 Generated with Claude Code

wjones127 and others added 6 commits July 7, 2026 10:59
Extend the experimental action-transaction types for the first compound-commit
slice. `AddFragments` now carries `NewFragment`s, each with an operation-local
`local_id` placeholder so a later action can reference a fragment before its real
id is assigned. Adds the `AddIndex` action, which registers an index segment and
expresses coverage as the union of already-committed fragment ids and same-op
placeholders.

All behind the non-default `unstable-action-transactions` feature.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an ExperimentalUserOperation message + oneof arm (field 115) to the
canonical transaction.proto. The action list is carried as an opaque `bytes`
payload (a serialized experimental UserOperation) so the PMC-voted schema stays
free of the unstable action structure. Builds that cannot interpret it reject
the transaction; a real Operation variant is wired up in the next commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the experimental action-based transaction through the existing commit
path. Adds a feature-gated `Operation::UserOperation` variant and an
`apply_user_operation` step in `build_manifest` that:

- mints fragment ids from the manifest counter (late binding) and records each
  `NewFragment.local_id` -> assigned id, and
- registers `AddIndex` metadata whose fragment bitmap is the union of
  `covers_existing` and the placeholders resolved above.

Committing a UserOperation declares the `action-transactions` experimental
writer feature (sets FLAG_EXPERIMENTAL). Conflict resolution treats the op like
an Append (commutes with concurrent appends); retries re-run `build_manifest`
against the latest manifest, so ids and placeholders are recomputed each
attempt. The wire payload is encoded into the opaque `experimental_user_operation`
transaction field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feature-gated integration tests: (1) append two fragments and register an index
covering only the first in one action-based transaction, asserting fragment
ids, the index fragment bitmap (placeholder-resolved), FLAG_EXPERIMENTAL, and
row count; (2) a stale UserOperation rebases past a concurrent plain Append and
still commits, confirming action-based appends don't conflict with appends.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add gated LanceOperation.UserOperation / UserAction / AddFragments / AddIndex /
NewFragment dataclasses, committed through the existing LanceDataset.commit path.
The PyO3 layer parses them into the Rust Operation::UserOperation under the
non-default `unstable-action-transactions` feature; without it, committing one
raises a clear error. A `lance.lance._action_transactions_enabled` capability
flag lets callers/tests detect whether the extension was built with the feature.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feature-gated (skips unless the extension was built with
`unstable-action-transactions`): a pylance user constructs and commits a
UserOperation that appends two fragments and registers an index over only the
first, in one transaction, then asserts the row count, fragment count, and the
index's resolved fragment coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added A-python Python bindings A-format On-disk format: protos and format spec docs labels Jul 7, 2026
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Important

This PR touches the Lance format specification.

Substantive changes to the format specification — the .proto definitions
and the spec docs under docs/src/format/ — require a PMC vote before merge.
Minor edits such as typo fixes, wording, or formatting are excluded; use your
judgment.

If this is a meaningful format change:

  • Start a vote following the Lance community voting process.
    Format specification modifications need 3 binding +1 votes (excluding the
    proposer), held on GitHub Discussions, with a minimum voting period of 1 week.
  • Once the vote passes, link the completed vote in this PR. It should not be
    merged until the vote is linked.

@github-actions github-actions Bot added the enhancement New feature or request label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-format On-disk format: protos and format spec docs A-python Python bindings enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant