rosett-ai 1.3.3
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/.ai-provenance.yml +119 -0
- data/.debride_whitelist +186 -0
- data/.fasterer.yml +29 -0
- data/.mdl_style.rb +10 -0
- data/.mdlrc +3 -0
- data/.mutant.yml +49 -0
- data/.namespace-allowlist +42 -0
- data/.reek.yml +1040 -0
- data/.rosett-ai/config.yml +3 -0
- data/.rspec +5 -0
- data/.rubocop.yml +380 -0
- data/.ruby-version +1 -0
- data/.yamllint +51 -0
- data/.yardopts +12 -0
- data/AI-DISCLOSURE.md +48 -0
- data/CHANGELOG.md +519 -0
- data/CLAUDE.md +141 -0
- data/CONTRIBUTING.md +734 -0
- data/INSTALL.md +154 -0
- data/LICENSE +674 -0
- data/LICENSE.md +675 -0
- data/QUICKSTART.md +73 -0
- data/README.md +366 -0
- data/Rakefile +200 -0
- data/SECURITY.md +114 -0
- data/bin/rai +1 -0
- data/cliff.toml +52 -0
- data/conf/adopt_redactions.yml +8 -0
- data/conf/behaviour/.gitkeep +0 -0
- data/conf/compliance/cra_rules.yml +25 -0
- data/conf/compliance/license_rules.yml +20 -0
- data/conf/design/aaif_alignment.yml +181 -0
- data/conf/design/ab_testing.yml +172 -0
- data/conf/design/accessibility.yml +84 -0
- data/conf/design/ai_authorship.yml +210 -0
- data/conf/design/ai_provenance.yml +224 -0
- data/conf/design/ai_tool_configuration.yml +207 -0
- data/conf/design/architecture.yml +139 -0
- data/conf/design/autocompletion.yml +115 -0
- data/conf/design/backward_compatibility.yml +112 -0
- data/conf/design/behaviour_composition.yml +246 -0
- data/conf/design/build_rake_extraction.yml +57 -0
- data/conf/design/ci_pipeline.yml +100 -0
- data/conf/design/claude_code_configuration.yml +157 -0
- data/conf/design/compiler.yml +128 -0
- data/conf/design/comply.yml +153 -0
- data/conf/design/content_packs.yml +84 -0
- data/conf/design/desktop_integration.yml +289 -0
- data/conf/design/distribution.yml +216 -0
- data/conf/design/doctor.yml +184 -0
- data/conf/design/documentation.yml +152 -0
- data/conf/design/engine_architecture.yml +257 -0
- data/conf/design/error_handling.yml +103 -0
- data/conf/design/feature_flags.yml +142 -0
- data/conf/design/git_hooks.yml +165 -0
- data/conf/design/gui_plugins.yml +475 -0
- data/conf/design/i18n.yml +84 -0
- data/conf/design/integration_testing.yml +56 -0
- data/conf/design/licensing_system.yml +88 -0
- data/conf/design/lifecycle_management.yml +208 -0
- data/conf/design/mcp_integration.yml +207 -0
- data/conf/design/mcp_settings.yml +126 -0
- data/conf/design/migration.yml +56 -0
- data/conf/design/monitoring_observability.yml +194 -0
- data/conf/design/namespace_cleanup.yml +145 -0
- data/conf/design/plugin_test_segregation.yml +145 -0
- data/conf/design/policy_management.yml +229 -0
- data/conf/design/project_management.yml +183 -0
- data/conf/design/rai_mcp_asset_discovery.yml +164 -0
- data/conf/design/rai_mcp_server.yml +605 -0
- data/conf/design/release_management.yml +117 -0
- data/conf/design/retrofit.yml +199 -0
- data/conf/design/retrospective_analyzer.yml +79 -0
- data/conf/design/scope_hierarchy.yml +352 -0
- data/conf/design/security.yml +115 -0
- data/conf/design/session_retrospective.yml +85 -0
- data/conf/design/smart_ui_feedback.yml +89 -0
- data/conf/design/structured_logging.yml +148 -0
- data/conf/design/styles.yml +123 -0
- data/conf/design/test_peer_review.yml +89 -0
- data/conf/design/testing.yml +136 -0
- data/conf/design/threat_model.yml +108 -0
- data/conf/design/ui_framework.yml +111 -0
- data/conf/design/usage_optimization.yml +122 -0
- data/conf/design/version_management.yml +60 -0
- data/conf/design/workflow.yml +227 -0
- data/conf/mcp/server_defaults.yml +42 -0
- data/conf/mcp/trust.yml +21 -0
- data/conf/packaging/core.yml +12 -0
- data/conf/packaging/gtk4.yml +11 -0
- data/conf/packaging/qt6.yml +11 -0
- data/conf/policy/default_deny_list.yml +197 -0
- data/conf/review/cli-command-audit.yml +857 -0
- data/conf/review/design-docs.yml +1064 -0
- data/conf/review/design-questionnaire.yml +153 -0
- data/conf/review/questionnaire.yml +146 -0
- data/conf/review/rosett-ai-core.yml +2919 -0
- data/conf/schemas/ai_config_schema.json +73 -0
- data/conf/schemas/behaviour_schema.json +132 -0
- data/conf/schemas/compliance_rule_schema.json +63 -0
- data/conf/schemas/content_pack_manifest_schema.json +51 -0
- data/conf/schemas/design_schema.json +210 -0
- data/conf/schemas/engine_manifest_schema.json +144 -0
- data/conf/schemas/lockfile_schema.json +74 -0
- data/conf/schemas/mcp_server_schema.json +48 -0
- data/conf/schemas/packaging_schema.json +70 -0
- data/conf/schemas/policy_schema.json +85 -0
- data/conf/schemas/provenance_schema.json +84 -0
- data/conf/schemas/rai_config_schema.json +56 -0
- data/conf/schemas/rai_project_schema.json +20 -0
- data/conf/schemas/scope_hierarchy_schema.json +49 -0
- data/conf/schemas/target_schema.json +67 -0
- data/conf/schemas/tooling_schema.json +65 -0
- data/conf/schemas/workflow_schema.json +112 -0
- data/conf/targets/agents_md.yml +17 -0
- data/conf/targets/claude.yml +12 -0
- data/conf/tooling/tools.yml +58 -0
- data/dist/rosett-ai-mcp.service +48 -0
- data/dist/rosett-ai-mcp.yml.default +45 -0
- data/doc/AAIF_POSITIONING.md +58 -0
- data/doc/ADOPT.md +224 -0
- data/doc/AI_PROVENANCE.md +139 -0
- data/doc/ARCHITECTURE.md +920 -0
- data/doc/BEHAVIOUR.md +409 -0
- data/doc/BUILD.md +138 -0
- data/doc/CI_CD_RECIPES.md +171 -0
- data/doc/CLAUDE_SESSIONS_MOVED.md +16 -0
- data/doc/COMMAND_ANALYSIS.md +229 -0
- data/doc/CONFIGURATION.md +281 -0
- data/doc/DESIGN_AUDIT.md +235 -0
- data/doc/DESIGN_PEER_REVIEW.md +771 -0
- data/doc/DESKTOP.md +447 -0
- data/doc/ENGINES.md +567 -0
- data/doc/ENGINE_DEVELOPMENT_GUIDE.md +417 -0
- data/doc/FEATURE_AUDIT.md +218 -0
- data/doc/IMPLEMENTATION_PLAN.md +669 -0
- data/doc/INCIDENT_REPORT_2026-02-02.md +251 -0
- data/doc/MIGRATION_GUIDE.md +88 -0
- data/doc/PACKAGING.md +232 -0
- data/doc/PROJECT_DASHBOARD.md +153 -0
- data/doc/PULP_DEPLOYMENT.md +164 -0
- data/doc/QUALITY_FIX_SUMMARY.md +110 -0
- data/doc/QUICK_START.md +162 -0
- data/doc/REEK_CONFIGURATION.md +166 -0
- data/doc/REFERENCE.md +253 -0
- data/doc/REFERENCES.md +324 -0
- data/doc/SECURITY_REVIEW_CHECKLIST.md +72 -0
- data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +359 -0
- data/doc/SETUP.md +202 -0
- data/doc/TEST_PEER_REVIEW.md +152 -0
- data/doc/THREAT_MODEL.md +230 -0
- data/doc/USAGE.md +545 -0
- data/doc/USER_MANUAL.md +585 -0
- data/doc/ai_test_review_checklist.md +110 -0
- data/doc/changes/2026-02-18-packaging-fpm.md +155 -0
- data/doc/changes/2026-02-19-testing-infrastructure.md +221 -0
- data/doc/changes/2026-02-20-security-implementation.md +281 -0
- data/doc/changes/2026-02-20-styles-implementation.md +220 -0
- data/doc/changes/2026-02-21-architecture-completion.md +95 -0
- data/doc/changes/2026-02-21-architecture-ui-layer.md +253 -0
- data/doc/changes/2026-02-21-cc-config-implementation.md +108 -0
- data/doc/changes/2026-02-21-ci-pipeline-implementation.md +214 -0
- data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +241 -0
- data/doc/changes/2026-02-21-config-design-show-commands.md +61 -0
- data/doc/changes/2026-02-21-design-implementation-overview.md +455 -0
- data/doc/changes/2026-02-21-lifecycle-management.md +196 -0
- data/doc/changes/2026-02-21-path-resolver.md +128 -0
- data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +45 -0
- data/doc/changes/2026-03-01-ci-bundler-strategy.md +120 -0
- data/doc/changes/2026-03-20-security-hardening-phase2.md +163 -0
- data/doc/context/SESSION-HANDOFF.md +69 -0
- data/doc/context/ai-engine-usage-trends-2026.md +80 -0
- data/doc/context/plan-pluggable-engines.md +590 -0
- data/doc/decisions/001-flog-deferred.md +32 -0
- data/doc/decisions/002-path-resolution-strategy.md +158 -0
- data/doc/decisions/003-ui-adapter-selection.md +193 -0
- data/doc/decisions/004-design-document-validation.md +179 -0
- data/doc/decisions/005-package-splitting-strategy.md +200 -0
- data/doc/decisions/006-multi-engine-architecture.md +147 -0
- data/doc/decisions/007-engine-agnostic-pivot.md +219 -0
- data/doc/decisions/008-ci-bundler-strategy.md +129 -0
- data/doc/decisions/009-core-only-v1-release.md +60 -0
- data/doc/decisions/010-engine-debian-packaging.md +66 -0
- data/doc/decisions/011-context-aware-cli.md +71 -0
- data/doc/dependency_decisions.yml +247 -0
- data/doc/issues/001-wrapper-missing-environment-variables.md +197 -0
- data/doc/issues/002-embedded-ruby-wrong-prefix.md +217 -0
- data/doc/issues/003-smoke-test-false-positive.md +127 -0
- data/doc/issues/004-market-research-design-updates.md +109 -0
- data/doc/issues/005-compile-scope-coexistence.md +161 -0
- data/doc/locales/.gitkeep +0 -0
- data/doc/man/rai.1.ronn +505 -0
- data/doc/operations/packaging.md +133 -0
- data/doc/operations/rosett-ai-release.md +65 -0
- data/doc/reference/error-catalog.md +107 -0
- data/doc/reference/rosett-ai-technical-reference.pdf +0 -0
- data/doc/reference/src/Pictures/cover.jpg +0 -0
- data/doc/reference/src/Pictures/head1.jpg +0 -0
- data/doc/reference/src/Pictures/head2.jpg +0 -0
- data/doc/reference/src/Pictures/head3.jpg +0 -0
- data/doc/reference/src/Pictures/head4.jpg +0 -0
- data/doc/reference/src/Pictures/head5.jpg +0 -0
- data/doc/reference/src/Pictures/head6.jpg +0 -0
- data/doc/reference/src/Pictures/head7.jpg +0 -0
- data/doc/reference/src/Pictures/head8.jpg +0 -0
- data/doc/reference/src/StyleInd.ist +4 -0
- data/doc/reference/src/bibliography.bib +79 -0
- data/doc/reference/src/main.tex +1288 -0
- data/doc/reference/src/structure.tex +303 -0
- data/doc/rosett-ai-bookmarks.html +301 -0
- data/kitchen.yml +46 -0
- data/lib/rosett_ai/adopter/executor_resolver.rb +77 -0
- data/lib/rosett_ai/adopter/local_analysis_collector.rb +154 -0
- data/lib/rosett_ai/adopter/rule_adopter.rb +254 -0
- data/lib/rosett_ai/ai_config/config_compiler.rb +111 -0
- data/lib/rosett_ai/ai_config/context_window.rb +55 -0
- data/lib/rosett_ai/ai_config/cost_controls.rb +44 -0
- data/lib/rosett_ai/ai_config/fallback_chain.rb +64 -0
- data/lib/rosett_ai/ai_config/model_router.rb +121 -0
- data/lib/rosett_ai/ai_config/validator.rb +45 -0
- data/lib/rosett_ai/authorship/attribution_compiler.rb +99 -0
- data/lib/rosett_ai/authorship/disclosure_policy.rb +81 -0
- data/lib/rosett_ai/authorship/review_validator.rb +39 -0
- data/lib/rosett_ai/authorship/trailer_generator.rb +88 -0
- data/lib/rosett_ai/backup/compressor.rb +180 -0
- data/lib/rosett_ai/backup/destination.rb +91 -0
- data/lib/rosett_ai/behaviour/manager.rb +156 -0
- data/lib/rosett_ai/compiler/backend.rb +86 -0
- data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +80 -0
- data/lib/rosett_ai/compiler/backends/claude_backend.rb +88 -0
- data/lib/rosett_ai/compiler/backends/generic_backend.rb +15 -0
- data/lib/rosett_ai/compiler/behaviour_compiler.rb +40 -0
- data/lib/rosett_ai/compiler/capability_checker.rb +104 -0
- data/lib/rosett_ai/compiler/compilation_pipeline.rb +361 -0
- data/lib/rosett_ai/compiler/compiled_output.rb +39 -0
- data/lib/rosett_ai/compiler/locale_compiler.rb +250 -0
- data/lib/rosett_ai/compiler/target_profile.rb +112 -0
- data/lib/rosett_ai/completion/generator.rb +101 -0
- data/lib/rosett_ai/completion/shells/bash_generator.rb +126 -0
- data/lib/rosett_ai/completion/shells/fish_generator.rb +78 -0
- data/lib/rosett_ai/completion/shells/zsh_generator.rb +126 -0
- data/lib/rosett_ai/comply/checkers/cra_checker.rb +102 -0
- data/lib/rosett_ai/comply/checkers/license_checker.rb +85 -0
- data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +98 -0
- data/lib/rosett_ai/comply/reporter.rb +113 -0
- data/lib/rosett_ai/comply/runner.rb +50 -0
- data/lib/rosett_ai/composition/circular_dependency_detector.rb +56 -0
- data/lib/rosett_ai/composition/composer.rb +158 -0
- data/lib/rosett_ai/composition/composition_result.rb +64 -0
- data/lib/rosett_ai/composition/conflict_detector.rb +53 -0
- data/lib/rosett_ai/composition/lockfile.rb +103 -0
- data/lib/rosett_ai/composition/merge_strategy.rb +131 -0
- data/lib/rosett_ai/composition/priority_sorter.rb +29 -0
- data/lib/rosett_ai/composition/scope_resolver.rb +55 -0
- data/lib/rosett_ai/config/compile_result.rb +37 -0
- data/lib/rosett_ai/config/compiler.rb +13 -0
- data/lib/rosett_ai/config/domain_transformer.rb +13 -0
- data/lib/rosett_ai/config/key_map.rb +13 -0
- data/lib/rosett_ai/config/masking_secret_resolver.rb +40 -0
- data/lib/rosett_ai/config/scope_router.rb +13 -0
- data/lib/rosett_ai/config/secret_resolver.rb +125 -0
- data/lib/rosett_ai/configuration.rb +119 -0
- data/lib/rosett_ai/content/content_client.rb +60 -0
- data/lib/rosett_ai/content/pack_installer.rb +117 -0
- data/lib/rosett_ai/content/pack_manifest.rb +50 -0
- data/lib/rosett_ai/content/pack_registry.rb +68 -0
- data/lib/rosett_ai/content_packs/manager.rb +50 -0
- data/lib/rosett_ai/dbus/compositor_detector.rb +77 -0
- data/lib/rosett_ai/dbus/focus_adapters/base.rb +59 -0
- data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +172 -0
- data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +77 -0
- data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +65 -0
- data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +103 -0
- data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +105 -0
- data/lib/rosett_ai/dbus/focus_monitor_interface.rb +103 -0
- data/lib/rosett_ai/dbus/manager_interface.rb +213 -0
- data/lib/rosett_ai/dbus/plugin_manager_interface.rb +169 -0
- data/lib/rosett_ai/dbus/rate_limiter.rb +89 -0
- data/lib/rosett_ai/dbus/service.rb +121 -0
- data/lib/rosett_ai/dbus/status_notifier_interface.rb +79 -0
- data/lib/rosett_ai/deprecation.rb +79 -0
- data/lib/rosett_ai/desktop/dbus_client.rb +259 -0
- data/lib/rosett_ai/desktop/gtk4_app.rb +371 -0
- data/lib/rosett_ai/desktop/gtk4_preferences.rb +331 -0
- data/lib/rosett_ai/desktop/gui_logger.rb +236 -0
- data/lib/rosett_ai/doctor/check.rb +92 -0
- data/lib/rosett_ai/doctor/checks/cache_health_check.rb +50 -0
- data/lib/rosett_ai/doctor/checks/dbus_availability_check.rb +39 -0
- data/lib/rosett_ai/doctor/checks/engine_detection_check.rb +46 -0
- data/lib/rosett_ai/doctor/checks/file_permission_check.rb +44 -0
- data/lib/rosett_ai/doctor/checks/gem_dependency_check.rb +55 -0
- data/lib/rosett_ai/doctor/checks/ruby_version_check.rb +50 -0
- data/lib/rosett_ai/doctor/checks/stale_config_nncc_check.rb +57 -0
- data/lib/rosett_ai/doctor/checks/stale_home_nncc_check.rb +59 -0
- data/lib/rosett_ai/doctor.rb +81 -0
- data/lib/rosett_ai/documentation/reference_compiler.rb +122 -0
- data/lib/rosett_ai/documentation/translator.rb +62 -0
- data/lib/rosett_ai/engines/base_config_compiler.rb +203 -0
- data/lib/rosett_ai/engines/detector.rb +63 -0
- data/lib/rosett_ai/engines/registry.rb +50 -0
- data/lib/rosett_ai/error_handler.rb +139 -0
- data/lib/rosett_ai/exit_codes.rb +76 -0
- data/lib/rosett_ai/feature_flags.rb +102 -0
- data/lib/rosett_ai/formatting.rb +33 -0
- data/lib/rosett_ai/gem_consistency_checker.rb +199 -0
- data/lib/rosett_ai/git_hooks/chain_detector.rb +86 -0
- data/lib/rosett_ai/git_hooks/installer.rb +175 -0
- data/lib/rosett_ai/git_hooks/script_generator.rb +125 -0
- data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +79 -0
- data/lib/rosett_ai/i18n/locale_resolver.rb +46 -0
- data/lib/rosett_ai/i18n/utf8_checker.rb +32 -0
- data/lib/rosett_ai/init/config_file_writer.rb +24 -0
- data/lib/rosett_ai/init/directory_builder.rb +38 -0
- data/lib/rosett_ai/init/file_copier.rb +95 -0
- data/lib/rosett_ai/init/global_initializer.rb +28 -0
- data/lib/rosett_ai/init/local_initializer.rb +27 -0
- data/lib/rosett_ai/init/mcp_registrar.rb +109 -0
- data/lib/rosett_ai/init/project_initializer.rb +38 -0
- data/lib/rosett_ai/licensing/license_key.rb +139 -0
- data/lib/rosett_ai/licensing/license_store.rb +64 -0
- data/lib/rosett_ai/licensing/license_validator.rb +60 -0
- data/lib/rosett_ai/licensing/tier.rb +42 -0
- data/lib/rosett_ai/mcp/admin/auditor.rb +88 -0
- data/lib/rosett_ai/mcp/admin/health_checker.rb +81 -0
- data/lib/rosett_ai/mcp/admin/registry.rb +100 -0
- data/lib/rosett_ai/mcp/admin/schema_validator.rb +63 -0
- data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
- data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +197 -0
- data/lib/rosett_ai/mcp/enforcement/validator.rb +215 -0
- data/lib/rosett_ai/mcp/governance.rb +160 -0
- data/lib/rosett_ai/mcp/http_security_config.rb +158 -0
- data/lib/rosett_ai/mcp/instructions.rb +266 -0
- data/lib/rosett_ai/mcp/key_hasher.rb +66 -0
- data/lib/rosett_ai/mcp/keyfile.rb +221 -0
- data/lib/rosett_ai/mcp/middleware/authentication.rb +146 -0
- data/lib/rosett_ai/mcp/middleware/content_type.rb +56 -0
- data/lib/rosett_ai/mcp/middleware/cors.rb +83 -0
- data/lib/rosett_ai/mcp/middleware/origin_validation.rb +73 -0
- data/lib/rosett_ai/mcp/middleware/rate_limit.rb +106 -0
- data/lib/rosett_ai/mcp/middleware/request_size.rb +51 -0
- data/lib/rosett_ai/mcp/plugins.rb +143 -0
- data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +40 -0
- data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +127 -0
- data/lib/rosett_ai/mcp/resources/config_resource.rb +72 -0
- data/lib/rosett_ai/mcp/resources/design_resource.rb +58 -0
- data/lib/rosett_ai/mcp/resources/hooks_resource.rb +74 -0
- data/lib/rosett_ai/mcp/resources/provenance_resource.rb +51 -0
- data/lib/rosett_ai/mcp/resources/rules_resource.rb +60 -0
- data/lib/rosett_ai/mcp/resources/schema_resource.rb +72 -0
- data/lib/rosett_ai/mcp/response_helper.rb +46 -0
- data/lib/rosett_ai/mcp/security_logger.rb +60 -0
- data/lib/rosett_ai/mcp/server.rb +212 -0
- data/lib/rosett_ai/mcp/settings/server_installer.rb +112 -0
- data/lib/rosett_ai/mcp/settings/trust_manager.rb +142 -0
- data/lib/rosett_ai/mcp/tools/adopt_tool.rb +70 -0
- data/lib/rosett_ai/mcp/tools/backup_tool.rb +64 -0
- data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +72 -0
- data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +56 -0
- data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +114 -0
- data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +62 -0
- data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +122 -0
- data/lib/rosett_ai/mcp/tools/compile_tool.rb +191 -0
- data/lib/rosett_ai/mcp/tools/comply_tool.rb +79 -0
- data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +71 -0
- data/lib/rosett_ai/mcp/tools/config_status_tool.rb +79 -0
- data/lib/rosett_ai/mcp/tools/content_tool.rb +78 -0
- data/lib/rosett_ai/mcp/tools/context_query_tool.rb +156 -0
- data/lib/rosett_ai/mcp/tools/design_list_tool.rb +57 -0
- data/lib/rosett_ai/mcp/tools/design_show_tool.rb +69 -0
- data/lib/rosett_ai/mcp/tools/doctor_tool.rb +62 -0
- data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +45 -0
- data/lib/rosett_ai/mcp/tools/engines_tool.rb +84 -0
- data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +190 -0
- data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +173 -0
- data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +84 -0
- data/lib/rosett_ai/mcp/tools/init_tool.rb +87 -0
- data/lib/rosett_ai/mcp/tools/license_status_tool.rb +44 -0
- data/lib/rosett_ai/mcp/tools/project_tool.rb +117 -0
- data/lib/rosett_ai/mcp/tools/provenance_tool.rb +97 -0
- data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +40 -0
- data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +81 -0
- data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +163 -0
- data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +94 -0
- data/lib/rosett_ai/mcp/tools/tooling_tool.rb +86 -0
- data/lib/rosett_ai/mcp/tools/validate_tool.rb +105 -0
- data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +74 -0
- data/lib/rosett_ai/mcp/tools/workflow_tool.rb +78 -0
- data/lib/rosett_ai/migration/detector.rb +117 -0
- data/lib/rosett_ai/migration/nncc_config_migrator.rb +94 -0
- data/lib/rosett_ai/migration/nncc_project_migrator.rb +90 -0
- data/lib/rosett_ai/migration/xdg_migrator.rb +123 -0
- data/lib/rosett_ai/package_manager/apt.rb +108 -0
- data/lib/rosett_ai/package_manager/base.rb +68 -0
- data/lib/rosett_ai/package_manager/gem_backend.rb +90 -0
- data/lib/rosett_ai/packaging/variant_config.rb +92 -0
- data/lib/rosett_ai/path_resolver.rb +115 -0
- data/lib/rosett_ai/plugins/contract.rb +43 -0
- data/lib/rosett_ai/plugins/engine_contract.rb +60 -0
- data/lib/rosett_ai/plugins/gui_contract.rb +74 -0
- data/lib/rosett_ai/plugins/mcp_contract.rb +48 -0
- data/lib/rosett_ai/plugins/registry.rb +150 -0
- data/lib/rosett_ai/policy/auditor.rb +41 -0
- data/lib/rosett_ai/policy/deny_list.rb +71 -0
- data/lib/rosett_ai/policy/opt_out_scanner.rb +37 -0
- data/lib/rosett_ai/policy/policy_compiler.rb +84 -0
- data/lib/rosett_ai/policy/protected_files.rb +47 -0
- data/lib/rosett_ai/policy/tier_hierarchy.rb +48 -0
- data/lib/rosett_ai/policy/validator.rb +35 -0
- data/lib/rosett_ai/profiler.rb +79 -0
- data/lib/rosett_ai/project/drift_detector.rb +126 -0
- data/lib/rosett_ai/project/manager.rb +115 -0
- data/lib/rosett_ai/project/sync_manager.rb +138 -0
- data/lib/rosett_ai/project/template_applier.rb +105 -0
- data/lib/rosett_ai/project_context.rb +82 -0
- data/lib/rosett_ai/provenance/entry.rb +63 -0
- data/lib/rosett_ai/provenance/file_source.rb +32 -0
- data/lib/rosett_ai/provenance/source.rb +62 -0
- data/lib/rosett_ai/provenance/store.rb +153 -0
- data/lib/rosett_ai/provenance/tracker.rb +62 -0
- data/lib/rosett_ai/provenance/trailer_generator.rb +43 -0
- data/lib/rosett_ai/provenance/validator.rb +45 -0
- data/lib/rosett_ai/quorum/collector.rb +59 -0
- data/lib/rosett_ai/quorum/comparator.rb +81 -0
- data/lib/rosett_ai/quorum/dispatcher.rb +57 -0
- data/lib/rosett_ai/quorum/strategies/adopt.rb +56 -0
- data/lib/rosett_ai/rai_config.rb +107 -0
- data/lib/rosett_ai/retrofit/base_parser.rb +66 -0
- data/lib/rosett_ai/retrofit/engine.rb +171 -0
- data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +50 -0
- data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +69 -0
- data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +82 -0
- data/lib/rosett_ai/retrofit/round_trip_validator.rb +65 -0
- data/lib/rosett_ai/retrofit/scanner.rb +47 -0
- data/lib/rosett_ai/retrofit/secret_detector.rb +87 -0
- data/lib/rosett_ai/secrets_resolver.rb +71 -0
- data/lib/rosett_ai/smart_feedback/suggester.rb +83 -0
- data/lib/rosett_ai/smart_feedback/thor_middleware.rb +84 -0
- data/lib/rosett_ai/structured_logger.rb +110 -0
- data/lib/rosett_ai/telemetry/json_lines_writer.rb +50 -0
- data/lib/rosett_ai/telemetry/log_rotator.rb +67 -0
- data/lib/rosett_ai/telemetry/provider.rb +26 -0
- data/lib/rosett_ai/telemetry/reporter.rb +144 -0
- data/lib/rosett_ai/telemetry.rb +47 -0
- data/lib/rosett_ai/text_sanitizer.rb +62 -0
- data/lib/rosett_ai/thor/cli.rb +269 -0
- data/lib/rosett_ai/thor/tasks/adopt.rb +250 -0
- data/lib/rosett_ai/thor/tasks/backup.rb +420 -0
- data/lib/rosett_ai/thor/tasks/behaviour.rb +474 -0
- data/lib/rosett_ai/thor/tasks/build.rb +1162 -0
- data/lib/rosett_ai/thor/tasks/compile.rb +415 -0
- data/lib/rosett_ai/thor/tasks/completion.rb +123 -0
- data/lib/rosett_ai/thor/tasks/comply.rb +82 -0
- data/lib/rosett_ai/thor/tasks/config.rb +265 -0
- data/lib/rosett_ai/thor/tasks/content.rb +193 -0
- data/lib/rosett_ai/thor/tasks/dbus.rb +321 -0
- data/lib/rosett_ai/thor/tasks/design.rb +258 -0
- data/lib/rosett_ai/thor/tasks/desktop.rb +129 -0
- data/lib/rosett_ai/thor/tasks/doctor.rb +127 -0
- data/lib/rosett_ai/thor/tasks/documentation.rb +321 -0
- data/lib/rosett_ai/thor/tasks/engines.rb +167 -0
- data/lib/rosett_ai/thor/tasks/hooks.rb +219 -0
- data/lib/rosett_ai/thor/tasks/init.rb +259 -0
- data/lib/rosett_ai/thor/tasks/license.rb +120 -0
- data/lib/rosett_ai/thor/tasks/mcp.rb +535 -0
- data/lib/rosett_ai/thor/tasks/migrate.rb +121 -0
- data/lib/rosett_ai/thor/tasks/plugins.rb +157 -0
- data/lib/rosett_ai/thor/tasks/project.rb +260 -0
- data/lib/rosett_ai/thor/tasks/provenance.rb +195 -0
- data/lib/rosett_ai/thor/tasks/release.rb +314 -0
- data/lib/rosett_ai/thor/tasks/retrofit.rb +90 -0
- data/lib/rosett_ai/thor/tasks/tooling.rb +308 -0
- data/lib/rosett_ai/thor/tasks/validate.rb +108 -0
- data/lib/rosett_ai/thor/tasks/workflow.rb +196 -0
- data/lib/rosett_ai/tooling/ci_yaml_validator.rb +37 -0
- data/lib/rosett_ai/tooling/version_checker.rb +35 -0
- data/lib/rosett_ai/ui/accessible_tui.rb +61 -0
- data/lib/rosett_ai/ui/base.rb +46 -0
- data/lib/rosett_ai/ui/gtk4.rb +98 -0
- data/lib/rosett_ai/ui/kde.rb +40 -0
- data/lib/rosett_ai/ui/qt6.rb +40 -0
- data/lib/rosett_ai/ui/registry.rb +60 -0
- data/lib/rosett_ai/ui/tty_helper.rb +74 -0
- data/lib/rosett_ai/ui/tui.rb +59 -0
- data/lib/rosett_ai/validators/behaviour_validator.rb +20 -0
- data/lib/rosett_ai/validators/design_validator.rb +17 -0
- data/lib/rosett_ai/validators/schema_validator.rb +84 -0
- data/lib/rosett_ai/validators/tooling_validator.rb +17 -0
- data/lib/rosett_ai/version.rb +8 -0
- data/lib/rosett_ai/version_consistency_checker.rb +129 -0
- data/lib/rosett_ai/workflow/audit_log.rb +86 -0
- data/lib/rosett_ai/workflow/engine.rb +142 -0
- data/lib/rosett_ai/workflow/manager.rb +82 -0
- data/lib/rosett_ai/workflow/schema_validator.rb +71 -0
- data/lib/rosett_ai/workflow/step_runner.rb +61 -0
- data/lib/rosett_ai/workflow/steps/prompt_step.rb +62 -0
- data/lib/rosett_ai/workflow/steps/rai_step.rb +74 -0
- data/lib/rosett_ai/workflow/steps/shell_step.rb +53 -0
- data/lib/rosett_ai/yaml_loader.rb +78 -0
- data/lib/rosett_ai.rb +221 -0
- data/lib/rubocop/cop/rosett_ai/shell_interpolation.rb +54 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_const_get.rb +60 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_send.rb +50 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_yaml_load.rb +40 -0
- data/lib/rubocop/rosett_ai.rb +9 -0
- data/lib/scripts/generated/docker_hub_tags.rb +126 -0
- data/locales/.gitkeep +0 -0
- data/locales/ar.yml +579 -0
- data/locales/en.yml +571 -0
- data/locales/fr.yml +567 -0
- data/packaging/build-engine-deb.sh +81 -0
- data/packaging/scripts/postinst +17 -0
- data/packaging/scripts/postrm +19 -0
- data/packaging/scripts/prerm +10 -0
- data/packaging/wrapper.sh.template +38 -0
- data/rosett-ai.gemspec +63 -0
- data/rules/.gitkeep +0 -0
- data/scripts/publish/pulp_upload.sh +123 -0
- data/settings.json +29 -0
- data/share/applications/be.neatnerds.rosettai.desktop +29 -0
- data/share/dbus-1/interfaces/be.neatnerds.rosettai.xml +103 -0
- data/share/dbus-1/services/be.neatnerds.rosettai.service +3 -0
- data/share/templates/behaviour/criticalthinking.yml +69 -0
- metadata +810 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scope_hierarchy
|
|
3
|
+
domain: core
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: implemented
|
|
6
|
+
priority: 2
|
|
7
|
+
author: hugo
|
|
8
|
+
created_at: "2026-03-23"
|
|
9
|
+
modified_at: "2026-04-14"
|
|
10
|
+
modified_by: claude opus-4.6
|
|
11
|
+
depends_on:
|
|
12
|
+
- architecture
|
|
13
|
+
- security
|
|
14
|
+
- error_handling
|
|
15
|
+
#
|
|
16
|
+
intent: |
|
|
17
|
+
Define the three-level scope hierarchy that makes rosett-ai directory-aware.
|
|
18
|
+
Currently, all commands (compile, validate, design) operate on rosett-ai's own
|
|
19
|
+
conf/ directory regardless of where the user invokes them. This design
|
|
20
|
+
introduces a Hiera-like scope model where configuration sources are
|
|
21
|
+
discovered based on the user's working directory, merged according to
|
|
22
|
+
configurable strategies, and compiled to scope-appropriate output locations.
|
|
23
|
+
|
|
24
|
+
The three scope levels are:
|
|
25
|
+
|
|
26
|
+
1. Global (~/.config/rosett-ai/conf/) — user-wide defaults following XDG
|
|
27
|
+
Base Directory Specification. Applied everywhere unless overridden.
|
|
28
|
+
|
|
29
|
+
2. Local (<group-dir>/.rosett-ai/conf/) — multi-project workspace defaults.
|
|
30
|
+
A local scope groups related projects (e.g. a monorepo or a team
|
|
31
|
+
workspace) under shared configuration. Detected by a .rosett-ai/ marker
|
|
32
|
+
directory that has child directories also containing .rosett-ai/ markers.
|
|
33
|
+
|
|
34
|
+
3. Project (<project-dir>/.rosett-ai/conf/) — project-specific overrides.
|
|
35
|
+
The most specific scope. A project scope is a leaf .rosett-ai/ directory
|
|
36
|
+
(no children with their own .rosett-ai/ markers).
|
|
37
|
+
|
|
38
|
+
The merge order is global -> local -> project: each successive layer
|
|
39
|
+
overrides the previous one. Merge strategies are configurable per key.
|
|
40
|
+
|
|
41
|
+
Without this design, rosett-ai cannot serve users who work across multiple
|
|
42
|
+
projects with shared conventions. Every project must duplicate global
|
|
43
|
+
defaults, and there is no way to express workspace-level settings that
|
|
44
|
+
apply to a group of related projects. The scope hierarchy solves this
|
|
45
|
+
by making configuration inheritance explicit, configurable, and auditable.
|
|
46
|
+
|
|
47
|
+
This design is the authoritative specification for scope semantics.
|
|
48
|
+
All other design documents that reference scopes (compiler.yml,
|
|
49
|
+
behaviour_composition.yml, engine_architecture.yml, project_management.yml,
|
|
50
|
+
architecture.yml) defer to this document for scope definitions, detection
|
|
51
|
+
algorithm, and merge behaviour.
|
|
52
|
+
#
|
|
53
|
+
constraints:
|
|
54
|
+
- "Exactly three scope levels exist: global, local, project — no more, no fewer"
|
|
55
|
+
- "Global scope source directory is ~/.config/rosett-ai/conf/ (XDG_CONFIG_HOME/rosett-ai/conf/)"
|
|
56
|
+
- "Local scope source directory is <group-dir>/.rosett-ai/conf/ where <group-dir>
|
|
57
|
+
is detected by walking up from RAI_ORIGINAL_PWD"
|
|
58
|
+
- "Project scope source directory is <project-dir>/.rosett-ai/conf/ where
|
|
59
|
+
<project-dir> is the nearest directory containing a .rosett-ai/ marker"
|
|
60
|
+
- "Scope detection walks up from RAI_ORIGINAL_PWD (or Dir.pwd if unset),
|
|
61
|
+
finding the nearest .rosett-ai/ marker first"
|
|
62
|
+
- "A .rosett-ai/ directory is classified as local (workspace) if it has child
|
|
63
|
+
directories that also contain .rosett-ai/ markers; otherwise it is project"
|
|
64
|
+
- "Merge order is always global -> local -> project (lower scope wins)"
|
|
65
|
+
- "Merge strategies are configurable per key in .rosett-ai/config.yml under
|
|
66
|
+
a merge_strategies key"
|
|
67
|
+
- "Supported merge strategies: deep_merge (default for hashes), replace
|
|
68
|
+
(default for scalars), array_union (combine + deduplicate), first_found
|
|
69
|
+
(first non-nil from most-specific scope)"
|
|
70
|
+
- "Default merge strategy when unconfigured: replace for scalar values,
|
|
71
|
+
deep_merge for hash values, array_union for array values"
|
|
72
|
+
- "When no .rosett-ai/ marker is found in the directory tree, only the global
|
|
73
|
+
scope is active — this is not an error"
|
|
74
|
+
- "When no global config exists (~/.config/rosett-ai/ absent), commands work
|
|
75
|
+
with whatever scopes are available — global is not required"
|
|
76
|
+
- "At most one local scope and one project scope can be active at any time.
|
|
77
|
+
Nested workspaces (a .rosett-ai/ marker whose parent also has a .rosett-ai/ marker
|
|
78
|
+
with children) are resolved by nearest-wins: the deepest workspace-level
|
|
79
|
+
marker is selected as local, and any higher markers are ignored"
|
|
80
|
+
- "CLI flags --global, --local, --project select a scope level. These
|
|
81
|
+
flags are mutually exclusive — specifying more than one is an error
|
|
82
|
+
(exit 2). Each level includes all scopes above it: --global uses only
|
|
83
|
+
global sources; --local merges global+local; --project merges
|
|
84
|
+
global+local+project. Output is written to the selected level's output
|
|
85
|
+
directory. Without flags, scope is auto-detected from working directory"
|
|
86
|
+
- "Scope detection must not traverse above the filesystem root or into
|
|
87
|
+
unreadable directories"
|
|
88
|
+
- "All YAML files in scope source directories are parsed with YAML.safe_load
|
|
89
|
+
(per security.yml constraints)"
|
|
90
|
+
- "Scope resolution result must be deterministic for a given directory tree"
|
|
91
|
+
- "Each engine declares per-scope output directories in its target profile.
|
|
92
|
+
Global output uses an absolute path (e.g. ~/.claude/rules/). Local and
|
|
93
|
+
project outputs use a relative path (e.g. .claude/rules/) resolved against
|
|
94
|
+
the scope directory by the compiler"
|
|
95
|
+
- "Scope-related errors use the what/why/fix format from error_handling.yml"
|
|
96
|
+
#
|
|
97
|
+
acceptance_criteria:
|
|
98
|
+
- "ScopeResolver.resolve(working_dir) returns a ScopeResult with global,
|
|
99
|
+
local (optional), and project (optional) source directories"
|
|
100
|
+
- "When invoked from a project directory, all active scopes are discovered
|
|
101
|
+
and merged in order global -> local (if present) -> project"
|
|
102
|
+
- "When invoked from a directory with no .rosett-ai/ marker above it, only
|
|
103
|
+
the global scope is active and returned"
|
|
104
|
+
- "deep_merge strategy recursively merges hashes from all active scopes,
|
|
105
|
+
with lower (more-specific) scope keys winning on conflict"
|
|
106
|
+
- "replace strategy uses the value from the most-specific active scope,
|
|
107
|
+
ignoring all higher scopes"
|
|
108
|
+
- "array_union strategy combines arrays from all active scopes and
|
|
109
|
+
deduplicates entries, preserving order (most-specific scope first)"
|
|
110
|
+
- "first_found strategy returns the first non-nil value scanning from
|
|
111
|
+
project -> local -> global"
|
|
112
|
+
- "bin/raictl compile --global compiles only global-scope sources to
|
|
113
|
+
global output directories"
|
|
114
|
+
- "bin/raictl compile --local compiles merged global+local sources to
|
|
115
|
+
local output directories"
|
|
116
|
+
- "bin/raictl compile --project compiles merged global+local+project
|
|
117
|
+
sources to project output directories"
|
|
118
|
+
- "bin/raictl compile (no flag) auto-detects scope from working directory
|
|
119
|
+
and compiles to the appropriate output location"
|
|
120
|
+
- "bin/raictl compile --simulate --verbose shows scope-resolved source
|
|
121
|
+
directories and target output paths before showing diffs"
|
|
122
|
+
- "bin/raictl validate operates on sources from the auto-detected scope"
|
|
123
|
+
- "Merge strategy configuration in .rosett-ai/config.yml is validated against
|
|
124
|
+
scope_hierarchy_schema.json"
|
|
125
|
+
- "Scope detection terminates at filesystem root without error"
|
|
126
|
+
- "Exit code 0 on success, 2 on scope configuration error, 3 on missing
|
|
127
|
+
required scope (when --local or --project is used but no marker found)"
|
|
128
|
+
#
|
|
129
|
+
examples:
|
|
130
|
+
- scenario: "User runs bin/raictl compile from ~/projects/acme-api/"
|
|
131
|
+
expected: |
|
|
132
|
+
ScopeResolver finds:
|
|
133
|
+
project: ~/projects/acme-api/.rosett-ai/conf/
|
|
134
|
+
local: ~/projects/.rosett-ai/conf/ (if ~/projects/.rosett-ai/ exists and has children with .rosett-ai/)
|
|
135
|
+
global: ~/.config/rosett-ai/conf/
|
|
136
|
+
Merges global -> local -> project. Compiles to project-scope output
|
|
137
|
+
directories (e.g. ~/projects/acme-api/.claude/rules/ for Claude engine).
|
|
138
|
+
not: "Compiles from rosett-ai's own conf/ directory. Ignores working directory."
|
|
139
|
+
- scenario: "User runs bin/raictl compile --global"
|
|
140
|
+
expected: |
|
|
141
|
+
Only global scope sources (~/.config/rosett-ai/conf/) are compiled.
|
|
142
|
+
Output goes to global output directories (e.g. ~/.claude/rules/).
|
|
143
|
+
Local and project scopes are ignored even if .rosett-ai/ markers exist
|
|
144
|
+
in the current directory tree.
|
|
145
|
+
not: "All scopes are merged. Project-specific rules appear in global output."
|
|
146
|
+
- scenario: "User runs bin/raictl compile from /tmp (no .rosett-ai/ anywhere)"
|
|
147
|
+
expected: |
|
|
148
|
+
Only global scope is active. Compiles global sources to global output.
|
|
149
|
+
No warning about missing local/project scopes (this is normal).
|
|
150
|
+
not: "Error: no .rosett-ai/ found. Compilation refuses to run."
|
|
151
|
+
- scenario: "Two behaviours define the same key with different merge strategies"
|
|
152
|
+
expected: |
|
|
153
|
+
.rosett-ai/config.yml specifies:
|
|
154
|
+
merge_strategies:
|
|
155
|
+
editor_settings: deep_merge
|
|
156
|
+
allowed_tools: array_union
|
|
157
|
+
Global defines editor_settings: { theme: dark }.
|
|
158
|
+
Project defines editor_settings: { font_size: 14 }.
|
|
159
|
+
Merged result: { theme: dark, font_size: 14 }.
|
|
160
|
+
not: "Project replaces entire editor_settings hash."
|
|
161
|
+
- scenario: "User runs bin/raictl compile --project but no .rosett-ai/ exists"
|
|
162
|
+
expected: |
|
|
163
|
+
Error (exit 3): 'No project scope found: no .rosett-ai/ marker in directory
|
|
164
|
+
tree from /current/dir. Run `rai init --project` to create one, or
|
|
165
|
+
omit --project to use auto-detection.'
|
|
166
|
+
not: "Silent fallback to global scope. Compiles without indicating scope mismatch."
|
|
167
|
+
- scenario: "Local scope has a .rosett-ai/config.yml with merge_strategies"
|
|
168
|
+
expected: |
|
|
169
|
+
Merge strategies from local config apply to the local+project merge.
|
|
170
|
+
Global config may also declare merge_strategies; the most-specific
|
|
171
|
+
merge_strategies configuration wins (project > local > global).
|
|
172
|
+
not: "Only project-level merge_strategies are respected."
|
|
173
|
+
- scenario: "Engine declares per-scope output directories"
|
|
174
|
+
expected: |
|
|
175
|
+
Claude engine target profile contains:
|
|
176
|
+
output_dirs:
|
|
177
|
+
global: ~/.claude/rules/
|
|
178
|
+
scoped: .claude/rules/
|
|
179
|
+
Global output uses the absolute path. For local and project scopes,
|
|
180
|
+
the compiler resolves the relative path against the scope directory:
|
|
181
|
+
local: ~/projects/.claude/rules/
|
|
182
|
+
project: ~/projects/acme-api/.claude/rules/
|
|
183
|
+
not: "All output goes to ~/.claude/rules/ regardless of scope."
|
|
184
|
+
- scenario: "User runs bin/raictl validate from a project directory"
|
|
185
|
+
expected: |
|
|
186
|
+
Validates sources from all active scopes (global, local, project).
|
|
187
|
+
Reports validation results grouped by scope:
|
|
188
|
+
[global] conf/behaviour/security.yml: valid
|
|
189
|
+
[project] conf/behaviour/api_rules.yml: 2 errors
|
|
190
|
+
not: "Only validates rosett-ai's own conf/ directory."
|
|
191
|
+
#
|
|
192
|
+
anti_patterns:
|
|
193
|
+
- "Hardcoding source or output directories instead of resolving from scope"
|
|
194
|
+
- "Assuming a single fixed source directory for all commands"
|
|
195
|
+
- "Merging scopes in wrong order (project before global)"
|
|
196
|
+
- "Treating missing scopes as errors (only --local/--project flags require presence)"
|
|
197
|
+
- "Scope detection that follows symlinks across filesystem boundaries"
|
|
198
|
+
- "Merge strategies that silently drop data without user visibility"
|
|
199
|
+
- "Scope resolution that depends on environment variables other than
|
|
200
|
+
RAI_ORIGINAL_PWD and XDG_CONFIG_HOME"
|
|
201
|
+
- "Caching scope resolution results across commands (directory tree can change)"
|
|
202
|
+
#
|
|
203
|
+
gui_notes: |
|
|
204
|
+
Document interactions (cross-references):
|
|
205
|
+
|
|
206
|
+
1. architecture.yml: scope hierarchy is an architectural principle.
|
|
207
|
+
Architecture declares scope-first as a constraint; this document
|
|
208
|
+
defines the full specification.
|
|
209
|
+
|
|
210
|
+
2. compiler.yml: compilation is scope-aware. Compiler resolves source
|
|
211
|
+
directories from the active scope before operating.
|
|
212
|
+
|
|
213
|
+
3. behaviour_composition.yml: composition uses the scope hierarchy for
|
|
214
|
+
layering behaviours. This document defines the scope model; composition
|
|
215
|
+
defines the merge and priority rules within that model.
|
|
216
|
+
|
|
217
|
+
4. engine_architecture.yml: engines declare per-scope output directories
|
|
218
|
+
in their target profiles. This document defines the scope levels;
|
|
219
|
+
engines map each level to tool-native paths.
|
|
220
|
+
|
|
221
|
+
5. project_management.yml: project lifecycle commands are scope-aware.
|
|
222
|
+
raictl init creates scope markers; rai project status reports scope.
|
|
223
|
+
|
|
224
|
+
6. security.yml: all YAML parsing in scope directories uses YAML.safe_load.
|
|
225
|
+
Path traversal in scope detection must be validated.
|
|
226
|
+
|
|
227
|
+
7. error_handling.yml: scope errors (missing marker, invalid config)
|
|
228
|
+
follow the what/why/fix format with dedicated exit codes.
|
|
229
|
+
|
|
230
|
+
Scope detection algorithm (pseudocode):
|
|
231
|
+
|
|
232
|
+
def resolve(start_dir):
|
|
233
|
+
global = XDG_CONFIG_HOME/rosett-ai/conf/ or ~/.config/rosett-ai/conf/
|
|
234
|
+
current = start_dir
|
|
235
|
+
markers = []
|
|
236
|
+
|
|
237
|
+
# Phase 1: collect all .rosett-ai/ markers from root to start_dir
|
|
238
|
+
while current != '/':
|
|
239
|
+
if current/.rosett-ai exists:
|
|
240
|
+
markers.prepend(current)
|
|
241
|
+
current = parent(current)
|
|
242
|
+
|
|
243
|
+
if markers.empty:
|
|
244
|
+
return ScopeResult(global: global, local: nil, project: nil)
|
|
245
|
+
|
|
246
|
+
# Phase 2: nearest marker (deepest) is the project candidate
|
|
247
|
+
project_candidate = markers.last
|
|
248
|
+
|
|
249
|
+
# Phase 3: scan remaining markers upward for a local (workspace) scope
|
|
250
|
+
# A marker is local if it has child directories that also contain
|
|
251
|
+
# .rosett-ai/ markers (i.e. it groups multiple projects)
|
|
252
|
+
local_candidate = nil
|
|
253
|
+
markers[0..-2].reverse_each do |dir|
|
|
254
|
+
if dir has child directories containing .rosett-ai/ markers:
|
|
255
|
+
local_candidate = dir
|
|
256
|
+
break
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
if local_candidate:
|
|
261
|
+
return ScopeResult(
|
|
262
|
+
global: global,
|
|
263
|
+
local: local_candidate/.rosett-ai/conf/,
|
|
264
|
+
project: project_candidate/.rosett-ai/conf/
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Single marker — check if it is local (workspace) or project (leaf)
|
|
268
|
+
if project_candidate has child directories containing .rosett-ai/ markers:
|
|
269
|
+
# User is at workspace level, not inside a child project
|
|
270
|
+
return ScopeResult(
|
|
271
|
+
global: global,
|
|
272
|
+
local: project_candidate/.rosett-ai/conf/,
|
|
273
|
+
project: nil
|
|
274
|
+
)
|
|
275
|
+
else:
|
|
276
|
+
return ScopeResult(
|
|
277
|
+
global: global,
|
|
278
|
+
local: nil,
|
|
279
|
+
project: project_candidate/.rosett-ai/conf/
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
Directory layout example:
|
|
283
|
+
|
|
284
|
+
~/.config/rosett-ai/ # Global scope
|
|
285
|
+
└── conf/
|
|
286
|
+
└── behaviour/
|
|
287
|
+
└── security.yml # User-wide security defaults
|
|
288
|
+
|
|
289
|
+
~/projects/ # Local scope (workspace)
|
|
290
|
+
├── .rosett-ai/
|
|
291
|
+
│ ├── config.yml # merge_strategies, workspace settings
|
|
292
|
+
│ └── conf/
|
|
293
|
+
│ └── behaviour/
|
|
294
|
+
│ └── team_style.yml # Shared across projects in workspace
|
|
295
|
+
├── acme-api/ # Project scope
|
|
296
|
+
│ ├── .rosett-ai/
|
|
297
|
+
│ │ ├── config.yml # project_name, default_engine
|
|
298
|
+
│ │ └── conf/
|
|
299
|
+
│ │ └── behaviour/
|
|
300
|
+
│ │ └── api_rules.yml # Project-specific rules
|
|
301
|
+
│ └── src/
|
|
302
|
+
└── acme-web/ # Another project in same workspace
|
|
303
|
+
├── .rosett-ai/
|
|
304
|
+
│ └── conf/
|
|
305
|
+
│ └── behaviour/
|
|
306
|
+
│ └── web_rules.yml
|
|
307
|
+
└── src/
|
|
308
|
+
#
|
|
309
|
+
preferences:
|
|
310
|
+
language: ruby
|
|
311
|
+
patterns:
|
|
312
|
+
- "ScopeResolver with upward directory traversal"
|
|
313
|
+
- "ScopeResult value object (global, local, project)"
|
|
314
|
+
- "Strategy pattern for merge strategies"
|
|
315
|
+
- "XDG Base Directory compliance"
|
|
316
|
+
- "Marker-based scope detection (.rosett-ai/)"
|
|
317
|
+
- "Hiera-like configurable merge"
|
|
318
|
+
testing: rspec with directory tree fixtures, scope detection edge cases
|
|
319
|
+
(no markers, nested markers, symlinks), merge strategy property tests,
|
|
320
|
+
CLI flag override tests, and scope-aware compilation integration tests
|
|
321
|
+
gems:
|
|
322
|
+
- json_schemer
|
|
323
|
+
- thor
|
|
324
|
+
|
|
325
|
+
implementation_notes: |
|
|
326
|
+
v1.2.0 implementation diverged from the original 3-level design:
|
|
327
|
+
|
|
328
|
+
1. ScopeResolver uses a 4-level model: global, organisation, project, local.
|
|
329
|
+
The "organisation" level was added to support multi-org workspaces.
|
|
330
|
+
SCOPE_ORDER = ['global', 'organisation', 'project', 'local'].
|
|
331
|
+
|
|
332
|
+
2. ScopeResolver.resolve() returns a scope name string
|
|
333
|
+
('global'/'organisation'/'project'/'local') for a given file path,
|
|
334
|
+
not a ScopeResult value object. The ScopeResult contract from the
|
|
335
|
+
design is not yet implemented.
|
|
336
|
+
|
|
337
|
+
3. Workspace (local) detection via child-marker walking is not yet
|
|
338
|
+
implemented. ProjectContext.detect_project_root() walks upward
|
|
339
|
+
looking for .rosett-ai/ but treats all markers as "project".
|
|
340
|
+
|
|
341
|
+
4. Merge strategies: first_wins (default), deep_merge, array_union
|
|
342
|
+
are implemented. "replace" and "first_found" from design are not.
|
|
343
|
+
Per-key merge strategy configuration from .rosett-ai/config.yml
|
|
344
|
+
is not yet implemented.
|
|
345
|
+
|
|
346
|
+
5. CompilationPipeline accepts scope: :global or :project (no :local).
|
|
347
|
+
CLI flags --global/--local/--project not yet integrated.
|
|
348
|
+
|
|
349
|
+
6. Per-scope output_dirs not in TargetProfile — uses single output_dir.
|
|
350
|
+
|
|
351
|
+
These are known gaps. The 4-level model is the intentional direction;
|
|
352
|
+
the design doc's 3-level model should be updated to match.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security
|
|
3
|
+
domain: security
|
|
4
|
+
version: 1.2.0
|
|
5
|
+
status: implemented
|
|
6
|
+
priority: 1
|
|
7
|
+
author: hugo
|
|
8
|
+
created_at: "2026-02-18"
|
|
9
|
+
modified_at: "2026-03-17"
|
|
10
|
+
modified_by: claude
|
|
11
|
+
depends_on: []
|
|
12
|
+
#
|
|
13
|
+
intent: |
|
|
14
|
+
Establish security as the foundation layer of Rosett-AI. Every line of code written
|
|
15
|
+
after this document is adopted must follow these constraints. Retrofitting
|
|
16
|
+
security is 10x more expensive than building it in. This document defines hard
|
|
17
|
+
rules, required tooling, and safe coding patterns that apply to ALL code in
|
|
18
|
+
the project — core, TUI, GUI, compilers, and tests.
|
|
19
|
+
#
|
|
20
|
+
constraints:
|
|
21
|
+
- Never use YAML.load — always YAML.safe_load with explicit permitted_classes
|
|
22
|
+
- Never interpolate user input into system() calls — use array form exclusively
|
|
23
|
+
- Never write files outside whitelisted directories (~/.claude/, project .claude/, ~/.config/rosett-ai/)
|
|
24
|
+
- All file writes must set restrictive permissions (0644 for files, 0755 for directories)
|
|
25
|
+
- Secrets files must use 0600 permissions
|
|
26
|
+
- Never log, display, or include in error messages any secrets, API keys, or tokens
|
|
27
|
+
- All external input (YAML, JSON, CLI arguments, environment variables) must be validated before use
|
|
28
|
+
- Tempfiles must use Tempfile.new with restrictive permissions and must be cleaned up in ensure blocks
|
|
29
|
+
- No information conveyed by colour alone (accessibility and security overlap)
|
|
30
|
+
- Destructive operations require explicit user confirmation before execution
|
|
31
|
+
- All dependencies must be audited for known CVEs before release
|
|
32
|
+
- No eval, instance_eval, or class_eval on user-supplied input
|
|
33
|
+
- File paths must be validated with File.expand_path and checked against whitelists
|
|
34
|
+
- YAML input must be bounded — max file size (1 MB), max nesting depth (10), max key count (1000)
|
|
35
|
+
- All user-authored content must be stripped of ANSI escape sequences and control characters before display in TUI/GUI
|
|
36
|
+
- Identifiers and filenames from external input must be NFC-normalized (Unicode) at input boundaries
|
|
37
|
+
- Secrets resolution order is ENV variable > system keyring (libsecret/kwallet) > secrets file (0600) — never write secrets to disk by default
|
|
38
|
+
#
|
|
39
|
+
acceptance_criteria:
|
|
40
|
+
- bundler-audit runs in CI and blocks merge on any known CVE
|
|
41
|
+
- ruby_audit runs in CI and blocks merge on Ruby stdlib vulnerabilities
|
|
42
|
+
- RuboCop security cops are enabled and enforced (no violations allowed)
|
|
43
|
+
- No instance of YAML.load exists in codebase (only YAML.safe_load)
|
|
44
|
+
- No string-interpolated system() calls exist in codebase
|
|
45
|
+
- All file write operations use explicit permission setting
|
|
46
|
+
- CI pipeline rejects code that violates any security constraint
|
|
47
|
+
- Custom RuboCop cop flags unsafe patterns (YAML.load, interpolated system calls)
|
|
48
|
+
- YAML files exceeding 1 MB, 10 levels nesting, or 1000 keys are rejected with clear error
|
|
49
|
+
- TUI output containing ANSI escape sequences from YAML content is sanitized before rendering
|
|
50
|
+
- Filenames and identifiers are NFC-normalized (verified by test with NFD input producing NFC output)
|
|
51
|
+
- Secrets are never written to disk unless user explicitly configures a secrets file
|
|
52
|
+
#
|
|
53
|
+
examples:
|
|
54
|
+
- scenario: "Code reads a user-provided YAML config file"
|
|
55
|
+
expected: "Uses YAML.safe_load(content, permitted_classes: [Date, Time]) with explicit class allowlist"
|
|
56
|
+
not: "Uses YAML.load(content) which allows arbitrary object instantiation"
|
|
57
|
+
- scenario: "Code executes a git command with a user-provided branch name"
|
|
58
|
+
expected: "system('git', 'checkout', '--', branch_name) using array form"
|
|
59
|
+
not: "system(\"git checkout #{branch_name}\") which allows shell injection"
|
|
60
|
+
- scenario: "Code writes a compiled behaviour file to disk"
|
|
61
|
+
expected: "Validates output path is within ~/.claude/rules/, writes with File.open(path, 'w', 0644)"
|
|
62
|
+
not: "Writes to arbitrary path without validation or permission setting"
|
|
63
|
+
- scenario: "An API key is needed for the adopt command"
|
|
64
|
+
expected: "Resolved via ENV['ANTHROPIC_API_KEY'] > system keyring > secrets file (0600). Never displayed in output."
|
|
65
|
+
not: "Hardcoded in source, logged in verbose mode, written to disk unprompted, or stored in world-readable config"
|
|
66
|
+
- scenario: "bundler-audit finds a CVE in a dependency"
|
|
67
|
+
expected: "CI pipeline fails, merge is blocked, developer must update or justify exception"
|
|
68
|
+
not: "Warning is ignored, code merges with known vulnerability"
|
|
69
|
+
- scenario: "A behaviour YAML file contains ANSI escape codes in a rule description"
|
|
70
|
+
expected: |
|
|
71
|
+
Control characters and escape sequences are stripped before TUI rendering.
|
|
72
|
+
'Rule description: clean text here' is displayed. Log warning in development mode.
|
|
73
|
+
not: "Terminal is cleared, title bar is changed, or garbled output is shown."
|
|
74
|
+
- scenario: "A 50 MB YAML file is provided as a behaviour config"
|
|
75
|
+
expected: "Rejected before parsing: 'File exceeds maximum size (1 MB): 50.0 MB'. No memory exhaustion."
|
|
76
|
+
not: "Parser attempts to load 50 MB into memory. Application hangs or crashes."
|
|
77
|
+
- scenario: "A filename contains Unicode NFD characters (e.g. e + combining acute)"
|
|
78
|
+
expected: "Filename is NFC-normalized at input boundary. Stored and compared as single precomposed character."
|
|
79
|
+
not: "Two visually identical filenames coexist. String comparisons fail silently."
|
|
80
|
+
- scenario: "User runs bin/raictl adopt and needs an API key"
|
|
81
|
+
expected: |
|
|
82
|
+
Checks ENV['ANTHROPIC_API_KEY'] first. If absent, checks system keyring.
|
|
83
|
+
If absent, checks ~/.config/rosett-ai/secrets.yml (0600). If no key found,
|
|
84
|
+
prompts user with instructions to set ENV variable.
|
|
85
|
+
not: "Prompts user to create a plaintext secrets file. Writes API key to disk unprompted."
|
|
86
|
+
#
|
|
87
|
+
anti_patterns:
|
|
88
|
+
- Using YAML.load for any reason (even when input seems trusted)
|
|
89
|
+
- String interpolation in shell commands (system, backticks, %x)
|
|
90
|
+
- Writing files without explicit permission bits
|
|
91
|
+
- Storing secrets in version-controlled files
|
|
92
|
+
- Silencing or skipping security audit failures in CI
|
|
93
|
+
- Using eval/instance_eval/class_eval on dynamic input
|
|
94
|
+
- Catching and swallowing exceptions without logging (hides security events)
|
|
95
|
+
- Trusting file paths from CLI arguments without canonicalization
|
|
96
|
+
- Rendering user-authored YAML content in TUI without stripping control characters
|
|
97
|
+
- Parsing unbounded YAML input without size or depth limits
|
|
98
|
+
- Writing secrets to disk as the default or first-choice storage method
|
|
99
|
+
- Comparing filenames or identifiers without Unicode normalization
|
|
100
|
+
#
|
|
101
|
+
preferences:
|
|
102
|
+
language: ruby
|
|
103
|
+
gems:
|
|
104
|
+
- bundler-audit
|
|
105
|
+
- ruby_audit
|
|
106
|
+
- rubocop
|
|
107
|
+
- rubocop-performance
|
|
108
|
+
- rubocop-rspec
|
|
109
|
+
- reek
|
|
110
|
+
- flay
|
|
111
|
+
patterns:
|
|
112
|
+
- input_validation_at_boundaries
|
|
113
|
+
- fail_fast_on_invalid_input
|
|
114
|
+
- principle_of_least_privilege
|
|
115
|
+
testing: rspec with security-focused fixtures
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: session_retrospective
|
|
3
|
+
domain: operations
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
status: draft
|
|
6
|
+
priority: 6
|
|
7
|
+
author: claude
|
|
8
|
+
created_at: '2026-03-24'
|
|
9
|
+
modified_at: '2026-03-24'
|
|
10
|
+
modified_by: claude
|
|
11
|
+
depends_on:
|
|
12
|
+
- testing
|
|
13
|
+
- ci_pipeline
|
|
14
|
+
|
|
15
|
+
intent: |
|
|
16
|
+
Define a repeatable methodology for AI session self-evaluation within the Rosett-AI
|
|
17
|
+
ecosystem. When Claude Code completes a multi-session campaign (coverage push,
|
|
18
|
+
feature branch, refactoring), it must produce a structured retrospective that
|
|
19
|
+
identifies what went well, what went poorly, and what concrete process changes
|
|
20
|
+
would prevent the same failures from recurring.
|
|
21
|
+
|
|
22
|
+
This document exists because the coverage push campaign (2026-03-20 through
|
|
23
|
+
2026-03-24) demonstrated that unchecked agent delegation, insufficient API
|
|
24
|
+
verification, and poor resource management can waste significant human and
|
|
25
|
+
compute time. The retrospective methodology captures these lessons in a
|
|
26
|
+
machine-readable format that persists across sessions.
|
|
27
|
+
|
|
28
|
+
constraints:
|
|
29
|
+
- Retrospectives must be honest assessments, never self-congratulatory
|
|
30
|
+
- Each failure identified must include a root cause (not just a symptom)
|
|
31
|
+
- Retrospectives must result in actionable process changes, not vague intentions
|
|
32
|
+
- The retrospective format must be machine-parseable (YAML or structured markdown)
|
|
33
|
+
- Retrospectives must not require user prompting to be triggered at session boundaries
|
|
34
|
+
- Agent-introduced failures count against the orchestrator, not the agent
|
|
35
|
+
|
|
36
|
+
acceptance_criteria:
|
|
37
|
+
- A /retrospective skill exists that Claude Code can invoke at session end
|
|
38
|
+
- The skill produces a structured assessment covering successes, failures, and process changes
|
|
39
|
+
- Each failure includes root cause analysis and a specific preventive action
|
|
40
|
+
- The retrospective is written to persistent storage (auto memory or project docs)
|
|
41
|
+
- The methodology is documented in a behaviour file with enforceable rules
|
|
42
|
+
|
|
43
|
+
examples:
|
|
44
|
+
- scenario: Claude Code completes a coverage push across 3 sessions
|
|
45
|
+
expected: >-
|
|
46
|
+
Before closing the final session, Claude invokes /retrospective and produces
|
|
47
|
+
a structured assessment. The assessment identifies that 27 agent-introduced
|
|
48
|
+
test failures were caused by agents writing specs against imagined APIs,
|
|
49
|
+
and proposes a process change: always read the implementation before writing
|
|
50
|
+
tests.
|
|
51
|
+
not: >-
|
|
52
|
+
Claude says 'the session went well' without identifying specific failures
|
|
53
|
+
or their root causes.
|
|
54
|
+
|
|
55
|
+
- scenario: A session hits the context window limit mid-task
|
|
56
|
+
expected: >-
|
|
57
|
+
The retrospective notes the context exhaustion, identifies what consumed
|
|
58
|
+
the context (e.g. reading too many files in the main window instead of
|
|
59
|
+
delegating to agents), and proposes a mitigation (e.g. use Explore agents
|
|
60
|
+
for initial research, keep main window for orchestration).
|
|
61
|
+
not: >-
|
|
62
|
+
The retrospective blames context limits as an external constraint without
|
|
63
|
+
analysing whether the session's approach was context-efficient.
|
|
64
|
+
|
|
65
|
+
- scenario: Rate limits are hit due to over-parallelisation
|
|
66
|
+
expected: >-
|
|
67
|
+
The retrospective identifies the specific parallel operation pattern that
|
|
68
|
+
triggered rate limits, estimates the wasted time, and proposes a concurrency
|
|
69
|
+
cap or sequential fallback strategy.
|
|
70
|
+
not: >-
|
|
71
|
+
The retrospective omits the rate limit incident or treats it as unavoidable.
|
|
72
|
+
|
|
73
|
+
anti_patterns:
|
|
74
|
+
- Retrospectives that only list successes ('coverage went from X to Y')
|
|
75
|
+
- Root causes that blame external systems ('the API was slow')
|
|
76
|
+
- Process changes that are too vague to verify ('be more careful next time')
|
|
77
|
+
- Skipping the retrospective because the session 'went well'
|
|
78
|
+
- Writing the retrospective to ephemeral scratch space
|
|
79
|
+
|
|
80
|
+
preferences:
|
|
81
|
+
language: ruby
|
|
82
|
+
patterns:
|
|
83
|
+
- structured_logging
|
|
84
|
+
- yaml_first_configuration
|
|
85
|
+
testing: rspec with schema validation
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: smart_ui_feedback
|
|
3
|
+
domain: ui
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
status: implemented
|
|
6
|
+
priority: 3
|
|
7
|
+
author: hugo
|
|
8
|
+
created_at: "2026-03-15"
|
|
9
|
+
modified_at: "2026-03-16"
|
|
10
|
+
modified_by: claude
|
|
11
|
+
depends_on:
|
|
12
|
+
- ui_framework
|
|
13
|
+
- architecture
|
|
14
|
+
- autocompletion
|
|
15
|
+
- error_handling
|
|
16
|
+
#
|
|
17
|
+
intent: >-
|
|
18
|
+
Transform generic Thor error messages into actionable suggestions using
|
|
19
|
+
edit distance (Levenshtein) matching. Provide "Did you mean?" feedback
|
|
20
|
+
for mistyped commands, subcommands, flags, and arguments — reducing
|
|
21
|
+
frustration, accelerating learning, and making the CLI feel responsive
|
|
22
|
+
and helpful across rosett-ai's 17+ subcommands and dozens of flags.
|
|
23
|
+
#
|
|
24
|
+
constraints:
|
|
25
|
+
- "Suggestions must use edit distance (Levenshtein), not substring matching"
|
|
26
|
+
- "Maximum 3 suggestions per error — more is noise"
|
|
27
|
+
- "Suggestion threshold: edit distance <= 2 for commands, <= 3 for flags"
|
|
28
|
+
- "Must not add measurable latency to valid command execution"
|
|
29
|
+
- "Must work for commands, subcommands, flags, and named arguments"
|
|
30
|
+
- "Suggestions must respect the current command context (not global)"
|
|
31
|
+
- "Must integrate with Thor's error handling, not replace it"
|
|
32
|
+
- "This design governs CLI typo suggestions only. Shell-level tab
|
|
33
|
+
completion is governed by autocompletion.yml"
|
|
34
|
+
#
|
|
35
|
+
acceptance_criteria:
|
|
36
|
+
- "`raictl complie` suggests `compile`"
|
|
37
|
+
- "`rai behaviour shw` suggests `show`"
|
|
38
|
+
- "`rai compile --verboes` suggests `--verbose`"
|
|
39
|
+
- "`raictl build package --varient` suggests `--variant`"
|
|
40
|
+
- "No suggestions shown when edit distance > threshold"
|
|
41
|
+
- "Valid commands execute without any suggestion overhead"
|
|
42
|
+
- "Suggestions are formatted consistently: 'Did you mean `X`?'"
|
|
43
|
+
- "Exit code 1 for unknown command with suggestion, 1 for unknown
|
|
44
|
+
command without suggestion (same exit code, different message)"
|
|
45
|
+
#
|
|
46
|
+
examples:
|
|
47
|
+
- scenario: "User types `raictl complie` (transposed letters)"
|
|
48
|
+
expected: |
|
|
49
|
+
Error: Unknown command 'complie'. Did you mean `compile`?
|
|
50
|
+
not: "Error: Could not find command 'complie'."
|
|
51
|
+
- scenario: "User types `raictl xyz` (no close match)"
|
|
52
|
+
expected: |
|
|
53
|
+
Error: Unknown command 'xyz'. Run `raictl help` for available commands.
|
|
54
|
+
not: "A list of all 17+ commands as suggestions"
|
|
55
|
+
- scenario: "User types `raictl build package --clean --verboes`"
|
|
56
|
+
expected: |
|
|
57
|
+
Error: Unknown option '--verboes'. Did you mean `--verbose`?
|
|
58
|
+
not: "Generic Thor error with no suggestion."
|
|
59
|
+
#
|
|
60
|
+
anti_patterns:
|
|
61
|
+
- "Suggesting commands from unrelated subcommand contexts"
|
|
62
|
+
- "Using substring matching instead of edit distance"
|
|
63
|
+
- "Showing more than 3 suggestions"
|
|
64
|
+
- "Adding latency to the happy path (valid commands)"
|
|
65
|
+
- "Reimplementing Thor's command routing"
|
|
66
|
+
#
|
|
67
|
+
gui_notes: |
|
|
68
|
+
Document interactions (cross-references):
|
|
69
|
+
|
|
70
|
+
1. autocompletion.yml: tab completion prevents typos proactively;
|
|
71
|
+
smart_ui_feedback handles typos reactively. Both improve CLI UX
|
|
72
|
+
but operate at different points in the interaction.
|
|
73
|
+
|
|
74
|
+
2. error_handling.yml: suggestions augment structured error messages.
|
|
75
|
+
The "Did you mean?" output follows the error hierarchy format.
|
|
76
|
+
|
|
77
|
+
3. ui_framework.yml: smart feedback is a CLI-layer feature, not a
|
|
78
|
+
TUI widget. TUI input fields may have their own completion logic.
|
|
79
|
+
#
|
|
80
|
+
preferences:
|
|
81
|
+
language: ruby
|
|
82
|
+
patterns:
|
|
83
|
+
- "Levenshtein distance for fuzzy matching"
|
|
84
|
+
- "Thor error handler middleware"
|
|
85
|
+
- "Cached command registry for zero-latency lookup"
|
|
86
|
+
testing: rspec with typo fixtures, threshold boundary tests, and
|
|
87
|
+
context-aware suggestion scenarios
|
|
88
|
+
gems:
|
|
89
|
+
- thor
|