Skip to content

Phase 4A: ProposalManager (Changeset Semantics) #13

@mikewolfd

Description

@mikewolfd

Motivation

The changeset/proposal system is the architectural centerpiece of the unified authoring architecture. It enables AI changes to be reviewed, accepted, or rejected using git merge semantics — the user is never locked out of editing.

Parent epic: #9 — Unified Authoring Architecture

Key Design Decisions

  • Middleware-based recording — captures commands by construction via CommandPipeline, never misses
  • Git merge model — user never locked out, conflicts detected at merge time, not prevented by locking
  • Command-level replay — deterministic (same commands + same snapshot = same state), not tool-level
  • Layered savepoints — error recovery at each replay phase (AI groups, user overlay, structural validation)
  • Undo/redo disabled during open changeset — the changeset IS the undo mechanism

Scope

Pass 4a-A: Recording Infrastructure (formspec-core)

  • ChangesetRecorderControl interface in core types
  • createChangesetMiddleware() factory function
  • Middleware injects via ProjectOptions.middleware
  • Actor-tagged recording ('ai' | 'user')
  • Unit tests for middleware capture behavior

Pass 4a-B: State Restoration (formspec-core)

  • IProjectCore.restoreState(snapshot: ProjectState) method
  • Implementation in RawProject — state assignment + notification
  • Must invalidate _cachedComponent and handle generatedComponent reconciliation
  • History stack cleared on restore
  • Unit tests for restore + re-notification

Pass 4a-C: ProposalManager (formspec-studio-core)

  • Changeset and ChangeEntry types
  • ProposalManager class — changeset lifecycle (open, close, merge, reject)
  • Actor-tagged recording orchestration (beginEntry/endEntry brackets)
  • Snapshot-and-replay for reject/partial merge
  • User overlay track (concurrent user edits during AI work)
  • Content immutability enforcement (VP-02: refuse changeset on non-draft definitions)
  • Undo/redo disabled guard during open changeset
  • Edge case handling: initialValue = prefix value capture, prePopulate, now() non-determinism
  • Error recovery with layered savepoints
  • Integration tests for full lifecycle

Pass 4a-D: Rust Dependency Analysis

  • New crate or extension to existing crate for dependency analysis
  • FEL expression scanning (reusing fel-core dependency extraction)
  • Reference edge extraction (bind paths, shape composition, variable scopes, optionSet refs, etc.)
  • Order-dependent grouping (screener routes, theme selectors)
  • Connected component computation for dependency groups
  • Cross-document edge detection (locale, ontology, references, theme overrides, component bindings)
  • WASM bridge for compute_dependency_groups()
  • Unit tests in Rust + integration tests via WASM

Pass 4a-E: Changeset MCP Tools

  • formspec_changeset_open — start changeset, capture snapshot
  • formspec_changeset_close — seal changeset, compute dependency groups
  • formspec_changeset_list — list changesets with status and groups
  • formspec_changeset_accept — accept all or specific dependency groups
  • formspec_changeset_reject — reject all or specific groups, snapshot-and-replay
  • Tool annotations: formspec_changeset_list readOnly, formspec_changeset_reject destructive

Acceptance Criteria

  • Recording middleware captures all commands flowing through the pipeline, tagged by actor
  • Changeset lifecycle works end-to-end: open -> AI mutations -> user edits -> close -> review -> merge/reject
  • Partial merge correctly replays accepted groups + user overlay in chronological order
  • Reject all preserves user overlay edits
  • Post-merge diagnose() runs and reports structural issues
  • Error recovery restores to safe state on replay failure
  • Dependency grouping correctly identifies related operations

Layer

Management Instance (Layers 1-4, plus Rust/WASM)

Dependencies

Spec Reference

thoughts/specs/2026-03-24-unified-authoring-architecture.md — Section 2 (ProposalManager)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions