# Experiment Designer Redesign (Production Baseline) This document defines the production-ready redesign of the Experiment Designer. It supersedes prior "modular refactor" notes and consolidates architecture, hashing, drift detection, UI/UX, state management, validation, plugin integration, saving/versioning, and export strategy. All implementation must adhere to this specification to ensure reproducibility, extensibility, and maintainability. --- ## 1. Goals - Provide a clear, fast, and intuitive hierarchical design workflow. - Guarantee reproducibility via deterministic hashing and provenance retention. - Surface plugin dependency health and schema drift early. - Support scalable experiments (many steps/actions) without UI degradation. - Enable structured validation (structural, parameter-level, semantic) before compilation. - Provide robust export/import and future multi-user collaboration readiness. - Maintain 100% type safety and consistent design patterns across the platform. --- ## 2. Conceptual Model Hierarchy: ``` Experiment └─ Step (ordered, typed) └─ Action (ordered, typed, provenance-bound) ``` Key invariants: - Step `order` is zero-based, contiguous after any mutation. - Action `orderIndex` is zero-based within its parent step. - Each action retains provenance: `{ source.kind, pluginId?, pluginVersion?, baseActionId? }` - Execution descriptors are retained for reproducibility (`transport`, `ros2`, `rest`, `retryable`, `timeoutMs`). --- ## 3. Hashing & Integrity Guarantees ### 3.1 Purposes of Hashing - Detect structural drift between persisted design and working edits. - Bind design to plugin and action schemas for reproducibility. - Support execution graph provenance (hash at compile time). - Enable export integrity and offline verification. ### 3.2 Design Hash Components Included: - Steps (ordered): `id`, `name`, `type`, `order`, `trigger.type`, sorted trigger condition keys. - Actions (per step, ordered): `id`, `type`, `source.kind`, `pluginId`, `pluginVersion`, `baseActionId`, `execution.transport`, parameter key set (NOT values by default—configurable). - Optional: parameter values (toggle design mode if needed—default: exclude values to reduce false-positive drift). Excluded: - Ephemeral UI state (`expanded`, selection state). - Human-friendly timestamps or transient meta. ### 3.3 Canonicalization Steps 1. Deep clone design subset. 2. Remove `undefined` keys. 3. Sort object keys recursively. 4. Sort arrays where semantic ordering is not meaningful (e.g. condition key sets). 5. JSON stringify (no whitespace). 6. SHA-256 digest → hex. ### 3.4 Incremental Hash Optimization Per-action hash → per-step hash → design hash: ``` H_action = hash(canonical(actionMeta)) H_step = hash(stepMeta + concat(H_action_i)) H_design = hash(globalMeta + concat(H_step_i)) ``` Recompute only modified branches for responsiveness. ### 3.5 Drift States | State | Condition | |--------------|----------------------------------------------------------------------------------------------------| | Unvalidated | No validation performed since load | | Validated | Last validated hash matches stored experiment integrity hash and working snapshot unchanged | | Drift | (A) Working snapshot changed since last validation OR (B) validated hash ≠ stored integrity hash | | Plugin Drift | Design validated, but one or more action definitions (schema/provenance) no longer match registry | ### 3.6 Plugin Signature Drift Signature hash per action definition: hash of `(type + category + parameterSchema + transport + baseActionId + pluginVersion)`. - If signature mismatch for existing action instance: mark as “schema drift”. - Provide reconciliation CTA to refetch schema and optionally run migration. --- ## 4. UI Architecture High-level layout: ``` ┌───────────────────────────────────────────────────────────────────────────┐ │ Header: breadcrumbs • experiment name • hash badge • plugin deps summary │ ├──────────────┬───────────────────────────────┬────────────────────────────┤ │ Action │ Step Flow (sortable linear) │ Properties / Inspector │ │ Library │ - Step cards (collapsible) │ - Step editor │ │ - Search │ - Inline action list │ - Action parameters │ │ - Categories │ - DnD (steps/actions/library) │ - Validation & drift panel │ │ - Plugins │ - Structural markers │ - Dependencies & provenance │ ├──────────────┴───────────────────────────────┴────────────────────────────┤ │ Bottom Save Bar: dirty state • versioning • export • last saved • conflicts│ └───────────────────────────────────────────────────────────────────────────┘ ``` Component responsibilities: | Component | Responsibility | |------------------------------|----------------| | `DesignerShell` | Data loading, permission guard, store boot | | `ActionLibraryPanel` | Search/filter, categorized draggable items | | `StepFlow` | Rendering + reordering steps & actions | | `StepCard` | Step context container | | `ActionItem` | Visual + selectable action row | | `PropertiesPanel` | Context editing (step/action) | | `ParameterFieldFactory` | Schema → control mapping | | `ValidationPanel` | Issue listing + filtering | | `DependencyInspector` | Plugin + action provenance health | | `SaveBar` | Hash/drift/dirtiness/export/version controls | | `hashing.ts` | Canonicalization + incremental hashing | | `validators.ts` | Rule execution (structural, parameter) | | `exporters.ts` | Export bundle builder | | `store/useDesignerStore.ts` | Central state store | --- ## 5. State Management Use a lightweight, framework-agnostic, fully typed store (Zustand). Core fields: ``` { steps: ExperimentStep[] dirty: Set selectedStepId?: string selectedActionId?: string lastPersistedHash?: string lastValidatedHash?: string lastValidatedSnapshot?: string pluginSignatureIndex: Record validationIssues: Record pendingSave?: boolean conflict?: { serverHash: string; localHash: string } } ``` ### Actions - `setSteps`, `upsertStep`, `removeStep`, `reorderStep` - `upsertAction`, `removeAction`, `reorderAction` - `markDirty(entityId)` - `computeDesignHash()` - `setValidationResult({ hash, issues, snapshot })` - `applyServerSync({ steps, hash })` - `recordConflict(serverHash, localHash)` --- ## 6. Drag & Drop Library → Step - Drag action definition placeholder onto step drop zone triggers action instantiation. Step reorder - Sortable vertical list with keyboard accessibility. Action reorder - Sortable within a step (no cross-step move initially; future extension). Framework: `@dnd-kit/core` + `@dnd-kit/sortable`. Accessibility: - Custom keyboard handlers: Up/Down to move selection; Alt+Up/Down to reorder. --- ## 7. Parameters & Control Mapping Mapping: | Schema Type | Control | |-------------|---------| | boolean | Switch | | number (bounded) | Slider + numeric display | | number (unbounded) | Numeric input | | text short | Text input | | text long | Textarea (expandable) | | select/enumeration | Select / Combobox | | multi-select | Tag list (future) | | json/object | Lazy code editor (future) | Enhancements: - Show required indicator - Inline validation message - Revert-to-default button if default provided - Modified badge (dot) for overridden parameters --- ## 8. Validation System Levels: 1. Structural - No empty step names - Steps must have valid `type` - Conditional/loop must define required condition semantics 2. Parameter - Required values present - Number bounds enforced - Enum membership 3. Semantic - No unresolved plugin dependency - Unique action IDs and step IDs - Loop guard presence (future) 4. Execution Preflight (optional) - Detect obviously irrecoverable execution (e.g. empty parallel block) Severity classification: - Error: blocks save/compile - Warning: surfaced but non-blocking - Info: advisory (e.g. unused parameter) Store format: ``` validationIssues: { [entityId: string]: { severity: "error" | "warning" | "info"; message: string }[] } ``` Rendering: - Badge on step/actions with count + highest severity color. - Panel filter toggles (Errors / Warnings / All). - Inline icon markers. --- ## 9. Plugin Integration & Drift Definitions loaded into `ActionRegistry`: ``` { id, type, name, category, parameters[], source: { kind, pluginId?, pluginVersion?, baseActionId? }, execution?, parameterSchemaRaw } ``` Per-definition signatureHash computed: `hash(type + category + JSON(parameterSchemaRaw) + execution.transport + baseActionId + pluginVersion)` Per-action drift logic: - If action.source.pluginVersion missing in registry → Blocked (hard drift). - If signatureHash mismatch → Soft drift (allow edit, prompt reconcile). - Provide “Reconcile” overlay listing changed parameters (added / removed / type changed). --- ## 10. Saving & Versioning Save triggers: - Manual (primary save button or Cmd+S) - Debounced auto-save (idle > 5s, no pending errors) - Forced save before export Payload: ``` { id, visualDesign: { steps, version, lastSaved }, createSteps: true, compileExecution: true } ``` Version management: - If structural change (add/remove/reorder step/action or change type) → version bump (auto unless user disables). - Parameter-only changes may optionally not bump version (configurable toggle; default: no bump). - UI: dropdown / toggle “Increment version on save”. Conflict detection: - Server returns persisted integrityHash. - If local lastPersistedHash differs and serverHash differs from our pre-save computed hash → conflict modal. - Provide: - View diff summary (step added/removed, action count deltas). - Override server (if authorized) or Reload. --- ## 11. Export / Import Export bundle structure: ```json { "format": "hristudio.design.v1", "exportedAt": "...ISO8601...", "experiment": { "id": "...", "name": "...", "version": 4, "integrityHash": "...", "steps": [... canonical steps ...], "pluginDependencies": ["pluginA@1.2.1", "robot.voice@0.9.3"] }, "compiled": { "graphHash": "...", "steps": 12, "actions": 47, "plan": { /* normalized execution nodes */ } } } ``` Import validation: - Check `format` signature & version. - Recompute design hash vs embedded. - Check plugin availability (list missing). - Offer “Install required plugins” if privileges allow. --- ## 12. Accessibility & UX Standards - Keyboard traversal (Tab / Arrow) across steps & actions. - Focus ring on selected entities. - ARIA labels on all interactive controls (drag handles, add buttons). - Color usage passes contrast (WCAG 2.1 AA). - Non-color indicators for drift (icons / labels). - All icons: Lucide only. --- ## 13. Performance Considerations - Virtualize StepFlow when step count > threshold (e.g. 50). - Memoize parameter forms (avoid re-render on unrelated step changes). - Incremental hashing—avoid full recompute on each keystroke. - Lazy-load advanced components (JSON editor, large schema viewers). --- ## 14. Testing Strategy Unit Tests: - Hash determinism (same structure -> same hash). - Hash sensitivity (reorder step / change action type -> different hash). - Signature drift detection logic. - Validation rule coverage (structural & parameter). Integration Tests: - Save cycle (design → save → fetch → hash equality). - Plugin dependency missing scenario. - Conflict resolution workflow. Edge Cases: - Empty experiment (0 steps) → validation error. - Conditional step with no conditions → error. - Loop step missing guard → warning (future escalation). - Plugin removed post-design → plugin drift surfaced. --- ## 15. Migration Plan (Internal) 1. Introduce new store + hashing modules. 2. Replace current `BlockDesigner` usage with `DesignerShell`. 3. Port ActionLibrary / StepFlow / PropertiesPanel to new contract. 4. Add SaveBar + drift/UI overlays. 5. Remove deprecated legacy design references (no “enhanced” terminology). 6. Update docs cross-links (`project-overview.md`, `implementation-details.md`). 7. Add export/import UI. 8. Stabilize, then enforce hash validation before trial creation. --- ## 16. Security & Integrity - Server must recompute its own structural hash during compile to trust design. - Client-submitted integrityHash considered advisory; never trusted alone. - Plugin versions pinned explicitly inside actions (no implicit latest resolution). - Attempting to execute an experiment with unresolved drift prompts required validation. --- ## 17. Future Extensions | Feature | Description | |--------------------------|-------------| | Real-time co-editing | WebSocket presence + granular patch sync | | Branching workflows | Conditional branches forming DAG (graph mode) | | Step templates library | Shareable reproducible step/action sets | | Parameter presets | Save named parameter bundles per action type | | Timeline estimation view | Aggregate predicted duration | | Replay / provenance diff | Compare two design versions side-by-side | | Plugin action migration | Scripted param transforms on schema changes | | Execution simulation | Dry-run graph traversal with timing estimates | --- ## 18. Implementation Checklist (Actionable) - [ ] hashing.ts (canonical + incremental) - [ ] validators.ts (structural + param rules) - [ ] store/useDesignerStore.ts - [ ] ActionRegistry rewrite with signature hashing - [ ] ActionLibraryPanel (search, categories, drift indicators) - [ ] StepFlow + StepCard + ActionItem (DnD with @dnd-kit) - [ ] PropertiesPanel + ParameterFieldFactory - [ ] ValidationPanel + badges - [ ] DependencyInspector + plugin drift mapping - [ ] SaveBar (dirty, versioning, export) - [ ] Exporter (JSON bundle) + import hook - [ ] Conflict modal - [ ] Drift reconciliation UI - [ ] Unit & integration tests - [ ] Docs cross-link updates - [ ] Remove obsolete legacy code paths (Track progress in `docs/work_in_progress.md` under “Experiment Designer Redesign Implementation”.) --- ## 19. Cross-References - See `docs/implementation-details.md` (update with hashing + drift model) - See `docs/api-routes.md` (`experiments.update`, `experiments.validateDesign`) - See `docs/database-schema.md` (`steps`, `actions`, provenance fields) - See `docs/project-overview.md` (designer feature summary) - See `docs/work_in_progress.md` (status tracking) --- ## 20. Summary This redesign formalizes a production-grade, reproducible, and extensible experiment design environment with deterministic hashing, plugin-aware action provenance, structured validation, export integrity, and a modular, performance-conscious UI framework. Implementation should now proceed directly against this spec; deviations require documentation updates and justification. --- End of specification.