Skip to content

Add XIP-81: App Data Updates#136

Merged
tylerhawkes merged 2 commits into
mainfrom
tyler/xip-appdata
Jun 15, 2026
Merged

Add XIP-81: App Data Updates#136
tylerhawkes merged 2 commits into
mainfrom
tyler/xip-appdata

Conversation

@tylerhawkes

@tylerhawkes tylerhawkes commented May 20, 2026

Copy link
Copy Markdown
Contributor

Original AppData/ComponentId design — replaces GroupContextExtensions with AppDataUpdate proposals for delta-based group state.

This is the pre-XIP draft as written. A follow-up PR (stacked on this branch) shows where the shipped implementation diverged.

Note

Add XIP-81 specification for App Data Updates

Adds xip-81-app-data-updates.md, a new protocol specification proposing to replace GroupContextExtensions with AppDataUpdate proposals for managing mutable group state.

  • Defines delta-based updates to a key-value AppDataDictionary with per-component permissions and ComponentId ranges
  • Specifies capability negotiation, proposal validation rules, deterministic serialization, and a custom atomic BatchProposal type
  • Covers migration strategy away from GCE, backward compatibility, security considerations, and reference implementation pointers

Changes since #136 opened

  • Replaced permission model with Component Registry at 0x8000 as single source of truth for per-component policies [b0e8475]
  • Redesigned ComponentId layout from permission-banded ranges to three contiguous ranges with immutable sub-ranges [b0e8475]
  • Overhauled AppDataUpdate validation to use registry-based permission checks with pre-commit state evaluation [b0e8475]
  • Revised application ComponentId registration to per-group runtime registration via Component Registry [b0e8475]
  • Reworked migration to two-step bootstrap process with legacy floor bump followed by proposal-then-commit [b0e8475]
  • Standardized serialization to mandate TLS codec for all component payloads and deltas [b0e8475]
  • Deferred Section 4 BatchProposal and Section 5 KeyValue API from v1 [b0e8475]
  • Updated documentation sections including rationale, security considerations, implementation status, and test cases [b0e8475]
📊 Macroscope summarized b0e8475. 1 file reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

@macroscopeapp

macroscopeapp Bot commented May 20, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This XIP specification document is owned by @jhaaaa, not the PR author. Additionally, there are two unresolved high-severity review comments identifying potential specification inconsistencies that should be addressed by the designated owner.

You can customize Macroscope's approvability policy. Learn more.

* Align XIP-81 with shipped libxmtp implementation

* xip-81: pre-commit permission evaluation + correctness pass

- Add explicit pre-commit evaluation rule (Section 2.4) and a matching
  security-considerations subsection. Permissions for every AppDataUpdate
  resolve against the pre-commit registry / admin lists; a commit cannot
  grant a permission and exercise it in the same commit. Bootstrap is the
  only exception and routes through a dedicated validator.
- Update Test Cases to use shipped ComponentIds (GroupName at 0x8004,
  SuperAdminList at 0x8001, ConversationType at 0xBFFF, reserved 0xFF50)
  and add tests for the pre-commit rule, unknown-component tolerance,
  steady-state floor bumps, and Step A pause behavior. Move BatchProposal
  and KeyValueDelta tests to a "deferred" list paired with their feature.
- Rationale: replace "Why range-based defaults with an override map" with
  "Why a per-component registry". Note BatchProposal deferral in the
  atomic-batching rationale.
- Security Considerations: drop the "ComponentId range model" framing,
  reference the registry directly, note pre-commit evaluation, drop the
  BatchProposal sub-operation paragraph.
- Backward Compatibility: BatchProposal subsection now notes deferral.
- Section 1.4 table: drop the BatchProposal exception (deferred); reword
  AppDataUpdate row from "proposed" to "shipped".
- Section 3.3 reference fix: "steps 2a-2d" -> "Step B".

* xip-81: second review pass

- §2.2.1: "register-then-write" was wrongly said to fit in one commit;
  pre-commit evaluation forces split commits (or bootstrap path).
- §2.2.1: clarify that SUPER_ADMIN_LIST permission is enforced in code,
  not from the registry — registry just covers it for type dispatch.
- Rationale "Why one-time migration": drop the "only happens when all
  members support" claim; the shipped version-bump path pauses
  non-supporting peers instead of blocking the migration on them.
- Rationale "Application ComponentId registration alternatives":
  on-chain registry is deferred; v1 ships per-group explicit
  registration with duplicate-id rejection at register time.
- Test 8: spell out the two-proposer scenario so the pre-commit
  evaluation property is testable rather than ambiguous.

* xip-81: note pre-d14n migrations are shipped + sketch 32-byte component handle

- Move pre-d14n migration support out of "Optional future work" and into
  the existing two-step bootstrap line — that mechanism is exactly what
  makes pre-d14n migrations safe (lower-version peers pause on Step A).
- §2.2.2 + Open Questions §5: add a brief note on a 32-byte stable
  identifier per application-range component, resolved by the SDK to the
  per-group 16-bit ComponentId. Lets multiple apps ship components
  without coordinating on the 16-bit namespace.
@tylerhawkes tylerhawkes merged commit 5f593ea into main Jun 15, 2026
3 checks passed
@tylerhawkes tylerhawkes deleted the tyler/xip-appdata branch June 15, 2026 18:45

**Wire shape: standalone proposal + commit.** Migrated sender intents publish two messages per metadata update: a standalone `AppDataUpdate` proposal first, then a commit that consumes the proposal store. This is the same MLS proposal-by-reference shape used elsewhere — it is *not* the inline-bundled GCE-proposal-plus-commit pattern from the legacy path.

**Lazy batching.** The commit issued by `stage_app_data_propose_and_commit` has no precondition on the pending proposal store. It sweeps every existing pending proposal — concurrent `AppDataUpdate`s, leaf-node `Update`s, `Add`/`Remove`/`SelfRemove`, PSK, etc. — into the same commit body. Producers of those pending proposals already accepted "ride into the next commit" by leaving them pending; MLS freezes message-send while proposals are pending regardless of which commit ultimately consumes them. The dictionary-update step in receivers iterates only the `AppDataUpdate` proposals; non-AppData proposals ride natively through OpenMLS.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 High XIPs/xip-81-app-data-updates.md:388

The lazy batching rule in stage_app_data_propose_and_commit can merge a pending ComponentRegistry permission change with a dependent AppDataUpdate in the same commit. Section 2.4 requires permission changes and dependent writes to land in separate commits because authorization is evaluated against the pre-commit registry state. When these proposals are batched together, the dependent AppDataUpdate is evaluated against the old registry and rejected. Consider filtering the pending proposal store to exclude registry/admin-list mutations before sweeping remaining proposals into the commit, or document that callers must ensure no permission-changing proposals are pending.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @XIPs/xip-81-app-data-updates.md around line 388:

The `lazy batching` rule in `stage_app_data_propose_and_commit` can merge a pending `ComponentRegistry` permission change with a dependent `AppDataUpdate` in the same commit. Section 2.4 requires permission changes and dependent writes to land in separate commits because authorization is evaluated against the pre-commit registry state. When these proposals are batched together, the dependent `AppDataUpdate` is evaluated against the old registry and rejected. Consider filtering the pending proposal store to exclude registry/admin-list mutations before sweeping remaining proposals into the commit, or document that callers must ensure no permission-changing proposals are pending.


### 1.2 Capability Negotiation

Before enabling proposals on a group, the initiator MUST verify that all current members support the proposal extension:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 High XIPs/xip-81-app-data-updates.md:49

Section 1.2 only checks for PROPOSAL_SUPPORT_EXTENSION_ID capability before enabling proposals, but the bootstrap commit in Section 3.2 Step B adds AppDataDictionary and uses AppDataUpdate proposals. A peer can advertise standalone-proposal support without advertising AppDataDictionary in its MLS capabilities, so the check passes for members who cannot actually process the migration. The result is a group that may execute Step A (version-floor bump), pause older clients, then fail Step B because some members lack the required MLS extension capability. Consider also requiring AppDataDictionary in the capability check before allowing migration.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @XIPs/xip-81-app-data-updates.md around line 49:

`Section 1.2` only checks for `PROPOSAL_SUPPORT_EXTENSION_ID` capability before enabling proposals, but the bootstrap commit in `Section 3.2 Step B` adds `AppDataDictionary` and uses `AppDataUpdate` proposals. A peer can advertise standalone-proposal support without advertising `AppDataDictionary` in its MLS capabilities, so the check passes for members who cannot actually process the migration. The result is a group that may execute Step A (version-floor bump), pause older clients, then fail Step B because some members lack the required MLS extension capability. Consider also requiring `AppDataDictionary` in the capability check before allowing migration.

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.

2 participants