stream_weaver 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.beads/.gitignore +77 -0
- data/.beads/README.md +81 -0
- data/.beads/config.yaml +54 -0
- data/.beads/metadata.json +7 -0
- data/.rspec +3 -0
- data/AGENTS.md +91 -0
- data/CHANGELOG.md +294 -0
- data/CLAUDE.md +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +565 -0
- data/Rakefile +13 -0
- data/assets/streamweaver-hero.jpg +0 -0
- data/bench/baselines/ledger.rb +58 -0
- data/bench/baselines/warroom.rb +51 -0
- data/bench/fixtures/ledger.rb +76 -0
- data/bench/fixtures/warroom.rb +60 -0
- data/bench/results/6daf8b8.md +102 -0
- data/bench/results/c8d749b.md +102 -0
- data/bench/results/eb06ab9.md +102 -0
- data/bench/run.rb +151 -0
- data/bench/support.rb +84 -0
- data/copy_this/dto_run_sample_run_7631.html +220 -0
- data/docs/SERVICE_MODE.md +302 -0
- data/docs/architecture/how_streamweaver_works.md +772 -0
- data/docs/blog/2026-01-16-streamweaver-introduction.md +515 -0
- data/docs/bug-2026-08-31-canvas-bridge-socket-collision.md +83 -0
- data/docs/canvas-ipc-session-summary.md +127 -0
- data/docs/canvas-panel-workflow.md +172 -0
- data/docs/canvas-read.md +147 -0
- data/docs/canvas-roadmap.md +275 -0
- data/docs/case-studies/2026-09-03-didx-canvas-read-shelf.md +147 -0
- data/docs/claude-code-companion-skill-spec.md +567 -0
- data/docs/components_reference.md +1223 -0
- data/docs/crud-patterns.md +265 -0
- data/docs/endpoints.md +122 -0
- data/docs/for_llms.md +1 -0
- data/docs/form-patterns.md +165 -0
- data/docs/frontend-only.md +169 -0
- data/docs/html-artifact-audit.md +238 -0
- data/docs/ideas/2025-01-01-as-a-service.md +203 -0
- data/docs/ideas/2026-01-16-charm-tui-exploration.md +542 -0
- data/docs/ideas/2026-08-27-static-doc-shelf-export.md +153 -0
- data/docs/ideas/dhh-review-future-refactors.md +142 -0
- data/docs/opal-jamstack.md +47 -0
- data/docs/opal-npm-direction.md +184 -0
- data/docs/opal-spike-findings.md +194 -0
- data/docs/plans/2025-12-16-form-blocks-design.md +124 -0
- data/docs/plans/2025-12-30-examples-browser-design.md +152 -0
- data/docs/plans/2026-01-02-charts-design.md +288 -0
- data/docs/plans/2026-01-10-canvas-ipc-design.md +247 -0
- data/docs/plans/2026-01-19-cabinet-control-components.md +176 -0
- data/docs/plans/2026-01-26-gem-release-and-panel.md +140 -0
- data/docs/plans/canvas-claude-project-design.md +238 -0
- data/docs/plans/canvas-doc-location-and-discovery.md +32 -0
- data/docs/plans/org-doc-preview-surfaces.md +293 -0
- data/docs/plans/shadcn-polish-plan.md +417 -0
- data/docs/porting-artifacts.md +252 -0
- data/docs/reference/agent-skills-comparison.md +369 -0
- data/docs/reference/travel-state-prd.artifact.html +780 -0
- data/docs/research/2026-08-17-hotwire-alike-landscape.md +268 -0
- data/docs/research/2026-08-17-hotwire-concept-map.md +404 -0
- data/docs/research/2026-08-22-lazy-fragments-trigger-decision.md +246 -0
- data/docs/research/2026-08-22-learnhotwire-syllabus-coverage.md +239 -0
- data/docs/research/frontend-only-matrix.md +278 -0
- data/docs/research/streamweaver-way-spike-findings.md +529 -0
- data/docs/resource-dsl.md +342 -0
- data/docs/routing.md +302 -0
- data/docs/ruby-ui-comparison.md +319 -0
- data/docs/shared-dsl-fragments.md +356 -0
- data/docs/streamweaver-for-ai-agents.md +401 -0
- data/docs/streamweaver-frontend-vision.md +123 -0
- data/docs/streamweaver_canvas/glimmer_initial_final_layer.rb +77 -0
- data/docs/streamweaver_canvas/save_example.rb +9 -0
- data/docs/templates.md +213 -0
- data/docs/testing.md +155 -0
- data/docs/theming-hooks.md +281 -0
- data/docs/tutorials/the-streamweaver-way.md +882 -0
- data/docs/university/capability-inventory.md +137 -0
- data/docs/university/dependency-survey.md +114 -0
- data/docs/university/design-spec.md +217 -0
- data/docs/university/mockups/code-block-doc-theme-dark.png +0 -0
- data/docs/university/mockups/code-block-doc-theme-light.png +0 -0
- data/docs/university/mockups/course-list-dark.png +0 -0
- data/docs/university/mockups/course-list-light.png +0 -0
- data/docs/university/mockups/course_canvas_mockup.rb +741 -0
- data/docs/university/mockups/step-screen-dark.png +0 -0
- data/docs/university/mockups/step-screen-light.png +0 -0
- data/docs/university/roadmap.md +72 -0
- data/docs/university/send-to-coworker.md +77 -0
- data/docs/university/worker-session-mining.md +109 -0
- data/docs/visual/browser-rendering-spike.md +173 -0
- data/docs/visual/builder-visual-plan-analysis.md +378 -0
- data/docs/visual/sw-plan-format-exploration.md +511 -0
- data/docs/visual/sw-plan-rendering-deep-dive.md +453 -0
- data/docs/visual-skills/PROGRESS.md +60 -0
- data/docs/visual-skills/SESSION-CONTEXT.md +207 -0
- data/docs/visual-skills/analysis/components.md +317 -0
- data/docs/visual-skills/analysis/overlap.md +360 -0
- data/docs/visual-skills/analysis/pi-design-deck.md +1102 -0
- data/docs/visual-skills/analysis/streamweaver-inventory.md +93 -0
- data/docs/visual-skills/analysis/unified-specs.feature +1003 -0
- data/docs/visual-skills/analysis/visual-explainer.md +964 -0
- data/docs/visual-skills/blog/blog-series-outline.md +39 -0
- data/docs/visual-skills/blog/token-efficiency.md +73 -0
- data/docs/visual-skills/design/architecture.md +1725 -0
- data/docs/visual-skills/design/codex-review.md +340 -0
- data/docs/visual-skills/design/dhh-review.md +209 -0
- data/docs/visual-skills/design/evolution.md +100 -0
- data/docs/visual-skills/design/gemini-review.md +55 -0
- data/docs/visual-skills/design/review-synthesis.md +149 -0
- data/docs/visual-skills/implementation/STATE.md +22 -0
- data/docs/visual-skills/implementation/plan.md +347 -0
- data/docs/visual-skills/implementation/spike-findings.md +237 -0
- data/docs/visual-skills/implementation/tasks.md +702 -0
- data/docs/visual-skills/lessons-learned/process.md +145 -0
- data/examples/README.md +96 -0
- data/examples/advanced/all_components.rb +177 -0
- data/examples/advanced/examples_browser.rb +394 -0
- data/examples/advanced/teachables_browser.rb +261 -0
- data/examples/advanced/theme_tweaker.rb +366 -0
- data/examples/advanced/tutorial.rb +1528 -0
- data/examples/agentic/agentic_form.rb +30 -0
- data/examples/agentic/agentic_form_autoclose.rb +30 -0
- data/examples/agentic/cultivation_tracker.rb +69 -0
- data/examples/basic/hello_world.rb +22 -0
- data/examples/basic/opal_tabs_table.rb +44 -0
- data/examples/basic/todo_list.rb +39 -0
- data/examples/button_loading_test.rb +36 -0
- data/examples/canvas/mermaid_canvas_demo.sh +151 -0
- data/examples/charts/bar_chart_demo.rb +57 -0
- data/examples/charts/line_chart_demo.rb +73 -0
- data/examples/charts/pie_area_demo.rb +87 -0
- data/examples/charts/stacked_bar_chart_demo.rb +69 -0
- data/examples/claude_code/README.md +85 -0
- data/examples/claude_code/codebreaker/.claude/commands/infiltrate.md +632 -0
- data/examples/claude_code/codebreaker/.claude/settings.json +11 -0
- data/examples/claude_code/codebreaker/.claude/settings.local.json +17 -0
- data/examples/claude_code/codebreaker/.claude/skills/infiltrate.md +0 -0
- data/examples/claude_code/codebreaker/README.md +213 -0
- data/examples/claude_code/tutorial/.claude/commands/learn.md +453 -0
- data/examples/claude_code/tutorial/README.md +102 -0
- data/examples/claude_code/verification_flow/.claude/commands/verify.md +171 -0
- data/examples/claude_code/verification_flow/README.md +126 -0
- data/examples/components/annotated_code_demo.rb +54 -0
- data/examples/components/callout_demo.rb +33 -0
- data/examples/components/checkbox_group_demo.rb +46 -0
- data/examples/components/design_review.css +468 -0
- data/examples/components/design_review_demo.rb +44 -0
- data/examples/components/design_review_dsl.rb +300 -0
- data/examples/components/diff_block_demo.rb +112 -0
- data/examples/components/events_demo.rb +184 -0
- data/examples/components/form_demo.rb +62 -0
- data/examples/components/lesson_demo.rb +53 -0
- data/examples/components/markdown_demo.rb +110 -0
- data/examples/components/mermaid_demo.rb +166 -0
- data/examples/components/pareto_set.rb +64 -0
- data/examples/components/prd_demo.rb +21 -0
- data/examples/components/prd_dsl.rb +385 -0
- data/examples/components/quiz_demo.rb +47 -0
- data/examples/components/run_viewer_demo.rb +100 -0
- data/examples/components/score_and_collapsible_demo.rb +82 -0
- data/examples/components/select_stale_value_smoke_test.rb +39 -0
- data/examples/components/table_demo.rb +247 -0
- data/examples/components/timer_with_state_demo.rb +58 -0
- data/examples/components/todo_due_dates.rb +63 -0
- data/examples/components/uat_gaps_demo.rb +112 -0
- data/examples/dashboard/feed_simulator.rb +60 -0
- data/examples/dashboard/live_dashboard.rb +80 -0
- data/examples/dashboard_components.rb +108 -0
- data/examples/deferred_fragments_demo.rb +62 -0
- data/examples/generate_more_spike/README.md +63 -0
- data/examples/generate_more_spike/app.rb +441 -0
- data/examples/git_health.sh +401 -0
- data/examples/layout/layout_components_demo.rb +174 -0
- data/examples/layout/modal_demo.rb +215 -0
- data/examples/layout/navigation_demo.rb +227 -0
- data/examples/layout/route_tabs_demo.rb +52 -0
- data/examples/layout/routing_demo.rb +52 -0
- data/examples/layout/scroll_box_demo.rb +154 -0
- data/examples/lazy_fragments_demo.rb +151 -0
- data/examples/my_todos/README.md +29 -0
- data/examples/my_todos/my_todos.rb +312 -0
- data/examples/my_todos/store.rb +86 -0
- data/examples/opal/reactive_demo.rb +62 -0
- data/examples/opal/scenarios/s1_counter.rb +15 -0
- data/examples/opal/scenarios/s2_search_filter.rb +17 -0
- data/examples/opal/scenarios/s3_sibling_tabs.rb +25 -0
- data/examples/opal/scenarios/s4_shopping_cart.rb +34 -0
- data/examples/opal/scenarios/s5_watch.rb +39 -0
- data/examples/opal/scenarios/s6_on_start.rb +20 -0
- data/examples/opal/scenarios/s7_wizard.rb +33 -0
- data/examples/opal/scenarios/s8_loan_calculator.rb +21 -0
- data/examples/opal/scenarios/s9_dashboard.rb +27 -0
- data/examples/operations_dashboard_demo.rb +167 -0
- data/examples/panel_demo.sh +447 -0
- data/examples/parity/assets/tyrion_slice.css +86 -0
- data/examples/parity/rivet_people_slice.rb +182 -0
- data/examples/parity/tyrion_components.css +777 -0
- data/examples/parity/tyrion_warroom_components.rb +414 -0
- data/examples/parity/tyrion_warroom_slice.rb +549 -0
- data/examples/puma_dev/README.md +124 -0
- data/examples/puma_dev/config.ru +34 -0
- data/examples/puma_dev/standalone_app.rb +34 -0
- data/examples/scaffolding/blog.rb +49 -0
- data/examples/scaffolding/utf_lite.rb +105 -0
- data/examples/styling/feedback_demo.rb +229 -0
- data/examples/styling/style_showcase.rb +172 -0
- data/examples/styling/theme_demo.rb +508 -0
- data/examples/timer_health_checker.rb +111 -0
- data/examples/timer_showcase.rb +131 -0
- data/examples/tutorials/render_markdown.rb +112 -0
- data/examples/tutorials/streamweaver_way_tutorial.rb +44 -0
- data/examples/tutorials/tutorial_content.rb +1082 -0
- data/examples/visual_skills/design_deck_demo.rb +314 -0
- data/examples/visual_skills/explainer_demo.rb +499 -0
- data/exe/streamweaver +9 -0
- data/gsd/ROADMAP-1.0.md +167 -0
- data/gsd/STATE.md +13 -0
- data/gsd/research/market-positioning-research.md +139 -0
- data/gsd/research/production-patterns-research.md +270 -0
- data/gsd/research/repo-audit-1.0.md +274 -0
- data/lib/stream_weaver/action_token.rb +58 -0
- data/lib/stream_weaver/adapter/alpinejs.rb +8249 -0
- data/lib/stream_weaver/adapter/base.rb +591 -0
- data/lib/stream_weaver/adapter/opal.rb +334 -0
- data/lib/stream_weaver/adapter/static.rb +1118 -0
- data/lib/stream_weaver/admin.rb +176 -0
- data/lib/stream_weaver/app.rb +1821 -0
- data/lib/stream_weaver/assets/js/sw-copy.js +50 -0
- data/lib/stream_weaver/assets/js/sw-heredoc-rewrite.js +68 -0
- data/lib/stream_weaver/assets/js/sw-keyboard.js +165 -0
- data/lib/stream_weaver/assets/js/sw-mermaid-zoom.js +621 -0
- data/lib/stream_weaver/assets/js/sw-route-tabs.js +53 -0
- data/lib/stream_weaver/assets/js/sw-sidebar-toc.js +116 -0
- data/lib/stream_weaver/assets/js/sw-slide-nav.js +103 -0
- data/lib/stream_weaver/canvas/bridge.rb +239 -0
- data/lib/stream_weaver/canvas/bridge_server.rb +646 -0
- data/lib/stream_weaver/canvas/client.rb +298 -0
- data/lib/stream_weaver/canvas/doc_roots.rb +233 -0
- data/lib/stream_weaver/canvas/doc_store.rb +252 -0
- data/lib/stream_weaver/canvas/gist_publisher.rb +264 -0
- data/lib/stream_weaver/canvas/gist_save_handler.rb +89 -0
- data/lib/stream_weaver/canvas/gist_store.rb +135 -0
- data/lib/stream_weaver/canvas/helpers.rb +109 -0
- data/lib/stream_weaver/canvas/history.rb +90 -0
- data/lib/stream_weaver/canvas/protocol.rb +86 -0
- data/lib/stream_weaver/canvas/reader.rb +853 -0
- data/lib/stream_weaver/canvas/save_doc_widget.rb +457 -0
- data/lib/stream_weaver/canvas/scroll_top_hint.rb +21 -0
- data/lib/stream_weaver/canvas/session.rb +132 -0
- data/lib/stream_weaver/cli.rb +3235 -0
- data/lib/stream_weaver/component_assets.rb +70 -0
- data/lib/stream_weaver/component_registry.rb +67 -0
- data/lib/stream_weaver/component_renderer.rb +48 -0
- data/lib/stream_weaver/components/annotated_code.rb +53 -0
- data/lib/stream_weaver/components/api_endpoint.rb +42 -0
- data/lib/stream_weaver/components/callout.rb +59 -0
- data/lib/stream_weaver/components/chart.rb +84 -0
- data/lib/stream_weaver/components/code_block.rb +77 -0
- data/lib/stream_weaver/components/comparison.rb +39 -0
- data/lib/stream_weaver/components/decision.rb +38 -0
- data/lib/stream_weaver/components/deck/close_overlay.rb +84 -0
- data/lib/stream_weaver/components/deck/confirmation_bar.rb +60 -0
- data/lib/stream_weaver/components/deck/deck_option.rb +61 -0
- data/lib/stream_weaver/components/deck/deck_slide.rb +77 -0
- data/lib/stream_weaver/components/deck/deck_state.rb +469 -0
- data/lib/stream_weaver/components/deck/deck_summary.rb +73 -0
- data/lib/stream_weaver/components/deck/design_deck.rb +60 -0
- data/lib/stream_weaver/components/deck/generate_more_controls.rb +84 -0
- data/lib/stream_weaver/components/deck/model_selector.rb +84 -0
- data/lib/stream_weaver/components/deck/skeleton_placeholder.rb +36 -0
- data/lib/stream_weaver/components/diff_block.rb +125 -0
- data/lib/stream_weaver/components/doc_header.rb +57 -0
- data/lib/stream_weaver/components/image_block.rb +70 -0
- data/lib/stream_weaver/components/implementation_map.rb +33 -0
- data/lib/stream_weaver/components/keyboard_shortcuts.rb +94 -0
- data/lib/stream_weaver/components/kpi_dashboard.rb +78 -0
- data/lib/stream_weaver/components/mermaid.rb +79 -0
- data/lib/stream_weaver/components/pipeline.rb +63 -0
- data/lib/stream_weaver/components/sidebar_toc.rb +46 -0
- data/lib/stream_weaver/components/slide_container.rb +141 -0
- data/lib/stream_weaver/components/timeline_event.rb +58 -0
- data/lib/stream_weaver/components/wireframe.rb +29 -0
- data/lib/stream_weaver/components/wireframe_block.rb +34 -0
- data/lib/stream_weaver/components.rb +2711 -0
- data/lib/stream_weaver/css.rb +230 -0
- data/lib/stream_weaver/dev_fallback_overlay.rb +61 -0
- data/lib/stream_weaver/display_dsl.rb +1004 -0
- data/lib/stream_weaver/export/html_exporter.rb +478 -0
- data/lib/stream_weaver/feed.rb +34 -0
- data/lib/stream_weaver/feed_builder.rb +31 -0
- data/lib/stream_weaver/fonts.rb +33 -0
- data/lib/stream_weaver/interaction_runner.rb +487 -0
- data/lib/stream_weaver/iterm.rb +460 -0
- data/lib/stream_weaver/layout_registry.rb +92 -0
- data/lib/stream_weaver/opal/bridge.rb +52 -0
- data/lib/stream_weaver/opal/builder.rb +193 -0
- data/lib/stream_weaver/opal/env.rb +29 -0
- data/lib/stream_weaver/opal/reactive_state.rb +75 -0
- data/lib/stream_weaver/opal/regexp_anchor_patch.rb +62 -0
- data/lib/stream_weaver/opal/renderer.rb +77 -0
- data/lib/stream_weaver/opal/runtime.rb +250 -0
- data/lib/stream_weaver/opal/shell.rb +145 -0
- data/lib/stream_weaver/opal/string_bridge.rb +50 -0
- data/lib/stream_weaver/opal/stubs/diff.min.js +1 -0
- data/lib/stream_weaver/opal/stubs/digest.rb +15 -0
- data/lib/stream_weaver/opal/stubs/marked.umd.js +79 -0
- data/lib/stream_weaver/opal/stubs/md5.rb +3 -0
- data/lib/stream_weaver/opal/stubs/morphdom.min.js +775 -0
- data/lib/stream_weaver/opal/stubs/prism-tomorrow.min.css +1 -0
- data/lib/stream_weaver/opal/stubs/prism.min.js +1967 -0
- data/lib/stream_weaver/opal_entry.rb +136 -0
- data/lib/stream_weaver/org/inline.rb +95 -0
- data/lib/stream_weaver/org/reader.rb +561 -0
- data/lib/stream_weaver/org/recording_context.rb +86 -0
- data/lib/stream_weaver/org/source_splitter.rb +63 -0
- data/lib/stream_weaver/org/writer.rb +300 -0
- data/lib/stream_weaver/page_shell.rb +530 -0
- data/lib/stream_weaver/portfile.rb +79 -0
- data/lib/stream_weaver/pushable.rb +42 -0
- data/lib/stream_weaver/resource/default_views.rb +111 -0
- data/lib/stream_weaver/resource/field_input.rb +25 -0
- data/lib/stream_weaver/resource/state_keys.rb +16 -0
- data/lib/stream_weaver/resource/store.rb +18 -0
- data/lib/stream_weaver/resource.rb +104 -0
- data/lib/stream_weaver/server.rb +1471 -0
- data/lib/stream_weaver/service.rb +1240 -0
- data/lib/stream_weaver/service_client.rb +104 -0
- data/lib/stream_weaver/session_store.rb +186 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/SKILL.md +66 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/examples/canvas-safe-showcase.rb +98 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/actions-and-buttons.md +47 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/charts-and-diagrams.md +38 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/deck.md +32 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/inputs-and-forms.md +65 -0
- data/lib/stream_weaver/skills/streamweaver-canvas-safe/references/tabs-and-navigation.md +53 -0
- data/lib/stream_weaver/skills/streamweaver-doc-builder/SKILL.md +298 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/SKILL.md +130 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.css +468 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example.rb +39 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/design-review-example_dsl.rb +300 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example.rb +24 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/examples/doc-parity-example_dsl.rb +385 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/checkpoints-and-forms.md +28 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/cleanup-and-panel.md +44 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/example-gallery.md +8 -0
- data/lib/stream_weaver/skills/streamweaver-visual-companion/references/persistence.md +58 -0
- data/lib/stream_weaver/skills/streamweaver-way/SKILL.md +396 -0
- data/lib/stream_weaver/skills/visual-plan/SKILL.md +201 -0
- data/lib/stream_weaver/skills/visual-recap/SKILL.md +244 -0
- data/lib/stream_weaver/streamer.rb +63 -0
- data/lib/stream_weaver/templates/choices.rb +149 -0
- data/lib/stream_weaver/templates/code.rb +157 -0
- data/lib/stream_weaver/templates/confirm.rb +110 -0
- data/lib/stream_weaver/templates/diff.rb +195 -0
- data/lib/stream_weaver/templates/info.rb +142 -0
- data/lib/stream_weaver/templates/table.rb +169 -0
- data/lib/stream_weaver/templates/wizard.rb +271 -0
- data/lib/stream_weaver/theme/auto_mode.rb +116 -0
- data/lib/stream_weaver/theme/presets.rb +555 -0
- data/lib/stream_weaver/theme.rb +639 -0
- data/lib/stream_weaver/university/canvas.rb +924 -0
- data/lib/stream_weaver/university/course.rb +699 -0
- data/lib/stream_weaver/university/demos/counter.rb +33 -0
- data/lib/stream_weaver/university/demos/dashboard.rb +147 -0
- data/lib/stream_weaver/university/demos/decision_form.rb +143 -0
- data/lib/stream_weaver/university/demos.rb +50 -0
- data/lib/stream_weaver/university/listener.rb +467 -0
- data/lib/stream_weaver/university/progress.rb +201 -0
- data/lib/stream_weaver/university/runner.rb +138 -0
- data/lib/stream_weaver/university/scripts/growing_doc.rb +609 -0
- data/lib/stream_weaver/university/scripts/growing_doc_state.rb +91 -0
- data/lib/stream_weaver/utils.rb +31 -0
- data/lib/stream_weaver/version.rb +5 -0
- data/lib/stream_weaver/views/canvas/reader_layout.erb +800 -0
- data/lib/stream_weaver/views.rb +3940 -0
- data/lib/stream_weaver.rb +122 -0
- data/llms.txt +1269 -0
- data/sig/stream_weaver.rbs +4 -0
- metadata +598 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Architecture Review: StreamWeaver Visual Skills
|
|
2
|
+
|
|
3
|
+
*Reviewer: Claude Opus (second-opinion review)*
|
|
4
|
+
*Date: 2026-03-12*
|
|
5
|
+
*Document under review: `architecture.md` (1618 lines)*
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overall Assessment
|
|
10
|
+
|
|
11
|
+
This is a well-structured architecture document. The design philosophy is sound -- "The DSL IS the API" is the right bet, and the decision to follow existing StreamWeaver patterns rather than introduce parallel systems will pay dividends. The overlap analysis is thorough and the 37% shared figure is credible.
|
|
12
|
+
|
|
13
|
+
That said, there are several areas where I see risk, over-engineering, or missing considerations. This review is organized around the nine focus areas requested.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Agent Communication Protocol (Section 6)
|
|
18
|
+
|
|
19
|
+
### The Good
|
|
20
|
+
|
|
21
|
+
"Agent writes Ruby script, runs it, reads stdout" is the correct primary protocol for the StreamWeaver ecosystem. It leverages the existing `run_once!` pattern and keeps the DSL as the single source of truth. For agents that already run in a Ruby-capable environment (Claude Code, Pi), this is zero friction.
|
|
22
|
+
|
|
23
|
+
### The Concern: Agents That Cannot Run Ruby
|
|
24
|
+
|
|
25
|
+
The design acknowledges only one protocol. What about:
|
|
26
|
+
- **Web-based agents** that can make HTTP calls but cannot execute arbitrary Ruby
|
|
27
|
+
- **Codex** running in a sandboxed environment where `ruby` may not be available or the gem may not be installed
|
|
28
|
+
- **Multi-agent orchestration** where a coordinator dispatches to StreamWeaver without running Ruby locally
|
|
29
|
+
|
|
30
|
+
**Recommendation:** Add a thin JSON-over-HTTP API as a secondary protocol. Not as the primary path, but as a fallback. The `Skills` classes in Section 6.5 already accept structured data (`slides:` as an array of hashes). Expose that same interface as a POST endpoint:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
POST /api/deck { title: "...", slides: [...] }
|
|
34
|
+
POST /api/explainer { title: "...", sections: [...] }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The server translates JSON to DSL calls internally. This is a small surface area (two endpoints) and dramatically widens the agent compatibility story. It can be Phase 5 work -- it does not block the core implementation -- but it should be in the design document as a planned extension rather than absent entirely.
|
|
38
|
+
|
|
39
|
+
### The Concern: `run_once!` Lifecycle and Generate-More Tension
|
|
40
|
+
|
|
41
|
+
The `run_once!` pattern assumes a single request-response cycle: start, collect input, return result, shut down. But the generate-more loop requires the agent script to remain active and responsive *during* user interaction. The document shows this with a `Thread.new` polling loop, but the implications are under-explored:
|
|
42
|
+
|
|
43
|
+
- The agent script must now be a long-running process, not a fire-and-forget script
|
|
44
|
+
- If the agent's Ruby process crashes mid-session, the user is stuck with a dead Generate button
|
|
45
|
+
- The `run_once!` shutdown trigger (submit) must cleanly terminate the polling thread
|
|
46
|
+
|
|
47
|
+
This is workable but the document should explicitly address the lifecycle: how does the polling thread know to stop? What happens if the agent process is killed? The heartbeat/watchdog from pi-design-deck seems relevant here and is mentioned in the overlap analysis but absent from the architecture.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 2. Generate-More Loop (Section 7)
|
|
52
|
+
|
|
53
|
+
### Polling is the Right Call -- With Caveats
|
|
54
|
+
|
|
55
|
+
I agree with the recommendation of polling over callbacks or stdout. The reasoning is correct: simplicity wins when the operation being waited on (LLM generation) takes 5-15 seconds anyway. A 1-2 second poll interval is noise.
|
|
56
|
+
|
|
57
|
+
### What is Missing
|
|
58
|
+
|
|
59
|
+
**Concurrency prevention is unaddressed.** The original pi-design-deck has explicit concurrent-generation prevention. What happens if the user clicks "Generate" twice quickly? The document shows `settings.generate_requests << request` using a simple append -- there is no deduplication or "already generating for this slide" guard. This needs to be in the state machine diagram.
|
|
60
|
+
|
|
61
|
+
**The state machine is too simple.** It covers the happy path and the timeout path. Missing states:
|
|
62
|
+
- **CANCELLED** -- user navigates away from the slide while generation is in progress
|
|
63
|
+
- **ERROR** -- the agent's LLM call fails (rate limit, network error, context too long)
|
|
64
|
+
- **PARTIAL** -- some options arrive but the agent fails mid-batch
|
|
65
|
+
|
|
66
|
+
The state machine should also address: what happens to pending skeletons when the user navigates to a different slide and back? Are they preserved? Cleared?
|
|
67
|
+
|
|
68
|
+
**WebSockets vs. SSE vs. polling:** The document does not mention WebSockets at all. For this specific use case, SSE (which StreamWeaver already has) is the right answer for server-to-browser push, and HTTP polling is fine for browser-to-agent communication. WebSockets would add complexity without benefit since the communication is asymmetric: the browser rarely sends to the server outside of form actions. This is the correct architecture, but the document should explicitly note *why* WebSockets were not chosen, since a reviewer will ask.
|
|
69
|
+
|
|
70
|
+
**Long-polling as an alternative to polling:** Instead of the agent polling `/deck/pending` every 1-2 seconds, the server could hold the connection open until a request arrives (long-polling). This eliminates latency entirely and reduces unnecessary HTTP requests. The implementation is slightly more complex but well-understood. Worth mentioning as a future optimization even if not implemented in Phase 3.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 3. State Machine Complexity
|
|
75
|
+
|
|
76
|
+
### The Concern: State Sprawl
|
|
77
|
+
|
|
78
|
+
The deck accumulates state from multiple sources:
|
|
79
|
+
- `state[:deck_selections]` -- slide_id -> option_label (core)
|
|
80
|
+
- `state[:deck_notes]` -- option-level notes (many keys)
|
|
81
|
+
- `state[:deck_generate]` -- generation status, timestamps
|
|
82
|
+
- `state[:_result]` -- submission payload
|
|
83
|
+
- Implicit state: current slide index (Alpine.js client-side), dirty tracking, layout override
|
|
84
|
+
|
|
85
|
+
This is spread across server session (cookie), client-side Alpine.js `x-data`, and localStorage. The document does not have a single "state map" showing where each piece of state lives and how they synchronize.
|
|
86
|
+
|
|
87
|
+
**What could go wrong:**
|
|
88
|
+
1. **Cookie size limit.** The recommendation says "start with server session, upgrade if needed." But `deck_notes` is variable-length user input. If each of 10 slides has a 200-character note, plus option notes, you can easily hit 4KB. I would recommend starting with (B) file-backed state from day one -- it is not significantly harder and avoids a mid-stream migration.
|
|
89
|
+
|
|
90
|
+
2. **Stale state after SSE push.** When a new option arrives via SSE, the client DOM updates but does the Alpine.js reactive state update? The option count changes, the selection set might need resetting, the summary slide's "Still need" list changes. The document says "needs validation" for Alpine + SSE integration (Section 4.12 in components.md) but the architecture should not leave this as a "maybe it works" -- it is load-bearing.
|
|
91
|
+
|
|
92
|
+
3. **Dirty tracking across server and client.** The original pi-design-deck tracks dirty state entirely client-side (localStorage). The architecture routes through server sessions. If the user modifies a note, that is a POST to the server, a session update, and then the client needs to know "saved at HH:MM." This round-trip for every keystroke is either chatty or requires debouncing, which the document does not specify.
|
|
93
|
+
|
|
94
|
+
**Recommendation:** Create a state ownership table in the document:
|
|
95
|
+
|
|
96
|
+
| State | Owner | Sync Mechanism |
|
|
97
|
+
|-------|-------|---------------|
|
|
98
|
+
| Current slide index | Client (Alpine) | None needed |
|
|
99
|
+
| Selections | Client (Alpine) + Server (session) | POST on change |
|
|
100
|
+
| Notes | Client (Alpine) | POST on blur/debounce |
|
|
101
|
+
| Generate status | Server | SSE push to client |
|
|
102
|
+
| Dirty flag | Client | Computed from last-save timestamp |
|
|
103
|
+
| Layout override | Client (localStorage) | None needed |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 4. Component Count: 50 Components
|
|
108
|
+
|
|
109
|
+
### Assessment: Slightly High But Defensible
|
|
110
|
+
|
|
111
|
+
The inventory lists approximately 50 components (9 shared, 10 deck, 19 explainer, 12 enhanced existing). This is a lot, but the breakdown reveals that many are small:
|
|
112
|
+
|
|
113
|
+
- **Genuinely complex:** Mermaid (zoom engine), SlideContainer (two modes), DesignDeck (orchestrator), SidebarToc (scroll spy), GenerateMoreControls (state machine)
|
|
114
|
+
- **Medium:** CodeBlock, Chart, DataTable, DeckSummary, HtmlExporter
|
|
115
|
+
- **Simple (CSS wrapper + div):** VeCard, Callout, Prose, Pullquote, HeroSection, Legend, FlowArrow, DirTree, SkeletonPlaceholder, ConfirmationBar, CloseOverlay, LayoutToggle, Pipeline, Comparison
|
|
116
|
+
|
|
117
|
+
### Components That Should Be Merged
|
|
118
|
+
|
|
119
|
+
1. **`VeCard` and `Card`**: The document argues against merging because "Card has header/body/footer sub-components." But `VeCard` is just Card with a `depth:` option and no sub-components. Consider adding `depth:` to the existing Card and using it without sub-components. Two card types will confuse agent prompt engineering ("when do I use `card` vs `ve_card`?").
|
|
120
|
+
|
|
121
|
+
2. **`DataTable` and `Table`**: Same argument. The document says they "serve different use cases" but the DSL distinction (`table` vs `data_table`) will confuse agents. Better: enhance `Table` with the sticky/hover/scrollable options and keep one component name. The different input formats (positional, file, headers+rows) can coexist.
|
|
122
|
+
|
|
123
|
+
3. **`code_file` (from components.md 3.9) and `code_block`**: The document already implicitly merged these (code_block has a `file:` option). Good. Just make sure components.md is updated to reflect this.
|
|
124
|
+
|
|
125
|
+
4. **`ProgressIndicator` and `progress_bar`**: The existing `progress_bar` with a `position: :fixed` variant seems sufficient. Adding a new name for what is visually the same element creates confusion.
|
|
126
|
+
|
|
127
|
+
### Components That Might Be Missing
|
|
128
|
+
|
|
129
|
+
1. **`Tabs` for explainer pages** -- multi-section pages where the user switches between views (e.g., "By File" vs "By Severity" in a diff review). StreamWeaver has tabs, but are they compatible with the explainer's use patterns?
|
|
130
|
+
|
|
131
|
+
2. **`Badge` variants for status in data tables** -- the document mentions "status badges rendered as styled spans" but does not define how the agent specifies them within row data. The `{ status: :match, label: "Match" }` hash syntax in the DataTable example needs a rendering rule.
|
|
132
|
+
|
|
133
|
+
3. **`Tooltip`** -- the deck has `description:` on options that is described as "hover text." How is this rendered? A native `title` attribute, or a styled tooltip component?
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 5. Five-Phase Implementation Sequencing
|
|
138
|
+
|
|
139
|
+
### Phase 1 (Shared Foundation) -- Correct
|
|
140
|
+
|
|
141
|
+
Building shared components first is the right call. No notes.
|
|
142
|
+
|
|
143
|
+
### Phase 2 (Design Deck Core) -- Correct but Large
|
|
144
|
+
|
|
145
|
+
Phase 2 is 6 items but includes the `DesignDeck` orchestrator, which is the single most complex piece. The risk is that it takes longer than estimated and delays everything after it. Consider splitting Phase 2 into:
|
|
146
|
+
- **2a:** SlideContainer (:swap mode) + ProgressIndicator + keyboard nav -- these are useful independently
|
|
147
|
+
- **2b:** DesignDeck + DeckSlide + DeckOption + selection state
|
|
148
|
+
- **2c:** DeckSummary
|
|
149
|
+
|
|
150
|
+
This lets you validate slide navigation before coupling it to the deck's selection logic.
|
|
151
|
+
|
|
152
|
+
### Phase 3 (Generate-More Loop) -- Correct Placement
|
|
153
|
+
|
|
154
|
+
Separating generate-more from deck core is wise. The deck is useful without generate-more. Ship Phase 2 and get user feedback before investing in the polling infrastructure.
|
|
155
|
+
|
|
156
|
+
### Phase 4 (Visual Explainer Core) -- Hidden Dependency
|
|
157
|
+
|
|
158
|
+
Phase 4 depends on the `HtmlExporter` from Phase 1. But the explainer also needs the *static export* path to be working end-to-end (write file, open in browser). This is a thin integration test but it should be called out: Phase 4 cannot be validated without a working export pipeline.
|
|
159
|
+
|
|
160
|
+
### Phase 5 (Polish) -- Too Much in One Phase
|
|
161
|
+
|
|
162
|
+
Phase 5 is a grab bag of 9 items with wildly different effort levels (ModelSelector: medium, FlowArrow: small, Animation choreography: medium, Skill entry points: medium). Consider splitting:
|
|
163
|
+
- **5a:** Typography and utility components (Prose, Pullquote, DirTree, etc.) -- small, can be done in parallel
|
|
164
|
+
- **5b:** ModelSelector + Save/Load + Animation -- medium, interdependent with deck workflow
|
|
165
|
+
- **5c:** Skill entry points -- this is really Phase 6, since it depends on everything else being stable
|
|
166
|
+
|
|
167
|
+
### Missing Phase: Integration Testing
|
|
168
|
+
|
|
169
|
+
There is no phase for end-to-end validation. After Phase 2, someone should write a real design deck script and test the full flow: write script, run it, make selections, submit, read result. After Phase 4, someone should generate a real diff review page. These integration checkpoints should be explicit.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 6. Open Questions Evaluation
|
|
174
|
+
|
|
175
|
+
### Q1 (Deck State: Server vs. Client) -- Disagree with Recommendation
|
|
176
|
+
|
|
177
|
+
The recommendation is "start with server session (A), upgrade if needed." As noted in Section 3 above, I think file-backed state (B) should be the starting point. The cost is minimal (write JSON to a temp file, read it back) and avoids the cookie-size cliff. Cookie-based session is fine for StreamWeaver's typical use (small form state), but the deck's state profile is different: variable-length user-generated notes make cookie overflow a when-not-if issue.
|
|
178
|
+
|
|
179
|
+
### Q2 (Adapter Extension) -- Agree
|
|
180
|
+
|
|
181
|
+
The hybrid approach (adapter for interactive, self-render for display) is pragmatic and matches the existing codebase. Good call.
|
|
182
|
+
|
|
183
|
+
### Q3 (Polling vs. Callback) -- Agree with Caveat
|
|
184
|
+
|
|
185
|
+
Polling is fine. Add long-polling as a documented future optimization path. Also document the poll interval as configurable (default 1s, adjustable for low-latency use cases).
|
|
186
|
+
|
|
187
|
+
### Q4 (Deck as App Subclass) -- Agree
|
|
188
|
+
|
|
189
|
+
DSL methods on App is correct. The deck is a component composition, not a new application type. The conditional route registration is a minor wart but far less painful than a class hierarchy.
|
|
190
|
+
|
|
191
|
+
### Q5 (DisplayDSL vs. App) -- Agree
|
|
192
|
+
|
|
193
|
+
Display components in DisplayDSL enables Feed-based push of rich content. This is exactly right for generate-more.
|
|
194
|
+
|
|
195
|
+
### Q6 (Mermaid Re-rendering) -- Agree
|
|
196
|
+
|
|
197
|
+
Calling `mermaid.run()` after SSE insertion is the simplest approach. MutationObserver adds complexity and is harder to debug. One note: ensure that `mermaid.run({ nodes: [newElement] })` scopes the re-render to the new element only, not the entire page. Full-page re-render on every SSE push would cause visible flicker on existing diagrams.
|
|
198
|
+
|
|
199
|
+
### Q7 (Anti-Slop) -- Agree
|
|
200
|
+
|
|
201
|
+
Documentation-only is correct for now. Theme presets are the enforcement mechanism. If slop becomes a problem, the fix is better prompts, not runtime CSS policing.
|
|
202
|
+
|
|
203
|
+
### Q8 (Comparison Block Syntax) -- Agree
|
|
204
|
+
|
|
205
|
+
Named blocks (`before`/`after`) are the most readable. This matches existing StreamWeaver patterns.
|
|
206
|
+
|
|
207
|
+
### Q9 (Explainer Slash Commands) -- Partially Disagree
|
|
208
|
+
|
|
209
|
+
The recommendation is (B) initially, (A) eventually. I agree with starting outside StreamWeaver, but I think (C) Claude Code custom commands is the better initial home, not standalone scripts. Custom commands are already the agent integration point -- they live in the project, they are discoverable, and they naturally separate data-gathering (agent-side) from rendering (StreamWeaver-side). Standalone scripts have no discoverability and will drift.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 7. Scalability Concerns
|
|
214
|
+
|
|
215
|
+
### 20-Slide Deck
|
|
216
|
+
|
|
217
|
+
The design is implicitly optimized for 3-8 slides (the typical design-decision deck). At 20 slides:
|
|
218
|
+
- **Cookie overflow:** Near-certain with server session state. File-backed state is essential.
|
|
219
|
+
- **Summary slide:** 20 summary cards in a grid will be visually overwhelming. Consider pagination or grouping.
|
|
220
|
+
- **Navigation:** Linear Back/Next through 20 slides is tedious. Consider adding a slide picker (dropdown or thumbnail strip) as a navigation shortcut.
|
|
221
|
+
- **Memory:** 20 slides with Mermaid diagrams each means 20 Mermaid render calls. Mermaid.js is not lightweight -- each render involves SVG generation. Lazy rendering (only render the active slide's diagrams) would help.
|
|
222
|
+
|
|
223
|
+
### 500-File Diff Review
|
|
224
|
+
|
|
225
|
+
This is the real scalability stress test. A diff review with 500 changed files means:
|
|
226
|
+
- **SidebarToc:** 500 entries in the sidebar TOC is unusable. Need grouping by directory or category, with collapsible sections.
|
|
227
|
+
- **IntersectionObserver:** 500 observed elements could cause performance issues on scroll. Batch observation, use a single observer with root margin, or virtualize.
|
|
228
|
+
- **Page weight:** 500 code blocks with Prism.js highlighting is a lot of DOM. Consider pagination (show 20 files at a time with "load more") or virtual scrolling.
|
|
229
|
+
- **HTML export:** A self-contained HTML file with 500 highlighted code blocks could be 5-10MB. This may be fine for local viewing but brutal for Vercel deployment.
|
|
230
|
+
- **Generation time:** The agent generating 500 file reviews is already slow. But the *rendering* should not add to the pain. Ensure the DSL-to-HTML path is O(n) and does not have quadratic behaviors (e.g., repeated CSS generation per component).
|
|
231
|
+
|
|
232
|
+
**Recommendation:** Add a "Scale Considerations" section to the architecture document. Define soft limits (recommended: up to 10 slides, up to 50 files) and hard limits (tested: up to 20 slides, up to 200 files). For beyond-limits use cases, document the degradation strategy (pagination, grouping, lazy loading).
|
|
233
|
+
|
|
234
|
+
### CDN Latency
|
|
235
|
+
|
|
236
|
+
The document notes "CDN latency is acceptable" for a local dev tool. True for first load, but Mermaid.js alone is ~2MB. If the user has a cold cache or is offline (airplane, VPN tunnel), the page will be broken. Consider:
|
|
237
|
+
- A local fallback for the most critical CDN assets (Mermaid, Prism)
|
|
238
|
+
- A "pre-warm" step that downloads CDN assets on gem install
|
|
239
|
+
- Graceful degradation: show raw code/text if Prism/Mermaid fail to load
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 8. Missing Features
|
|
244
|
+
|
|
245
|
+
Comparing the overlap analysis against the architecture:
|
|
246
|
+
|
|
247
|
+
### Covered Well
|
|
248
|
+
- Mermaid rendering (both modes)
|
|
249
|
+
- Code highlighting
|
|
250
|
+
- Theme system
|
|
251
|
+
- Keyboard shortcuts
|
|
252
|
+
- HTML export
|
|
253
|
+
- Slide navigation (both modes)
|
|
254
|
+
- Selection and generate-more
|
|
255
|
+
- All major explainer components
|
|
256
|
+
|
|
257
|
+
### Missing or Under-Specified
|
|
258
|
+
|
|
259
|
+
1. **Heartbeat/Watchdog (from pi-design-deck Section 2.10):** The original deck has a 5-second heartbeat with 60-second grace period and idle timer. The architecture mentions none of this. If the browser tab is closed or the network drops, the agent script should know. StreamWeaver's existing SSE could serve as the heartbeat (connection drop = client gone), but this needs to be explicit.
|
|
260
|
+
|
|
261
|
+
2. **Touch/Swipe Navigation (from visual-explainer):** The overlap analysis lists touch swipe support. The architecture mentions `keyboard_nav` but not touch. For scroll-snap mode, CSS handles the basic case, but the 50px swipe threshold and explicit touch handling from the explainer are not covered.
|
|
262
|
+
|
|
263
|
+
3. **Accessibility (ARIA):** The DeckOption section mentions `role="radio"` and `aria-checked`, which is good. But the rest of the architecture is silent on accessibility. The slide container needs `aria-live` for slide transitions. The sidebar TOC needs `aria-current`. The generate-more skeleton needs `aria-busy`. Add an "Accessibility Requirements" subsection.
|
|
264
|
+
|
|
265
|
+
4. **Auto-Trigger on Complex Tables (from visual-explainer Section 3.1):** This agent-side behavior (automatically rendering tables with 4+ rows as HTML) is not addressed. It is agent logic, not StreamWeaver logic, but the skill entry point should at least accept a flag like `auto_visual: true` that tells the rendering to upgrade tables.
|
|
266
|
+
|
|
267
|
+
5. **Vercel Deployment / Share (from visual-explainer Section 3.6):** Mentioned in the overlap analysis but absent from the architecture. Even if it is out of scope for initial phases, it should be listed as a future extension.
|
|
268
|
+
|
|
269
|
+
6. **`beforeunload` Handler:** The original deck sends a beacon on tab close. This is important for clean shutdown of `run_once!`. The architecture relies on `run_once!` blocking until submit, but what if the user closes the tab without submitting? The agent script would hang indefinitely. Need a cancellation path.
|
|
270
|
+
|
|
271
|
+
7. **Double-Submit Prevention:** The original deck prevents double-submit on the summary slide. Not mentioned in the architecture.
|
|
272
|
+
|
|
273
|
+
8. **surf-cli Image Generation:** The optional Gemini-powered image generation from visual-explainer. This is clearly out of scope for initial implementation, but worth listing as a future integration point.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 9. Risk Assessment
|
|
278
|
+
|
|
279
|
+
### Biggest Risk: Generate-More Loop Complexity
|
|
280
|
+
|
|
281
|
+
The generate-more loop is the riskiest feature. It introduces:
|
|
282
|
+
- Bidirectional communication between three parties (browser, server, agent)
|
|
283
|
+
- A long-running agent process with a polling thread
|
|
284
|
+
- Race conditions between user navigation and async option delivery
|
|
285
|
+
- Timeout handling across two processes
|
|
286
|
+
- DOM manipulation of content that contains embedded JavaScript (Mermaid init)
|
|
287
|
+
|
|
288
|
+
This feature alone accounts for ~20% of the estimated effort and contains the highest density of edge cases. If any single feature needs a spike/prototype before committing to the design, it is this one.
|
|
289
|
+
|
|
290
|
+
**Mitigation:** Phase 3 is correctly separated from Phase 2. Ship the deck without generate-more first. Validate the core selection/submission flow. Then tackle generate-more as a separate effort with its own spike.
|
|
291
|
+
|
|
292
|
+
### Most Likely to Need Rework: State Management
|
|
293
|
+
|
|
294
|
+
The hybrid state approach (server session + client Alpine + localStorage) will accumulate inconsistencies. The most likely rework scenario: discovering mid-implementation that cookie-based sessions cannot hold deck state, requiring a migration to file-backed state that touches every route handler.
|
|
295
|
+
|
|
296
|
+
**Mitigation:** Start with file-backed state (recommendation above). Also, centralize state access behind a `DeckState` object that abstracts the storage backend.
|
|
297
|
+
|
|
298
|
+
### Second Most Likely Rework: CSS Architecture
|
|
299
|
+
|
|
300
|
+
50 components means a large CSS surface area. The document plans to add visual skills CSS as additional sections in `StreamWeaver::CSS`. But there is no mention of:
|
|
301
|
+
- CSS naming convention (BEM? `sw-` prefix?)
|
|
302
|
+
- Specificity management (what happens when depth-tier styles conflict with card styles?)
|
|
303
|
+
- CSS custom property namespacing (the example uses `--sw-vs-*` which is good, but is this enforced?)
|
|
304
|
+
|
|
305
|
+
Without a CSS architecture, the 50 components will accumulate specificity conflicts and !important overrides.
|
|
306
|
+
|
|
307
|
+
**Mitigation:** Define a CSS convention in the architecture document. The `sw-` prefix is already used in examples (`sw-mermaid-wrap`, `sw-code-block`). Make this explicit and enforce it.
|
|
308
|
+
|
|
309
|
+
### Lower but Non-Zero Risk: CDN Dependency
|
|
310
|
+
|
|
311
|
+
The architecture depends on four CDN-hosted libraries (Mermaid, Prism, Chart.js, Google Fonts). Any of these being down, rate-limited, or serving a breaking update will break the user experience. Mermaid.js in particular has had breaking changes between minor versions.
|
|
312
|
+
|
|
313
|
+
**Mitigation:** Pin CDN versions (already done: `mermaid@11`). Consider adding integrity hashes (`integrity="sha384-..."`) to CDN script tags. Document the offline degradation story.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Summary of Recommendations
|
|
318
|
+
|
|
319
|
+
| # | Recommendation | Priority | Effort |
|
|
320
|
+
|---|---------------|----------|--------|
|
|
321
|
+
| 1 | Add JSON-over-HTTP API as secondary agent protocol | Low (Phase 5) | Small |
|
|
322
|
+
| 2 | Document agent process lifecycle (heartbeat, crash recovery, clean shutdown) | High | Doc only |
|
|
323
|
+
| 3 | Add CANCELLED, ERROR, PARTIAL states to generate-more state machine | High | Doc + Small code |
|
|
324
|
+
| 4 | Start with file-backed state instead of cookie session | High | Small |
|
|
325
|
+
| 5 | Create state ownership table (what lives where, how it syncs) | High | Doc only |
|
|
326
|
+
| 6 | Merge VeCard into Card (add `depth:` option) | Medium | Small |
|
|
327
|
+
| 7 | Merge DataTable into Table (add sticky/hover options) | Medium | Small |
|
|
328
|
+
| 8 | Split Phase 2 into 2a/2b/2c for incremental validation | Medium | Planning only |
|
|
329
|
+
| 9 | Add explicit integration test checkpoints between phases | Medium | Planning only |
|
|
330
|
+
| 10 | Add scalability section with soft/hard limits | Medium | Doc only |
|
|
331
|
+
| 11 | Address `beforeunload` / tab-close cancellation for `run_once!` | High | Small |
|
|
332
|
+
| 12 | Define CSS naming convention and specificity rules | Medium | Doc only |
|
|
333
|
+
| 13 | Add accessibility requirements subsection | Medium | Doc only |
|
|
334
|
+
| 14 | Spike the generate-more loop before committing to full implementation | High | Medium |
|
|
335
|
+
|
|
336
|
+
### Bottom Line
|
|
337
|
+
|
|
338
|
+
The architecture is solid. The DSL-first approach, the reuse of existing StreamWeaver patterns, the phased implementation, and the component decomposition are all well-reasoned. The main risks are in the generate-more loop (complex distributed state) and state management (hybrid storage). Both can be mitigated by spiking early and centralizing state behind an abstraction. The component count is manageable if you merge the redundant pairs (VeCard/Card, DataTable/Table).
|
|
339
|
+
|
|
340
|
+
Ship Phase 1, spike generate-more in parallel, and validate the full deck flow end-to-end before investing in polish.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# DHH-Style Architecture Review: StreamWeaver Visual Skills
|
|
2
|
+
|
|
3
|
+
*Reviewed: 2026-03-12*
|
|
4
|
+
*Document under review: `docs/visual-skills/design/architecture.md`*
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overall Assessment
|
|
9
|
+
|
|
10
|
+
This is a strong architecture document that mostly respects the existing codebase and resists the temptation to over-engineer. The DSL reads like Ruby, the flat namespace decision is correct, and the "DSL IS the API" philosophy is sound. The design deck DSL -- `design_deck`, `slide`, `option` -- composes beautifully and would feel natural to any Ruby developer. However, there are areas where the document drifts into enterprise architecture territory: too many component classes for what are essentially styled divs, a polling-based generate-more loop that should be simpler, and a directory tree that implies 40+ new files when half of them could be collapsed. The good bones are here, but the document needs a ruthless editing pass to separate what must exist from what merely could exist.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Critical Issues
|
|
15
|
+
|
|
16
|
+
### 1. The Component Explosion
|
|
17
|
+
|
|
18
|
+
The document proposes roughly 30 new component classes. Many of these are CSS variations, not behavioral differences:
|
|
19
|
+
|
|
20
|
+
- `VeCard` is a `Card` with a CSS class. The document even acknowledges this: "a simpler depth-styled container." That is not a new class -- that is a `card depth: :hero` option.
|
|
21
|
+
- `DataTable` is `Table` with `sticky_header: true`. Add the options to `Table`.
|
|
22
|
+
- `HeroSection` is a `div` with a CSS class.
|
|
23
|
+
- `Prose` is a `div` with `max-width` set.
|
|
24
|
+
- `Pullquote` is a `blockquote` with styling.
|
|
25
|
+
- `FlowArrow` is an SVG arrow.
|
|
26
|
+
- `Legend` is a list of colored dots with labels.
|
|
27
|
+
|
|
28
|
+
Every new class is a file to maintain, a DSL method to document, and a concept a developer must learn. The bar for "this deserves to be a Component subclass" should be: does it have meaningful behavior or state that a CSS class cannot express?
|
|
29
|
+
|
|
30
|
+
**Recommendation:** Collapse pure-display components into existing primitives with variant/class options. Reserve new classes for components with actual behavior (Mermaid, SlideContainer, DesignDeck, KeyboardShortcuts, CodeBlock, Comparison).
|
|
31
|
+
|
|
32
|
+
### 2. Duplicate Table Implementations
|
|
33
|
+
|
|
34
|
+
Creating `DataTable` alongside `Table` is wrong. You already have a `Table` component. Extend it:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
table headers: ["Risk", "Severity"], rows: [...],
|
|
38
|
+
sticky_header: true, alternating: true, scrollable: true
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Two table classes in the same component library is a maintenance nightmare and a source of developer confusion. "Should I use `table` or `data_table`?" is a question no one should have to ask.
|
|
42
|
+
|
|
43
|
+
### 3. The Generate-More Polling Loop is Over-Engineered
|
|
44
|
+
|
|
45
|
+
Section 7 introduces a state machine with five states, a polling endpoint, a request queue, a thread in the agent script, timeout tracking, and skeleton replacement via SSE. This is a lot of machinery for "user clicks button, agent generates options, options appear."
|
|
46
|
+
|
|
47
|
+
The existing `Feed` + `Pushable` infrastructure already handles server-to-browser push. The missing piece is browser-to-agent signaling, and polling is the simplest answer -- fine. But the state machine diagram, the `deck_generate` state hash with six keys, and the explicit timeout handling are premature. Start with:
|
|
48
|
+
|
|
49
|
+
1. User clicks Generate. POST goes to server. Server queues it.
|
|
50
|
+
2. Agent polls, gets request, generates, pushes via Feed.
|
|
51
|
+
3. Done.
|
|
52
|
+
|
|
53
|
+
Timeout? The browser shows a spinner. If nothing arrives, the user clicks again. No state machine needed. No `started_at` tracking. No client-side timeout logic. Build the complex version when the simple version proves insufficient.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Improvements Needed
|
|
58
|
+
|
|
59
|
+
### 4. The Deck Namespace is Correct but Inconsistent
|
|
60
|
+
|
|
61
|
+
The document says "flat namespace" then immediately creates `Components::Deck::*` with 10 classes. That is not flat. The deck subsystem deserves its own namespace -- that decision is sound. But call it what it is: a namespaced subsystem, not a flat namespace. The document's framing is misleading.
|
|
62
|
+
|
|
63
|
+
### 5. Repeated Container Capture Pattern
|
|
64
|
+
|
|
65
|
+
The existing `App` class has this pattern repeated approximately 15 times:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
parent_components = @components
|
|
69
|
+
@components = []
|
|
70
|
+
instance_eval(&block)
|
|
71
|
+
component.children = @components
|
|
72
|
+
@components = parent_components
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The document proposes adding more instances of this same pattern for `design_deck`, `slide`, `option`, `comparison`, etc. The `capture_children_then_append` and `with_container` private methods exist but are not consistently used. Every new container DSL method should use one of these two helpers, not inline the pattern again.
|
|
76
|
+
|
|
77
|
+
The `design_deck` method in Section 4.1 inlines the pattern. The `slide` method inlines it. The `option` method inlines it. Use `with_container` or `capture_children_then_append`:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
def design_deck(title, **options, &block)
|
|
81
|
+
deck = Components::Deck::DesignDeck.new(title, **options)
|
|
82
|
+
with_container(deck, &block)
|
|
83
|
+
deck.children << Components::Deck::DeckSummary.new
|
|
84
|
+
deck.validate!
|
|
85
|
+
deck
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def slide(id, title = nil, **options, &block)
|
|
89
|
+
raise "slide must be inside design_deck" unless @current_deck
|
|
90
|
+
capture_children_then_append(Components::Deck::DeckSlide.new(id, title, **options), &block)
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 6. DSL Method Naming Collisions
|
|
95
|
+
|
|
96
|
+
The document proposes adding `slide` and `option` as top-level DSL methods on `App`. These are extremely generic names. Today, `slide` might mean a deck slide. Tomorrow, someone wants a carousel slide or a presentation slide.
|
|
97
|
+
|
|
98
|
+
The existing codebase avoids this -- `tab` is scoped by `@current_tabs` context, `crumb` by `@current_breadcrumbs`. The document does include context checks (`raise "slide must be inside design_deck"`), which is good. But consider whether `deck_slide` and `deck_option` would be clearer in the DSL:
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
design_deck "Direction" do
|
|
102
|
+
deck_slide "arch", "Architecture" do
|
|
103
|
+
deck_option "Monolith" do ... end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Actually, no. Within the `design_deck` block, the context is unambiguous. `slide` and `option` read better. The context checks are sufficient. Keep the short names. The DSL reads like prose, which is the goal.
|
|
109
|
+
|
|
110
|
+
### 7. CDN Asset Declaration is Good, But the Method Name is Wrong
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
def cdn_assets
|
|
114
|
+
[:mermaid]
|
|
115
|
+
end
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This conflates the asset with its delivery mechanism. What if you later vendor these? Call it `required_assets` or `external_assets`. The component should declare what it needs, not how it is delivered.
|
|
119
|
+
|
|
120
|
+
### 8. The Skill Entry Points are Premature
|
|
121
|
+
|
|
122
|
+
Section 6.5 proposes `DesignDeckSkill` and `VisualExplainerSkill` classes that accept structured data and generate Ruby DSL scripts. This is a code generator that generates code for a DSL. That is one layer of indirection too many.
|
|
123
|
+
|
|
124
|
+
The agent already writes Ruby. The DSL IS the API. Why would the agent pass structured data to a skill class that then generates the same Ruby the agent could have written directly? This only makes sense if the agent cannot write Ruby -- but the entire architecture assumes it can.
|
|
125
|
+
|
|
126
|
+
Kill the skill entry points. The DSL is the skill entry point.
|
|
127
|
+
|
|
128
|
+
### 9. Theme Presets -- Good Concept, Watch the Scope
|
|
129
|
+
|
|
130
|
+
Nine presets is a lot for a first pass. Ship with two (one for deck, one for explainer). Add more when users ask. The preset mechanism itself is clean -- CSS custom properties via `theme_overrides` is the right approach.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## What Works Well
|
|
135
|
+
|
|
136
|
+
### The DSL Reads Beautifully
|
|
137
|
+
|
|
138
|
+
Section 10's examples are genuinely pleasant to read. This is the gold standard:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
design_deck "Component Library Direction" do
|
|
142
|
+
slide "palette", "Color Palette",
|
|
143
|
+
context: "Choose the color direction" do
|
|
144
|
+
option "Warm Earth Tones", recommended: true do
|
|
145
|
+
code_block <<~CSS, lang: "css"
|
|
146
|
+
:root { --primary: #c2825a; }
|
|
147
|
+
CSS
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
That reads like a description of what should appear. An agent could write this. A human could read this. This is what good DSL design looks like.
|
|
154
|
+
|
|
155
|
+
### The Visual Explainer Example (Section 10.2) is Excellent
|
|
156
|
+
|
|
157
|
+
The diff review page example composes cleanly. `hero_section`, `ve_card`, `callout`, `code_block`, `data_table` -- each call earns its place. The `sidebar_toc` with section IDs that match `ve_card` IDs is elegant implicit linking.
|
|
158
|
+
|
|
159
|
+
### Flat Namespace for Shared Components
|
|
160
|
+
|
|
161
|
+
Correct decision. `mermaid` belongs next to `table` and `card`. No `VisualSkills::Components::Mermaid` namespace soup.
|
|
162
|
+
|
|
163
|
+
### Design Deck as DSL Methods, Not a Subclass
|
|
164
|
+
|
|
165
|
+
Correct decision. `design_deck` is like `tabs` or `modal` -- a DSL method that composes children. No `DesignDeckApp < App` parallel hierarchy.
|
|
166
|
+
|
|
167
|
+
### The Open Questions are Well-Reasoned
|
|
168
|
+
|
|
169
|
+
All nine recommendations are sound:
|
|
170
|
+
|
|
171
|
+
- **Q1 (Session storage):** Server-side session, overflow to file if needed. Correct. Do not prematurely optimize.
|
|
172
|
+
- **Q2 (Adapter extension):** Display components render themselves, interactive components use the adapter. This is already the implicit pattern -- making it explicit is good.
|
|
173
|
+
- **Q3 (Polling):** Simple polling wins. Correct.
|
|
174
|
+
- **Q4 (Not a subclass):** Correct, as noted above.
|
|
175
|
+
- **Q5 (DisplayDSL for shared components):** Correct. Feed push of mermaid diagrams is powerful.
|
|
176
|
+
- **Q6 (Mermaid re-rendering):** `mermaid.run({ nodes: [newElement] })` after DOM insertion. Simple and correct.
|
|
177
|
+
- **Q7 (Anti-slop):** Documentation only. Correct. Do not build a CSS linter.
|
|
178
|
+
- **Q8 (Comparison syntax):** Named blocks (`before`/`after`). Correct. Follows existing `trigger`/`menu` pattern.
|
|
179
|
+
- **Q9 (Slash commands outside gem):** Correct. Agent logic and rendering logic should not be coupled.
|
|
180
|
+
|
|
181
|
+
### The Comparison Component DSL
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
comparison before_label: "Current", after_label: "Proposed" do
|
|
185
|
+
before { mermaid "..." }
|
|
186
|
+
after { mermaid "..." }
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
This is clean and follows the established `dropdown` pattern with `trigger`/`menu`. Named blocks for multi-region components is the right idiom for this DSL.
|
|
191
|
+
|
|
192
|
+
### HtmlExporter as Infrastructure, Not a Component
|
|
193
|
+
|
|
194
|
+
Correct separation. Export is a pipeline operation on the entire app, not a renderable component.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Summary of Recommendations
|
|
199
|
+
|
|
200
|
+
1. **Collapse CSS-only components** into existing primitives with options. Cut the class count by 40%.
|
|
201
|
+
2. **Merge DataTable into Table.** One table class, more options.
|
|
202
|
+
3. **Simplify the generate-more loop.** Kill the state machine. Queue, poll, push. Three steps.
|
|
203
|
+
4. **Use `with_container`/`capture_children_then_append` consistently** in all new DSL methods. Do not inline the capture pattern again.
|
|
204
|
+
5. **Rename `cdn_assets` to `required_assets`.**
|
|
205
|
+
6. **Kill the Skill entry points.** The DSL is the API. The agent writes Ruby directly.
|
|
206
|
+
7. **Ship two theme presets**, not nine. Add more when demanded.
|
|
207
|
+
8. **Phase 1 is correctly prioritized.** Mermaid, CodeBlock, and theme enhancements unblock everything. Ship those first and let the rest follow from real usage.
|
|
208
|
+
|
|
209
|
+
The architecture is fundamentally sound. The DSL design is strong. The main risk is building too many small classes that each do too little. Ruby's power is in expressive, composable abstractions -- not in having a class for every visual concept. A `div` with a CSS class is still a `div`. Treat it that way.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Design Evolution Log
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Track every design decision, iteration, and review so future LLMs (and humans)
|
|
5
|
+
can understand WHY the architecture looks the way it does.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Entry 1: Analysis Phase Complete (2026-03-12)
|
|
10
|
+
|
|
11
|
+
### What we learned
|
|
12
|
+
- **37% overlap confirmed** — user predicted ~1/3, analysis yielded 37%
|
|
13
|
+
- **Token savings are asymmetric:** deck saves 30-45%, explainer saves 80-85%
|
|
14
|
+
- **The explainer's savings are architectural:** 30K tokens of design system in the prompt → 0 in framework code
|
|
15
|
+
- **50 components identified:** 9 shared, 10 deck, 19 explainer, 12 existing enhancements
|
|
16
|
+
|
|
17
|
+
### Decisions made
|
|
18
|
+
1. Analysis-first approach validated — parallel subagents with shared template produced consistent, comparable output
|
|
19
|
+
2. Gherkin as bridge format — 1003 lines of scenarios, detailed enough for implementation
|
|
20
|
+
3. 5-phase implementation sequence confirmed (shared → deck → explainer → polish → integration)
|
|
21
|
+
|
|
22
|
+
### Key risks identified
|
|
23
|
+
1. **Generate-more loop** is the hardest architectural challenge — Promise-based blocking in Pi doesn't map to StreamWeaver's reactive model
|
|
24
|
+
2. **Agent communication protocol** is bidirectional — agent needs to both send data (create deck) and receive results (user selections)
|
|
25
|
+
3. **CSS complexity** — visual-explainer has 40+ CSS components, 13 font pairings, 5 color palettes. Quality bar is high.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Entry 2: OO Design Phase (2026-03-12, in progress)
|
|
30
|
+
|
|
31
|
+
### Design agent launched with:
|
|
32
|
+
- All 6 analysis artifacts as input
|
|
33
|
+
- 16 existing StreamWeaver source files for pattern matching
|
|
34
|
+
- Explicit instruction to be opinionated and flag genuine trade-offs
|
|
35
|
+
- Required outputs: module structure, class hierarchies, data flow diagrams, DSL examples
|
|
36
|
+
|
|
37
|
+
### Reviews completed:
|
|
38
|
+
- [x] DHH reviewer — "fundamentally sound, needs ruthless editing pass"
|
|
39
|
+
- [x] Codex second opinion — "solid, spike generate-more, file-backed state"
|
|
40
|
+
- [ ] User review of progression before implementation
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Entry 4: Review Synthesis (2026-03-12)
|
|
45
|
+
|
|
46
|
+
### Key outcomes from dual review
|
|
47
|
+
1. **Component count reduced 50 → ~32** by merging CSS-only wrappers into existing primitives
|
|
48
|
+
2. **State management changed** from cookie session to file-backed state (Codex convinced us)
|
|
49
|
+
3. **Generate-more: spike first** — both reviewers had different concerns; a spike will reveal which matter
|
|
50
|
+
4. **Skill entry points killed** — "the DSL IS the API" (DHH). Agent glue lives outside the gem as custom commands (Codex)
|
|
51
|
+
5. **5 new doc sections needed**: state ownership table, CSS convention, accessibility, scalability limits, agent lifecycle
|
|
52
|
+
|
|
53
|
+
### Where reviewers disagreed (and how we resolved)
|
|
54
|
+
- **State storage:** DHH said cookies, Codex said files → files (Codex is right about note overflow)
|
|
55
|
+
- **Generate-more complexity:** DHH said simpler, Codex said more states needed → spike it (both right from different angles)
|
|
56
|
+
- **Component count:** DHH said cut 40%, Codex said defensible → cut ~36% (DHH's instinct is right)
|
|
57
|
+
|
|
58
|
+
### Revised component count: ~32 classes + ~7 CSS helpers = ~39 DSL methods
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Entry 5: Gemini Adversarial Review (2026-03-12)
|
|
63
|
+
|
|
64
|
+
### Best insight: Push-to-state, not push-to-DOM
|
|
65
|
+
Gemini proposed that generate-more should push new options to server-side state and let
|
|
66
|
+
StreamWeaver's reactive re-render handle display, instead of pushing HTML snippets via SSE.
|
|
67
|
+
This aligns with StreamWeaver's existing model and solves the "phantom option" race condition
|
|
68
|
+
(user navigates away during generation). **Adopted as architecture change.**
|
|
69
|
+
|
|
70
|
+
### Good catch: Session-scoped request queue
|
|
71
|
+
Generate requests queued on the server must be scoped to session ID, otherwise stale
|
|
72
|
+
requests from killed agent processes persist. Neither prior reviewer caught this.
|
|
73
|
+
|
|
74
|
+
### Overruled: Token efficiency concern
|
|
75
|
+
Gemini argued DSL reference docs in agent context erode savings. Math doesn't support this:
|
|
76
|
+
~3K DSL reference vs ~30K CSS patterns = still 80%+ net savings. Overruled.
|
|
77
|
+
|
|
78
|
+
### Overruled: Component rot / plugin system
|
|
79
|
+
StreamWeaver is a bounded DSL, not a general-purpose UI framework. Component set is
|
|
80
|
+
intentionally focused. No plugin system needed.
|
|
81
|
+
|
|
82
|
+
### Running tally of reviews: 3 reviewers, all approve core architecture
|
|
83
|
+
- DHH: "fundamentally sound" — cut components, simplify generate-more
|
|
84
|
+
- Codex: "solid" — spike generate-more, file-backed state, accessibility
|
|
85
|
+
- Gemini: "push-to-state is better" — best architectural improvement so far
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Entry 3: Blog Series Recognized (2026-03-12)
|
|
90
|
+
|
|
91
|
+
### Insight
|
|
92
|
+
The process itself is generating multiple blog-worthy artifacts:
|
|
93
|
+
1. **Token efficiency** — the flagship technical argument
|
|
94
|
+
2. **Claude Code capabilities** — parallel analysis, quality of autonomous work
|
|
95
|
+
3. **Engineering process + GenAI** — specification depth as the new 10x multiplier
|
|
96
|
+
4. **Repeatable process** — skill extraction from a successful workflow
|
|
97
|
+
|
|
98
|
+
### Decision
|
|
99
|
+
Track blog material as we go rather than reconstructing after the fact.
|
|
100
|
+
The process IS the content.
|