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,1288 @@
|
|
|
1
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
2
|
+
% NeatNerds Code Companion -- Technical Reference
|
|
3
|
+
% Comprehensive reference for all design documents, architectural decisions,
|
|
4
|
+
% schemas, and configuration settings.
|
|
5
|
+
%
|
|
6
|
+
% Owner: Hugo Antonio Sepulveda Manriquez (hugo@neatnerds.be)
|
|
7
|
+
%
|
|
8
|
+
% Based on the template: Clustering the Interstellar Medium
|
|
9
|
+
% https://www.overleaf.com/articles/clustering-the-interstellar-medium/mtthgyyfrdkn
|
|
10
|
+
% Licensed under the LaTeX Project Public License 1.3c
|
|
11
|
+
%
|
|
12
|
+
% Chapter heading images should have a 2:1 width:height ratio.
|
|
13
|
+
%
|
|
14
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
15
|
+
|
|
16
|
+
%------------------------------------------------------------------------------
|
|
17
|
+
% PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
|
|
18
|
+
%------------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
\documentclass[11pt,fleqn]{book}
|
|
21
|
+
|
|
22
|
+
\usepackage[top=3cm,bottom=3cm,left=3cm,right=3cm,headsep=10pt,a4paper]{geometry}
|
|
23
|
+
|
|
24
|
+
\usepackage{xcolor}
|
|
25
|
+
\definecolor{ocre}{RGB}{52,177,201}
|
|
26
|
+
|
|
27
|
+
% Font Settings
|
|
28
|
+
\usepackage{avant}
|
|
29
|
+
\usepackage{mathptmx}
|
|
30
|
+
|
|
31
|
+
\usepackage{microtype}
|
|
32
|
+
\usepackage[utf8]{inputenc}
|
|
33
|
+
\usepackage[T1]{fontenc}
|
|
34
|
+
|
|
35
|
+
% Bibliography
|
|
36
|
+
\usepackage[style=alphabetic,sorting=nyt,sortcites=true,autopunct=true,
|
|
37
|
+
autolang=hyphen,hyperref=true,abbreviate=false,backref=true,backend=biber]{
|
|
38
|
+
biblatex}
|
|
39
|
+
\addbibresource{bibliography.bib}
|
|
40
|
+
\defbibheading{bibempty}{}
|
|
41
|
+
|
|
42
|
+
\input{structure}
|
|
43
|
+
|
|
44
|
+
\begin{document}
|
|
45
|
+
|
|
46
|
+
%------------------------------------------------------------------------------
|
|
47
|
+
% TITLE PAGE
|
|
48
|
+
%------------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
\begingroup
|
|
51
|
+
\thispagestyle{empty}
|
|
52
|
+
\AddToShipoutPicture*{\put(0,0){\includegraphics[scale=1.25]{cover}}}
|
|
53
|
+
\centering
|
|
54
|
+
\vspace*{5cm}
|
|
55
|
+
\par\normalfont\fontsize{35}{35}\sffamily\selectfont
|
|
56
|
+
\textbf{\textcolor{white}{NeatNerds Code Companion}}\\[0.5cm]
|
|
57
|
+
{\LARGE \textcolor{white}{Technical Reference \& Design Specification}}\par
|
|
58
|
+
\vspace*{1.5cm}
|
|
59
|
+
{\Large \textcolor{white}{Version 1.0.0}}\par
|
|
60
|
+
\vspace*{0.5cm}
|
|
61
|
+
{\large \textcolor{white}{Hugo Antonio Sepulveda Manriquez}}\par
|
|
62
|
+
\endgroup
|
|
63
|
+
|
|
64
|
+
%------------------------------------------------------------------------------
|
|
65
|
+
% COPYRIGHT PAGE
|
|
66
|
+
%------------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
\newpage
|
|
69
|
+
~\vfill
|
|
70
|
+
\thispagestyle{empty}
|
|
71
|
+
|
|
72
|
+
\noindent \textsc{NeatNerds -- Antwerp, Belgium}\\
|
|
73
|
+
|
|
74
|
+
\noindent \textsc{https://gitlab.neatnerds.be/neatnerds/nncc}\\
|
|
75
|
+
|
|
76
|
+
\noindent Licensed under the GNU General Public License v3.0 only
|
|
77
|
+
(GPL-3.0-only).\\
|
|
78
|
+
This is free software: you are free to change and redistribute it under
|
|
79
|
+
the terms of the GPL-3.0-only license.\cite{gpl3}\\
|
|
80
|
+
|
|
81
|
+
\noindent \textit{First edition, February 2026}
|
|
82
|
+
|
|
83
|
+
%------------------------------------------------------------------------------
|
|
84
|
+
% TABLE OF CONTENTS
|
|
85
|
+
%------------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
\chapterimage{head1.jpg}
|
|
88
|
+
|
|
89
|
+
\pagestyle{empty}
|
|
90
|
+
|
|
91
|
+
\tableofcontents
|
|
92
|
+
|
|
93
|
+
\pagestyle{fancy}
|
|
94
|
+
|
|
95
|
+
\cleardoublepage
|
|
96
|
+
|
|
97
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
98
|
+
% CHAPTER 1: PROJECT OVERVIEW
|
|
99
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
100
|
+
|
|
101
|
+
\chapterimage{head2.jpg}
|
|
102
|
+
\chapter{Project Overview}\label{ch:overview}
|
|
103
|
+
|
|
104
|
+
\section{Introduction}\index{Introduction}
|
|
105
|
+
|
|
106
|
+
The \textbf{NeatNerds Code Companion} (\texttt{nncc}) is a Ruby-based
|
|
107
|
+
configuration management tool for AI-assisted development workflows. It provides a
|
|
108
|
+
structured, schema-validated approach to managing AI assistant configurations,
|
|
109
|
+
compiling them into target-specific output formats (Claude Code, Cursor, AGENTS.md,
|
|
110
|
+
and more), and enforcing security and quality standards throughout the
|
|
111
|
+
development lifecycle.
|
|
112
|
+
|
|
113
|
+
\begin{constraintbox}
|
|
114
|
+
\textbf{Core Principle:} Author once, compile to many. A single set of YAML
|
|
115
|
+
source files is compiled into configurations for Claude, Mistral, GPT-NeoX,
|
|
116
|
+
or any generic AI assistant target.
|
|
117
|
+
\end{constraintbox}
|
|
118
|
+
|
|
119
|
+
\section{Project Identity}\index{Project Identity}
|
|
120
|
+
|
|
121
|
+
\begin{longtable}{ll}
|
|
122
|
+
\toprule
|
|
123
|
+
\textbf{Field} & \textbf{Value} \\
|
|
124
|
+
\midrule
|
|
125
|
+
Project Name & nncc \\
|
|
126
|
+
Full Name & NeatNerds Code Companion \\
|
|
127
|
+
Author & Hugo Antonio Sepulveda Manriquez \\
|
|
128
|
+
Contact & hugo@neatnerds.be \\
|
|
129
|
+
License & GPL-3.0-only \\
|
|
130
|
+
Ruby Version & 3.3.10 (via rbenv) \\
|
|
131
|
+
Repository & gitlab.neatnerds.be/neatnerds/nncc \\
|
|
132
|
+
Version & 0.1.0 \\
|
|
133
|
+
\bottomrule
|
|
134
|
+
\end{longtable}
|
|
135
|
+
|
|
136
|
+
\section{Architecture at a Glance}\index{Architecture}
|
|
137
|
+
|
|
138
|
+
The system follows a layered architecture with clear extension points:
|
|
139
|
+
|
|
140
|
+
\begin{lstlisting}[language={},caption={Layer architecture}]
|
|
141
|
+
CLI Layer lib/nncc/thor/tasks/*.rb Thor subcommands
|
|
142
|
+
Library Layer lib/nncc/**/*.rb Domain logic
|
|
143
|
+
Config Layer conf/**/*.yml YAML configurations
|
|
144
|
+
Schema Layer conf/schemas/*.json JSON Schema validation
|
|
145
|
+
Compiler Layer lib/nncc/compiler/backends/ AI target backends
|
|
146
|
+
UI Layer lib/nncc/ui/ Pluggable display adapters
|
|
147
|
+
i18n Layer locales/*.yml Translation files
|
|
148
|
+
\end{lstlisting}
|
|
149
|
+
|
|
150
|
+
\section{Implementation Priority}\index{Priority}
|
|
151
|
+
|
|
152
|
+
Design documents are implemented in strict priority order, with security
|
|
153
|
+
and quality gates established before any feature code:
|
|
154
|
+
|
|
155
|
+
\begin{longtable}{clp{9cm}}
|
|
156
|
+
\toprule
|
|
157
|
+
\textbf{Priority} & \textbf{Tier} & \textbf{Documents} \\
|
|
158
|
+
\midrule
|
|
159
|
+
P1 & Foundation & security, testing, styles, ci\_pipeline \\
|
|
160
|
+
P2 & Structure & architecture, compiler, claude\_code\_configuration \\
|
|
161
|
+
P3 & Interface & ui\_framework, accessibility, i18n \\
|
|
162
|
+
P4 & Business & licensing\_system, content\_packs \\
|
|
163
|
+
P5 & Operations & release\_management, documentation, distribution \\
|
|
164
|
+
\bottomrule
|
|
165
|
+
\end{longtable}
|
|
166
|
+
|
|
167
|
+
\begin{criterionbox}
|
|
168
|
+
\textbf{Rule:} Guardrails before features. Validation before implementation.
|
|
169
|
+
No feature code merges until P1 gates exist.
|
|
170
|
+
\end{criterionbox}
|
|
171
|
+
|
|
172
|
+
\section{Key Decisions}\index{Key Decisions}
|
|
173
|
+
|
|
174
|
+
\begin{itemize}
|
|
175
|
+
\item \textbf{GPL-3.0-only} -- open-core model: software is free, premium
|
|
176
|
+
content is paid
|
|
177
|
+
\item \textbf{TUI-first} with pluggable GUI: \texttt{nncc},
|
|
178
|
+
\texttt{nncc-gtk4}, \texttt{nncc-qt6}, \texttt{nncc-kde}
|
|
179
|
+
\item \textbf{Multi-target AI} -- author once, compile to
|
|
180
|
+
Claude/Mistral/GPT-NeoX/generic
|
|
181
|
+
\item \textbf{Mutant} as independent test quality validator (three-party model)
|
|
182
|
+
\item \textbf{Ed25519-signed JWT}\cite{ed25519,jwt} license keys,
|
|
183
|
+
offline-verifiable
|
|
184
|
+
\item \textbf{EN 301 549}\cite{en301549} (EU) accessibility compliance
|
|
185
|
+
\item \textbf{UTF-8 everywhere}, Linux/Debian only initially
|
|
186
|
+
\end{itemize}
|
|
187
|
+
|
|
188
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
189
|
+
% CHAPTER 2: P1 FOUNDATION
|
|
190
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
191
|
+
|
|
192
|
+
\chapterimage{head3.jpg}
|
|
193
|
+
\chapter{P1 -- Foundation}\label{ch:p1}
|
|
194
|
+
|
|
195
|
+
Priority 1 establishes the security, testing, style, and CI foundations
|
|
196
|
+
that all subsequent work depends on.
|
|
197
|
+
|
|
198
|
+
\section{Security}\index{Security}
|
|
199
|
+
|
|
200
|
+
\subsection{Intent}
|
|
201
|
+
|
|
202
|
+
Define and enforce security boundaries for every operation \texttt{nncc}
|
|
203
|
+
performs. Security is not a feature -- it is a constraint that applies to
|
|
204
|
+
every line of code, every file operation, and every external interaction.
|
|
205
|
+
|
|
206
|
+
\subsection{Core Constraints}
|
|
207
|
+
|
|
208
|
+
\begin{constraintbox}
|
|
209
|
+
\begin{enumerate}
|
|
210
|
+
\item \textbf{YAML.safe\_load only} -- never \texttt{YAML.load}
|
|
211
|
+
(arbitrary code execution risk)
|
|
212
|
+
\item \textbf{Array-form system()} -- never string interpolation
|
|
213
|
+
in shell commands (injection risk)
|
|
214
|
+
\item \textbf{File writes to whitelisted directories only} -- prevent
|
|
215
|
+
path traversal
|
|
216
|
+
\item \textbf{Secrets at 0600 permissions} -- never logged, never in
|
|
217
|
+
version control
|
|
218
|
+
\item \textbf{All external input validated before use} -- schema
|
|
219
|
+
validation for YAML, JSON Schema for configs
|
|
220
|
+
\end{enumerate}
|
|
221
|
+
\end{constraintbox}
|
|
222
|
+
|
|
223
|
+
\subsection{Secret Management}
|
|
224
|
+
|
|
225
|
+
Secrets are referenced using a DSL convention:
|
|
226
|
+
|
|
227
|
+
\begin{lstlisting}[language=yaml,caption={Secret reference DSL}]
|
|
228
|
+
api:
|
|
229
|
+
key: "${secret:env:ANTHROPIC_API_KEY}"
|
|
230
|
+
auth_token: "${secret:file:~/.config/nncc/token}"
|
|
231
|
+
\end{lstlisting}
|
|
232
|
+
|
|
233
|
+
The \texttt{SecretsResolver} class resolves these references at runtime
|
|
234
|
+
from environment variables, files, or system keyrings. The reference
|
|
235
|
+
string itself is never a secret -- it is a pointer.
|
|
236
|
+
|
|
237
|
+
\subsection{Input Validation}
|
|
238
|
+
|
|
239
|
+
Every YAML file loaded by \texttt{nncc} is validated against its JSON
|
|
240
|
+
Schema before any data is used. The validation chain:
|
|
241
|
+
|
|
242
|
+
\begin{enumerate}
|
|
243
|
+
\item \texttt{YAML.safe\_load} -- parse safely
|
|
244
|
+
\item \texttt{JSONSchemer.schema} -- validate against schema
|
|
245
|
+
\item Domain-specific checks -- e.g., permission patterns, version
|
|
246
|
+
constraints
|
|
247
|
+
\end{enumerate}
|
|
248
|
+
|
|
249
|
+
\subsection{File Permission Model}
|
|
250
|
+
|
|
251
|
+
\begin{longtable}{lll}
|
|
252
|
+
\toprule
|
|
253
|
+
\textbf{File Type} & \textbf{Mode} & \textbf{Rationale} \\
|
|
254
|
+
\midrule
|
|
255
|
+
License keys & 0600 & Contains subscription identity \\
|
|
256
|
+
Configuration & 0644 & Readable, owner-writable \\
|
|
257
|
+
Executables & 0755 & Standard Unix convention \\
|
|
258
|
+
Directories & 0755 & Standard traversal \\
|
|
259
|
+
Secret dirs & 0700 & Owner-only access \\
|
|
260
|
+
\bottomrule
|
|
261
|
+
\end{longtable}
|
|
262
|
+
|
|
263
|
+
\begin{antipatternbox}
|
|
264
|
+
\textbf{Anti-patterns:}
|
|
265
|
+
\begin{itemize}
|
|
266
|
+
\item Using \texttt{YAML.load} with untrusted input
|
|
267
|
+
\item Building shell commands with string interpolation
|
|
268
|
+
\item Writing files outside the whitelisted directories
|
|
269
|
+
\item Logging secret values, even at debug level
|
|
270
|
+
\item Storing secrets in YAML configuration files
|
|
271
|
+
\end{itemize}
|
|
272
|
+
\end{antipatternbox}
|
|
273
|
+
|
|
274
|
+
\section{Testing}\index{Testing}
|
|
275
|
+
|
|
276
|
+
\subsection{Intent}
|
|
277
|
+
|
|
278
|
+
Ensure every component has meaningful, fast tests that catch regressions
|
|
279
|
+
early. The testing strategy uses a three-party model: RSpec for
|
|
280
|
+
specifications, SimpleCov for coverage measurement, and Mutant as an
|
|
281
|
+
independent test quality validator.
|
|
282
|
+
|
|
283
|
+
\subsection{Testing Pyramid}
|
|
284
|
+
|
|
285
|
+
\begin{longtable}{lp{5cm}p{5cm}}
|
|
286
|
+
\toprule
|
|
287
|
+
\textbf{Level} & \textbf{Scope} & \textbf{Tools} \\
|
|
288
|
+
\midrule
|
|
289
|
+
Unit & Individual classes/methods & RSpec + factory\_bot \\
|
|
290
|
+
Integration & Module interactions & RSpec + tmpdir isolation \\
|
|
291
|
+
Mutation & Test quality validation & Mutant (mutant-rspec) \\
|
|
292
|
+
Security & Vulnerability scanning & bundler-audit, ruby-audit \\
|
|
293
|
+
Style & Code consistency & RuboCop, Reek \\
|
|
294
|
+
\bottomrule
|
|
295
|
+
\end{longtable}
|
|
296
|
+
|
|
297
|
+
\subsection{Constraints}
|
|
298
|
+
|
|
299
|
+
\begin{constraintbox}
|
|
300
|
+
\begin{itemize}
|
|
301
|
+
\item RSpec suite must pass with 0 failures before any commit
|
|
302
|
+
\item Coverage target: 90\%+ line coverage (SimpleCov)
|
|
303
|
+
\item Mutation testing validates test effectiveness -- tests that
|
|
304
|
+
do not detect mutations are insufficient
|
|
305
|
+
\item All specs run in isolation -- no shared mutable state, no
|
|
306
|
+
filesystem leaks
|
|
307
|
+
\item Test fixtures use \texttt{factory\_bot} -- never hand-crafted
|
|
308
|
+
hashes
|
|
309
|
+
\end{itemize}
|
|
310
|
+
\end{constraintbox}
|
|
311
|
+
|
|
312
|
+
\section{Styles}\index{Styles}
|
|
313
|
+
|
|
314
|
+
\subsection{Intent}
|
|
315
|
+
|
|
316
|
+
Enforce consistent code style across all Ruby source files. Style rules
|
|
317
|
+
are not aesthetic preferences -- they are communication standards that
|
|
318
|
+
reduce cognitive load during code review.
|
|
319
|
+
|
|
320
|
+
\subsection{Tool Configuration}
|
|
321
|
+
|
|
322
|
+
\begin{longtable}{lll}
|
|
323
|
+
\toprule
|
|
324
|
+
\textbf{Tool} & \textbf{Config} & \textbf{Standard} \\
|
|
325
|
+
\midrule
|
|
326
|
+
RuboCop & .rubocop.yml & 0 offenses required \\
|
|
327
|
+
Reek & .reek.yml & 0 warnings (or justified exclusions) \\
|
|
328
|
+
Flay & (Rakefile) & Duplication monitoring \\
|
|
329
|
+
\bottomrule
|
|
330
|
+
\end{longtable}
|
|
331
|
+
|
|
332
|
+
\subsection{Key Style Rules}
|
|
333
|
+
|
|
334
|
+
\begin{itemize}
|
|
335
|
+
\item \textbf{Frozen string literals} -- every Ruby file starts with
|
|
336
|
+
\texttt{\# frozen\_string\_literal: true}
|
|
337
|
+
\item \textbf{SPDX headers} -- every Ruby file includes
|
|
338
|
+
\texttt{\# SPDX-License-Identifier: GPL-3.0-only}
|
|
339
|
+
\item \textbf{UTF-8 encoding} -- no Latin-1, no BOM markers
|
|
340
|
+
\item \textbf{2-space indentation} -- Ruby community standard
|
|
341
|
+
\item \textbf{No trailing whitespace} -- enforced by pre-commit hooks
|
|
342
|
+
\end{itemize}
|
|
343
|
+
|
|
344
|
+
\section{CI Pipeline}\index{CI Pipeline}
|
|
345
|
+
|
|
346
|
+
\subsection{Intent}
|
|
347
|
+
|
|
348
|
+
Automate all verification steps so that no broken code reaches the main
|
|
349
|
+
branch. The CI pipeline mirrors the pre-commit hook chain but runs in an
|
|
350
|
+
isolated, reproducible environment.
|
|
351
|
+
|
|
352
|
+
\subsection{Pipeline Stages}
|
|
353
|
+
|
|
354
|
+
\begin{longtable}{llp{7cm}}
|
|
355
|
+
\toprule
|
|
356
|
+
\textbf{Stage} & \textbf{Job} & \textbf{Description} \\
|
|
357
|
+
\midrule
|
|
358
|
+
validate & yaml\_lint & YAML syntax validation \\
|
|
359
|
+
code\_quality & rubocop & Style enforcement (0 offenses) \\
|
|
360
|
+
code\_quality & reek & Code smell detection \\
|
|
361
|
+
code\_quality & flay & Duplication detection \\
|
|
362
|
+
security\_scan & bundler\_audit & Gem CVE scanning \\
|
|
363
|
+
security\_scan & ruby\_audit & Ruby CVE scanning \\
|
|
364
|
+
security\_scan & gitleaks & Secret detection \\
|
|
365
|
+
test & rspec & Full test suite \\
|
|
366
|
+
build & package & Debian package build \\
|
|
367
|
+
\bottomrule
|
|
368
|
+
\end{longtable}
|
|
369
|
+
|
|
370
|
+
\begin{criterionbox}
|
|
371
|
+
\textbf{CI Rule:} All stages must pass before merge. There are no
|
|
372
|
+
``allowed failures'' in the pipeline.
|
|
373
|
+
\end{criterionbox}
|
|
374
|
+
|
|
375
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
376
|
+
% CHAPTER 3: P2 STRUCTURE
|
|
377
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
378
|
+
|
|
379
|
+
\chapterimage{head4.jpg}
|
|
380
|
+
\chapter{P2 -- Structure}\label{ch:p2}
|
|
381
|
+
|
|
382
|
+
Priority 2 builds the core structural components: the modular architecture,
|
|
383
|
+
the multi-target compiler, and the Claude Code configuration management
|
|
384
|
+
system.
|
|
385
|
+
|
|
386
|
+
\section{Architecture}\index{Architecture}
|
|
387
|
+
|
|
388
|
+
\subsection{Intent}
|
|
389
|
+
|
|
390
|
+
Define the modular structure that allows \texttt{nncc} to grow without
|
|
391
|
+
becoming a monolith. Each module has a single responsibility, clear
|
|
392
|
+
interfaces, and minimal coupling.
|
|
393
|
+
|
|
394
|
+
\subsection{Module Map}
|
|
395
|
+
|
|
396
|
+
\begin{longtable}{lp{9cm}}
|
|
397
|
+
\toprule
|
|
398
|
+
\textbf{Module} & \textbf{Responsibility} \\
|
|
399
|
+
\midrule
|
|
400
|
+
\texttt{Nncc::Thor} & CLI interface (Thor subcommands) \\
|
|
401
|
+
\texttt{Nncc::Compiler} & Multi-target compilation pipeline \\
|
|
402
|
+
\texttt{Nncc::Config} & Claude Code configuration management \\
|
|
403
|
+
\texttt{Nncc::Security} & Secret resolution, input validation \\
|
|
404
|
+
\texttt{Nncc::Ui} & Pluggable UI adapters (TUI/GUI) \\
|
|
405
|
+
\texttt{Nncc::Licensing} & Ed25519 JWT license validation \\
|
|
406
|
+
\texttt{Nncc::I18n} & Locale resolution and string externalization \\
|
|
407
|
+
\texttt{Nncc::ContentPack} & Premium content pack management \\
|
|
408
|
+
\bottomrule
|
|
409
|
+
\end{longtable}
|
|
410
|
+
|
|
411
|
+
\subsection{Path Resolution}
|
|
412
|
+
|
|
413
|
+
All filesystem paths are resolved through \texttt{Nncc::PathResolver},
|
|
414
|
+
ensuring consistent path computation regardless of the current working
|
|
415
|
+
directory. Key paths:
|
|
416
|
+
|
|
417
|
+
\begin{lstlisting}[language=ruby,caption={Path resolution}]
|
|
418
|
+
Nncc.paths.root # Project root
|
|
419
|
+
Nncc.paths.conf_dir # conf/
|
|
420
|
+
Nncc.paths.rules_dir # ~/.claude/rules/
|
|
421
|
+
Nncc.paths.license_file # ~/.config/nncc/license.key
|
|
422
|
+
Nncc.paths.premium_content_dir # ~/.local/share/nncc/content/
|
|
423
|
+
\end{lstlisting}
|
|
424
|
+
|
|
425
|
+
\begin{decisionbox}
|
|
426
|
+
\textbf{ADR-001: PathResolver centralisation.} All path computation goes
|
|
427
|
+
through a single resolver class to prevent path drift between modules.
|
|
428
|
+
Each method returns a \texttt{Pathname} object for safe path manipulation.
|
|
429
|
+
\end{decisionbox}
|
|
430
|
+
|
|
431
|
+
\section{Compiler}\index{Compiler}
|
|
432
|
+
|
|
433
|
+
\subsection{Intent}
|
|
434
|
+
|
|
435
|
+
Transform YAML source configurations into target-specific output formats.
|
|
436
|
+
The compiler uses a strategy pattern where each AI target has a
|
|
437
|
+
\texttt{Backend} class and a \texttt{TargetProfile} YAML configuration.
|
|
438
|
+
|
|
439
|
+
\subsection{Compilation Pipeline}
|
|
440
|
+
|
|
441
|
+
The \texttt{CompilationPipeline} class orchestrates the full flow:
|
|
442
|
+
|
|
443
|
+
\begin{enumerate}
|
|
444
|
+
\item \textbf{Discovery} -- scan \texttt{conf/} for categories that
|
|
445
|
+
have matching schemas
|
|
446
|
+
\item \textbf{Loading} -- parse YAML with \texttt{YAML.safe\_load}
|
|
447
|
+
\item \textbf{Validation} -- verify against JSON Schema
|
|
448
|
+
\item \textbf{Rendering} -- delegate to the backend for format-specific
|
|
449
|
+
output
|
|
450
|
+
\item \textbf{Checksumming} -- SHA-256 digest for change detection
|
|
451
|
+
\item \textbf{Orphan cleanup} -- remove managed files that no longer
|
|
452
|
+
have sources
|
|
453
|
+
\end{enumerate}
|
|
454
|
+
|
|
455
|
+
\subsection{Backend Architecture}
|
|
456
|
+
|
|
457
|
+
\begin{lstlisting}[language=ruby,caption={Backend registration}]
|
|
458
|
+
BACKENDS = {
|
|
459
|
+
'claude' => 'Nncc::Compiler::Backends::ClaudeBackend',
|
|
460
|
+
'generic' => 'Nncc::Compiler::Backends::GenericBackend'
|
|
461
|
+
}.freeze
|
|
462
|
+
\end{lstlisting}
|
|
463
|
+
|
|
464
|
+
Each backend implements:
|
|
465
|
+
\begin{itemize}
|
|
466
|
+
\item \texttt{render(category, data)} -- produce output string
|
|
467
|
+
\item \texttt{generated\_marker} -- identify managed files
|
|
468
|
+
\item \texttt{file\_extension} -- output format (\texttt{.md} for markdown)
|
|
469
|
+
\end{itemize}
|
|
470
|
+
|
|
471
|
+
\subsection{Target Profiles}
|
|
472
|
+
|
|
473
|
+
\begin{lstlisting}[language=yaml,caption={Claude target profile}]
|
|
474
|
+
name: claude
|
|
475
|
+
description: Claude Code (Anthropic) target
|
|
476
|
+
backend: claude
|
|
477
|
+
engine_version: ">=1.0.0"
|
|
478
|
+
output_format: markdown
|
|
479
|
+
output_dir: null
|
|
480
|
+
max_context_window: 200000
|
|
481
|
+
rendering:
|
|
482
|
+
include_source_metadata: true
|
|
483
|
+
include_priority_annotations: true
|
|
484
|
+
include_generated_marker: true
|
|
485
|
+
\end{lstlisting}
|
|
486
|
+
|
|
487
|
+
\begin{decisionbox}
|
|
488
|
+
\textbf{ADR-005: Multi-engine architecture.} Adding a new AI target
|
|
489
|
+
requires only a YAML profile and a Ruby backend class. No changes to
|
|
490
|
+
the compilation pipeline, CLI, or test infrastructure.
|
|
491
|
+
\end{decisionbox}
|
|
492
|
+
|
|
493
|
+
\section{Claude Code Configuration}\index{Claude Code Configuration}
|
|
494
|
+
|
|
495
|
+
\subsection{Intent}
|
|
496
|
+
|
|
497
|
+
Manage Claude Code settings across four scopes: user, project, local,
|
|
498
|
+
and managed. Each scope compiles to a specific JSON file that Claude Code
|
|
499
|
+
reads at runtime.
|
|
500
|
+
|
|
501
|
+
\subsection{Scope Hierarchy}
|
|
502
|
+
|
|
503
|
+
\begin{longtable}{llp{6cm}}
|
|
504
|
+
\toprule
|
|
505
|
+
\textbf{Scope} & \textbf{Output Path} & \textbf{Purpose} \\
|
|
506
|
+
\midrule
|
|
507
|
+
managed & /etc/claude-code/managed-settings.json & Enterprise policies \\
|
|
508
|
+
user & \textasciitilde/.claude/settings.json & User defaults \\
|
|
509
|
+
project & .claude/settings.json & Project-specific \\
|
|
510
|
+
local & .claude/settings.local.json & Local overrides (gitignored) \\
|
|
511
|
+
\bottomrule
|
|
512
|
+
\end{longtable}
|
|
513
|
+
|
|
514
|
+
\subsection{Key Mapping}
|
|
515
|
+
|
|
516
|
+
YAML source files use \texttt{snake\_case} keys which are transformed
|
|
517
|
+
to \texttt{camelCase} for the JSON output that Claude Code expects.
|
|
518
|
+
The \texttt{KeyMap} class handles this transformation:
|
|
519
|
+
|
|
520
|
+
\begin{lstlisting}[language=ruby,caption={Key mapping example}]
|
|
521
|
+
# YAML source
|
|
522
|
+
auto_allow_bash: true
|
|
523
|
+
max_output_tokens: 32000
|
|
524
|
+
|
|
525
|
+
# JSON output
|
|
526
|
+
"autoAllowBash": true,
|
|
527
|
+
"maxOutputTokens": 32000
|
|
528
|
+
\end{lstlisting}
|
|
529
|
+
|
|
530
|
+
\subsection{Permission Model}
|
|
531
|
+
|
|
532
|
+
Permissions are structured as allow/deny/ask lists with glob patterns:
|
|
533
|
+
|
|
534
|
+
\begin{lstlisting}[language=yaml,caption={Permission configuration}]
|
|
535
|
+
permissions:
|
|
536
|
+
default_mode: acceptEdits
|
|
537
|
+
allow:
|
|
538
|
+
- "Bash(bundle *)"
|
|
539
|
+
- "Bash(bin/nncc *)"
|
|
540
|
+
- "Bash(rbenv *)"
|
|
541
|
+
deny:
|
|
542
|
+
- "Read(./.env)"
|
|
543
|
+
- "Read(~/.ssh/**/*)"
|
|
544
|
+
- "Read(~/.gnupg/**/*)"
|
|
545
|
+
ask:
|
|
546
|
+
- "Bash(git push *)"
|
|
547
|
+
\end{lstlisting}
|
|
548
|
+
|
|
549
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
550
|
+
% CHAPTER 4: P3 INTERFACE
|
|
551
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
552
|
+
|
|
553
|
+
\chapterimage{head5.jpg}
|
|
554
|
+
\chapter{P3 -- Interface}\label{ch:p3}
|
|
555
|
+
|
|
556
|
+
Priority 3 implements the user-facing interface layer: pluggable UI
|
|
557
|
+
adapters, accessibility compliance, and internationalization.
|
|
558
|
+
|
|
559
|
+
\section{UI Framework}\index{UI Framework}
|
|
560
|
+
|
|
561
|
+
\subsection{Intent}
|
|
562
|
+
|
|
563
|
+
Provide a pluggable display layer that decouples domain logic from
|
|
564
|
+
presentation. The default is a terminal UI (TUI); GUI adapters are
|
|
565
|
+
optional extensions distributed as separate Debian packages.
|
|
566
|
+
|
|
567
|
+
\subsection{Adapter Registry}
|
|
568
|
+
|
|
569
|
+
The \texttt{Nncc::Ui::Registry} class manages adapter discovery
|
|
570
|
+
and resolution:
|
|
571
|
+
|
|
572
|
+
\begin{lstlisting}[language=ruby,caption={UI adapter registration}]
|
|
573
|
+
Registry.register(:tui, Tui)
|
|
574
|
+
Registry.register(:accessible_tui, AccessibleTui)
|
|
575
|
+
Registry.register(:gtk4, Gtk4)
|
|
576
|
+
Registry.register(:qt6, Qt6)
|
|
577
|
+
Registry.register(:kde, Kde)
|
|
578
|
+
\end{lstlisting}
|
|
579
|
+
|
|
580
|
+
\subsection{Package Variants}
|
|
581
|
+
|
|
582
|
+
\begin{longtable}{llp{6cm}}
|
|
583
|
+
\toprule
|
|
584
|
+
\textbf{Package} & \textbf{Adapter} & \textbf{System Dependencies} \\
|
|
585
|
+
\midrule
|
|
586
|
+
nncc & tui & ruby, libncurses \\
|
|
587
|
+
nncc-gtk4 & gtk4 & nncc, libgtk-4-dev, ruby-gnome \\
|
|
588
|
+
nncc-qt6 & qt6 & nncc (placeholder -- bindings pending) \\
|
|
589
|
+
nncc-kde & kde & nncc-qt6 (placeholder -- bindings pending) \\
|
|
590
|
+
\bottomrule
|
|
591
|
+
\end{longtable}
|
|
592
|
+
|
|
593
|
+
\begin{decisionbox}
|
|
594
|
+
\textbf{ADR-002: UI adapter registry.} Adding a new GUI adapter
|
|
595
|
+
requires only a Ruby class implementing the \texttt{Base} interface
|
|
596
|
+
and a packaging variant YAML. The CLI \texttt{--ui} flag selects
|
|
597
|
+
the adapter at runtime.
|
|
598
|
+
\end{decisionbox}
|
|
599
|
+
|
|
600
|
+
\subsection{Base Interface}
|
|
601
|
+
|
|
602
|
+
Every UI adapter must implement five methods:
|
|
603
|
+
|
|
604
|
+
\begin{longtable}{lp{6.5cm}}
|
|
605
|
+
\toprule
|
|
606
|
+
\textbf{Method} & \textbf{Purpose} \\
|
|
607
|
+
\midrule
|
|
608
|
+
\texttt{render(content)} & Display text to the user \\
|
|
609
|
+
\texttt{display\_table(h, rows)} & Display tabular data \\
|
|
610
|
+
\texttt{prompt\_user(q, choices:)} & Interactive input \\
|
|
611
|
+
\texttt{show\_spinner(msg, \&blk)} & Progress indication \\
|
|
612
|
+
\texttt{announce(message)} & Accessibility announcement \\
|
|
613
|
+
\bottomrule
|
|
614
|
+
\end{longtable}
|
|
615
|
+
|
|
616
|
+
\section{Accessibility}\index{Accessibility}
|
|
617
|
+
|
|
618
|
+
\subsection{Intent}
|
|
619
|
+
|
|
620
|
+
Ensure \texttt{nncc} is usable by people with disabilities, in compliance
|
|
621
|
+
with EN 301 549 (EU accessibility standard)\cite{en301549}. This is not
|
|
622
|
+
optional -- it is a legal requirement for publicly-funded ICT in the EU.
|
|
623
|
+
|
|
624
|
+
\subsection{Implementation}
|
|
625
|
+
|
|
626
|
+
The \texttt{AccessibleTui} adapter provides:
|
|
627
|
+
|
|
628
|
+
\begin{itemize}
|
|
629
|
+
\item \textbf{Linear output} -- no box-drawing characters, no
|
|
630
|
+
decorative ANSI escapes
|
|
631
|
+
\item \textbf{NO\_COLOR support} -- respects the \texttt{NO\_COLOR}
|
|
632
|
+
environment variable
|
|
633
|
+
\item \textbf{Screen reader compatibility} -- tested with Orca and BRLTTY
|
|
634
|
+
\item \textbf{Auto-detection} -- switches to accessible mode when
|
|
635
|
+
\texttt{ORCA\_RUNNING} or \texttt{BRLTTY\_TTY} is set
|
|
636
|
+
\item \textbf{Announcement priorities} -- \texttt{:polite} and
|
|
637
|
+
\texttt{:assertive} levels for screen reader output
|
|
638
|
+
\item \textbf{RTL support} -- detects RTL locales (Arabic, Hebrew)
|
|
639
|
+
and adjusts text direction
|
|
640
|
+
\end{itemize}
|
|
641
|
+
|
|
642
|
+
\begin{constraintbox}
|
|
643
|
+
\textbf{Accessibility constraint:} Every UI adapter must pass the
|
|
644
|
+
shared example \texttt{it\_behaves\_like 'a UI implementation'}
|
|
645
|
+
which verifies all five interface methods are implemented.
|
|
646
|
+
\end{constraintbox}
|
|
647
|
+
|
|
648
|
+
\section{Internationalization}\index{Internationalization}
|
|
649
|
+
|
|
650
|
+
\subsection{Intent}
|
|
651
|
+
|
|
652
|
+
Externalize all user-facing strings so that \texttt{nncc} can be used
|
|
653
|
+
in any language. The i18n system uses ruby-i18n with YAML source files.
|
|
654
|
+
|
|
655
|
+
\subsection{Locale Resolution}
|
|
656
|
+
|
|
657
|
+
The \texttt{LocaleResolver} determines the active locale through a
|
|
658
|
+
priority chain:
|
|
659
|
+
|
|
660
|
+
\begin{enumerate}
|
|
661
|
+
\item \texttt{--locale} CLI flag (highest priority)
|
|
662
|
+
\item \texttt{NNCC\_LOCALE} environment variable
|
|
663
|
+
\item \texttt{LANG} environment variable
|
|
664
|
+
\item English fallback (lowest priority)
|
|
665
|
+
\end{enumerate}
|
|
666
|
+
|
|
667
|
+
\subsection{Translation Structure}
|
|
668
|
+
|
|
669
|
+
\begin{lstlisting}[language=yaml,caption={Locale file structure}]
|
|
670
|
+
en:
|
|
671
|
+
nncc:
|
|
672
|
+
meta:
|
|
673
|
+
direction: ltr
|
|
674
|
+
language_name: "English"
|
|
675
|
+
cli:
|
|
676
|
+
version: "nncc Version %{version}"
|
|
677
|
+
compile:
|
|
678
|
+
compiling: "Compiling %{category}..."
|
|
679
|
+
success: "Compiled %{count} files"
|
|
680
|
+
\end{lstlisting}
|
|
681
|
+
|
|
682
|
+
\subsection{UTF-8 Enforcement}
|
|
683
|
+
|
|
684
|
+
A \texttt{TextSanitizer} module enforces UTF-8 throughout:
|
|
685
|
+
|
|
686
|
+
\begin{itemize}
|
|
687
|
+
\item \texttt{normalize\_nfc(text)} -- Unicode NFC normalization
|
|
688
|
+
\item \texttt{strip\_ansi(text)} -- remove ANSI escape sequences
|
|
689
|
+
\item \texttt{valid\_utf8?(text)} -- encoding validation
|
|
690
|
+
\end{itemize}
|
|
691
|
+
|
|
692
|
+
\subsection{Locale Compilation}
|
|
693
|
+
|
|
694
|
+
The \texttt{LocaleCompiler} transforms YAML locale files into
|
|
695
|
+
distribution formats:
|
|
696
|
+
|
|
697
|
+
\begin{longtable}{llp{5cm}}
|
|
698
|
+
\toprule
|
|
699
|
+
\textbf{Format} & \textbf{Extension} & \textbf{Use Case} \\
|
|
700
|
+
\midrule
|
|
701
|
+
Gettext & .pot/.po & GNU toolchain integration \\
|
|
702
|
+
Qt Linguist & .ts & Qt6 GUI adapter \\
|
|
703
|
+
\bottomrule
|
|
704
|
+
\end{longtable}
|
|
705
|
+
|
|
706
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
707
|
+
% CHAPTER 5: P4 BUSINESS
|
|
708
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
709
|
+
|
|
710
|
+
\chapterimage{head6.jpg}
|
|
711
|
+
\chapter{P4 -- Business}\label{ch:p4}
|
|
712
|
+
|
|
713
|
+
Priority 4 implements the business model: an open-core licensing system
|
|
714
|
+
where the software is free (GPL-3.0) and premium content packs are paid.
|
|
715
|
+
|
|
716
|
+
\section{Licensing System}\index{Licensing}
|
|
717
|
+
|
|
718
|
+
\subsection{Intent}
|
|
719
|
+
|
|
720
|
+
Enable a sustainable open-source business model. The licensing system
|
|
721
|
+
controls access to premium content packs -- it NEVER restricts software
|
|
722
|
+
functionality. This distinction is critical for GPL-3.0 compliance.
|
|
723
|
+
|
|
724
|
+
\begin{criterionbox}
|
|
725
|
+
\textbf{GPL-3.0 compliance rule:} License tiers gate content pack
|
|
726
|
+
\emph{downloads}, not software features. A community user has full
|
|
727
|
+
access to all \texttt{nncc} functionality -- they simply do not have
|
|
728
|
+
access to premium behaviour and design packs.
|
|
729
|
+
\end{criterionbox}
|
|
730
|
+
|
|
731
|
+
\subsection{License Key Format}
|
|
732
|
+
|
|
733
|
+
License keys are Ed25519-signed JWTs\cite{jwt,ed25519} with an
|
|
734
|
+
\texttt{NNCC-} prefix:
|
|
735
|
+
|
|
736
|
+
\begin{lstlisting}[language={},caption={License key structure}]
|
|
737
|
+
NNCC-eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...
|
|
738
|
+
\end{lstlisting}
|
|
739
|
+
|
|
740
|
+
JWT claims include:
|
|
741
|
+
\begin{longtable}{llp{5cm}}
|
|
742
|
+
\toprule
|
|
743
|
+
\textbf{Claim} & \textbf{Type} & \textbf{Description} \\
|
|
744
|
+
\midrule
|
|
745
|
+
tier & string & community, supporter, subscriber, enterprise \\
|
|
746
|
+
exp & integer & Expiry timestamp (Unix epoch) \\
|
|
747
|
+
perpetual & boolean & Perpetual license flag \\
|
|
748
|
+
sub & string & Subscriber identifier \\
|
|
749
|
+
\bottomrule
|
|
750
|
+
\end{longtable}
|
|
751
|
+
|
|
752
|
+
\subsection{Tier Hierarchy}
|
|
753
|
+
|
|
754
|
+
\begin{longtable}{clp{6cm}}
|
|
755
|
+
\toprule
|
|
756
|
+
\textbf{Level} & \textbf{Tier} & \textbf{Access} \\
|
|
757
|
+
\midrule
|
|
758
|
+
0 & Community & Free software, no premium content \\
|
|
759
|
+
1 & Supporter & Basic premium packs \\
|
|
760
|
+
2 & Subscriber & All premium packs + updates \\
|
|
761
|
+
3 & Enterprise & All packs + priority support \\
|
|
762
|
+
\bottomrule
|
|
763
|
+
\end{longtable}
|
|
764
|
+
|
|
765
|
+
\subsection{Grace Periods}
|
|
766
|
+
|
|
767
|
+
\begin{longtable}{lll}
|
|
768
|
+
\toprule
|
|
769
|
+
\textbf{Period} & \textbf{Duration} & \textbf{Behaviour} \\
|
|
770
|
+
\midrule
|
|
771
|
+
Active & Until expiry & Full access \\
|
|
772
|
+
Grace & 14 days post-expiry & Access with warning \\
|
|
773
|
+
Offline & 30 days & Verify without network \\
|
|
774
|
+
Expired & After grace & Content frozen at last version \\
|
|
775
|
+
\bottomrule
|
|
776
|
+
\end{longtable}
|
|
777
|
+
|
|
778
|
+
\subsection{Storage Security}
|
|
779
|
+
|
|
780
|
+
The \texttt{LicenseStore} class persists the license key at
|
|
781
|
+
\texttt{\textasciitilde/.config/nncc/license.key} with:
|
|
782
|
+
|
|
783
|
+
\begin{itemize}
|
|
784
|
+
\item File mode \texttt{0600} (owner read/write only)
|
|
785
|
+
\item Directory mode \texttt{0700} (owner access only)
|
|
786
|
+
\item UID verification (must match current process)
|
|
787
|
+
\end{itemize}
|
|
788
|
+
|
|
789
|
+
\begin{antipatternbox}
|
|
790
|
+
\textbf{Anti-patterns:}
|
|
791
|
+
\begin{itemize}
|
|
792
|
+
\item Restricting software features based on license tier (GPL violation)
|
|
793
|
+
\item Storing license keys in YAML config files (wrong permissions)
|
|
794
|
+
\item Logging license key contents
|
|
795
|
+
\item Phone-home license validation (must work offline)
|
|
796
|
+
\end{itemize}
|
|
797
|
+
\end{antipatternbox}
|
|
798
|
+
|
|
799
|
+
\section{Content Packs}\index{Content Packs}
|
|
800
|
+
|
|
801
|
+
\subsection{Intent}
|
|
802
|
+
|
|
803
|
+
Distribute premium behaviour and design packs to licensed users. Content
|
|
804
|
+
packs are the revenue mechanism that sustains the open-source project.
|
|
805
|
+
|
|
806
|
+
\subsection{Pack Structure}
|
|
807
|
+
|
|
808
|
+
\begin{lstlisting}[language=yaml,caption={Content pack manifest}]
|
|
809
|
+
name: enterprise_security
|
|
810
|
+
version: 1.0.0
|
|
811
|
+
tier_required: subscriber
|
|
812
|
+
description: "Advanced security behaviours for enterprise"
|
|
813
|
+
author: "NeatNerds"
|
|
814
|
+
contents:
|
|
815
|
+
behaviours:
|
|
816
|
+
- advanced_audit.yml
|
|
817
|
+
- compliance_reporting.yml
|
|
818
|
+
designs:
|
|
819
|
+
- soc2_compliance.yml
|
|
820
|
+
\end{lstlisting}
|
|
821
|
+
|
|
822
|
+
\subsection{Installation Path}
|
|
823
|
+
|
|
824
|
+
Premium content is installed to
|
|
825
|
+
\texttt{\textasciitilde/.local/share/nncc/content/<pack\_name>/}
|
|
826
|
+
and discovered automatically by the compilation pipeline.
|
|
827
|
+
|
|
828
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
829
|
+
% CHAPTER 6: P5 OPERATIONS
|
|
830
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
831
|
+
|
|
832
|
+
\chapterimage{head7.jpg}
|
|
833
|
+
\chapter{P5 -- Operations}\label{ch:p5}
|
|
834
|
+
|
|
835
|
+
Priority 5 covers operational concerns: release management, documentation
|
|
836
|
+
generation, and package distribution.
|
|
837
|
+
|
|
838
|
+
\section{Release Management}\index{Release Management}
|
|
839
|
+
|
|
840
|
+
\subsection{Intent}
|
|
841
|
+
|
|
842
|
+
Define a repeatable, automated process for releasing \texttt{nncc}
|
|
843
|
+
versions. The release process eliminates manual version edits, manual
|
|
844
|
+
CHANGELOG writing, and manual tag creation -- all sources of
|
|
845
|
+
inconsistency and human error.
|
|
846
|
+
|
|
847
|
+
\subsection{Release Workflow}
|
|
848
|
+
|
|
849
|
+
\begin{enumerate}
|
|
850
|
+
\item \texttt{bin/nncc release prepare LEVEL} --
|
|
851
|
+
bumps version, generates CHANGELOG, creates release commit
|
|
852
|
+
\item Developer reviews the commit
|
|
853
|
+
\item \texttt{bin/nncc release tag} -- creates annotated tag
|
|
854
|
+
\item \texttt{git push origin branch --tags} -- triggers CI release
|
|
855
|
+
\end{enumerate}
|
|
856
|
+
|
|
857
|
+
\subsection{Constraints}
|
|
858
|
+
|
|
859
|
+
\begin{constraintbox}
|
|
860
|
+
\begin{itemize}
|
|
861
|
+
\item Version follows Semantic Versioning 2.0.0\cite{semver}
|
|
862
|
+
\item CHANGELOG follows Keep a Changelog 1.1.0\cite{keepachangelog}
|
|
863
|
+
\item Full verification suite must pass before any release commit
|
|
864
|
+
\item Version source of truth: \texttt{lib/nncc/version.rb}
|
|
865
|
+
\item Tags are annotated (not lightweight) with pattern \texttt{vX.Y.Z}
|
|
866
|
+
\item Release commits use \texttt{chore(release):} prefix
|
|
867
|
+
\item Auto-push is forbidden -- push is always explicit
|
|
868
|
+
\end{itemize}
|
|
869
|
+
\end{constraintbox}
|
|
870
|
+
|
|
871
|
+
\subsection{git-cliff Configuration}
|
|
872
|
+
|
|
873
|
+
CHANGELOG generation uses git-cliff\cite{gitcliff} with conventional
|
|
874
|
+
commit parsing:
|
|
875
|
+
|
|
876
|
+
\begin{lstlisting}[language={},caption={Conventional commit mapping}]
|
|
877
|
+
feat -> Added
|
|
878
|
+
fix -> Fixed
|
|
879
|
+
refactor -> Changed
|
|
880
|
+
perf -> Changed
|
|
881
|
+
docs -> Documentation
|
|
882
|
+
chore -> Other
|
|
883
|
+
\end{lstlisting}
|
|
884
|
+
|
|
885
|
+
\begin{antipatternbox}
|
|
886
|
+
\textbf{Anti-patterns:}
|
|
887
|
+
\begin{itemize}
|
|
888
|
+
\item Auto-pushing to remote as part of the release process
|
|
889
|
+
\item Editing CHANGELOG manually when automation exists
|
|
890
|
+
\item Using lightweight git tags
|
|
891
|
+
\item Coupling version bump and tag creation into one command
|
|
892
|
+
\end{itemize}
|
|
893
|
+
\end{antipatternbox}
|
|
894
|
+
|
|
895
|
+
\section{Documentation}\index{Documentation}
|
|
896
|
+
|
|
897
|
+
\subsection{Intent}
|
|
898
|
+
|
|
899
|
+
Provide end users with complete documentation for installing, configuring,
|
|
900
|
+
and using \texttt{nncc}. Three documentation tiers:
|
|
901
|
+
|
|
902
|
+
\begin{longtable}{llp{6cm}}
|
|
903
|
+
\toprule
|
|
904
|
+
\textbf{Tier} & \textbf{Format} & \textbf{Audience} \\
|
|
905
|
+
\midrule
|
|
906
|
+
Man pages & ronn-ng (roff) & End users (\texttt{man nncc}) \\
|
|
907
|
+
API docs & YARD (HTML) & Contributors \\
|
|
908
|
+
Guides & Markdown & All (INSTALL.md, SETUP.md) \\
|
|
909
|
+
\bottomrule
|
|
910
|
+
\end{longtable}
|
|
911
|
+
|
|
912
|
+
\subsection{Man Page Structure}
|
|
913
|
+
|
|
914
|
+
\begin{lstlisting}[language={},caption={Man page sections}]
|
|
915
|
+
NAME - nncc -- NeatNerds Code Companion
|
|
916
|
+
SYNOPSIS - nncc [OPTIONS] COMMAND [ARGS]
|
|
917
|
+
DESCRIPTION - Overview of what nncc does
|
|
918
|
+
COMMANDS - All CLI subcommands
|
|
919
|
+
OPTIONS - Global flags (--accessible, --locale, --ui)
|
|
920
|
+
FILES - Configuration file locations
|
|
921
|
+
EXIT STATUS - Return codes and meanings
|
|
922
|
+
ENVIRONMENT - Relevant environment variables
|
|
923
|
+
SEE ALSO - Related commands and resources
|
|
924
|
+
\end{lstlisting}
|
|
925
|
+
|
|
926
|
+
\subsection{Documentation Consistency}
|
|
927
|
+
|
|
928
|
+
A CI job verifies documentation consistency:
|
|
929
|
+
\begin{itemize}
|
|
930
|
+
\item Ruby version in \texttt{doc/SETUP.md} matches \texttt{.ruby-version}
|
|
931
|
+
\item Subcommands in man page match CLI \texttt{--help} output
|
|
932
|
+
\item No stale version references in documentation files
|
|
933
|
+
\end{itemize}
|
|
934
|
+
|
|
935
|
+
\section{Distribution}\index{Distribution}
|
|
936
|
+
|
|
937
|
+
\subsection{Intent}
|
|
938
|
+
|
|
939
|
+
Deliver \texttt{nncc} Debian packages to end users through a managed
|
|
940
|
+
APT repository. The distribution system uses Pulp\cite{pulp} as the
|
|
941
|
+
repository management platform.
|
|
942
|
+
|
|
943
|
+
\subsection{Packaging}
|
|
944
|
+
|
|
945
|
+
The \texttt{bin/nncc build package} command creates Debian packages
|
|
946
|
+
using fpm (Effing Package Management):
|
|
947
|
+
|
|
948
|
+
\begin{longtable}{lp{8cm}}
|
|
949
|
+
\toprule
|
|
950
|
+
\textbf{Stage} & \textbf{Description} \\
|
|
951
|
+
\midrule
|
|
952
|
+
verify & Pre-flight checks (Ruby version, fpm, dpkg) \\
|
|
953
|
+
clean & Reset staging directory \\
|
|
954
|
+
stage\_ruby & Install gems to staging (--deployment) \\
|
|
955
|
+
install\_bin & Copy executables \\
|
|
956
|
+
install\_lib & Copy library files \\
|
|
957
|
+
install\_conf & Copy configuration and schemas \\
|
|
958
|
+
install\_locales & Copy translation files \\
|
|
959
|
+
install\_man & Generate and install man pages \\
|
|
960
|
+
fpm & Build .deb package \\
|
|
961
|
+
verify\_deb & Validate package with dpkg-deb \\
|
|
962
|
+
\bottomrule
|
|
963
|
+
\end{longtable}
|
|
964
|
+
|
|
965
|
+
\subsection{Repository Architecture}
|
|
966
|
+
|
|
967
|
+
\begin{lstlisting}[language={},caption={Pulp repository layout}]
|
|
968
|
+
Distribution:
|
|
969
|
+
nncc-stable -> latest releases
|
|
970
|
+
nncc-testing -> release candidates
|
|
971
|
+
nncc-nightly -> CI builds (auto-pruned)
|
|
972
|
+
|
|
973
|
+
Signing:
|
|
974
|
+
GPG Ed25519 or RSA-4096
|
|
975
|
+
SHA256+ digest only
|
|
976
|
+
|
|
977
|
+
Phases:
|
|
978
|
+
Phase 1: pulp_deb (Debian/Ubuntu)
|
|
979
|
+
Phase 2: pulp_rpm (RHEL/Fedora) -- future
|
|
980
|
+
Phase 3: pulp_file (generic tarballs) -- future
|
|
981
|
+
\end{lstlisting}
|
|
982
|
+
|
|
983
|
+
\begin{decisionbox}
|
|
984
|
+
\textbf{ADR: Pulp over aptly.} The distribution system uses
|
|
985
|
+
Pulp instead of aptly because Pulp supports multi-format repositories
|
|
986
|
+
(deb + rpm + file) through a plugin architecture, provides a REST API
|
|
987
|
+
for CI integration, and runs in OCI containers for reproducibility.
|
|
988
|
+
\end{decisionbox}
|
|
989
|
+
|
|
990
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
991
|
+
% CHAPTER 7: LIFECYCLE MANAGEMENT
|
|
992
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
993
|
+
|
|
994
|
+
\chapterimage{head8.jpg}
|
|
995
|
+
\chapter{Lifecycle Management}\label{ch:lifecycle}
|
|
996
|
+
|
|
997
|
+
\section{Intent}\index{Lifecycle Management}
|
|
998
|
+
|
|
999
|
+
Define repeatable, auditable processes for upgrading software components
|
|
1000
|
+
(Ruby runtime, gems, system libraries, build tools) across the project.
|
|
1001
|
+
Upgrades are security-critical operations -- a missed CVE fix is a
|
|
1002
|
+
vulnerability, a botched upgrade is downtime.
|
|
1003
|
+
|
|
1004
|
+
\section{Upgrade Methodology}\index{Upgrade Methodology}
|
|
1005
|
+
|
|
1006
|
+
The lifecycle management methodology consists of six phases:
|
|
1007
|
+
|
|
1008
|
+
\subsection{Phase 1: Discovery}
|
|
1009
|
+
|
|
1010
|
+
\begin{itemize}
|
|
1011
|
+
\item Run security audit tools (\texttt{ruby-audit}, \texttt{bundler-audit})
|
|
1012
|
+
\item Record each CVE identifier, severity, and affected component
|
|
1013
|
+
\item Determine the minimum version that resolves all identified CVEs
|
|
1014
|
+
\end{itemize}
|
|
1015
|
+
|
|
1016
|
+
\subsection{Phase 2: Research}
|
|
1017
|
+
|
|
1018
|
+
\begin{itemize}
|
|
1019
|
+
\item Check official release pages for the target version
|
|
1020
|
+
\item Check version manager availability (\texttt{rbenv install --list})
|
|
1021
|
+
\item Read release notes for breaking changes or new deprecations
|
|
1022
|
+
\item Verify target version satisfies gemspec/dependency constraints
|
|
1023
|
+
\end{itemize}
|
|
1024
|
+
|
|
1025
|
+
\subsection{Phase 3: Scope}
|
|
1026
|
+
|
|
1027
|
+
\begin{itemize}
|
|
1028
|
+
\item Grep the entire codebase for all version references
|
|
1029
|
+
\item Categorize findings: config, docs, specs, build scripts
|
|
1030
|
+
\item Note any version-dependent logic in source code
|
|
1031
|
+
\end{itemize}
|
|
1032
|
+
|
|
1033
|
+
\subsection{Phase 4: Execute}
|
|
1034
|
+
|
|
1035
|
+
\begin{itemize}
|
|
1036
|
+
\item Install the new version
|
|
1037
|
+
\item Update version pins
|
|
1038
|
+
\item Reinstall dependencies
|
|
1039
|
+
\item Update all version references identified in scope phase
|
|
1040
|
+
\end{itemize}
|
|
1041
|
+
|
|
1042
|
+
\subsection{Phase 5: Verify}
|
|
1043
|
+
|
|
1044
|
+
\begin{longtable}{ll}
|
|
1045
|
+
\toprule
|
|
1046
|
+
\textbf{Check} & \textbf{Expected Result} \\
|
|
1047
|
+
\midrule
|
|
1048
|
+
ruby-audit & 0 vulnerabilities \\
|
|
1049
|
+
bundler-audit & 0 vulnerabilities \\
|
|
1050
|
+
RuboCop & 0 offenses \\
|
|
1051
|
+
Reek & 0 warnings \\
|
|
1052
|
+
RSpec & 0 failures \\
|
|
1053
|
+
Grep & No stale version references \\
|
|
1054
|
+
\bottomrule
|
|
1055
|
+
\end{longtable}
|
|
1056
|
+
|
|
1057
|
+
\subsection{Phase 6: Commit}
|
|
1058
|
+
|
|
1059
|
+
\begin{itemize}
|
|
1060
|
+
\item Stage only upgrade-related files
|
|
1061
|
+
\item Write commit message referencing CVEs or upgrade rationale
|
|
1062
|
+
\item Let pre-commit hooks run (never \texttt{--no-verify})
|
|
1063
|
+
\end{itemize}
|
|
1064
|
+
|
|
1065
|
+
\section{Reference Execution}\index{Reference Execution}
|
|
1066
|
+
|
|
1067
|
+
The methodology was derived from the Ruby 3.3.8 to 3.3.10 upgrade % rai:no-version-check
|
|
1068
|
+
(2026-02-19), triggered by \texttt{ruby-audit} flagging three CVEs:
|
|
1069
|
+
|
|
1070
|
+
\begin{longtable}{lp{8cm}}
|
|
1071
|
+
\toprule
|
|
1072
|
+
\textbf{CVE} & \textbf{Description} \\
|
|
1073
|
+
\midrule
|
|
1074
|
+
CVE-2025-24294 & resolv library denial of service \\
|
|
1075
|
+
CVE-2025-58767 & REXML denial of service \\
|
|
1076
|
+
CVE-2025-61594 & URI credential leak \\
|
|
1077
|
+
\bottomrule
|
|
1078
|
+
\end{longtable}
|
|
1079
|
+
|
|
1080
|
+
Verification results after upgrade:
|
|
1081
|
+
\begin{itemize}
|
|
1082
|
+
\item ruby-audit: 0 vulnerabilities
|
|
1083
|
+
\item RuboCop: 44 files, 0 offenses
|
|
1084
|
+
\item Reek: 0 warnings
|
|
1085
|
+
\item Flay: 199 total score (unchanged)
|
|
1086
|
+
\item RSpec: 277 examples, 0 failures
|
|
1087
|
+
\item Coverage: 92.92\%
|
|
1088
|
+
\end{itemize}
|
|
1089
|
+
|
|
1090
|
+
\begin{antipatternbox}
|
|
1091
|
+
\textbf{Anti-patterns:}
|
|
1092
|
+
\begin{itemize}
|
|
1093
|
+
\item Upgrading without checking official release notes
|
|
1094
|
+
\item Partial version reference updates
|
|
1095
|
+
\item Running \texttt{bundle update} without targeting specific gems
|
|
1096
|
+
\item Skipping verification because ``it is just a patch version''
|
|
1097
|
+
\item Bypassing pre-commit hooks with \texttt{--no-verify}
|
|
1098
|
+
\item Mixing unrelated changes into an upgrade commit
|
|
1099
|
+
\end{itemize}
|
|
1100
|
+
\end{antipatternbox}
|
|
1101
|
+
|
|
1102
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
1103
|
+
% CHAPTER 8: SCHEMA REFERENCE
|
|
1104
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
1105
|
+
|
|
1106
|
+
\chapterimage{head1.jpg}
|
|
1107
|
+
\chapter{Schema Reference}\label{ch:schemas}
|
|
1108
|
+
|
|
1109
|
+
All YAML configuration files are validated against JSON
|
|
1110
|
+
Schemas\cite{jsonschema} before use. This chapter documents each schema.
|
|
1111
|
+
|
|
1112
|
+
\section{Design Document Schema}\index{Design Schema}
|
|
1113
|
+
|
|
1114
|
+
Validates the structure of design documents in \texttt{conf/design/}.
|
|
1115
|
+
|
|
1116
|
+
\begin{longtable}{llp{5cm}}
|
|
1117
|
+
\toprule
|
|
1118
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1119
|
+
\midrule
|
|
1120
|
+
name & string & Unique identifier (pattern: \texttt{[\^{}a-z0-9\_]}) \\
|
|
1121
|
+
domain & enum & core, ui, security, testing, styles, i18n, accessibility,
|
|
1122
|
+
licensing, ci, compiler, release, documentation \\
|
|
1123
|
+
version & string & Semantic version (X.Y.Z) \\
|
|
1124
|
+
status & enum & draft, review, approved, deprecated \\
|
|
1125
|
+
priority & integer & 1--6 (P1=highest) \\
|
|
1126
|
+
author & string & Creator \\
|
|
1127
|
+
created\_at & date & ISO 8601 date \\
|
|
1128
|
+
modified\_at & date & Last modification date \\
|
|
1129
|
+
modified\_by & string & Last modifier \\
|
|
1130
|
+
depends\_on & array & List of dependency document names \\
|
|
1131
|
+
intent & string & Purpose and rationale \\
|
|
1132
|
+
constraints & array & Hard boundaries \\
|
|
1133
|
+
acceptance\_criteria & array & Testable done conditions \\
|
|
1134
|
+
examples & array & Usage scenarios \\
|
|
1135
|
+
anti\_patterns & array & What to avoid \\
|
|
1136
|
+
preferences & object & Implementation preferences \\
|
|
1137
|
+
\bottomrule
|
|
1138
|
+
\end{longtable}
|
|
1139
|
+
|
|
1140
|
+
\section{Behaviour Schema}\index{Behaviour Schema}
|
|
1141
|
+
|
|
1142
|
+
Validates behaviour configuration files in \texttt{conf/behaviour/}.
|
|
1143
|
+
|
|
1144
|
+
\begin{longtable}{llp{5cm}}
|
|
1145
|
+
\toprule
|
|
1146
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1147
|
+
\midrule
|
|
1148
|
+
name & string & Unique identifier (1--100 chars) \\
|
|
1149
|
+
description & string & Human-readable explanation \\
|
|
1150
|
+
version & string & Semantic version \\
|
|
1151
|
+
author & string & Creator \\
|
|
1152
|
+
created\_at & date & Creation date \\
|
|
1153
|
+
modified\_at & date & Last modification \\
|
|
1154
|
+
modified\_by & string & Last modifier \\
|
|
1155
|
+
sensitive & boolean & Exclude from API analysis \\
|
|
1156
|
+
used\_in & array & Projects using this behaviour \\
|
|
1157
|
+
rules & array & Operational rules (min 1) \\
|
|
1158
|
+
\bottomrule
|
|
1159
|
+
\end{longtable}
|
|
1160
|
+
|
|
1161
|
+
\subsection{Rule Schema}
|
|
1162
|
+
|
|
1163
|
+
Each rule within a behaviour has:
|
|
1164
|
+
|
|
1165
|
+
\begin{longtable}{llp{5cm}}
|
|
1166
|
+
\toprule
|
|
1167
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1168
|
+
\midrule
|
|
1169
|
+
id & string & Unique rule identifier \\
|
|
1170
|
+
description & string & What this rule instructs \\
|
|
1171
|
+
priority & integer & 1--100 (90--100 critical, 70--89 high,
|
|
1172
|
+
50--69 medium, 30--49 low, 1--29 minimal) \\
|
|
1173
|
+
enabled & boolean & Whether rule is active \\
|
|
1174
|
+
\bottomrule
|
|
1175
|
+
\end{longtable}
|
|
1176
|
+
|
|
1177
|
+
\section{Claude Code Config Schema}\index{CC Config Schema}
|
|
1178
|
+
|
|
1179
|
+
Validates Claude Code configuration files in \texttt{conf/claude\_code/}.
|
|
1180
|
+
This is the most complex schema, covering all Claude Code settings.
|
|
1181
|
+
|
|
1182
|
+
\subsection{Top-Level Sections}
|
|
1183
|
+
|
|
1184
|
+
\begin{longtable}{lp{8cm}}
|
|
1185
|
+
\toprule
|
|
1186
|
+
\textbf{Section} & \textbf{Description} \\
|
|
1187
|
+
\midrule
|
|
1188
|
+
model & Default model, available models, effort level \\
|
|
1189
|
+
permissions & Allow/deny/ask lists with glob patterns \\
|
|
1190
|
+
sandbox & Network restrictions, command filtering \\
|
|
1191
|
+
context & Token limits, compaction threshold \\
|
|
1192
|
+
display & Language, progress bar, spinner configuration \\
|
|
1193
|
+
hooks & Pre/post tool-use event handlers \\
|
|
1194
|
+
mcp & Model Context Protocol server policies \\
|
|
1195
|
+
attribution & Commit and PR attribution strings \\
|
|
1196
|
+
api & API key helpers, provider configuration \\
|
|
1197
|
+
system & Auto-updates, cleanup, team mate mode \\
|
|
1198
|
+
env & Pass-through environment variables \\
|
|
1199
|
+
\bottomrule
|
|
1200
|
+
\end{longtable}
|
|
1201
|
+
|
|
1202
|
+
\section{Target Profile Schema}\index{Target Schema}
|
|
1203
|
+
|
|
1204
|
+
Validates compiler target profiles in \texttt{conf/targets/}.
|
|
1205
|
+
|
|
1206
|
+
\begin{longtable}{llp{5cm}}
|
|
1207
|
+
\toprule
|
|
1208
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1209
|
+
\midrule
|
|
1210
|
+
name & string & Target identifier \\
|
|
1211
|
+
backend & enum & claude, generic \\
|
|
1212
|
+
output\_format & enum & markdown, json, yaml \\
|
|
1213
|
+
output\_dir & string/null & Override output directory \\
|
|
1214
|
+
max\_context\_window & integer/null & Max tokens \\
|
|
1215
|
+
rendering & object & Source metadata, priority annotations, marker \\
|
|
1216
|
+
\bottomrule
|
|
1217
|
+
\end{longtable}
|
|
1218
|
+
|
|
1219
|
+
\section{Content Pack Manifest Schema}\index{Content Pack Schema}
|
|
1220
|
+
|
|
1221
|
+
Validates premium content pack manifests.
|
|
1222
|
+
|
|
1223
|
+
\begin{longtable}{llp{5cm}}
|
|
1224
|
+
\toprule
|
|
1225
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1226
|
+
\midrule
|
|
1227
|
+
name & string & Pack identifier (lowercase, underscores) \\
|
|
1228
|
+
version & string & Semantic version \\
|
|
1229
|
+
tier\_required & enum & supporter, subscriber, enterprise \\
|
|
1230
|
+
description & string & Human-readable description \\
|
|
1231
|
+
author & string & Pack author \\
|
|
1232
|
+
contents & object & behaviours and designs arrays \\
|
|
1233
|
+
\bottomrule
|
|
1234
|
+
\end{longtable}
|
|
1235
|
+
|
|
1236
|
+
\section{Packaging Schema}\index{Packaging Schema}
|
|
1237
|
+
|
|
1238
|
+
Validates Debian packaging variant configurations.
|
|
1239
|
+
|
|
1240
|
+
\begin{longtable}{llp{5cm}}
|
|
1241
|
+
\toprule
|
|
1242
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1243
|
+
\midrule
|
|
1244
|
+
name & string & Debian package name (nncc*) \\
|
|
1245
|
+
variant & enum & core, gtk4, qt6, kde \\
|
|
1246
|
+
description & string & Package description \\
|
|
1247
|
+
ui\_adapter & enum & tui, gtk4, qt6, kde \\
|
|
1248
|
+
system\_dependencies & array & Debian package names \\
|
|
1249
|
+
package\_dependencies & array & nncc packages with versions \\
|
|
1250
|
+
\bottomrule
|
|
1251
|
+
\end{longtable}
|
|
1252
|
+
|
|
1253
|
+
\section{Tooling Schema}\index{Tooling Schema}
|
|
1254
|
+
|
|
1255
|
+
Validates the tool registry for external CLI tool management.
|
|
1256
|
+
|
|
1257
|
+
\begin{longtable}{llp{5cm}}
|
|
1258
|
+
\toprule
|
|
1259
|
+
\textbf{Field} & \textbf{Type} & \textbf{Description} \\
|
|
1260
|
+
\midrule
|
|
1261
|
+
tools & object & Map of tool names to configs \\
|
|
1262
|
+
\quad description & string & Tool description \\
|
|
1263
|
+
\quad permission\_pattern & string & Claude Code pattern \\
|
|
1264
|
+
\quad category & enum & json, yaml, search, text, system, network \\
|
|
1265
|
+
\quad packages & object & Package manager to package name map \\
|
|
1266
|
+
\bottomrule
|
|
1267
|
+
\end{longtable}
|
|
1268
|
+
|
|
1269
|
+
%------------------------------------------------------------------------------
|
|
1270
|
+
% BIBLIOGRAPHY
|
|
1271
|
+
%------------------------------------------------------------------------------
|
|
1272
|
+
|
|
1273
|
+
\chapter*{Bibliography}
|
|
1274
|
+
\addcontentsline{toc}{chapter}{\textcolor{ocre}{Bibliography}}
|
|
1275
|
+
|
|
1276
|
+
\printbibliography[heading=bibempty]
|
|
1277
|
+
|
|
1278
|
+
%------------------------------------------------------------------------------
|
|
1279
|
+
% INDEX
|
|
1280
|
+
%------------------------------------------------------------------------------
|
|
1281
|
+
|
|
1282
|
+
\cleardoublepage
|
|
1283
|
+
\phantomsection
|
|
1284
|
+
\setlength{\columnsep}{0.75cm}
|
|
1285
|
+
\addcontentsline{toc}{chapter}{\textcolor{ocre}{Index}}
|
|
1286
|
+
\printindex
|
|
1287
|
+
|
|
1288
|
+
\end{document}
|