feat(sdk): variable declaration edit ops (declare/update/remove)#2047
Open
Conversation
Collaborator
Author
This was referenced Jul 8, 2026
c9bc8fb to
d3ab9db
Compare
d3ab9db to
ed9f222
Compare
9e24243 to
5a63475
Compare
ed9f222 to
52b7e1d
Compare
Second PR of the template-variables Studio stack — the SDK write surface.
The SDK could edit an existing declaration's default (setVariableValue) but
had no way to create, reshape, or delete declarations. These ops complete
the schema-authoring surface so Studio and embedders build on one contract.
- new EditOps + typed Composition wrappers:
- declareVariable(declaration) — creates data-composition-variables when
absent; refuses duplicates and invalid shapes
- updateVariableDeclaration(id, declaration) — wholesale replace; id is
immutable (rename = remove + declare); keeps the --{id} CSS compat
custom prop in sync when the default changes, mirroring setVariableValue
- removeVariableDeclaration(id) — drops the attribute with the last entry
and clears the CSS compat prop
- patch grammar: /variableDeclarations/{id} ↔ override key varDecl.{id}
(distinct from /variables/{id}, which stays the default *value* path);
apply-patches replays declaration patches for T3 host undo
- can() validation: E_DUPLICATE_VARIABLE, E_VARIABLE_NOT_FOUND,
E_INVALID_ARGS, and E_FRAGMENT_COMPOSITION — fragment sources have no
<html> to carry the schema, so declaring would silently vanish on
serialize; the ops refuse instead
- parsers: export isCompositionVariable (the parse filter predicate) so
writers validate with the exact same rules readers filter by
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5a63475 to
6844906
Compare
52b7e1d to
1935108
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Second PR of the template-variables stack: the SDK write surface for the variable schema.
Compositionwrappers:declareVariable(declaration),updateVariableDeclaration(id, declaration)(wholesale replace, id immutable — rename = remove + declare),removeVariableDeclaration(id)(last removal drops the whole attribute)/variableDeclarations/{id}↔ override keyvarDecl.{id}— distinct from/variables/{id}, which stays the default-value path; apply-patches replays declaration patches for T3 host undocan()validation:E_DUPLICATE_VARIABLE,E_VARIABLE_NOT_FOUND,E_INVALID_ARGS, andE_FRAGMENT_COMPOSITIONisCompositionVariableso writers validate with the exact predicate readers filter by--{id}CSS compat custom prop consistently (declare included), andupdateVariableDeclarationemits a paired/variables/{id}patch when the default changes so the T3 override-set stays coherent regardless of replay order (review fixes absorbed into this PR)Why
setVariableValuecould edit an existing declaration's default but nothing could create, reshape, or delete declarations — the missing half of the schema-authoring surface Studio's Variables panel (and any embedder) needs. Everything flows through the established dispatch → patch → override-set pipeline so history, undo, and embedded hosts work for free.How
Notable contract decision: fragment compositions refuse declaration ops (
E_FRAGMENT_COMPOSITION). A fragment source has no<html>of its own — a declaration written to the synthetic wrapper is silently dropped byserialize(), which a test proved before the guard existed. Refusing loudly beats losing data quietly.The patch replay path (
apply-patches.ts) is deliberately not strict: inverse patches capture raw entries verbatim (including loose hand-authored declarations the strict parser drops), so undo must restore them verbatim — gating replay onisCompositionVariablemade undo of a remove/update on a loose entry silently no-op (caught in review, fixed here).Test plan
session.variabledecls.test.ts— dispatch semantics,can()error paths, CSS compat sync, patch grammar round-trips, undo/redo (including CSS prop restoration), fragment refusal🤖 Generated with Claude Code