



  

<!DOCTYPE html>
<html
  lang="en"
  
  data-color-mode="auto" data-light-theme="light" data-dark-theme="dark"
  data-a11y-animated-images="system" data-a11y-link-underlines="true"
  
  >




  <head>
    <meta charset="utf-8">
  <link rel="dns-prefetch" href="https://github.githubassets.com">
  <link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
  <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
  <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
  <link rel="preconnect" href="https://github.githubassets.com" crossorigin>
  <link rel="preconnect" href="https://avatars.githubusercontent.com">

<script type="importmap">{"imports":{"react":"https://github.githubassets.com/assets/react-e27d1b3e03961e68.js","react-dom":"https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js","react-dom/client":"https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js","react-is":"https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js","react-reconciler":"https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js","react/compiler-runtime":"https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js","react/jsx-dev-runtime":"https://github.githubassets.com/assets/react-jsx-dev-runtime-ea55d68667d559e5.js","react/jsx-runtime":"https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js","scheduler":"https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js"}}</script>
<meta name="react-profiling" content="0" data-turbo-transient="true" />
<meta name="react-import-map" content="react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@777f63f87cd0" data-turbo-track="reload" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-e27d1b3e03961e68.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js" />

  


  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-5c4e9fc574bf49f3.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light_high_contrast-fb37c309e0603a69.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-afff6c53aef9b9d1.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark_high_contrast-c409873d7987dffa.css" /><link data-color-theme="light" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light-5c4e9fc574bf49f3.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-fb37c309e0603a69.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-0f910d8806d5761b.css" /><link data-color-theme="light_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind_high_contrast-a7abd4d4c49ac593.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-5fc4c4a9cb41e596.css" /><link data-color-theme="light_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia_high_contrast-ed0cee9214dedabd.css" /><link data-color-theme="dark" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark-afff6c53aef9b9d1.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-c409873d7987dffa.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-78a2491d538dab5a.css" /><link data-color-theme="dark_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind_high_contrast-c26b63d7c532d0a2.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-a6f60cea68c08405.css" /><link data-color-theme="dark_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia_high_contrast-f66faf28b2ea18b6.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-6701f6218c53cf5b.css" /><link data-color-theme="dark_dimmed_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed_high_contrast-7037fa46ae124d97.css" />

  <style type="text/css">
    :root {
      --tab-size-preference: 4;
    }

    pre, code {
      tab-size: var(--tab-size-preference);
    }
  </style>

    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-97df7784617ce1ea.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-9be9fe6313f476af.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-62747e27e61258dc.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-b04ca6fccda778e2.css" />
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-72bd7d974b5ac1cc.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-4c5c0895f723f870.css" />

  

  <script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_caches_react_shell","actions_enable_background_steps","actions_new_hosted_runner_image_select_sizes_and_versions","actions_runners_react_shell","agent_author_search_expansion","agent_author_search_expansion_ui_pulls","alternate_user_config_repo","async_conversion_coverage_enabled","billing_billable_licenses_cost_center_bucket_fix","billing_budget_expiration","billing_cost_center_list_assigned_resources","billing_discount_threshold_notification","code_quality_enablement_banner_targeting","code_quality_remove_preview","code_view_raf_sticky_lines","codespaces_prebuild_region_target_update","coding_agent_third_party_model_ui","copilot_agent_snippy","copilot_ahp_tool_call_timing","copilot_api_agentic_issue_marshal_yaml","copilot_automation_repo_mcp_servers","copilot_automations_pagination","copilot_base_model_policy_row","copilot_chat_auto_mode_v2","copilot_chat_clear_model_selection_for_default_change","copilot_chat_early_task_provisioning","copilot_chat_persist_session_drafts","copilot_chat_vision_dotcom_chat_ga_gate","copilot_css_textarea_autosize","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_removal_on_marketplace","copilot_fix_failed_workflows_all_skus","copilot_hide_hovercard","copilot_immersive_task_hyperlinking","copilot_mc_cli_resume_any_users_task","copilot_mission_control_agent_merge_fix_ci","copilot_mission_control_agent_merge_resolve_conflicts","copilot_mission_control_awps_batching","copilot_mission_control_early_stop","copilot_mission_control_managed_sandbox_environments","copilot_mission_control_needs_attention","copilot_mission_control_reasoning_effort","copilot_mission_control_sandbox_remote_bypass","copilot_mission_control_task_alive_updates","copilot_mission_control_task_sharing","copilot_org_policy_page_focus_mode","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_swe_agent_authorization_status_ui","copilot_swe_agent_automation_resource_scoped_writes","copilot_swe_agent_discussion_comment_trigger","copilot_swe_agent_discussion_opened_trigger","copilot_swe_agent_discussion_updated_trigger","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_issue_assigned_trigger","copilot_swe_agent_issue_comment_trigger","copilot_swe_agent_issue_labeled_trigger","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_pull_request_assigned_trigger","copilot_swe_agent_pull_request_comment_trigger","copilot_swe_agent_pull_request_labeled_trigger","copilot_swe_agent_pull_request_merged_trigger","copilot_swe_agent_pull_request_opened_trigger","copilot_swe_agent_pull_request_ready_for_review_trigger","copilot_swe_agent_pull_request_review_requested_trigger","copilot_swe_agent_pull_request_review_submitted_trigger","copilot_swe_agent_pull_request_synchronize_trigger","copilot_swe_agent_sub_issue_added_trigger","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_task_scoped_alive_channel","copilot_token_based_billing","copilot_unconfigured_is_inherited","copilot_user_can_upgrade_plan_field","copilot_web_integration_cutover","copilot_workbench_sunset_redirect","dashboard_agents_module_auth_token_check","dashboard_indexeddb_caching","fgpat_permissions_selector_redesign","glc_code_quality_repo_settings_workflow_config","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","in_product_messaging_datadog_monitoring","ipm_ubb_individual_budget_banner","issue_fields_multi_select","issue_inline_avatars","issue_pinned_views","issue_pinned_views_team_vs_personal","issue_relative_time_micro","issue_viewer_paved_path","issues_expanded_file_types","issues_hide_closed_sub_issues","issues_lazy_load_comment_box_suggestions","issues_react_chrome_container_query_fix","labels_archiving","labels_archiving_info","landing_pages_ninetailed","lifecycle_label_name_updates","marketing_cookie_consent_banner","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_queue_restricted_pushers_warning","merge_status_header_feedback","milestone_closed_issues_prioritization","octocaptcha_origin_optimization","primer_react_css_anchor_positioning","primer_react_merged_forwarded_refs","primer_react_timeline_list_semantics","prs_copilot_app_open_action","prs_css_anchor_positioning","pull_request_copilot_attribution_header","pull_request_overview_merge_control","pull_request_overview_panel_edit_description","pull_request_persister","pull_request_stacks_navigation_shortcuts","pull_request_virtualization_image_estimate","pull_request_virtualization_loader_batching","pull_request_virtualization_scroll_compensation","pull_request_virtualization_scroll_intent","quick_search_lazy_suggestions","react_blob_isolate_code_lines","react_blob_ssr_content_visibility","react_data_router_tanstack_allowed","react_logged_out_repository_header","react_query_props_with_key","react_sandbox_future_tanstack","repo_app_turbo","repo_issues_sidebar_layout","repo_pulls_dashboard_declutter","repo_pulls_dashboard_ga","repo_pulls_dashboard_persistence","repos_contributors_limited_default_range","review_involves_filter","rule_ignored_file_paths","rulesets_actor_list_editor","sample_network_conn_type","security_center_artifact_filters_popover","see_who_reacted","semantic_similarity_duplicate_issue_detection","session_logs_ungroup_reasoning_text","set_sha256_on_repo_creation_form","site_banner_desktop_copilot_app","site_ghca_pixel_mona","site_github_app_ga_page","site_github_app_ga_page_highlight","site_github_app_mobile_native_share","site_global_banner_dev_days_attendee","site_global_nav_spark_models_removed","speculation_rules_ui_service","suggest_custom_property_values_copilot","suppress_automated_browser_vitals","swp_forms_disable_octocaptcha","thread_resolution_reason","update_issue_suggestions","viewscreen_sandbox","warn_inaccessible_attachments","webp_support","workstream_plugin_bootstrap"],"githubDomain":"https://github.com","copilotApiOverrideUrl":"https://api.githubcopilot.com","cmcApiUrl":"https://api.github.com/cmc_internal/api"}</script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/high-contrast-cookie-3663bcaacc724f4c.js"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wp-runtime-721126455a2225e3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-foundation-156c6259e31cc551.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-runtime-f6ce38f47c2e1d56.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fetch-utilities-804a14996977c014.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ser-fb5d13278eb42203.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tp-ea613009a991e211.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/environment-107a7753389a8a2d.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-runtime.25915bc98fb322a6.module.css" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/catalyst-52ed81112a548e10.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/selector-observer-e8810f64c443fb9b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/relative-time-element-fe7e72f699fdf493.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/by-9da36843ba9d191d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ja9-9a1160b939f2cd52.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3h-55903cf2303047ad.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hk-0d35a1220587d888.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jz5-c964b1a3671f2a92.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hj-1d800d09e9a8720a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j0-1ad12374da9777f2.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/github-elements-531d35538b61fd0d.js" defer="defer"></script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/element-registry-bf5e3b2aee197122.js" defer="defer"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/runtime-helpers-5e0b3ae3c4036207.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/aria-live-752acdc868e2da64.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hotkey-e87ffadced20a3c9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-core-75bc55d9971828b7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a9-34620c7b13885011.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ur-643d2814115561a9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4t6-5d0869970ac0aac0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pb0-a5c5ec36d311aeef.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/6n-afcf86ccabc4cad2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zj-f08c728cf00018aa.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/o6-2a1c68d269710ee9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/h9a-c6405aa090de0e84.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/vy6-3c3e6e96629c2ce4.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/js-4eb97d5803e657c0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/g7-baf9e817ae102b01.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/unc-96389cade7bad821.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/nu-65322a6997c6c93c.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/behaviors-5dd3809b5c8bac3c.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-core.3792087592bf207a.module.css" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-menu-4318f0f4c608f3dd.js" defer="defer"></script>
  
  <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/primer-react-7afef75d393cf294.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/op-acddf38478d45ef9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ncx-461e4b09f2e67ee5.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/qmp-c7cfba40cf5a93b0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j6-148a74299e5a01ab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t7l-a52ba56147f77909.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4u-ec4874f70bfd5d76.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s0-481bd34f90bc2bd7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/y5-ed17e73b4c0bd15e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/n4-be595475cdbf7d4b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j8-23a3c5ff8eef412d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/la-27679061f16e1495.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/iu-9806a0291a782cbe.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ftx-39fb490e3c1d778f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zi-32a0c3c081ea5cce.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sg-7a5d50475874c0e1.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pd-6a8710840033e042.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/86g-ec28c25ed7d5de06.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sn-1bab7384818953b7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/iq-6d4ecf6d2fb6993c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p2-7d8e7cee5b46cb45.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7d-2e3cc25d719f3a95.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4d-76d8acdf21a33266.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tsb-e0f6288ab985d9d2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/lf-910ef220ce85c660.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/2j-2f19c1afd2ceaf93.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/me-f1476ec44a29f34a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p2u-e654a57b1a70c47d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5d-d97cc006d4da4d9b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r5-38f013bc2c0fd298.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r6s-9039f5619230a653.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/9e-cece06724bf6ea3b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/x9-3e077a3a37a73f9f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pj-87629cb5389d7663.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/eq-3764fd5f66494289.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/13-d889936dff7e5c0f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/44-8193eea4af825ead.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/v4-9c1327d212e52a0d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/id-7f39706ba9007db6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ah-271362a1ed227d03.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s1g-d434d712bca59d3a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/vz-d7f4a583896f872e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/47-c8c0ce2700acc5be.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-view-4118a687d0150749.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/pj.75627bfeb9ceb1da.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/ah.2623f7c6ecbe2ecd.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/47.78770c57a48a810c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-view.37656c95a9729fb9.module.css" />


  <title>RuView/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md at main · Esbroro/RuView · GitHub</title>



  <meta name="route-pattern" content="/:user_id/:repository/blob/*name(/*path)" data-turbo-transient>
  <meta name="route-controller" content="blob" data-turbo-transient>
  <meta name="route-action" content="show" data-turbo-transient>
  <meta name="fetch-nonce" content="v2:0fcd4dd8-4212-8c73-5a14-c3bf1748764b">

    
  <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb">


  <meta name="request-id" content="BE1A:300585:D5A7F3A:1153C0AE:6ACAA44D" data-pjax-transient="true"/><meta name="html-safe-nonce" content="2ca9ee4ab558f0e60a63030d3a60049977dc6b086b8aad246376fc26a22cd592" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCRTFBOjMwMDU4NTpENUE3RjNBOjExNTNDMEFFOjZBQ0FBNDREIiwidmlzaXRvcl9pZCI6IjMxMDg1MTQxOTc1MjU5MzEwODUiLCJyZWdpb25fZWRnZSI6ImZyYSIsInJlZ2lvbl9yZW5kZXIiOiJmcmEifQ==" data-pjax-transient="true"/><meta name="visitor-hmac" content="70b56d177f7eab126844cdfb3f48081348f50cbef021e68a7486d85062ccac1e" data-pjax-transient="true"/>


    <meta name="hovercard-subject-tag" content="repository:1343065552" data-turbo-transient>


  <meta name="github-keyboard-shortcuts" content="repository,source-code,file-tree,copilot" data-turbo-transient="true" />
  

  <meta name="selected-link" value="repo_source" data-turbo-transient>
  <link rel="assets" href="https://github.githubassets.com/">

    <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I">

<meta name="octolytics-url" content="https://collector.github.com/github/collect" />





  <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show" data-turbo-transient="true" />

  




    <meta name="user-login" content="">

  

    <meta name="viewport" content="width=device-width">

    

      <meta name="description" content="π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video. - RuView/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md at main · Esbroro/RuView">

      <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">

    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
    <meta property="fb:app_id" content="1401488693436528">
    <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md" />

      <meta name="twitter:image" content="https://opengraph.githubassets.com/0f194c4c12f3d814fec843d8e2e6890e1b4b4b77c8de8ef102aca531c6102a50/Esbroro/RuView" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="RuView/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md at main · Esbroro/RuView" /><meta name="twitter:description" content="π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video. - Esbroro/RuView" />
  <meta property="og:image" content="https://opengraph.githubassets.com/0f194c4c12f3d814fec843d8e2e6890e1b4b4b77c8de8ef102aca531c6102a50/Esbroro/RuView" /><meta property="og:image:alt" content="π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video. - Esbroro/RuView" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="RuView/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md at main · Esbroro/RuView" /><meta property="og:url" content="https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md" /><meta property="og:description" content="π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video. - Esbroro/RuView" />
  




      <meta name="hostname" content="github.com">



        <meta name="expected-hostname" content="github.com">


  <meta http-equiv="x-pjax-version" content="d05be8f8b6905b6460fc264e80447721dfee1e32cf9e4291c4bf58f160c9f705" data-turbo-track="reload">
  <meta http-equiv="x-pjax-csp-version" content="c4a65e47b0c850e1157ae8e66298070851d7e3b558038de5a3b4ff7a93e630ed" data-turbo-track="reload">
  <meta http-equiv="x-pjax-css-version" content="a80b0545b169f440b929ce2b977c76b6988f014cca6513fb83c5df6581635fb3" data-turbo-track="reload">
  <meta http-equiv="x-pjax-js-version" content="af51c6f9d659be0324665373df3ee542f817dbd7f66f352a087935f2ceabe545" data-turbo-track="reload">

  <meta name="turbo-cache-control" content="no-preview" data-turbo-transient="">

      <meta name="turbo-cache-control" content="no-cache" data-turbo-transient>

    <meta data-hydrostats="publish">

  <meta name="go-import" content="github.com/Esbroro/RuView git https://github.com/Esbroro/RuView.git">

  <meta name="octolytics-dimension-user_id" content="257900615" /><meta name="octolytics-dimension-user_login" content="Esbroro" /><meta name="octolytics-dimension-repository_id" content="1343065552" /><meta name="octolytics-dimension-repository_nwo" content="Esbroro/RuView" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="true" /><meta name="octolytics-dimension-repository_parent_id" content="997737944" /><meta name="octolytics-dimension-repository_parent_nwo" content="ruvnet/RuView" /><meta name="octolytics-dimension-repository_network_root_id" content="997737944" /><meta name="octolytics-dimension-repository_network_root_nwo" content="ruvnet/RuView" />
  



    

    <meta name="turbo-body-classes" content="logged-out env-production page-responsive">
  <meta name="disable-turbo" content="false">


  <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">


  <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">

  <meta name="release" content="3b1bb5b10f5c7fd1769d56e38b15dfddb34052a8" data-turbo-track="reload">
  <meta name="ui-target" content="full">

  <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000">
  <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png">
  <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon">

<meta name="theme-color" content="#1e2327">
<meta name="color-scheme" content="light dark" />


  <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials">

  </head>

  <body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
    <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
      <div id="__primerPortalRoot__" style="z-index: 1000; position: absolute; width: 100%;" data-turbo-permanent></div>
      

    <div class="position-relative header-wrapper js-header-wrapper ">
      <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 tmp-py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a>

      <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full">
    <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span>
</span>      
      <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/19-c660652a0a1639be.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-47c5223d8d1af8ef.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog.d53d993320d57e14.module.css" />

<react-partial
  partial-name="keyboard-shortcuts-dialog"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>





      

          <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-install-banner-partial-3c87deb7f0f20434.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-install-banner-partial.7b357012e82003e7.module.css" />

<react-partial
  partial-name="app-install-banner-partial"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>


          

                <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/et9-7eeec247c287fca4.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/94v-e20946127faa8f6e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fz5-892a9e99cc92858d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jag-441e702bfd4c7904.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hw-8ce7888b57d0a23c.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/rq-0ec82a12cf538a4d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/1m-a7a4c022483b2713.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/marketing-header-70703fe17422eb58.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-brand-css.fbc35b3d20e988ff.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/1m.fec8b575d0e5234f.module.css" />

<react-partial
  partial-name="marketing-header"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"color_mode":"dark","logged_in":false,"marketing_page":false,"home_path":"/","login_path":"/login?return_to=https%3A%2F%2Fgithub.com%2FEsbroro%2FRuView%2Fblob%2Fmain%2Fdocs%2Fadr%2FADR-096-rvcsi-ffi-crate-layout.md","signup_path":"/signup?ref_cta=Sign+up\u0026ref_loc=header+logged+out\u0026ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow\u0026source=header-repo\u0026source_repo=Esbroro%2FRuView","signup_enabled":true,"is_signup_controller":false,"show_search_and_nav":true,"hide_search":false,"private_mode_enabled":false,"should_use_dotcom_links":true,"auth_hydro_click":"{\"event_type\":\"authentication.click\",\"payload\":{\"location_in_page\":\"site header menu\",\"repository_id\":null,\"auth_type\":\"SIGN_UP\",\"originating_url\":\"https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md\",\"user_id\":null}}","auth_hydro_click_hmac":"facd6c265f578bdae856c2473f518e87f1382927855b8d063b19e992c2aeb5e5","overlay":false,"fixed":false}}</script>
  <div data-target="react-partial.reactRoot"><div data-color-mode="dark" data-light-theme="light" data-dark-theme="dark"><header class="MarketingHeader-module__root__Tk7n3 HeaderMktg header-logged-out" role="banner" data-marketing-header="true" data-color-mode="dark" data-light-theme="light" data-dark-theme="dark" data-is-top="true"><h2 class="MarketingHeader-module__visuallyHidden__sqKsl">Navigation Menu</h2><button type="button" class="MarketingHeader-module__backdrop__sw4RU" aria-label="Close navigation menu"></button><div class="MarketingHeader-module__bar__mBSyE"><div class="MarketingHeader-module__topRow__yeury"><div class="MarketingHeader-module__toggleSlot__hDxbh"><button type="button" class="HeaderMenuToggle-module__toggle__i8EiC" aria-label="Toggle navigation" aria-expanded="false"><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span></button></div><a href="/" aria-label="Homepage" class="HeaderLogo-module__logo__UFyHI" data-analytics-event="{&quot;action&quot;:&quot;homepage&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;logo&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;homepage_link_logo_header&quot;}"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github" viewBox="0 0 24 24" width="32" height="32" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path></svg></a><div class="AuthCTAs-module__mobileActions__NNzeV"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/login?return_to=https%3A%2F%2Fgithub.com%2FEsbroro%2FRuView%2Fblob%2Fmain%2Fdocs%2Fadr%2FADR-096-rvcsi-ffi-crate-layout.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="facd6c265f578bdae856c2473f518e87f1382927855b8d063b19e992c2aeb5e5"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_3dd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_3dd_">Appearance settings</div></div></div><div class="MarketingHeader-module__menu__GIy3y"><div class="MarketingHeader-module__menuWrapper__owstH"><nav class="MarketingNavigation-module__nav__W0KYY" aria-label="Global"><ul class="MarketingNavigation-module__list__tFbMb"><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_nd_">Platform<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5knd_">AI CODE CREATION</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot" data-analytics-event="{&quot;action&quot;:&quot;github_copilot&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>GitHub Copilot</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Write better code with AI</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/ai/github-app" data-analytics-event="{&quot;action&quot;:&quot;github_copilot_app&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_app_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.766 11.328c-2.063-.25-3.516-1.734-3.516-3.656 0-.781.281-1.625.75-2.188-.203-.515-.172-1.609.063-2.062.625-.078 1.468.25 1.968.703.594-.187 1.219-.281 1.985-.281.765 0 1.39.094 1.953.265.484-.437 1.344-.765 1.969-.687.218.422.25 1.515.046 2.047.5.593.766 1.39.766 2.203 0 1.922-1.453 3.375-3.547 3.64.531.344.89 1.094.89 1.954v1.625c0 .468.391.734.86.547C13.781 14.359 16 11.53 16 8.03 16 3.61 12.406 0 7.984 0 3.563 0 0 3.61 0 8.031a7.88 7.88 0 0 0 5.172 7.422c.422.156.828-.125.828-.547v-1.25c-.219.094-.5.156-.75.156-1.031 0-1.64-.562-2.078-1.609-.172-.422-.36-.672-.719-.719-.187-.015-.25-.093-.25-.187 0-.188.313-.328.625-.328.453 0 .844.281 1.25.86.313.452.64.655 1.031.655s.641-.14 1-.5c.266-.265.47-.5.657-.656"></path></svg>GitHub Copilot app</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Direct agents from issue to merge</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/mcp" data-analytics-event="{&quot;action&quot;:&quot;mcp_registry&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;mcp_registry_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mcp NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.52 1.12a3.578 3.578 0 0 1 6.078 2.98 3.578 3.578 0 0 1 2.982 6.08l-3.292 3.293a.252.252 0 0 0 0 .354l.843.843a.749.749 0 1 1-1.06 1.06l-.844-.843a1.75 1.75 0 0 1 0-2.474L13.52 9.12a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0L7.731 9.03A.75.75 0 0 1 6.67 7.97l2.85-2.85a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0l-4.799 4.8A.75.75 0 0 1 .72 5.92Z"></path><path d="M7.52 3.12a.749.749 0 1 1 1.06 1.06L5.731 7.03A2.079 2.079 0 0 0 8.67 9.97l2.85-2.85a.749.749 0 1 1 1.06 1.06l-2.849 2.85A3.578 3.578 0 0 1 4.67 5.97Z"></path></svg>MCP Registry</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Integrate external tools</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9knd_">DEVELOPER WORKFLOWS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/actions" data-analytics-event="{&quot;action&quot;:&quot;actions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;actions_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-workflow NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path></svg>Actions</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Automate any workflow</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/codespaces" data-analytics-event="{&quot;action&quot;:&quot;codespaces&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;codespaces_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codespaces NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path></svg>Codespaces</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Instant dev environments</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/issues" data-analytics-event="{&quot;action&quot;:&quot;issues&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;issues_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-issue-opened NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg>Issues</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Plan and track work</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-review" data-analytics-event="{&quot;action&quot;:&quot;code_review&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_review_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg>Code Review</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Manage code changes</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-quality" data-analytics-event="{&quot;action&quot;:&quot;code_quality&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_quality_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codescan-checkmark NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.28 6.28a.75.75 0 1 0-1.06-1.06L6.25 8.19l-.97-.97a.75.75 0 0 0-1.06 1.06l1.5 1.5a.75.75 0 0 0 1.06 0l3.5-3.5Z"></path><path d="M7.5 15a7.5 7.5 0 1 1 5.807-2.754l2.473 2.474a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2.474-2.473A7.472 7.472 0 0 1 7.5 15Zm0-13.5a6 6 0 1 0 4.094 10.386.748.748 0 0 1 .293-.292 6.002 6.002 0 0 0 1.117-6.486A6.002 6.002 0 0 0 7.5 1.5Z"></path></svg>Code Quality</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enforce quality at merge</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dknd_">APPLICATION SECURITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Find and fix vulnerabilities</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/code-security" data-analytics-event="{&quot;action&quot;:&quot;code_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code-square NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>Code security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Secure your code as you build</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/secret-protection" data-analytics-event="{&quot;action&quot;:&quot;secret_protection&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;secret_protection_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-lock NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M4 4a4 4 0 0 1 8 0v2h.25c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25v-5.5C2 6.784 2.784 6 3.75 6H4Zm8.25 3.5h-8.5a.25.25 0 0 0-.25.25v5.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25ZM10.5 6V4a2.5 2.5 0 1 0-5 0v2Z"></path></svg>Secret protection</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Stop leaks before they start</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ NavGroup-module__hasSeparator__FnMrN"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_hknd_">EXPLORE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_hknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/why-github" data-analytics-event="{&quot;action&quot;:&quot;why_github&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;why_github_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Why GitHub</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog" data-analytics-event="{&quot;action&quot;:&quot;blog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;blog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Blog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog/changelog" data-analytics-event="{&quot;action&quot;:&quot;changelog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;changelog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Changelog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/marketplace" data-analytics-event="{&quot;action&quot;:&quot;marketplace&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;marketplace_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Marketplace</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/features" data-analytics-event="{&quot;action&quot;:&quot;view_all_features&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_features_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all features</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_17d_">Solutions<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_17d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5l7d_">BY COMPANY SIZE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprises&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprises_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Enterprises</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/team" data-analytics-event="{&quot;action&quot;:&quot;small_and_medium_teams&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;small_and_medium_teams_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Small and medium teams</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise/startups" data-analytics-event="{&quot;action&quot;:&quot;startups&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;startups_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Startups</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/nonprofits" data-analytics-event="{&quot;action&quot;:&quot;nonprofits&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;nonprofits_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Nonprofits</span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9l7d_">BY USE CASE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/app-modernization" data-analytics-event="{&quot;action&quot;:&quot;app_modernization&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;app_modernization_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">App Modernization</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devsecops" data-analytics-event="{&quot;action&quot;:&quot;devsecops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devsecops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevSecOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/ci-cd" data-analytics-event="{&quot;action&quot;:&quot;ci/cd&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ci/cd_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">CI/CD</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/use-case" data-analytics-event="{&quot;action&quot;:&quot;view_all_use_cases&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_use_cases_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all use cases</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dl7d_">BY INDUSTRY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dl7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/healthcare" data-analytics-event="{&quot;action&quot;:&quot;healthcare&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;healthcare_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Healthcare</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/financial-services" data-analytics-event="{&quot;action&quot;:&quot;financial_services&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;financial_services_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Financial services</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/manufacturing" data-analytics-event="{&quot;action&quot;:&quot;manufacturing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;manufacturing_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Manufacturing</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/government" data-analytics-event="{&quot;action&quot;:&quot;government&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;government_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Government</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/industry" data-analytics-event="{&quot;action&quot;:&quot;view_all_industries&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_industries_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all industries</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions" data-analytics-event="{&quot;action&quot;:&quot;view_all_solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_solutions_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all solutions</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_1nd_">Resources<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_1nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5lnd_">EXPLORE BY TOPIC</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=ai" data-analytics-event="{&quot;action&quot;:&quot;ai&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ai_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">AI</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=software-development" data-analytics-event="{&quot;action&quot;:&quot;software_development&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;software_development_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Software Development</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=security" data-analytics-event="{&quot;action&quot;:&quot;security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources/articles" data-analytics-event="{&quot;action&quot;:&quot;view_all_topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_topics_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all topics</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9lnd_">EXPLORE BY TYPE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/customer-stories" data-analytics-event="{&quot;action&quot;:&quot;customer_stories&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_stories_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer stories</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/events" data-analytics-event="{&quot;action&quot;:&quot;events__webinars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;events__webinars_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Events &amp; webinars</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/whitepapers" data-analytics-event="{&quot;action&quot;:&quot;ebooks__reports&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ebooks__reports_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Ebooks &amp; reports</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/executive-insights" data-analytics-event="{&quot;action&quot;:&quot;business_insights&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;business_insights_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Business insights</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://skills.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_skills&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_skills_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Skills</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dlnd_">SUPPORT &amp; SERVICES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dlnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://support.github.com" data-analytics-event="{&quot;action&quot;:&quot;customer_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_support_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer support</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/orgs/community/discussions" data-analytics-event="{&quot;action&quot;:&quot;community_forum&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;community_forum_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Community forum</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trust-center" data-analytics-event="{&quot;action&quot;:&quot;trust_center&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trust_center_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trust center</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/partners" data-analytics-event="{&quot;action&quot;:&quot;partners&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;partners_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Partners</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources" data-analytics-event="{&quot;action&quot;:&quot;view_all_resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_resources_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all resources</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_27d_">Open Source<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_27d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5m7d_">COMMUNITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/open-source/sponsors" data-analytics-event="{&quot;action&quot;:&quot;github_sponsors&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_sponsors_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sponsor-tiers NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.586 1C12.268 1 13.5 2.37 13.5 4.25c0 1.745-.996 3.359-2.622 4.831-.166.15-.336.297-.509.438l1.116 5.584a.75.75 0 0 1-.991.852l-2.409-.876a.25.25 0 0 0-.17 0l-2.409.876a.75.75 0 0 1-.991-.852L5.63 9.519a13.78 13.78 0 0 1-.51-.438C3.497 7.609 2.5 5.995 2.5 4.25 2.5 2.37 3.732 1 5.414 1c.963 0 1.843.403 2.474 1.073L8 2.198l.112-.125a3.385 3.385 0 0 1 2.283-1.068L10.586 1Zm-3.621 9.495-.718 3.594 1.155-.42a1.75 1.75 0 0 1 1.028-.051l.168.051 1.154.42-.718-3.592c-.199.13-.37.235-.505.314l-.169.097a.75.75 0 0 1-.72 0 9.54 9.54 0 0 1-.515-.308l-.16-.105ZM10.586 2.5c-.863 0-1.611.58-1.866 1.459-.209.721-1.231.721-1.44 0C7.025 3.08 6.277 2.5 5.414 2.5 4.598 2.5 4 3.165 4 4.25c0 1.23.786 2.504 2.128 3.719.49.443 1.018.846 1.546 1.198l.325.21.076-.047.251-.163a13.341 13.341 0 0 0 1.546-1.198C11.214 6.754 12 5.479 12 4.25c0-1.085-.598-1.75-1.414-1.75Z"></path></svg>GitHub Sponsors</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Fund open source developers</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9m7d_">PROGRAMS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://securitylab.github.com" data-analytics-event="{&quot;action&quot;:&quot;security_lab&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_lab_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security Lab</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://maintainers.github.com" data-analytics-event="{&quot;action&quot;:&quot;maintainer_community&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;maintainer_community_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Maintainer Community</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://stars.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_stars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_stars_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Stars</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://archiveprogram.github.com" data-analytics-event="{&quot;action&quot;:&quot;archive_program&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;archive_program_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Archive Program</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dm7d_">REPOSITORIES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dm7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/topics" data-analytics-event="{&quot;action&quot;:&quot;topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;topics_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Topics</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trending" data-analytics-event="{&quot;action&quot;:&quot;trending&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trending_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trending</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/collections" data-analytics-event="{&quot;action&quot;:&quot;collections&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;collections_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Collections</span></a></li></ul></div></li></ul></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_2nd_">Enterprise<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_2nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5mnd_">ENTERPRISE SOLUTIONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprise_platform&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprise_platform_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-stack NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.122.392a1.75 1.75 0 0 1 1.756 0l5.003 2.902c.83.481.83 1.68 0 2.162L8.878 8.358a1.75 1.75 0 0 1-1.756 0L2.119 5.456a1.251 1.251 0 0 1 0-2.162ZM8.125 1.69a.248.248 0 0 0-.25 0l-4.63 2.685 4.63 2.685a.248.248 0 0 0 .25 0l4.63-2.685ZM1.601 7.789a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0L1.874 8.814A.75.75 0 0 1 1.6 7.789Zm0 3.5a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0l-5.248-3.044a.75.75 0 0 1-.273-1.025Z"></path></svg>Enterprise platform</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">AI-powered developer platform</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9mnd_">AVAILABLE ADD-ONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade security features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot/copilot-business" data-analytics-event="{&quot;action&quot;:&quot;copilot_for_business&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;copilot_for_business_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>Copilot for Business</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade AI features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise/premium-support" data-analytics-event="{&quot;action&quot;:&quot;premium_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;premium_support_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-comment-discussion NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path></svg>Premium Support</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade 24/7 support</span></span></a></li></ul></div></li></ul></div></div></li><li><a href="https://github.com/pricing" data-analytics-event="{&quot;action&quot;:&quot;pricing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;pricing&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;pricing_link_pricing_navbar&quot;}" class="MarketingNavigation-module__navLink__hUomM">Pricing</a></li></ul></nav><div class="MarketingHeader-module__ctaContainer__tBmPz"><div class="HeaderSearch-module__searchSlot__oVOUS"><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderSearch-module__trigger__zsF9q" type="button" aria-haspopup="dialog" aria-expanded="false" aria-label="Search or jump to, type / to search" data-analytics-event="{&quot;action&quot;:&quot;searchbar&quot;,&quot;tag&quot;:&quot;input&quot;,&quot;context&quot;:&quot;global&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;searchbar_input_global_navbar&quot;}"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"><span class="HeaderSearch-module__content__kMpxU"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search HeaderSearch-module__icon__wcrHX" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg><span class="HeaderSearch-module__label__d1iWG">Search</span><kbd class="HeaderSearch-module__kbd__HNG0o" aria-hidden="true">/</kbd></span></span></span></button><div class="d-none"></div></div><div class="AuthCTAs-module__signInWrap__q2P60"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq AuthCTAs-module__desktopActionGap__UZuXT AuthCTAs-module__hiddenBelowLg__BfKBw" href="/login?return_to=https%3A%2F%2Fgithub.com%2FEsbroro%2FRuView%2Fblob%2Fmain%2Fdocs%2Fadr%2FADR-096-rvcsi-ffi-crate-layout.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="facd6c265f578bdae856c2473f518e87f1382927855b8d063b19e992c2aeb5e5"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a></div><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--secondary___gHnw_ Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow&amp;source=header-repo&amp;source_repo=Esbroro%2FRuView" data-analytics-event="{&quot;action&quot;:&quot;sign_up&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_up_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="facd6c265f578bdae856c2473f518e87f1382927855b8d063b19e992c2aeb5e5"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-secondary___eJ0_a">Sign up</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_fbd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_fbd_">Appearance settings</div></div></div></div></div><div class="MarketingHeader-module__bottomBorder__uZT38" aria-hidden="true"></div></header></div></div>
</react-partial>



      <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full">
  
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
        <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>

    <button id="icon-button-be87c561-31a2-44ff-93b1-07b051e38eff" aria-labelledby="tooltip-4e0bef94-940a-4b94-96fb-d1ce4e8c3f03" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close">  <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
</button><tool-tip id="tooltip-4e0bef94-940a-4b94-96fb-d1ce4e8c3f03" for="icon-button-be87c561-31a2-44ff-93b1-07b051e38eff" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip>


  
</div>
    </div>

  <div id="start-of-content" class="show-on-focus"></div>








    <div id="js-flash-container" class="flash-container" data-turbo-replace>






  <template class="js-flash-template">
    
<div class="flash flash-full   {{ className }}">
  <div >
    <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    <div aria-atomic="true" role="alert" class="js-flash-alert">
      
      <div>{{ message }}</div>

    </div>
  </div>
</div>
  </template>
</div>


    






  <div
    class="application-main "
    data-commit-hovercards-enabled
    data-discussion-hovercards-enabled
    data-issue-and-pr-hovercards-enabled
    data-project-hovercards-enabled
  >
        <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class="">
    <main id="js-repo-pjax-container" >
      
      








  

    <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ym-6bc2c9bf8112c038.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sk2-8deeef9351be3911.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ni-3e194d222c7770bf.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7x-71d30cb240cd901f.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wwk-ad869086822937b1.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a1-9f79841ecac1da8e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wzg-40a3213b3e83400b.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5f-64f8e7d5bcbd4787.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z5-b53a93078d026f1e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/8h-cef26f68c1331011.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fq-3ce13a77e863807a.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a7-596b507bd20acddc.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/xfx-c82d8352413aea0a.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j4-b3a9e87fa7878a98.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/global-nav-bar-29c7aef68ee9db41.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/pj.75627bfeb9ceb1da.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-nav-bar.2f2560cba06ab359.module.css" />

<react-partial
  partial-name="global-nav-bar"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"contextRegion":{"crumbs":[{"crumb_type":"user","label":"Esbroro","is_root":false,"href":"/Esbroro"},{"crumb_type":"repository","label":"RuView","is_root":false,"octicon":"repo-forked","href":"/Esbroro/RuView"}],"localNavigation":[{"id":"code","icon":"code","label":"Code","href":"/Esbroro/RuView","selectedLinks":["repo_source","repo_downloads","repo_commits","repo_releases","repo_tags","repo_branches","repo_packages","repo_deployments","repo_attestations"],"popoverTarget":false,"commandId":"repositories:go-to-code","reactNav":{"appTarget":"code-view","anchor":"code-view-repo-link"},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"pull-requests","icon":"git-pull-request","label":"Pull requests","href":"/Esbroro/RuView/pulls","selectedLinks":["repo_pulls","checks"],"count":0,"popoverTarget":false,"commandId":"repositories:go-to-pull-requests","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"actions","icon":"play","label":"Actions","href":"/Esbroro/RuView/actions","selectedLinks":["repo_actions"],"popoverTarget":false,"commandId":"repositories:go-to-actions","reactNav":{"appTarget":"actions-workflows","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"projects","icon":"table","label":"Projects","href":"/Esbroro/RuView/projects","selectedLinks":["repo_projects","new_repo_project","repo_project"],"popoverTarget":false,"commandId":"repositories:go-to-projects","reactNav":{"appTarget":"repo","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"security-and-quality","icon":"shield","label":"Security and quality","href":"/Esbroro/RuView/security","selectedLinks":["security","overview","alerts","policy","token_scanning","code_scanning"],"count":0,"popoverTarget":false,"commandId":"repositories:go-to-security","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"insights","icon":"graph","label":"Insights","href":"/Esbroro/RuView/pulse","selectedLinks":["repo_graphs","repo_contributors","dependency_graph","dependabot_updates","pulse","people","community"],"popoverTarget":false,"commandId":"repositories:go-to-insights","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}}],"localNavigationUpdateChannel":null,"selectedLink":"repo_source"},"owner":null,"headerLogo":{"href":"/","aria-label":"Homepage "},"notifications":{"indicatorMode":"disabled","websocketChannel":null,"fetchIndicatorSrc":"/notifications/indicator","fetchIndicatorEnabled":false},"issues":{"href":"/issues"},"pulls":{"href":"/pulls"},"contributedRepos":{"href":"/repos"},"copilot":{"show":false,"showAgentsButton":false,"showRelaunchAnnouncement":false,"copilotChatUrl":null,"copilotApiUrl":"https://api.githubcopilot.com"},"search":{"show":true,"showCommandPalette":false,"isSearchPage":false,"isJumpToSearch":false,"searchContext":{"scope":"repo:Esbroro/RuView","current_repo_name":"RuView","current_repo_nwo":"Esbroro/RuView","user_id":"Esbroro"}},"commandPalette":null,"enterpriseBar":{"show":false},"globalTransactionalMessage":[],"payloadsUrl":"/_global-navigation/payloads.json?can_toggle_site_admin_and_employee_status=0\u0026is_admin_mode_on=0\u0026is_ui_opted_out=0\u0026show_ui_opt_out=0\u0026v=7","contextRegionUrl":"/_global-navigation/context-region.json"}}</script>
  <div data-target="react-partial.reactRoot"><header aria-label="Global navigation menu" data-component="Stack" class="GlobalNav styles-module__appHeader__YzYWk prc-Stack-Stack-UQ9k6" data-gap="none" data-direction="vertical" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="none"><div data-component="Stack" class="prc-Stack-Stack-UQ9k6" data-direction="horizontal" data-align="center" data-wrap="nowrap" data-justify="center" data-padding="none"><div data-testid="top-nav-center" data-component="Stack" class="styles-module__center__R3QRv styles-module__withLocalNavigation__rjTJ_ GlobalNavBar-module__loggedOut__Jv1rk prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="normal"><nav class="styles-module__contextRegion__VbSp2 prc-Breadcrumbs-BreadcrumbsBase-3Gb-B" aria-label="Breadcrumbs" data-overflow="menu" data-variant="normal" data-component="Breadcrumbs"><ol class="prc-Breadcrumbs-BreadcrumbsList-BKjpe"><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="styles-module__contextCrumb__IzGIq prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/Esbroro" data-discover="true"><span class="">Esbroro</span></a></li><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="styles-module__contextCrumb__IzGIq prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/Esbroro/RuView" data-discover="true"><span class="styles-module__contextCrumbLast__tI2e3">RuView</span><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-repo-forked styles-module__trailingIcon__sCKDh" viewBox="0 0 16 16" width="12" height="12" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path></svg></a></li></ol></nav></div><div data-testid="top-nav-right" data-component="Stack" class="styles-module__right__mlBQg styles-module__withLocalNavigation__rjTJ_ styles-module__rightWithResponsiveCreateButton__SKn2W prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="center" data-wrap="nowrap" data-justify="start" data-padding="normal"></div></div><h2 class="prc-src-InternalVisuallyHidden-2YaI6">Repository navigation</h2><nav class="prc-components-UnderlineWrapper-eT-Yj prc-UnderlineNav-UnderlineWrapper-GWONT LocalNavigation-module__LocalNavigation__b0Xc0" aria-label="Repository" data-variant="inset" data-overflow-mode="wrap" data-hide-icons-breakpoint="medium"><ul class="prc-UnderlineNav-ItemsList-oj8gN prc-components-UnderlineItemList-xKlKC" role="list"><li role="presentation" aria-hidden="true" class="prc-UnderlineNav-WrapSpacer--aLgz"></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a aria-current="page" data-tab-item="code" data-react-nav="code-view" data-react-nav-anchor="code-view-repo-link" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/Esbroro/RuView" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg></span><span data-component="text" data-content="Code">Code</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="pull-requests" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/Esbroro/RuView/pulls" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-pull-request" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path></svg></span><span data-component="text" data-content="Pull requests">Pull requests</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="actions" data-react-nav="actions-workflows" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/Esbroro/RuView/actions" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-play" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path></svg></span><span data-component="text" data-content="Actions">Actions</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="projects" data-react-nav="repo" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/Esbroro/RuView/projects" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-table" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path></svg></span><span data-component="text" data-content="Projects">Projects</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="security-and-quality" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/Esbroro/RuView/security" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg></span><span data-component="text" data-content="Security and quality">Security and quality</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="insights" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/Esbroro/RuView/pulse" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-graph" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg></span><span data-component="text" data-content="Insights">Insights</span></a></li></ul><div class="prc-UnderlineNav-MoreButtonContainer-Dnrq6"><div class="prc-UnderlineNav-MoreButtonDivider-dN0a-"></div><button data-component="overflow-menu-button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk prc-UnderlineNav-MoreButton-Y8soj" data-loading="false" data-size="medium" data-variant="invisible" id="_R_2ktp_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3"><span>More<span class="prc-src-InternalVisuallyHidden-2YaI6"> items</span></span></span></span><span data-component="trailingAction" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></button></div></nav><div class="d-none"></div></header></div>
</react-partial>


  



<turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class="">
    <div id="repo-content-pjax-container" class="repository-content " >
    



    
      
    








<react-app
  app-name="code-view"
  initial-path="/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md"
  style="display: block; min-height: calc(100vh - 64px);"
  data-attempted-ssr="true"
  data-ssr="true"
  data-lazy="false"
  data-alternate="false"
  data-data-router-enabled="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-app.embeddedData">{"payload":{"codeViewBlobRoute":{"csv":null,"csvError":null,"headerInfo":{"toc":[{"level":1,"text":"ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface","anchor":"adr-096-rvcsi--crate-topology-the-napi-c-shim-and-the-napi-rs-node-surface","htmlText":"ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface"},{"level":2,"text":"1. Context","anchor":"1-context","htmlText":"1. Context"},{"level":2,"text":"2. Decision","anchor":"2-decision","htmlText":"2. Decision"},{"level":3,"text":"2.1 Crate topology","anchor":"21-crate-topology","htmlText":"2.1 Crate topology"},{"level":3,"text":"2.2 The napi-c shim — record formats and contract","anchor":"22-the-napi-c-shim--record-formats-and-contract","htmlText":"2.2 The napi-c shim — record formats and contract"},{"level":3,"text":"2.3 The napi-rs surface — what crosses the seam","anchor":"23-the-napi-rs-surface--what-crosses-the-seam","htmlText":"2.3 The napi-rs surface — what crosses the seam"},{"level":3,"text":"2.4 Build \u0026 test invariants","anchor":"24-build--test-invariants","htmlText":"2.4 Build \u0026amp; test invariants"},{"level":2,"text":"3. Consequences","anchor":"3-consequences","htmlText":"3. Consequences"},{"level":2,"text":"4. Alternatives considered","anchor":"4-alternatives-considered","htmlText":"4. Alternatives considered"},{"level":2,"text":"5. Status of the implementation","anchor":"5-status-of-the-implementation","htmlText":"5. Status of the implementation"},{"level":2,"text":"6. References","anchor":"6-references","htmlText":"6. References"}]},"issueTemplate":null,"discussionTemplate":null,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface\u003c/h1\u003e\u003ca id=\"user-content-adr-096-rvcsi--crate-topology-the-napi-c-shim-and-the-napi-rs-node-surface\" class=\"anchor\" aria-label=\"Permalink: ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface\" href=\"#adr-096-rvcsi--crate-topology-the-napi-c-shim-and-the-napi-rs-node-surface\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eField\u003c/th\u003e\n\u003cth\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eStatus\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eProposed\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eDate\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e2026-05-12\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eDeciders\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eruv\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eCodename\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cstrong\u003ervCSI\u003c/strong\u003e — RuVector Channel State Information runtime\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eRelates to\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eADR-095 (rvCSI platform — D1 Rust core, D2 C-at-the-boundary, D3 TS SDK, D4 napi-rs, D5 normalized schema, D6 validate-before-FFI, D15 plugin adapters), ADR-009/ADR-040 (WASM runtimes), ADR-049 (cross-platform WiFi interface detection)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003ePRD\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/Esbroro/RuView/blob/main/docs/prd/rvcsi-platform-prd.md\"\u003ervCSI Platform PRD\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eDomain model\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/Esbroro/RuView/blob/main/docs/ddd/rvcsi-domain-model.md\"\u003ervCSI Domain Model\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eImplements\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ev2/crates/rvcsi-core\u003c/code\u003e, \u003ccode\u003ervcsi-dsp\u003c/code\u003e, \u003ccode\u003ervcsi-events\u003c/code\u003e, \u003ccode\u003ervcsi-adapter-file\u003c/code\u003e, \u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e, \u003ccode\u003ervcsi-ruvector\u003c/code\u003e, \u003ccode\u003ervcsi-node\u003c/code\u003e, \u003ccode\u003ervcsi-cli\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e1. Context\u003c/h2\u003e\u003ca id=\"user-content-1-context\" class=\"anchor\" aria-label=\"Permalink: 1. Context\" href=\"#1-context\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eADR-095 set the platform-level invariant \u003ccode\u003eC → Rust → TypeScript\u003c/code\u003e and the fifteen decisions that constrain rvCSI. This ADR makes the \u003cem\u003eimplementation\u003c/em\u003e concrete: which crates exist, what each owns, where the two FFI seams are (the \u003cstrong\u003enapi-c\u003c/strong\u003e C shim below Rust, and the \u003cstrong\u003enapi-rs\u003c/strong\u003e Node addon above it), and the rules that keep \u003ccode\u003eunsafe\u003c/code\u003e confined and the boundary objects validated.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe two seams:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003enapi-c\u003c/strong\u003e — the \u003cem\u003edownward\u003c/em\u003e seam to fragile vendor/firmware/driver code. Per ADR-095 D2, C is the only language allowed here, and only as a thin, allocation-free, bounds-checked shim. The Nexmon family is the first consumer.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003enapi-rs\u003c/strong\u003e — the \u003cem\u003eupward\u003c/em\u003e seam to Node.js/TypeScript. Per ADR-095 D3/D4, the Rust runtime is exposed to JS via \u003ca href=\"https://napi.rs/\" rel=\"nofollow\"\u003enapi-rs\u003c/a\u003e; nothing crosses this seam that hasn't been validated (D6) and normalized (D5).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eBoth seams are \u003cem\u003enarrow on purpose\u003c/em\u003e: everything in between — parsing, validation, DSP, windowing, event extraction, RuVector export — is safe Rust (\u003ccode\u003e#![forbid(unsafe_code)]\u003c/code\u003e in every crate except \u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e, which needs \u003ccode\u003eextern \"C\"\u003c/code\u003e).\u003c/p\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2. Decision\u003c/h2\u003e\u003ca id=\"user-content-2-decision\" class=\"anchor\" aria-label=\"Permalink: 2. Decision\" href=\"#2-decision\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2.1 Crate topology\u003c/h3\u003e\u003ca id=\"user-content-21-crate-topology\" class=\"anchor\" aria-label=\"Permalink: 2.1 Crate topology\" href=\"#21-crate-topology\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEight new workspace members under \u003ccode\u003ev2/crates/\u003c/code\u003e:\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eCrate\u003c/th\u003e\n\u003cth\u003e\u003ccode\u003eunsafe\u003c/code\u003e?\u003c/th\u003e\n\u003cth\u003eDepends on\u003c/th\u003e\n\u003cth\u003eOwns\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003eforbid\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003e— (serde, thiserror)\u003c/td\u003e\n\u003ctd\u003eThe normalized schema (\u003ccode\u003eCsiFrame\u003c/code\u003e/\u003ccode\u003eCsiWindow\u003c/code\u003e/\u003ccode\u003eCsiEvent\u003c/code\u003e), \u003ccode\u003eAdapterProfile\u003c/code\u003e, the \u003ccode\u003eCsiSource\u003c/code\u003e plugin trait, id newtypes + \u003ccode\u003eIdGenerator\u003c/code\u003e, \u003ccode\u003eRvcsiError\u003c/code\u003e, and the \u003ccode\u003evalidate_frame\u003c/code\u003e pipeline + quality scoring. The shared kernel.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-dsp\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003eforbid\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eReusable DSP stages (DC removal, phase unwrap, smoothing, Hampel/MAD outlier filter, sliding variance, baseline subtraction) and scalar features (motion energy, presence score, confidence, heuristic breathing-band estimate), plus a non-destructive \u003ccode\u003eSignalPipeline::process_frame\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-events\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003eforbid\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eWindowBuffer\u003c/code\u003e (frames → \u003ccode\u003eCsiWindow\u003c/code\u003e), the \u003ccode\u003eEventDetector\u003c/code\u003e trait + presence/motion/quality/baseline-drift state machines, and \u003ccode\u003eEventPipeline\u003c/code\u003e (windows → \u003ccode\u003eCsiEvent\u003c/code\u003es). The baseline-drift detector measures drift \u003cstrong\u003erelative to the running baseline's RMS magnitude\u003c/strong\u003e (a fraction, not absolute amplitude units), so the same thresholds work for raw \u003ccode\u003eint8\u003c/code\u003e ESP32 CSI, \u003ccode\u003eint16\u003c/code\u003e-scaled Nexmon CSI, and baseline-subtracted streams alike — see ADR-095 D13.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-adapter-file\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003eforbid\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eThe \u003ccode\u003e.rvcsi\u003c/code\u003e capture format (JSONL: a header line + one \u003ccode\u003eCsiFrame\u003c/code\u003e per line), \u003ccode\u003eFileRecorder\u003c/code\u003e, and \u003ccode\u003eFileReplayAdapter\u003c/code\u003e (a \u003ccode\u003eCsiSource\u003c/code\u003e) — deterministic replay (D9).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cstrong\u003eyes\u003c/strong\u003e (FFI only)\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e + the C shim\u003c/td\u003e\n\u003ctd\u003eThe \u003cstrong\u003enapi-c\u003c/strong\u003e seam: \u003ccode\u003enative/rvcsi_nexmon_shim.{c,h}\u003c/code\u003e compiled via \u003ccode\u003ebuild.rs\u003c/code\u003e+\u003ccode\u003ecc\u003c/code\u003e, a documented \u003ccode\u003effi\u003c/code\u003e module wrapping it, a pure-Rust libpcap reader (\u003ccode\u003epcap.rs\u003c/code\u003e), the Nexmon-chip / Raspberry-Pi-model registry (\u003ccode\u003echips.rs\u003c/code\u003e — \u003ccode\u003eNexmonChip\u003c/code\u003e, \u003ccode\u003eRaspberryPiModel\u003c/code\u003e incl. \u003cstrong\u003ePi 5\u003c/strong\u003e, profile builders), and two \u003ccode\u003eCsiSource\u003c/code\u003es — \u003ccode\u003eNexmonAdapter\u003c/code\u003e (rvCSI-record buffers) and \u003ccode\u003eNexmonPcapAdapter\u003c/code\u003e (real nexmon_csi UDP payloads inside a \u003ccode\u003e.pcap\u003c/code\u003e, with chip auto-detection).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-ruvector\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003eforbid\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eThe RuVector RF-memory bridge: deterministic \u003ccode\u003ewindow_embedding\u003c/code\u003e/\u003ccode\u003eevent_embedding\u003c/code\u003e, \u003ccode\u003ecosine_similarity\u003c/code\u003e, the \u003ccode\u003eRfMemoryStore\u003c/code\u003e trait, and \u003ccode\u003eInMemoryRfMemory\u003c/code\u003e + \u003ccode\u003eJsonlRfMemory\u003c/code\u003e (a standin until the production RuVector binding lands).\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-runtime\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003eforbid\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003ecore, dsp, events, adapter-file, adapter-nexmon, ruvector\u003c/td\u003e\n\u003ctd\u003eThe composition layer (no FFI): \u003ccode\u003eCaptureRuntime\u003c/code\u003e (a \u003ccode\u003eCsiSource\u003c/code\u003e + \u003ccode\u003evalidate_frame\u003c/code\u003e + \u003ccode\u003eSignalPipeline\u003c/code\u003e + \u003ccode\u003eEventPipeline\u003c/code\u003e) plus one-shot helpers (\u003ccode\u003esummarize_capture\u003c/code\u003e, \u003ccode\u003edecode_nexmon_records\u003c/code\u003e, \u003ccode\u003edecode_nexmon_pcap\u003c/code\u003e, \u003ccode\u003esummarize_nexmon_pcap\u003c/code\u003e, \u003ccode\u003eevents_from_capture\u003c/code\u003e, \u003ccode\u003eexport_capture_to_rf_memory\u003c/code\u003e). The shared layer under \u003ccode\u003ervcsi-node\u003c/code\u003e and \u003ccode\u003ervcsi-cli\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-node\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno (\u003ccode\u003edeny(clippy::all)\u003c/code\u003e)\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e, \u003ccode\u003ervcsi-runtime\u003c/code\u003e, \u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eThe \u003cstrong\u003enapi-rs\u003c/strong\u003e seam: the \u003ccode\u003e.node\u003c/code\u003e addon (cdylib + rlib) exposing a safe TS-facing surface (thin \u003ccode\u003e#[napi]\u003c/code\u003e wrappers over \u003ccode\u003ervcsi-runtime\u003c/code\u003e); \u003ccode\u003ebuild.rs\u003c/code\u003e runs \u003ccode\u003enapi_build::setup()\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-cli\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eno\u003c/td\u003e\n\u003ctd\u003ecore, adapter-file, adapter-nexmon, runtime\u003c/td\u003e\n\u003ctd\u003eThe \u003ccode\u003ervcsi\u003c/code\u003e binary: \u003ccode\u003erecord\u003c/code\u003e (Nexmon-dump or nexmon-pcap → \u003ccode\u003e.rvcsi\u003c/code\u003e), \u003ccode\u003einspect\u003c/code\u003e, \u003ccode\u003einspect-nexmon\u003c/code\u003e, \u003ccode\u003edecode-chanspec\u003c/code\u003e, \u003ccode\u003ereplay\u003c/code\u003e, \u003ccode\u003estream\u003c/code\u003e, \u003ccode\u003eevents\u003c/code\u003e, \u003ccode\u003ehealth\u003c/code\u003e, \u003ccode\u003ecalibrate\u003c/code\u003e, \u003ccode\u003eexport ruvector\u003c/code\u003e (ADR-095 FR7).\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003ervcsi-events\u003c/code\u003e does \u003cstrong\u003enot\u003c/strong\u003e call into \u003ccode\u003ervcsi-dsp\u003c/code\u003e: window statistics are simple enough to compute in \u003ccode\u003eWindowBuffer\u003c/code\u003e itself, and keeping the two leaves independent removes a coordination point. \u003ccode\u003ervcsi-cli\u003c/code\u003e does \u003cstrong\u003enot\u003c/strong\u003e depend on \u003ccode\u003ervcsi-node\u003c/code\u003e (a binary can't link a napi cdylib's undefined Node symbols) — the shared logic lives in \u003ccode\u003ervcsi-runtime\u003c/code\u003e, which both build on. Higher layers wire \u003ccode\u003eSignalPipeline::process_frame\u003c/code\u003e → \u003ccode\u003eWindowBuffer::push\u003c/code\u003e when they want cleaned frames.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe MCP tool server (\u003ccode\u003ervcsi-mcp\u003c/code\u003e) and the long-running daemon (\u003ccode\u003ervcsi-daemon\u003c/code\u003e) — and live radio capture — are \u003cem\u003enot\u003c/em\u003e in this ADR's scope; they sit on top of \u003ccode\u003ervcsi-runtime\u003c/code\u003e / the crates above and are tracked as follow-ups. The \u003ccode\u003e@ruv/rvcsi\u003c/code\u003e npm package ships alongside \u003ccode\u003ervcsi-node\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2.2 The napi-c shim — record formats and contract\u003c/h3\u003e\u003ca id=\"user-content-22-the-napi-c-shim--record-formats-and-contract\" class=\"anchor\" aria-label=\"Permalink: 2.2 The napi-c shim — record formats and contract\" href=\"#22-the-napi-c-shim--record-formats-and-contract\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003enative/rvcsi_nexmon_shim.{c,h}\u003c/code\u003e is the only C in the runtime. It handles \u003cstrong\u003etwo byte formats\u003c/strong\u003e (ABI \u003ccode\u003e1.1\u003c/code\u003e):\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e(1) The \"rvCSI Nexmon record\"\u003c/strong\u003e — a compact, self-describing record (\u003ccode\u003e'RVNX'\u003c/code\u003e magic, version, flags, RSSI/noise, channel, bandwidth, timestamp, then interleaved \u003ccode\u003eint16\u003c/code\u003e I/Q in Q8.8 fixed point; total \u003ccode\u003e24 + 4*N\u003c/code\u003e). Used by the \u003ccode\u003ervcsi capture\u003c/code\u003e/\u003ccode\u003erecord\u003c/code\u003e recorder, the file replay path, and tests. Functions: \u003ccode\u003ervcsi_nx_record_len\u003c/code\u003e, \u003ccode\u003ervcsi_nx_parse_record\u003c/code\u003e, \u003ccode\u003ervcsi_nx_write_record\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003e(2) The \u003cem\u003ereal\u003c/em\u003e nexmon_csi UDP payload\u003c/strong\u003e — what the patched Broadcom firmware actually sends to the host (port 5500 by default): the 18-byte header \u003ccode\u003emagic=0x1111 (2) · rssi int8 (1) · fctl (1) · src_mac (6) · seq_cnt (2) · core/stream (2) · chanspec (2) · chip_ver (2)\u003c/code\u003e, followed by \u003ccode\u003ensub\u003c/code\u003e complex CSI samples. The shim implements the \u003cstrong\u003emodern int16 I/Q export\u003c/strong\u003e (\u003ccode\u003ensub\u003c/code\u003e pairs of little-endian \u003ccode\u003eint16\u003c/code\u003e \u003ccode\u003e(real, imag)\u003c/code\u003e, raw counts — what CSIKit / \u003ccode\u003ecsireader.py\u003c/code\u003e read for the BCM43455c0 / 4358 / 4366c0); \u003ccode\u003ensub\u003c/code\u003e is derived from the payload length, \u003ccode\u003e(len − 18) / 4\u003c/code\u003e. Functions: \u003ccode\u003ervcsi_nx_csi_udp_header\u003c/code\u003e (just the 18-byte header), \u003ccode\u003ervcsi_nx_csi_udp_decode\u003c/code\u003e (header + CSI body, \u003ccode\u003ecsi_format\u003c/code\u003e selector), \u003ccode\u003ervcsi_nx_csi_udp_write\u003c/code\u003e (synthesize a payload — tests/examples), and \u003ccode\u003ervcsi_nx_decode_chanspec\u003c/code\u003e (decode a Broadcom d11ac chanspec word → \u003ccode\u003echannel\u003c/code\u003e = \u003ccode\u003echanspec \u0026amp; 0xff\u003c/code\u003e, bandwidth from bits \u003ccode\u003e[13:11]\u003c/code\u003e cross-checked against the FFT size, band from bits \u003ccode\u003e[15:14]\u003c/code\u003e cross-checked against the channel number). The legacy nexmon \u003cem\u003epacked-float\u003c/em\u003e export used by some 4339/4358 firmwares is a documented follow-up (it sits behind the same \u003ccode\u003ecsi_format\u003c/code\u003e selector).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003etimestamp_ns\u003c/code\u003e of a frame from format (2) comes from the \u003cstrong\u003epcap packet timestamp\u003c/strong\u003e, not the wire (nexmon_csi doesn't carry one). The pcap file itself is parsed in \u003cstrong\u003epure Rust\u003c/strong\u003e (\u003ccode\u003ervcsi-adapter-nexmon::pcap\u003c/code\u003e — classic libpcap, all four byte-order/timestamp-resolution magics, Ethernet / raw-IPv4 / Linux-SLL link types; pcapng is a follow-up): peeling the Ethernet/IPv4/UDP headers down to the payload is not a vendor-fragility concern, so it doesn't belong in C.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eContract (both formats):\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eAllocation-free, global-free.\u003c/strong\u003e Every read is bounds-checked against the caller-supplied length; nothing can scribble outside caller buffers; no \u003ccode\u003emalloc\u003c/code\u003e, no statics.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStructured errors, never panics.\u003c/strong\u003e Functions return one of a small set of \u003ccode\u003eRvcsiNxError\u003c/code\u003e codes (\u003ccode\u003eTOO_SHORT\u003c/code\u003e, \u003ccode\u003eBAD_MAGIC\u003c/code\u003e, \u003ccode\u003eBAD_VERSION\u003c/code\u003e, \u003ccode\u003eCAPACITY\u003c/code\u003e, \u003ccode\u003eTRUNCATED\u003c/code\u003e, \u003ccode\u003eZERO_SUBCARRIERS\u003c/code\u003e, \u003ccode\u003eTOO_MANY_SUBCARRIERS\u003c/code\u003e, \u003ccode\u003eNULL_ARG\u003c/code\u003e, \u003ccode\u003eBAD_NEXMON_MAGIC\u003c/code\u003e, \u003ccode\u003eBAD_CSI_LEN\u003c/code\u003e, \u003ccode\u003eUNKNOWN_FORMAT\u003c/code\u003e); \u003ccode\u003ervcsi_nx_strerror\u003c/code\u003e maps each to a static string.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eABI versioned.\u003c/strong\u003e \u003ccode\u003ervcsi_nx_abi_version()\u003c/code\u003e returns \u003ccode\u003emajor \u0026lt;\u0026lt; 16 | minor\u003c/code\u003e (\u003ccode\u003e0x0001_0001\u003c/code\u003e); the Rust side \u003ccode\u003edebug_assert\u003c/code\u003es the major matches the header it was compiled against. The minor was bumped from \u003ccode\u003e1.0\u003c/code\u003e → \u003ccode\u003e1.1\u003c/code\u003e when the format-(2) entry points landed (additive — format (1) is unchanged).\u003c/li\u003e\n\u003cli\u003eThe Rust \u003ccode\u003effi\u003c/code\u003e module wraps these in safe functions (\u003ccode\u003erecord_len\u003c/code\u003e, \u003ccode\u003edecode_record\u003c/code\u003e, \u003ccode\u003eencode_record\u003c/code\u003e, \u003ccode\u003edecode_chanspec\u003c/code\u003e, \u003ccode\u003eparse_nexmon_udp_header\u003c/code\u003e, \u003ccode\u003edecode_nexmon_udp\u003c/code\u003e, \u003ccode\u003eencode_nexmon_udp\u003c/code\u003e, \u003ccode\u003eshim_abi_version\u003c/code\u003e); every \u003ccode\u003eunsafe\u003c/code\u003e block is limited to the FFI call (and reading back C-initialised structs) and carries a \u003ccode\u003e// SAFETY:\u003c/code\u003e comment, per the project rule.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eChip registry (\u003ccode\u003ervcsi-adapter-nexmon::chips\u003c/code\u003e).\u003c/strong\u003e nexmon_csi runs on a handful of patched Broadcom/Cypress chips; \u003ccode\u003eNexmonChip\u003c/code\u003e names them, \u003ccode\u003eRaspberryPiModel\u003c/code\u003e maps Pi boards to their chip, and \u003ccode\u003enexmon_adapter_profile\u003c/code\u003e / \u003ccode\u003eraspberry_pi_profile\u003c/code\u003e build the [\u003ccode\u003eAdapterProfile\u003c/code\u003e] (supported channels / bandwidths / expected subcarrier counts — 20→64, 40→128, 80→256, 160→512) \u003ccode\u003evalidate_frame\u003c/code\u003e bounds CSI frames against. The \u003cstrong\u003eRaspberry Pi 5\u003c/strong\u003e carries the same \u003cstrong\u003eCYW43455 / BCM43455c0\u003c/strong\u003e 802.11ac wireless as the Pi 3B+ / Pi 4 / Pi 400 (20/40/80 MHz, 2.4 + 5 GHz) — the chip with the most mature nexmon_csi support — so \u003ccode\u003eRaspberryPiModel::Pi5 → NexmonChip::Bcm43455c0\u003c/code\u003e; the Pi Zero 2 W is \u003ccode\u003eBcm43436b0\u003c/code\u003e (2.4 GHz, ≤40 MHz). \u003ccode\u003eNexmonPcapAdapter\u003c/code\u003e \u003cstrong\u003eauto-detects\u003c/strong\u003e the chip from each packet's \u003ccode\u003echip_ver\u003c/code\u003e word (\u003ccode\u003e0x4345\u003c/code\u003e → \u003ccode\u003eBcm43455c0\u003c/code\u003e, etc.) and uses the matching profile; \u003ccode\u003e.with_chip(...)\u003c/code\u003e / \u003ccode\u003e.with_pi_model(...)\u003c/code\u003e override it. \u003ccode\u003eNexmonChip::from_chip_ver\u003c/code\u003e and the \u003ccode\u003echip_ver\u003c/code\u003e field are best-effort/preserved respectively — the c0/b0 revision suffix isn't carried by that word, and the int16-vs-packed-float export distinction is handled by the \u003ccode\u003ecsi_format\u003c/code\u003e selector, not by chip-ver parsing.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA real deployment captures with \u003ccode\u003etcpdump -i wlan0 dst port 5500 -w csi.pcap\u003c/code\u003e on the Pi and feeds the \u003ccode\u003e.pcap\u003c/code\u003e to \u003ccode\u003eNexmonPcapAdapter::open\u003c/code\u003e (or \u003ccode\u003ervcsi record --source nexmon-pcap --in csi.pcap --out cap.rvcsi --chip pi5\u003c/code\u003e, then the rest of the toolchain works on the \u003ccode\u003e.rvcsi\u003c/code\u003e; \u003ccode\u003ervcsi inspect-nexmon\u003c/code\u003e reports the resolved chip, \u003ccode\u003ervcsi nexmon-chips\u003c/code\u003e lists the matrix). Production \u003cem\u003elive\u003c/em\u003e capture (binding the UDP socket, monitor mode, firmware patch hooks) is a later increment that reuses the same shim parse path — the shim's job is the \u003cem\u003eparse\u003c/em\u003e, not the \u003cem\u003esocket\u003c/em\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2.3 The napi-rs surface — what crosses the seam\u003c/h3\u003e\u003ca id=\"user-content-23-the-napi-rs-surface--what-crosses-the-seam\" class=\"anchor\" aria-label=\"Permalink: 2.3 The napi-rs surface — what crosses the seam\" href=\"#23-the-napi-rs-surface--what-crosses-the-seam\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003ervcsi-node\u003c/code\u003e is a \u003ccode\u003e[\"cdylib\", \"rlib\"]\u003c/code\u003e crate (cdylib = the \u003ccode\u003e.node\u003c/code\u003e addon; rlib so \u003ccode\u003ecargo test --workspace\u003c/code\u003e can link and test the Rust side without Node). Rules:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eOnly normalized/validated data crosses.\u003c/strong\u003e The boundary types are JS-friendly mirrors of \u003ccode\u003eCsiFrame\u003c/code\u003e/\u003ccode\u003eCsiWindow\u003c/code\u003e/\u003ccode\u003eCsiEvent\u003c/code\u003e/\u003ccode\u003eAdapterProfile\u003c/code\u003e/\u003ccode\u003eSourceHealth\u003c/code\u003e, or plain JSON strings — never raw pointers, never \u003ccode\u003ePending\u003c/code\u003e frames. A frame is run through \u003ccode\u003ervcsi_core::validate_frame\u003c/code\u003e before it is handed to JS.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eErrors map to JS exceptions\u003c/strong\u003e via napi-rs's \u003ccode\u003eResult\u003c/code\u003e integration; \u003ccode\u003eRvcsiError\u003c/code\u003e's \u003ccode\u003eDisplay\u003c/code\u003e is the message.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eThe build emits link args + \u003ccode\u003ebinding.js\u003c/code\u003e/\u003ccode\u003ebinding.d.ts\u003c/code\u003e\u003c/strong\u003e via \u003ccode\u003enapi_build::setup()\u003c/code\u003e in \u003ccode\u003ebuild.rs\u003c/code\u003e; the \u003ccode\u003e@ruv/rvcsi\u003c/code\u003e npm package's hand-written \u003ccode\u003eindex.js\u003c/code\u003e/\u003ccode\u003eindex.d.ts\u003c/code\u003e wrap that loader and \u003ccode\u003eJSON.parse\u003c/code\u003e the addon's returns into plain \u003ccode\u003eCsiFrame\u003c/code\u003e/\u003ccode\u003eCsiWindow\u003c/code\u003e/\u003ccode\u003eCsiEvent\u003c/code\u003e/\u003ccode\u003eSourceHealth\u003c/code\u003e/\u003ccode\u003eCaptureSummary\u003c/code\u003e/\u003ccode\u003eNexmonPcapSummary\u003c/code\u003e/\u003ccode\u003eDecodedChanspec\u003c/code\u003e objects.\u003c/li\u003e\n\u003cli\u003eThe free functions exposed are: \u003ccode\u003ervcsiVersion\u003c/code\u003e, \u003ccode\u003enexmonShimAbiVersion\u003c/code\u003e (the linked shim's ABI), \u003ccode\u003enexmonDecodeRecords\u003c/code\u003e, \u003ccode\u003enexmonDecodePcap\u003c/code\u003e, \u003ccode\u003einspectNexmonPcap\u003c/code\u003e, \u003ccode\u003edecodeChanspec\u003c/code\u003e, \u003ccode\u003einspectCaptureFile\u003c/code\u003e, \u003ccode\u003eeventsFromCaptureFile\u003c/code\u003e, \u003ccode\u003eexportCaptureToRfMemory\u003c/code\u003e; plus the \u003ccode\u003eRvcsiRuntime\u003c/code\u003e streaming class (\u003ccode\u003eopenCaptureFile\u003c/code\u003e / \u003ccode\u003eopenNexmonFile\u003c/code\u003e / \u003ccode\u003eopenNexmonPcap\u003c/code\u003e factories + \u003ccode\u003enextFrameJson\u003c/code\u003e / \u003ccode\u003enextCleanFrameJson\u003c/code\u003e / \u003ccode\u003edrainEventsJson\u003c/code\u003e / \u003ccode\u003ehealthJson\u003c/code\u003e).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e2.4 Build \u0026amp; test invariants\u003c/h3\u003e\u003ca id=\"user-content-24-build--test-invariants\" class=\"anchor\" aria-label=\"Permalink: 2.4 Build \u0026amp; test invariants\" href=\"#24-build--test-invariants\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ecargo build --workspace\u003c/code\u003e and \u003ccode\u003ecargo test --workspace --no-default-features\u003c/code\u003e (the repo's pre-merge gate) must stay green; the new crates add tests and don't regress the existing 1,031+.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-node\u003c/code\u003e stays a workspace \u003cem\u003emember\u003c/em\u003e (not \u003ccode\u003eexclude\u003c/code\u003ed like \u003ccode\u003ewifi-densepose-wasm-edge\u003c/code\u003e): on Linux/macOS a napi cdylib links fine with Node symbols left undefined (resolved at addon-load time), so \u003ccode\u003ecargo build\u003c/code\u003e/\u003ccode\u003ecargo test\u003c/code\u003e work without a Node toolchain. Only \u003ccode\u003enapi build\u003c/code\u003e (npm packaging) needs Node.\u003c/li\u003e\n\u003cli\u003eNo new heavy dependencies in the rvCSI crates: \u003ccode\u003eserde\u003c/code\u003e, \u003ccode\u003eserde_json\u003c/code\u003e, \u003ccode\u003ethiserror\u003c/code\u003e, \u003ccode\u003ecc\u003c/code\u003e (build only), \u003ccode\u003enapi\u003c/code\u003e/\u003ccode\u003enapi-derive\u003c/code\u003e/\u003ccode\u003enapi-build\u003c/code\u003e, \u003ccode\u003eclap\u003c/code\u003e (CLI only), \u003ccode\u003etempfile\u003c/code\u003e (dev only). DSP math is hand-rolled — no \u003ccode\u003endarray\u003c/code\u003e/\u003ccode\u003erustfft\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e3. Consequences\u003c/h2\u003e\u003ca id=\"user-content-3-consequences\" class=\"anchor\" aria-label=\"Permalink: 3. Consequences\" href=\"#3-consequences\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003ePositive\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe two FFI seams are small, audited, and independently testable: the C shim round-trips through Rust tests; the napi surface tests run under \u003ccode\u003ecargo test\u003c/code\u003e without Node.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eunsafe\u003c/code\u003e is confined to one crate (\u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e) and within it to one module (\u003ccode\u003effi\u003c/code\u003e), every block documented.\u003c/li\u003e\n\u003cli\u003eEach leaf crate (\u003ccode\u003ervcsi-dsp\u003c/code\u003e, \u003ccode\u003ervcsi-events\u003c/code\u003e, \u003ccode\u003ervcsi-adapter-file\u003c/code\u003e, \u003ccode\u003ervcsi-ruvector\u003c/code\u003e) depends only on \u003ccode\u003ervcsi-core\u003c/code\u003e, so they can evolve (and be reviewed, and be swarm-implemented) independently.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003e.rvcsi\u003c/code\u003e JSONL capture format and the \u003ccode\u003eJsonlRfMemory\u003c/code\u003e standin make the whole pipeline runnable and testable end-to-end before any hardware or the real RuVector binding exists.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eNegative / costs\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eA \u003ccode\u003ecc\u003c/code\u003e-built C library means a C toolchain is required to build \u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e (already true for many workspace crates via transitive \u003ccode\u003ecc\u003c/code\u003e deps; acceptable).\u003c/li\u003e\n\u003cli\u003eThe \"rvCSI Nexmon record\" is a \u003cem\u003enormalized\u003c/em\u003e format, not byte-identical to any upstream nexmon_csi build — a thin demux/transcode step is needed when wiring real Nexmon output. This is intentional (we control the contract the shim parses) and documented.\u003c/li\u003e\n\u003cli\u003eJSONL captures are larger than a packed binary format; fine for v0 (and the PRD already standardizes on JSON/WebSocket on the wire), revisit if capture size becomes a problem.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-node\u003c/code\u003e as a workspace member adds the \u003ccode\u003enapi\u003c/code\u003e dependency tree to \u003ccode\u003ecargo build --workspace\u003c/code\u003e; mitigated by it being a small, well-maintained crate.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eRisks\u003c/strong\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003enapi-rs major-version churn could change the macro/\u003ccode\u003ebuild.rs\u003c/code\u003e surface; pinned to \u003ccode\u003enapi = \"2.16\"\u003c/code\u003e in workspace deps, bumped deliberately.\u003c/li\u003e\n\u003cli\u003eIf a future platform can't link a napi cdylib under plain \u003ccode\u003ecargo build\u003c/code\u003e, \u003ccode\u003ervcsi-node\u003c/code\u003e moves to the workspace \u003ccode\u003eexclude\u003c/code\u003e list (like \u003ccode\u003ewifi-densepose-wasm-edge\u003c/code\u003e) with a separate build command — same pattern, already established.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e4. Alternatives considered\u003c/h2\u003e\u003ca id=\"user-content-4-alternatives-considered\" class=\"anchor\" aria-label=\"Permalink: 4. Alternatives considered\" href=\"#4-alternatives-considered\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eAlternative\u003c/th\u003e\n\u003cth\u003eWhy not\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eOne mega-crate \u003ccode\u003ervcsi\u003c/code\u003e instead of eight\u003c/td\u003e\n\u003ctd\u003eCouples DSP/events/adapters/FFI; can't review or implement them independently; bloats compile units for downstream users who only want \u003ccode\u003ervcsi-core\u003c/code\u003e.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ebindgen\u003c/code\u003e for the C shim\u003c/td\u003e\n\u003ctd\u003ePulls in \u003ccode\u003elibclang\u003c/code\u003e; the shim's C API is six functions — hand-written \u003ccode\u003eextern \"C\"\u003c/code\u003e decls are clearer and dependency-free.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBinary \u003ccode\u003e.rvcsi\u003c/code\u003e capture format (bincode/custom)\u003c/td\u003e\n\u003ctd\u003eSmaller, but not human-inspectable; JSONL is debuggable, append-friendly, and matches the PRD's on-the-wire JSON. Revisit if size matters.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExpose raw \u003ccode\u003eCsiFrame\u003c/code\u003e pointers / typed arrays across napi for zero-copy\u003c/td\u003e\n\u003ctd\u003eViolates ADR-095 D6 (validate-before-FFI) and the \"no raw pointers to TS\" safety NFR; the per-frame copy cost is negligible at the target rates.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ewasm-bindgen\u003c/code\u003e instead of napi-rs for the JS surface\u003c/td\u003e\n\u003ctd\u003eWASM can't do live capture (no raw sockets/serial); great for offline parsing (a later target) but not the primary Node runtime.\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003ervcsi-events\u003c/code\u003e depending on \u003ccode\u003ervcsi-dsp\u003c/code\u003e for window stats\u003c/td\u003e\n\u003ctd\u003eAdds a coordination point for two leaf crates; the stats are a few lines — keep the leaves independent and let higher layers compose them.\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e5. Status of the implementation\u003c/h2\u003e\u003ca id=\"user-content-5-status-of-the-implementation\" class=\"anchor\" aria-label=\"Permalink: 5. Status of the implementation\" href=\"#5-status-of-the-implementation\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-core\u003c/code\u003e — implemented, \u003ccode\u003eforbid(unsafe_code)\u003c/code\u003e, 29 unit tests.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-adapter-nexmon\u003c/code\u003e + the napi-c shim — implemented; C (ABI \u003ccode\u003e1.1\u003c/code\u003e) compiled via \u003ccode\u003ebuild.rs\u003c/code\u003e+\u003ccode\u003ecc\u003c/code\u003e; the \u003ccode\u003effi\u003c/code\u003e module wraps both record formats (rvCSI record \u003cstrong\u003eand\u003c/strong\u003e the real nexmon_csi UDP payload + chanspec decode); a pure-Rust \u003ccode\u003epcap\u003c/code\u003e reader; the Nexmon-chip / Raspberry-Pi-model registry (\u003ccode\u003echips.rs\u003c/code\u003e — incl. \u003cstrong\u003ePi 5 → BCM43455c0\u003c/strong\u003e + chip auto-detection from \u003ccode\u003echip_ver\u003c/code\u003e); \u003ccode\u003eNexmonAdapter\u003c/code\u003e + \u003ccode\u003eNexmonPcapAdapter\u003c/code\u003e \u003ccode\u003eCsiSource\u003c/code\u003es; 28 tests, several round-tripping through the C shim and through synthetic libpcap files.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-dsp\u003c/code\u003e (28 tests), \u003ccode\u003ervcsi-events\u003c/code\u003e (19 tests — incl. a scale-invariance regression for the baseline-drift detector), \u003ccode\u003ervcsi-adapter-file\u003c/code\u003e (20 + 1 doctest), \u003ccode\u003ervcsi-ruvector\u003c/code\u003e (20 + 1 doctest) — implemented.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-runtime\u003c/code\u003e (13 tests) — composition layer + the one-shot helpers, including \u003ccode\u003edecode_nexmon_pcap\u003c/code\u003e / \u003ccode\u003edecode_nexmon_pcap_for\u003c/code\u003e (per-chip) / \u003ccode\u003esummarize_nexmon_pcap\u003c/code\u003e / \u003ccode\u003enexmon_profile_for\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-node\u003c/code\u003e (napi-rs surface — incl. \u003ccode\u003enexmonDecodePcap\u003c/code\u003e (with \u003ccode\u003echip\u003c/code\u003e) / \u003ccode\u003einspectNexmonPcap\u003c/code\u003e / \u003ccode\u003edecodeChanspec\u003c/code\u003e / \u003ccode\u003enexmonChipName\u003c/code\u003e / \u003ccode\u003enexmonProfile\u003c/code\u003e / \u003ccode\u003enexmonChips\u003c/code\u003e / \u003ccode\u003eRvcsiRuntime.openNexmonPcap\u003c/code\u003e) and \u003ccode\u003ervcsi-cli\u003c/code\u003e (10 tests — incl. \u003ccode\u003erecord --source nexmon-pcap [--chip pi5]\u003c/code\u003e, \u003ccode\u003einspect-nexmon\u003c/code\u003e, \u003ccode\u003enexmon-chips\u003c/code\u003e, \u003ccode\u003edecode-chanspec\u003c/code\u003e) — implemented; the \u003ccode\u003e@ruv/rvcsi\u003c/code\u003e npm package + a Node smoke test ship alongside.\u003c/li\u003e\n\u003cli\u003eTotals: 169 rvcsi unit/integration tests + 2 doctests, 0 failures; all rvcsi crates build together and are clippy-clean.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eValidated against real ESP32 CSI\u003c/strong\u003e (a 7,000-frame node-1 capture, transcoded to \u003ccode\u003e.rvcsi\u003c/code\u003e via \u003ccode\u003escripts/esp32_jsonl_to_rvcsi.py\u003c/code\u003e — the stand-in for the not-yet-shipped \u003ccode\u003erecord --source esp32-jsonl\u003c/code\u003e): \u003ccode\u003ervcsi inspect\u003c/code\u003e / \u003ccode\u003ereplay\u003c/code\u003e / \u003ccode\u003ecalibrate\u003c/code\u003e / \u003ccode\u003eevents\u003c/code\u003e all run end-to-end. This surfaced and fixed the baseline-drift over-trigger (absolute → relative thresholds, above).\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ervcsi-adapter-esp32\u003c/code\u003e (live serial/UDP ESP32 source — ADR-095 §1.2 / D15), \u003ccode\u003ervcsi-mcp\u003c/code\u003e (MCP tool server), \u003ccode\u003ervcsi-daemon\u003c/code\u003e (live capture + WebSocket), and the legacy nexmon \u003cem\u003epacked-float\u003c/em\u003e CSI export — not in this PR; tracked as follow-ups.\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e6. References\u003c/h2\u003e\u003ca id=\"user-content-6-references\" class=\"anchor\" aria-label=\"Permalink: 6. References\" href=\"#6-references\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"/Esbroro/RuView/blob/main/docs/adr/ADR-095-rvcsi-edge-rf-sensing-platform.md\"\u003eADR-095 — rvCSI Edge RF Sensing Platform\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/Esbroro/RuView/blob/main/docs/prd/rvcsi-platform-prd.md\"\u003ervCSI Platform PRD\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"/Esbroro/RuView/blob/main/docs/ddd/rvcsi-domain-model.md\"\u003ervCSI Domain Model\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003enapi-rs — \u003ca href=\"https://napi.rs/\" rel=\"nofollow\"\u003ehttps://napi.rs/\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003enexmon_csi — the upstream Broadcom CSI extractor the record format normalizes\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/article\u003e","richTextTruncated":false,"renderedFileInfo":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface","fully_qualified_name":"ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface","kind":"section_1","ident_start":2,"ident_end":82,"extent_start":0,"extent_end":19015,"ident_utf16":{"start":{"line_number":0,"utf16_col":2},"end":{"line_number":0,"utf16_col":80}},"extent_utf16":{"start":{"line_number":0,"utf16_col":0},"end":{"line_number":144,"utf16_col":0}}},{"name":"1. Context","fully_qualified_name":"1. Context","kind":"section_2","ident_start":842,"ident_end":852,"extent_start":839,"extent_end":1963,"ident_utf16":{"start":{"line_number":15,"utf16_col":3},"end":{"line_number":15,"utf16_col":13}},"extent_utf16":{"start":{"line_number":15,"utf16_col":0},"end":{"line_number":28,"utf16_col":0}}},{"name":"2. Decision","fully_qualified_name":"2. Decision","kind":"section_2","ident_start":1966,"ident_end":1977,"extent_start":1963,"extent_end":13368,"ident_utf16":{"start":{"line_number":28,"utf16_col":3},"end":{"line_number":28,"utf16_col":14}},"extent_utf16":{"start":{"line_number":28,"utf16_col":0},"end":{"line_number":88,"utf16_col":0}}},{"name":"2.1 Crate topology","fully_qualified_name":"2.1 Crate topology","kind":"section_3","ident_start":1983,"ident_end":2001,"extent_start":1979,"extent_end":6053,"ident_utf16":{"start":{"line_number":30,"utf16_col":4},"end":{"line_number":30,"utf16_col":22}},"extent_utf16":{"start":{"line_number":30,"utf16_col":0},"end":{"line_number":50,"utf16_col":0}}},{"name":"2.2 The napi-c shim — record formats and contract","fully_qualified_name":"2.2 The napi-c shim — record formats and contract","kind":"section_3","ident_start":6057,"ident_end":6108,"extent_start":6053,"extent_end":11180,"ident_utf16":{"start":{"line_number":50,"utf16_col":4},"end":{"line_number":50,"utf16_col":53}},"extent_utf16":{"start":{"line_number":50,"utf16_col":0},"end":{"line_number":71,"utf16_col":0}}},{"name":"2.3 The napi-rs surface — what crosses the seam","fully_qualified_name":"2.3 The napi-rs surface — what crosses the seam","kind":"section_3","ident_start":11184,"ident_end":11233,"extent_start":11180,"extent_end":12605,"ident_utf16":{"start":{"line_number":71,"utf16_col":4},"end":{"line_number":71,"utf16_col":51}},"extent_utf16":{"start":{"line_number":71,"utf16_col":0},"end":{"line_number":80,"utf16_col":0}}},{"name":"2.4 Build \u0026 test invariants","fully_qualified_name":"2.4 Build \u0026 test invariants","kind":"section_3","ident_start":12609,"ident_end":12636,"extent_start":12605,"extent_end":13368,"ident_utf16":{"start":{"line_number":80,"utf16_col":4},"end":{"line_number":80,"utf16_col":31}},"extent_utf16":{"start":{"line_number":80,"utf16_col":0},"end":{"line_number":88,"utf16_col":0}}},{"name":"3. Consequences","fully_qualified_name":"3. Consequences","kind":"section_2","ident_start":13371,"ident_end":13386,"extent_start":13368,"extent_end":15239,"ident_utf16":{"start":{"line_number":88,"utf16_col":3},"end":{"line_number":88,"utf16_col":18}},"extent_utf16":{"start":{"line_number":88,"utf16_col":0},"end":{"line_number":111,"utf16_col":0}}},{"name":"4. Alternatives considered","fully_qualified_name":"4. Alternatives considered","kind":"section_2","ident_start":15242,"ident_end":15268,"extent_start":15239,"extent_end":16486,"ident_utf16":{"start":{"line_number":111,"utf16_col":3},"end":{"line_number":111,"utf16_col":29}},"extent_utf16":{"start":{"line_number":111,"utf16_col":0},"end":{"line_number":124,"utf16_col":0}}},{"name":"5. Status of the implementation","fully_qualified_name":"5. Status of the implementation","kind":"section_2","ident_start":16489,"ident_end":16520,"extent_start":16486,"extent_end":18688,"ident_utf16":{"start":{"line_number":124,"utf16_col":3},"end":{"line_number":124,"utf16_col":34}},"extent_utf16":{"start":{"line_number":124,"utf16_col":0},"end":{"line_number":137,"utf16_col":0}}},{"name":"6. References","fully_qualified_name":"6. References","kind":"section_2","ident_start":18691,"ident_end":18704,"extent_start":18688,"extent_end":19015,"ident_utf16":{"start":{"line_number":137,"utf16_col":3},"end":{"line_number":137,"utf16_col":16}},"extent_utf16":{"start":{"line_number":137,"utf16_col":0},"end":{"line_number":144,"utf16_col":0}}}]}},"codeViewLayoutRoute":{"repo":{"id":1343065552,"defaultBranch":"main","name":"RuView","ownerLogin":"Esbroro","currentUserCanPush":false,"isFork":true,"isEmpty":false,"createdAt":"2026-08-22T18:24:46.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/257900615?v=4","public":true,"private":false,"isOrgOwned":false,"isArchived":false},"currentUser":null,"uploadToken":"9U10nW3GPqHor8N8sUp3va7NFuyRA6_CcSbWVGVBlG0150sWuIOHMroWdjpAIfJw_aS6PKBnPWSU5PH27dTN2g","allShortcutsEnabled":false,"treeExpanded":true,"path":"docs/adr/ADR-096-rvcsi-ffi-crate-layout.md","symbolsExpanded":false,"refInfo":{"name":"main","listCacheKey":"v0:1787423101.0","canEdit":false,"currentOid":"a3b6e1d500df784b9ad1846dd39deb07e2c69a34"},"helpUrl":"https://docs.github.com","githubDevUrl":null},"codeViewFileTreeLayoutRoute":{"fileTree":{"docs/adr":{"items":[{"name":"gap-analysis","path":"docs/adr/gap-analysis","contentType":"directory"},{"name":".issue-177-body.md","path":"docs/adr/.issue-177-body.md","contentType":"file"},{"name":"ADR-001-wifi-mat-disaster-detection.md","path":"docs/adr/ADR-001-wifi-mat-disaster-detection.md","contentType":"file"},{"name":"ADR-002-ruvector-rvf-integration-strategy.md","path":"docs/adr/ADR-002-ruvector-rvf-integration-strategy.md","contentType":"file"},{"name":"ADR-003-rvf-cognitive-containers-csi.md","path":"docs/adr/ADR-003-rvf-cognitive-containers-csi.md","contentType":"file"},{"name":"ADR-004-hnsw-vector-search-fingerprinting.md","path":"docs/adr/ADR-004-hnsw-vector-search-fingerprinting.md","contentType":"file"},{"name":"ADR-005-sona-self-learning-pose-estimation.md","path":"docs/adr/ADR-005-sona-self-learning-pose-estimation.md","contentType":"file"},{"name":"ADR-006-gnn-enhanced-csi-pattern-recognition.md","path":"docs/adr/ADR-006-gnn-enhanced-csi-pattern-recognition.md","contentType":"file"},{"name":"ADR-007-post-quantum-cryptography-secure-sensing.md","path":"docs/adr/ADR-007-post-quantum-cryptography-secure-sensing.md","contentType":"file"},{"name":"ADR-008-distributed-consensus-multi-ap.md","path":"docs/adr/ADR-008-distributed-consensus-multi-ap.md","contentType":"file"},{"name":"ADR-009-rvf-wasm-runtime-edge-deployment.md","path":"docs/adr/ADR-009-rvf-wasm-runtime-edge-deployment.md","contentType":"file"},{"name":"ADR-010-witness-chains-audit-trail-integrity.md","path":"docs/adr/ADR-010-witness-chains-audit-trail-integrity.md","contentType":"file"},{"name":"ADR-011-python-proof-of-reality-mock-elimination.md","path":"docs/adr/ADR-011-python-proof-of-reality-mock-elimination.md","contentType":"file"},{"name":"ADR-012-esp32-csi-sensor-mesh.md","path":"docs/adr/ADR-012-esp32-csi-sensor-mesh.md","contentType":"file"},{"name":"ADR-013-feature-level-sensing-commodity-gear.md","path":"docs/adr/ADR-013-feature-level-sensing-commodity-gear.md","contentType":"file"},{"name":"ADR-014-sota-signal-processing.md","path":"docs/adr/ADR-014-sota-signal-processing.md","contentType":"file"},{"name":"ADR-015-public-dataset-training-strategy.md","path":"docs/adr/ADR-015-public-dataset-training-strategy.md","contentType":"file"},{"name":"ADR-016-ruvector-integration.md","path":"docs/adr/ADR-016-ruvector-integration.md","contentType":"file"},{"name":"ADR-017-ruvector-signal-mat-integration.md","path":"docs/adr/ADR-017-ruvector-signal-mat-integration.md","contentType":"file"},{"name":"ADR-018-esp32-dev-implementation.md","path":"docs/adr/ADR-018-esp32-dev-implementation.md","contentType":"file"},{"name":"ADR-019-sensing-only-ui-mode.md","path":"docs/adr/ADR-019-sensing-only-ui-mode.md","contentType":"file"},{"name":"ADR-020-rust-ruvector-ai-model-migration.md","path":"docs/adr/ADR-020-rust-ruvector-ai-model-migration.md","contentType":"file"},{"name":"ADR-021-vital-sign-detection-rvdna-pipeline.md","path":"docs/adr/ADR-021-vital-sign-detection-rvdna-pipeline.md","contentType":"file"},{"name":"ADR-022-windows-wifi-enhanced-fidelity-ruvector.md","path":"docs/adr/ADR-022-windows-wifi-enhanced-fidelity-ruvector.md","contentType":"file"},{"name":"ADR-023-trained-densepose-model-ruvector-pipeline.md","path":"docs/adr/ADR-023-trained-densepose-model-ruvector-pipeline.md","contentType":"file"},{"name":"ADR-024-contrastive-csi-embedding-model.md","path":"docs/adr/ADR-024-contrastive-csi-embedding-model.md","contentType":"file"},{"name":"ADR-025-macos-corewlan-wifi-sensing.md","path":"docs/adr/ADR-025-macos-corewlan-wifi-sensing.md","contentType":"file"},{"name":"ADR-026-survivor-track-lifecycle.md","path":"docs/adr/ADR-026-survivor-track-lifecycle.md","contentType":"file"},{"name":"ADR-027-cross-environment-domain-generalization.md","path":"docs/adr/ADR-027-cross-environment-domain-generalization.md","contentType":"file"},{"name":"ADR-028-esp32-capability-audit.md","path":"docs/adr/ADR-028-esp32-capability-audit.md","contentType":"file"},{"name":"ADR-029-ruvsense-multistatic-sensing-mode.md","path":"docs/adr/ADR-029-ruvsense-multistatic-sensing-mode.md","contentType":"file"},{"name":"ADR-030-ruvsense-persistent-field-model.md","path":"docs/adr/ADR-030-ruvsense-persistent-field-model.md","contentType":"file"},{"name":"ADR-031-ruview-sensing-first-rf-mode.md","path":"docs/adr/ADR-031-ruview-sensing-first-rf-mode.md","contentType":"file"},{"name":"ADR-032-multistatic-mesh-security-hardening.md","path":"docs/adr/ADR-032-multistatic-mesh-security-hardening.md","contentType":"file"},{"name":"ADR-033-crv-signal-line-sensing-integration.md","path":"docs/adr/ADR-033-crv-signal-line-sensing-integration.md","contentType":"file"},{"name":"ADR-034-expo-mobile-app.md","path":"docs/adr/ADR-034-expo-mobile-app.md","contentType":"file"},{"name":"ADR-035-live-sensing-ui-accuracy.md","path":"docs/adr/ADR-035-live-sensing-ui-accuracy.md","contentType":"file"},{"name":"ADR-036-rvf-training-pipeline-ui.md","path":"docs/adr/ADR-036-rvf-training-pipeline-ui.md","contentType":"file"},{"name":"ADR-037-multi-person-pose-detection.md","path":"docs/adr/ADR-037-multi-person-pose-detection.md","contentType":"file"},{"name":"ADR-038-sublinear-goal-oriented-action-planning.md","path":"docs/adr/ADR-038-sublinear-goal-oriented-action-planning.md","contentType":"file"},{"name":"ADR-039-esp32-edge-intelligence.md","path":"docs/adr/ADR-039-esp32-edge-intelligence.md","contentType":"file"},{"name":"ADR-040-wasm-programmable-sensing.md","path":"docs/adr/ADR-040-wasm-programmable-sensing.md","contentType":"file"},{"name":"ADR-041-wasm-module-collection.md","path":"docs/adr/ADR-041-wasm-module-collection.md","contentType":"file"},{"name":"ADR-042-coherent-human-channel-imaging.md","path":"docs/adr/ADR-042-coherent-human-channel-imaging.md","contentType":"file"},{"name":"ADR-043-sensing-server-ui-api-completion.md","path":"docs/adr/ADR-043-sensing-server-ui-api-completion.md","contentType":"file"},{"name":"ADR-044-geospatial-satellite-integration.md","path":"docs/adr/ADR-044-geospatial-satellite-integration.md","contentType":"file"},{"name":"ADR-045-amoled-display-support.md","path":"docs/adr/ADR-045-amoled-display-support.md","contentType":"file"},{"name":"ADR-046-android-tv-box-armbian-deployment.md","path":"docs/adr/ADR-046-android-tv-box-armbian-deployment.md","contentType":"file"},{"name":"ADR-047-psychohistory-observatory-visualization.md","path":"docs/adr/ADR-047-psychohistory-observatory-visualization.md","contentType":"file"},{"name":"ADR-048-adaptive-csi-classifier.md","path":"docs/adr/ADR-048-adaptive-csi-classifier.md","contentType":"file"},{"name":"ADR-049-cross-platform-wifi-interface-detection.md","path":"docs/adr/ADR-049-cross-platform-wifi-interface-detection.md","contentType":"file"},{"name":"ADR-050-provisioning-tool-enhancements.md","path":"docs/adr/ADR-050-provisioning-tool-enhancements.md","contentType":"file"},{"name":"ADR-052-tauri-desktop-frontend.md","path":"docs/adr/ADR-052-tauri-desktop-frontend.md","contentType":"file"},{"name":"ADR-053-ui-design-system.md","path":"docs/adr/ADR-053-ui-design-system.md","contentType":"file"},{"name":"ADR-054-desktop-full-implementation.md","path":"docs/adr/ADR-054-desktop-full-implementation.md","contentType":"file"},{"name":"ADR-055-integrated-sensing-server.md","path":"docs/adr/ADR-055-integrated-sensing-server.md","contentType":"file"},{"name":"ADR-056-ruview-desktop-capabilities.md","path":"docs/adr/ADR-056-ruview-desktop-capabilities.md","contentType":"file"},{"name":"ADR-057-firmware-csi-build-guard.md","path":"docs/adr/ADR-057-firmware-csi-build-guard.md","contentType":"file"},{"name":"ADR-058-ruvector-wasm-browser-pose-example.md","path":"docs/adr/ADR-058-ruvector-wasm-browser-pose-example.md","contentType":"file"},{"name":"ADR-059-live-esp32-csi-pipeline.md","path":"docs/adr/ADR-059-live-esp32-csi-pipeline.md","contentType":"file"},{"name":"ADR-060-provision-channel-mac-filter.md","path":"docs/adr/ADR-060-provision-channel-mac-filter.md","contentType":"file"},{"name":"ADR-061-qemu-esp32s3-firmware-testing.md","path":"docs/adr/ADR-061-qemu-esp32s3-firmware-testing.md","contentType":"file"},{"name":"ADR-062-qemu-swarm-configurator.md","path":"docs/adr/ADR-062-qemu-swarm-configurator.md","contentType":"file"},{"name":"ADR-063-mmwave-sensor-fusion.md","path":"docs/adr/ADR-063-mmwave-sensor-fusion.md","contentType":"file"},{"name":"ADR-064-multimodal-ambient-intelligence.md","path":"docs/adr/ADR-064-multimodal-ambient-intelligence.md","contentType":"file"},{"name":"ADR-065-happiness-scoring-seed-bridge.md","path":"docs/adr/ADR-065-happiness-scoring-seed-bridge.md","contentType":"file"},{"name":"ADR-066-esp32-swarm-seed-coordinator.md","path":"docs/adr/ADR-066-esp32-swarm-seed-coordinator.md","contentType":"file"},{"name":"ADR-067-ruvector-v2.0.5-upgrade.md","path":"docs/adr/ADR-067-ruvector-v2.0.5-upgrade.md","contentType":"file"},{"name":"ADR-068-per-node-state-pipeline.md","path":"docs/adr/ADR-068-per-node-state-pipeline.md","contentType":"file"},{"name":"ADR-069-cognitum-seed-csi-pipeline.md","path":"docs/adr/ADR-069-cognitum-seed-csi-pipeline.md","contentType":"file"},{"name":"ADR-070-self-supervised-pretraining.md","path":"docs/adr/ADR-070-self-supervised-pretraining.md","contentType":"file"},{"name":"ADR-071-ruvllm-training-pipeline.md","path":"docs/adr/ADR-071-ruvllm-training-pipeline.md","contentType":"file"},{"name":"ADR-072-wiflow-architecture.md","path":"docs/adr/ADR-072-wiflow-architecture.md","contentType":"file"},{"name":"ADR-073-multifrequency-mesh-scan.md","path":"docs/adr/ADR-073-multifrequency-mesh-scan.md","contentType":"file"},{"name":"ADR-074-spiking-neural-csi-sensing.md","path":"docs/adr/ADR-074-spiking-neural-csi-sensing.md","contentType":"file"},{"name":"ADR-075-mincut-person-separation.md","path":"docs/adr/ADR-075-mincut-person-separation.md","contentType":"file"},{"name":"ADR-076-csi-spectrogram-embeddings.md","path":"docs/adr/ADR-076-csi-spectrogram-embeddings.md","contentType":"file"},{"name":"ADR-077-novel-rf-sensing-applications.md","path":"docs/adr/ADR-077-novel-rf-sensing-applications.md","contentType":"file"},{"name":"ADR-078-multifreq-mesh-applications.md","path":"docs/adr/ADR-078-multifreq-mesh-applications.md","contentType":"file"},{"name":"ADR-079-camera-ground-truth-training.md","path":"docs/adr/ADR-079-camera-ground-truth-training.md","contentType":"file"},{"name":"ADR-080-qe-remediation-plan.md","path":"docs/adr/ADR-080-qe-remediation-plan.md","contentType":"file"},{"name":"ADR-081-adaptive-csi-mesh-firmware-kernel.md","path":"docs/adr/ADR-081-adaptive-csi-mesh-firmware-kernel.md","contentType":"file"},{"name":"ADR-082-pose-tracker-confirmed-output-filter.md","path":"docs/adr/ADR-082-pose-tracker-confirmed-output-filter.md","contentType":"file"},{"name":"ADR-083-per-cluster-pi-compute-hop.md","path":"docs/adr/ADR-083-per-cluster-pi-compute-hop.md","contentType":"file"},{"name":"ADR-084-rabitq-similarity-sensor.md","path":"docs/adr/ADR-084-rabitq-similarity-sensor.md","contentType":"file"},{"name":"ADR-085-rabitq-pipeline-expansion.md","path":"docs/adr/ADR-085-rabitq-pipeline-expansion.md","contentType":"file"},{"name":"ADR-086-edge-novelty-gate.md","path":"docs/adr/ADR-086-edge-novelty-gate.md","contentType":"file"},{"name":"ADR-089-nvsim-nv-diamond-simulator.md","path":"docs/adr/ADR-089-nvsim-nv-diamond-simulator.md","contentType":"file"},{"name":"ADR-090-nvsim-lindblad-extension.md","path":"docs/adr/ADR-090-nvsim-lindblad-extension.md","contentType":"file"},{"name":"ADR-091-stand-off-radar-tier-research.md","path":"docs/adr/ADR-091-stand-off-radar-tier-research.md","contentType":"file"},{"name":"ADR-092-nvsim-dashboard-implementation.md","path":"docs/adr/ADR-092-nvsim-dashboard-implementation.md","contentType":"file"},{"name":"ADR-093-dashboard-gap-analysis.md","path":"docs/adr/ADR-093-dashboard-gap-analysis.md","contentType":"file"},{"name":"ADR-094-pointcloud-github-pages-deployment.md","path":"docs/adr/ADR-094-pointcloud-github-pages-deployment.md","contentType":"file"},{"name":"ADR-095-rvcsi-edge-rf-sensing-platform.md","path":"docs/adr/ADR-095-rvcsi-edge-rf-sensing-platform.md","contentType":"file"},{"name":"ADR-096-rvcsi-ffi-crate-layout.md","path":"docs/adr/ADR-096-rvcsi-ffi-crate-layout.md","contentType":"file"},{"name":"ADR-097-adopt-rvcsi-as-ruview-csi-runtime.md","path":"docs/adr/ADR-097-adopt-rvcsi-as-ruview-csi-runtime.md","contentType":"file"},{"name":"ADR-098-evaluate-midstream-fit.md","path":"docs/adr/ADR-098-evaluate-midstream-fit.md","contentType":"file"},{"name":"ADR-099-midstream-introspection-tap.md","path":"docs/adr/ADR-099-midstream-introspection-tap.md","contentType":"file"},{"name":"ADR-100-cog-packaging-specification.md","path":"docs/adr/ADR-100-cog-packaging-specification.md","contentType":"file"},{"name":"ADR-101-pose-estimation-cog.md","path":"docs/adr/ADR-101-pose-estimation-cog.md","contentType":"file"},{"name":"ADR-102-edge-module-registry.md","path":"docs/adr/ADR-102-edge-module-registry.md","contentType":"file"},{"name":"ADR-103-learned-multi-person-counter.md","path":"docs/adr/ADR-103-learned-multi-person-counter.md","contentType":"file"},{"name":"ADR-104-ruview-mcp-cli-distribution.md","path":"docs/adr/ADR-104-ruview-mcp-cli-distribution.md","contentType":"file"},{"name":"ADR-105-federated-csi-training.md","path":"docs/adr/ADR-105-federated-csi-training.md","contentType":"file"},{"name":"ADR-106-dp-sgd-and-primitive-isolation.md","path":"docs/adr/ADR-106-dp-sgd-and-primitive-isolation.md","contentType":"file"},{"name":"ADR-107-cross-installation-federation.md","path":"docs/adr/ADR-107-cross-installation-federation.md","contentType":"file"},{"name":"ADR-108-kyber-post-quantum-key-exchange.md","path":"docs/adr/ADR-108-kyber-post-quantum-key-exchange.md","contentType":"file"},{"name":"ADR-109-dilithium-pqc-signatures.md","path":"docs/adr/ADR-109-dilithium-pqc-signatures.md","contentType":"file"},{"name":"ADR-110-esp32-c6-firmware-extension.md","path":"docs/adr/ADR-110-esp32-c6-firmware-extension.md","contentType":"file"},{"name":"ADR-113-multistatic-placement-strategy.md","path":"docs/adr/ADR-113-multistatic-placement-strategy.md","contentType":"file"},{"name":"ADR-114-cog-quantum-vitals.md","path":"docs/adr/ADR-114-cog-quantum-vitals.md","contentType":"file"},{"name":"ADR-115-home-assistant-integration.md","path":"docs/adr/ADR-115-home-assistant-integration.md","contentType":"file"},{"name":"ADR-116-cog-ha-matter-seed.md","path":"docs/adr/ADR-116-cog-ha-matter-seed.md","contentType":"file"},{"name":"ADR-117-pip-wifi-densepose-modernization.md","path":"docs/adr/ADR-117-pip-wifi-densepose-modernization.md","contentType":"file"},{"name":"ADR-118-bfld-beamforming-feedback-layer-for-detection.md","path":"docs/adr/ADR-118-bfld-beamforming-feedback-layer-for-detection.md","contentType":"file"},{"name":"ADR-119-bfld-frame-format-and-wire-protocol.md","path":"docs/adr/ADR-119-bfld-frame-format-and-wire-protocol.md","contentType":"file"},{"name":"ADR-120-bfld-privacy-class-and-hash-rotation.md","path":"docs/adr/ADR-120-bfld-privacy-class-and-hash-rotation.md","contentType":"file"},{"name":"ADR-121-bfld-identity-risk-scoring.md","path":"docs/adr/ADR-121-bfld-identity-risk-scoring.md","contentType":"file"},{"name":"ADR-122-bfld-ruview-ha-matter-exposure.md","path":"docs/adr/ADR-122-bfld-ruview-ha-matter-exposure.md","contentType":"file"},{"name":"ADR-123-bfld-capture-path-nexmon-and-esp32.md","path":"docs/adr/ADR-123-bfld-capture-path-nexmon-and-esp32.md","contentType":"file"},{"name":"ADR-124-rvagent-mcp-ruvector-npm-integration.md","path":"docs/adr/ADR-124-rvagent-mcp-ruvector-npm-integration.md","contentType":"file"},{"name":"ADR-125-ruview-apple-home-native-hap-bridge.md","path":"docs/adr/ADR-125-ruview-apple-home-native-hap-bridge.md","contentType":"file"},{"name":"ADR-126-ruview-native-ha-port-master.md","path":"docs/adr/ADR-126-ruview-native-ha-port-master.md","contentType":"file"},{"name":"ADR-127-homecore-state-machine-rust.md","path":"docs/adr/ADR-127-homecore-state-machine-rust.md","contentType":"file"},{"name":"ADR-128-homecore-integration-plugin-system.md","path":"docs/adr/ADR-128-homecore-integration-plugin-system.md","contentType":"file"},{"name":"ADR-129-homecore-automation-engine.md","path":"docs/adr/ADR-129-homecore-automation-engine.md","contentType":"file"},{"name":"ADR-130-homecore-rest-websocket-api.md","path":"docs/adr/ADR-130-homecore-rest-websocket-api.md","contentType":"file"},{"name":"ADR-131-homecore-ui-operational-dashboard.md","path":"docs/adr/ADR-131-homecore-ui-operational-dashboard.md","contentType":"file"},{"name":"ADR-132-homecore-recorder-history-semantic-search.md","path":"docs/adr/ADR-132-homecore-recorder-history-semantic-search.md","contentType":"file"},{"name":"ADR-133-homecore-assist-ruflo.md","path":"docs/adr/ADR-133-homecore-assist-ruflo.md","contentType":"file"},{"name":"ADR-134-csi-to-cir-time-domain-multipath.md","path":"docs/adr/ADR-134-csi-to-cir-time-domain-multipath.md","contentType":"file"},{"name":"ADR-135-empty-room-baseline-calibration.md","path":"docs/adr/ADR-135-empty-room-baseline-calibration.md","contentType":"file"},{"name":"ADR-136-ruview-streaming-engine-frame-contracts.md","path":"docs/adr/ADR-136-ruview-streaming-engine-frame-contracts.md","contentType":"file"},{"name":"ADR-137-fusion-engine-quality-scoring-evidence.md","path":"docs/adr/ADR-137-fusion-engine-quality-scoring-evidence.md","contentType":"file"},{"name":"ADR-138-linkgroup-array-coordinator-clock-quality.md","path":"docs/adr/ADR-138-linkgroup-array-coordinator-clock-quality.md","contentType":"file"},{"name":"ADR-139-worldgraph-environmental-digital-twin.md","path":"docs/adr/ADR-139-worldgraph-environmental-digital-twin.md","contentType":"file"},{"name":"ADR-140-semantic-state-record-and-agent-bridge.md","path":"docs/adr/ADR-140-semantic-state-record-and-agent-bridge.md","contentType":"file"},{"name":"ADR-141-bfld-privacy-control-plane-modes-attestation.md","path":"docs/adr/ADR-141-bfld-privacy-control-plane-modes-attestation.md","contentType":"file"},{"name":"ADR-142-evolution-tracker-temporal-voxel-aggregation.md","path":"docs/adr/ADR-142-evolution-tracker-temporal-voxel-aggregation.md","contentType":"file"},{"name":"ADR-143-rf-slam-reflector-discovery-anchor-learning.md","path":"docs/adr/ADR-143-rf-slam-reflector-discovery-anchor-learning.md","contentType":"file"},{"name":"ADR-144-uwb-range-constraint-fusion.md","path":"docs/adr/ADR-144-uwb-range-constraint-fusion.md","contentType":"file"},{"name":"ADR-145-ablation-eval-harness-privacy-leakage.md","path":"docs/adr/ADR-145-ablation-eval-harness-privacy-leakage.md","contentType":"file"},{"name":"ADR-146-rf-encoder-multitask-heads-uncertainty.md","path":"docs/adr/ADR-146-rf-encoder-multitask-heads-uncertainty.md","contentType":"file"},{"name":"ADR-147-nvidia-cosmos-world-foundation-model-integration.md","path":"docs/adr/ADR-147-nvidia-cosmos-world-foundation-model-integration.md","contentType":"file"},{"name":"ADR-148-drone-swarm-control-system.md","path":"docs/adr/ADR-148-drone-swarm-control-system.md","contentType":"file"},{"name":"ADR-149-public-community-leaderboard-huggingface.md","path":"docs/adr/ADR-149-public-community-leaderboard-huggingface.md","contentType":"file"},{"name":"ADR-150-rf-foundation-encoder.md","path":"docs/adr/ADR-150-rf-foundation-encoder.md","contentType":"file"},{"name":"ADR-151-room-calibration-specialist-training.md","path":"docs/adr/ADR-151-room-calibration-specialist-training.md","contentType":"file"},{"name":"ADR-152-wifi-pose-sota-2026-intake.md","path":"docs/adr/ADR-152-wifi-pose-sota-2026-intake.md","contentType":"file"},{"name":"ADR-153-ieee-802-11bf-sensing-protocol-layer.md","path":"docs/adr/ADR-153-ieee-802-11bf-sensing-protocol-layer.md","contentType":"file"},{"name":"ADR-154-signal-dsp-beyond-sota.md","path":"docs/adr/ADR-154-signal-dsp-beyond-sota.md","contentType":"file"},{"name":"ADR-155-nn-training-beyond-sota.md","path":"docs/adr/ADR-155-nn-training-beyond-sota.md","contentType":"file"},{"name":"ADR-156-ruvector-fusion-beyond-sota.md","path":"docs/adr/ADR-156-ruvector-fusion-beyond-sota.md","contentType":"file"},{"name":"ADR-157-hardware-sensing-beyond-sota.md","path":"docs/adr/ADR-157-hardware-sensing-beyond-sota.md","contentType":"file"},{"name":"ADR-158-mat-worldmodel-beyond-sota.md","path":"docs/adr/ADR-158-mat-worldmodel-beyond-sota.md","contentType":"file"},{"name":"ADR-159-cognitum-appliance-beyond-sota.md","path":"docs/adr/ADR-159-cognitum-appliance-beyond-sota.md","contentType":"file"},{"name":"ADR-160-edge-skill-library-honest-labeling.md","path":"docs/adr/ADR-160-edge-skill-library-honest-labeling.md","contentType":"file"},{"name":"ADR-161-homecore-server-layer-security.md","path":"docs/adr/ADR-161-homecore-server-layer-security.md","contentType":"file"},{"name":"ADR-162-plugin-security-and-bounded-runmodes.md","path":"docs/adr/ADR-162-plugin-security-and-bounded-runmodes.md","contentType":"file"},{"name":"ADR-163-edge-latency-measurement.md","path":"docs/adr/ADR-163-edge-latency-measurement.md","contentType":"file"},{"name":"ADR-164-adr-corpus-gap-analysis.md","path":"docs/adr/ADR-164-adr-corpus-gap-analysis.md","contentType":"file"},{"name":"ADR-165-homecore-migrate-from-home-assistant.md","path":"docs/adr/ADR-165-homecore-migrate-from-home-assistant.md","contentType":"file"},{"name":"ADR-166-quality-engineering-security-hardening.md","path":"docs/adr/ADR-166-quality-engineering-security-hardening.md","contentType":"file"},{"name":"ADR-167-ddd-bounded-contexts.md","path":"docs/adr/ADR-167-ddd-bounded-contexts.md","contentType":"file"},{"name":"ADR-168-benchmark-proof.md","path":"docs/adr/ADR-168-benchmark-proof.md","contentType":"file"},{"name":"ADR-169-adam-mode-light-theme.md","path":"docs/adr/ADR-169-adam-mode-light-theme.md","contentType":"file"},{"name":"ADR-170-yoga-mode-pose-system.md","path":"docs/adr/ADR-170-yoga-mode-pose-system.md","contentType":"file"},{"name":"ADR-171-swarm-benchmarking-evaluation-methodology.md","path":"docs/adr/ADR-171-swarm-benchmarking-evaluation-methodology.md","contentType":"file"},{"name":"ADR-172-cli-core-csi-deserialiser-security-review.md","path":"docs/adr/ADR-172-cli-core-csi-deserialiser-security-review.md","contentType":"file"},{"name":"ADR-173-metric-locked-pck-mpjpe-accuracy-harness.md","path":"docs/adr/ADR-173-metric-locked-pck-mpjpe-accuracy-harness.md","contentType":"file"},{"name":"ADR-174-ci-bench-regression-compile-verify-gate.md","path":"docs/adr/ADR-174-ci-bench-regression-compile-verify-gate.md","contentType":"file"},{"name":"ADR-175-int8-quantization-half-pose-model-measured.md","path":"docs/adr/ADR-175-int8-quantization-half-pose-model-measured.md","contentType":"file"},{"name":"ADR-176-ruview-swarm-nan-fail-open-safety-review.md","path":"docs/adr/ADR-176-ruview-swarm-nan-fail-open-safety-review.md","contentType":"file"},{"name":"ADR-177-nvsim-degenerate-input-hardening.md","path":"docs/adr/ADR-177-nvsim-degenerate-input-hardening.md","contentType":"file"},{"name":"ADR-178-desktop-ipc-injection-and-capability-least-privilege.md","path":"docs/adr/ADR-178-desktop-ipc-injection-and-capability-least-privilege.md","contentType":"file"},{"name":"ADR-179-occworld-candle-checkpoint-load-hardening.md","path":"docs/adr/ADR-179-occworld-candle-checkpoint-load-hardening.md","contentType":"file"},{"name":"ADR-182-npx-ruview-harness-via-metaharness.md","path":"docs/adr/ADR-182-npx-ruview-harness-via-metaharness.md","contentType":"file"},{"name":"ADR-183-onboard-led-gamma-stimulus-csi-colormap.md","path":"docs/adr/ADR-183-onboard-led-gamma-stimulus-csi-colormap.md","contentType":"file"},{"name":"ADR-184-adr117-completion-pypi-trusted-publishing.md","path":"docs/adr/ADR-184-adr117-completion-pypi-trusted-publishing.md","contentType":"file"},{"name":"ADR-185-python-p6-sota-bindings.md","path":"docs/adr/ADR-185-python-p6-sota-bindings.md","contentType":"file"},{"name":"ADR-186-training-progress-api.md","path":"docs/adr/ADR-186-training-progress-api.md","contentType":"file"},{"name":"ADR-187-archive-v1-deprecation-honest-labeling.md","path":"docs/adr/ADR-187-archive-v1-deprecation-honest-labeling.md","contentType":"file"},{"name":"ADR-260-rufield-mfs.md","path":"docs/adr/ADR-260-rufield-mfs.md","contentType":"file"},{"name":"ADR-261-ruvector-graph-ann-index.md","path":"docs/adr/ADR-261-ruvector-graph-ann-index.md","contentType":"file"},{"name":"ADR-262-rufield-ruview-integration.md","path":"docs/adr/ADR-262-rufield-ruview-integration.md","contentType":"file"},{"name":"ADR-263-rtl8720f-2-4ghz-fmcw-radar-platform.md","path":"docs/adr/ADR-263-rtl8720f-2-4ghz-fmcw-radar-platform.md","contentType":"file"},{"name":"ADR-263-ruview-npm-harness-deep-review.md","path":"docs/adr/ADR-263-ruview-npm-harness-deep-review.md","contentType":"file"},{"name":"ADR-264-rtl8720f-radar-wire-protocol.md","path":"docs/adr/ADR-264-rtl8720f-radar-wire-protocol.md","contentType":"file"},{"name":"ADR-264-rvagent-mcp-and-cli-npm-deep-review.md","path":"docs/adr/ADR-264-rvagent-mcp-and-cli-npm-deep-review.md","contentType":"file"},{"name":"ADR-265-ruview-npm-distribution-strategy.md","path":"docs/adr/ADR-265-ruview-npm-distribution-strategy.md","contentType":"file"},{"name":"ADR-266-mediatek-filogic-csi-platform.md","path":"docs/adr/ADR-266-mediatek-filogic-csi-platform.md","contentType":"file"},{"name":"ADR-267-mediatek-mimo-csi-wire-protocol.md","path":"docs/adr/ADR-267-mediatek-mimo-csi-wire-protocol.md","contentType":"file"},{"name":"ADR-268-qualcomm-atheros-csi-platform.md","path":"docs/adr/ADR-268-qualcomm-atheros-csi-platform.md","contentType":"file"},{"name":"ADR-269-qualcomm-csi-wire-protocol.md","path":"docs/adr/ADR-269-qualcomm-csi-wire-protocol.md","contentType":"file"},{"name":"ADR-270-vendor-rf-sensing-integration-program.md","path":"docs/adr/ADR-270-vendor-rf-sensing-integration-program.md","contentType":"file"},{"name":"ADR-271-cognitum-oauth-resource-server.md","path":"docs/adr/ADR-271-cognitum-oauth-resource-server.md","contentType":"file"},{"name":"ADR-272-websocket-authentication-tickets.md","path":"docs/adr/ADR-272-websocket-authentication-tickets.md","contentType":"file"},{"name":"ADR-273-unified-rf-spatial-world-model.md","path":"docs/adr/ADR-273-unified-rf-spatial-world-model.md","contentType":"file"},{"name":"ADR-274-universal-rf-encoder-adapter-registry.md","path":"docs/adr/ADR-274-universal-rf-encoder-adapter-registry.md","contentType":"file"},{"name":"ADR-275-rf-aware-gaussian-spatial-memory.md","path":"docs/adr/ADR-275-rf-aware-gaussian-spatial-memory.md","contentType":"file"},{"name":"ADR-276-physics-guided-synthetic-rf-worlds.md","path":"docs/adr/ADR-276-physics-guided-synthetic-rf-worlds.md","contentType":"file"},{"name":"ADR-277-edge-sensing-control-plane.md","path":"docs/adr/ADR-277-edge-sensing-control-plane.md","contentType":"file"},{"name":"ADR-278-radar-inverse-rendering-research-program.md","path":"docs/adr/ADR-278-radar-inverse-rendering-research-program.md","contentType":"file"},{"name":"ADR-279-native-rf-frame-contract.md","path":"docs/adr/ADR-279-native-rf-frame-contract.md","contentType":"file"},{"name":"ADR-280-active-sensing-programmable-perception.md","path":"docs/adr/ADR-280-active-sensing-programmable-perception.md","contentType":"file"},{"name":"ADR-281-ble-cs-delay-doppler-pose-factorization.md","path":"docs/adr/ADR-281-ble-cs-delay-doppler-pose-factorization.md","contentType":"file"},{"name":"ADR-282-ruview-ecosystem-positioning.md","path":"docs/adr/ADR-282-ruview-ecosystem-positioning.md","contentType":"file"},{"name":"ADR-283-ruview-community-metaharness-flywheel.md","path":"docs/adr/ADR-283-ruview-community-metaharness-flywheel.md","contentType":"file"},{"name":"ADR-284-bounded-nightly-sota-agent.md","path":"docs/adr/ADR-284-bounded-nightly-sota-agent.md","contentType":"file"},{"name":"ADR-285-homecore-wasm-first-metaharness.md","path":"docs/adr/ADR-285-homecore-wasm-first-metaharness.md","contentType":"file"},{"name":"ADR-286-wifi-densepose-sar-harness-via-metaharness.md","path":"docs/adr/ADR-286-wifi-densepose-sar-harness-via-metaharness.md","contentType":"file"},{"name":"ADR-287-coherent-wideband-rf-tomography-crate.md","path":"docs/adr/ADR-287-coherent-wideband-rf-tomography-crate.md","contentType":"file"},{"name":"ADR-288-veil-privacy-shield-compliant-waveform.md","path":"docs/adr/ADR-288-veil-privacy-shield-compliant-waveform.md","contentType":"file"},{"name":"ADR-289-wifi-densepose-privshield-harness-via-metaharness.md","path":"docs/adr/ADR-289-wifi-densepose-privshield-harness-via-metaharness.md","contentType":"file"},{"name":"ADR-290-veil-e2e-hardware-implementation-program.md","path":"docs/adr/ADR-290-veil-e2e-hardware-implementation-program.md","contentType":"file"},{"name":"ADR-291-public-benchmark-evaluation-harness.md","path":"docs/adr/ADR-291-public-benchmark-evaluation-harness.md","contentType":"file"},{"name":"ADR-292-wideband-80211ax-csi-ingest.md","path":"docs/adr/ADR-292-wideband-80211ax-csi-ingest.md","contentType":"file"},{"name":"ADR-293-vitals-ground-truth-rig.md","path":"docs/adr/ADR-293-vitals-ground-truth-rig.md","contentType":"file"},{"name":"ADR-294-wifi-veil-integration.md","path":"docs/adr/ADR-294-wifi-veil-integration.md","contentType":"file"},{"name":"ADR-295-source-provenance-state-machine.md","path":"docs/adr/ADR-295-source-provenance-state-machine.md","contentType":"file"},{"name":"ADR-296-sensor-data-plane-bind-hardening.md","path":"docs/adr/ADR-296-sensor-data-plane-bind-hardening.md","contentType":"file"},{"name":"ADR-297-multi-node-semantic-correctness.md","path":"docs/adr/ADR-297-multi-node-semantic-correctness.md","contentType":"file"},{"name":"ADR-298-model-release-sanity-gates.md","path":"docs/adr/ADR-298-model-release-sanity-gates.md","contentType":"file"},{"name":"ADR-299-csi-data-incident-repo-controls.md","path":"docs/adr/ADR-299-csi-data-incident-repo-controls.md","contentType":"file"},{"name":"ADR-300-perception-substrate-program.md","path":"docs/adr/ADR-300-perception-substrate-program.md","contentType":"file"},{"name":"ADR-301-automatic-domain-calibration.md","path":"docs/adr/ADR-301-automatic-domain-calibration.md","contentType":"file"},{"name":"ADR-302-out-of-distribution-detection.md","path":"docs/adr/ADR-302-out-of-distribution-detection.md","contentType":"file"},{"name":"ADR-303-ground-truth-synchronization.md","path":"docs/adr/ADR-303-ground-truth-synchronization.md","contentType":"file"},{"name":"ADR-304-evidence-engine.md","path":"docs/adr/ADR-304-evidence-engine.md","contentType":"file"},{"name":"ADR-305-authenticated-sensor-identity.md","path":"docs/adr/ADR-305-authenticated-sensor-identity.md","contentType":"file"},{"name":"ADR-306-canonical-spatial-ontology.md","path":"docs/adr/ADR-306-canonical-spatial-ontology.md","contentType":"file"},{"name":"ADR-307-persistent-identity-tracking.md","path":"docs/adr/ADR-307-persistent-identity-tracking.md","contentType":"file"},{"name":"ADR-308-sensor-placement-optimizer.md","path":"docs/adr/ADR-308-sensor-placement-optimizer.md","contentType":"file"},{"name":"ADR-309-active-sensing.md","path":"docs/adr/ADR-309-active-sensing.md","contentType":"file"},{"name":"ADR-310-80211bf-native-architecture.md","path":"docs/adr/ADR-310-80211bf-native-architecture.md","contentType":"file"},{"name":"ADR-311-real-sensor-fusion.md","path":"docs/adr/ADR-311-real-sensor-fusion.md","contentType":"file"},{"name":"ADR-312-long-term-spatial-memory.md","path":"docs/adr/ADR-312-long-term-spatial-memory.md","contentType":"file"},{"name":"ADR-313-counterfactual-inference.md","path":"docs/adr/ADR-313-counterfactual-inference.md","contentType":"file"},{"name":"ADR-314-information-gain-scheduler.md","path":"docs/adr/ADR-314-information-gain-scheduler.md","contentType":"file"},{"name":"ADR-315-digital-rf-twin.md","path":"docs/adr/ADR-315-digital-rf-twin.md","contentType":"file"},{"name":"ADR-316-fleet-control-plane.md","path":"docs/adr/ADR-316-fleet-control-plane.md","contentType":"file"},{"name":"ADR-317-benchmark-multi-domain-scorecard.md","path":"docs/adr/ADR-317-benchmark-multi-domain-scorecard.md","contentType":"file"},{"name":"ADR-318-capability-certificates.md","path":"docs/adr/ADR-318-capability-certificates.md","contentType":"file"},{"name":"ADR-319-witness-chain.md","path":"docs/adr/ADR-319-witness-chain.md","contentType":"file"},{"name":"ADR-320-sensor-hal.md","path":"docs/adr/ADR-320-sensor-hal.md","contentType":"file"},{"name":"ADR-321-decision-policy-action-authorization.md","path":"docs/adr/ADR-321-decision-policy-action-authorization.md","contentType":"file"},{"name":"ADR-323-native-rust-physics-constrained-pose-refinement.md","path":"docs/adr/ADR-323-native-rust-physics-constrained-pose-refinement.md","contentType":"file"},{"name":"ADR-324-off-axis-head-coupled-perspective-demo.md","path":"docs/adr/ADR-324-off-axis-head-coupled-perspective-demo.md","contentType":"file"},{"name":"ADR-325-cognitum-spaces-activation-and-governed-spatial-exchange.md","path":"docs/adr/ADR-325-cognitum-spaces-activation-and-governed-spatial-exchange.md","contentType":"file"},{"name":"ADR-326-tenant-scoped-ruvector-spatial-memory.md","path":"docs/adr/ADR-326-tenant-scoped-ruvector-spatial-memory.md","contentType":"file"},{"name":"ADR-327-governed-action-intents-and-witness-receipts.md","path":"docs/adr/ADR-327-governed-action-intents-and-witness-receipts.md","contentType":"file"},{"name":"README.md","path":"docs/adr/README.md","contentType":"file"}],"totalCount":252},"docs":{"items":[{"name":"adr","path":"docs/adr","contentType":"directory"},{"name":"archtocode-visual-overview","path":"docs/archtocode-visual-overview","contentType":"directory"},{"name":"benchmarks","path":"docs/benchmarks","contentType":"directory"},{"name":"ddd","path":"docs/ddd","contentType":"directory"},{"name":"design","path":"docs/design","contentType":"directory"},{"name":"edge-modules","path":"docs/edge-modules","contentType":"directory"},{"name":"huggingface","path":"docs/huggingface","contentType":"directory"},{"name":"integration","path":"docs/integration","contentType":"directory"},{"name":"integrations","path":"docs/integrations","contentType":"directory"},{"name":"prd","path":"docs/prd","contentType":"directory"},{"name":"qe-reports","path":"docs/qe-reports","contentType":"directory"},{"name":"releases","path":"docs/releases","contentType":"directory"},{"name":"research","path":"docs/research","contentType":"directory"},{"name":"schemas","path":"docs/schemas","contentType":"directory"},{"name":"security","path":"docs/security","contentType":"directory"},{"name":"tutorials","path":"docs/tutorials","contentType":"directory"},{"name":"ADR-110-BRANCH-STATE.md","path":"docs/ADR-110-BRANCH-STATE.md","contentType":"file"},{"name":"ADR-110-REVIEW-GUIDE.md","path":"docs/ADR-110-REVIEW-GUIDE.md","contentType":"file"},{"name":"RELEASE-streaming-engine-v0.3.0.md","path":"docs/RELEASE-streaming-engine-v0.3.0.md","contentType":"file"},{"name":"TROUBLESHOOTING.md","path":"docs/TROUBLESHOOTING.md","contentType":"file"},{"name":"WITNESS-LOG-028.md","path":"docs/WITNESS-LOG-028.md","contentType":"file"},{"name":"WITNESS-LOG-110.md","path":"docs/WITNESS-LOG-110.md","contentType":"file"},{"name":"build-guide.md","path":"docs/build-guide.md","contentType":"file"},{"name":"calibration-guide.md","path":"docs/calibration-guide.md","contentType":"file"},{"name":"observability.md","path":"docs/observability.md","contentType":"file"},{"name":"proof-of-capabilities.md","path":"docs/proof-of-capabilities.md","contentType":"file"},{"name":"readme-details.md","path":"docs/readme-details.md","contentType":"file"},{"name":"security-audit-wasm-edge-vendor.md","path":"docs/security-audit-wasm-edge-vendor.md","contentType":"file"},{"name":"trust-and-engine-errors.md","path":"docs/trust-and-engine-errors.md","contentType":"file"},{"name":"user-guide-apple-homepod.md","path":"docs/user-guide-apple-homepod.md","contentType":"file"},{"name":"user-guide.md","path":"docs/user-guide.md","contentType":"file"},{"name":"vendor-rf-providers.md","path":"docs/vendor-rf-providers.md","contentType":"file"},{"name":"wifi-mat-user-guide.md","path":"docs/wifi-mat-user-guide.md","contentType":"file"}],"totalCount":33},"":{"items":[{"name":".claude-flow","path":".claude-flow","contentType":"directory"},{"name":".claude-plugin","path":".claude-plugin","contentType":"directory"},{"name":".claude","path":".claude","contentType":"directory"},{"name":".github","path":".github","contentType":"directory"},{"name":".swarm","path":".swarm","contentType":"directory"},{"name":".vscode","path":".vscode","contentType":"directory"},{"name":"aether-arena","path":"aether-arena","contentType":"directory"},{"name":"archive","path":"archive","contentType":"directory"},{"name":"assets","path":"assets","contentType":"directory"},{"name":"benchmarks","path":"benchmarks","contentType":"directory"},{"name":"dashboard","path":"dashboard","contentType":"directory"},{"name":"data","path":"data","contentType":"directory"},{"name":"docker","path":"docker","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"examples","path":"examples","contentType":"directory"},{"name":"firmware","path":"firmware","contentType":"directory"},{"name":"harness","path":"harness","contentType":"directory"},{"name":"logging","path":"logging","contentType":"directory"},{"name":"monitoring","path":"monitoring","contentType":"directory"},{"name":"plans","path":"plans","contentType":"directory"},{"name":"plugins","path":"plugins","contentType":"directory"},{"name":"python","path":"python","contentType":"directory"},{"name":"references","path":"references","contentType":"directory"},{"name":"releases","path":"releases","contentType":"directory"},{"name":"scripts","path":"scripts","contentType":"directory"},{"name":"semconv","path":"semconv","contentType":"directory"},{"name":"templates","path":"templates","contentType":"directory"},{"name":"tests","path":"tests","contentType":"directory"},{"name":"tools","path":"tools","contentType":"directory"},{"name":"ui","path":"ui","contentType":"directory"},{"name":"v2","path":"v2","contentType":"directory"},{"name":"vendor","path":"vendor","contentType":"directory"},{"name":"wifi-veil","path":"wifi-veil","contentType":"directory"},{"name":"wifi_densepose","path":"wifi_densepose","contentType":"directory"},{"name":".dockerignore","path":".dockerignore","contentType":"file"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".gitmodules","path":".gitmodules","contentType":"file"},{"name":".mcp.json","path":".mcp.json","contentType":"file"},{"name":"AGENTS.md","path":"AGENTS.md","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"CLAUDE.md","path":"CLAUDE.md","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"Makefile","path":"Makefile","contentType":"file"},{"name":"PROOF.md","path":"PROOF.md","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"benchmark_baseline.json","path":"benchmark_baseline.json","contentType":"file"},{"name":"deploy.sh","path":"deploy.sh","contentType":"file"},{"name":"example.env","path":"example.env","contentType":"file"},{"name":"install.sh","path":"install.sh","contentType":"file"},{"name":"pyproject.toml","path":"pyproject.toml","contentType":"file"},{"name":"requirements-dev.txt","path":"requirements-dev.txt","contentType":"file"},{"name":"requirements.txt","path":"requirements.txt","contentType":"file"},{"name":"verify","path":"verify","contentType":"file"}],"totalCount":54}},"fileTreeProcessingTime":89.999338,"foldersToFetch":[]},"codeViewBlobLayoutRoute":{"codeLineWrapEnabled":false,"refInfo":{"name":"main","listCacheKey":"v0:1787423101.0","canEdit":false,"refType":"branch","currentOid":"a3b6e1d500df784b9ad1846dd39deb07e2c69a34","canEditOnDefaultBranch":false,"fileExistsOnDefault":true},"path":"docs/adr/ADR-096-rvcsi-ffi-crate-layout.md","blob":{"copilotSWEAgentEnabled":false,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/Esbroro/RuView/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"ADR-096-rvcsi-ffi-crate-layout.md","displayUrl":"https://github.com/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md?raw=true","headerInfo":{"blobSize":"18.6 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"794f093","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2FEsbroro%2FRuView%2Fblob%2Fmain%2Fdocs%2Fadr%2FADR-096-rvcsi-ffi-crate-layout.md","isCSV":false,"isRichtext":true,"lineInfo":{"truncatedLoc":"144","truncatedSloc":"99"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"isIssueTemplate":false,"isDiscussionTemplate":false,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/Esbroro/RuView/blob/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/Esbroro/RuView/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/Esbroro/RuView/raw/refs/heads/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md","renderImageOrRaw":false,"shortPath":null,"symbolsEnabled":true,"tabSize":4,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null},"copilotInfo":null,"copilotAccessAllowed":false,"copilotSpacesEnabled":false,"modelsAccessAllowed":false,"modelsRepoIntegrationEnabled":false,"isMarketplaceEnabled":true},"codeViewBlobLayoutRoute.StyledBlob":{"rawLines":["# ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface","","| Field | Value |","|-------|-------|","| **Status** | Proposed |","| **Date** | 2026-05-12 |","| **Deciders** | ruv |","| **Codename** | **rvCSI** — RuVector Channel State Information runtime |","| **Relates to** | ADR-095 (rvCSI platform — D1 Rust core, D2 C-at-the-boundary, D3 TS SDK, D4 napi-rs, D5 normalized schema, D6 validate-before-FFI, D15 plugin adapters), ADR-009/ADR-040 (WASM runtimes), ADR-049 (cross-platform WiFi interface detection) |","| **PRD** | [rvCSI Platform PRD](../prd/rvcsi-platform-prd.md) |","| **Domain model** | [rvCSI Domain Model](../ddd/rvcsi-domain-model.md) |","| **Implements** | `v2/crates/rvcsi-core`, `rvcsi-dsp`, `rvcsi-events`, `rvcsi-adapter-file`, `rvcsi-adapter-nexmon`, `rvcsi-ruvector`, `rvcsi-node`, `rvcsi-cli` |","","---","","## 1. Context","","ADR-095 set the platform-level invariant `C → Rust → TypeScript` and the fifteen decisions that constrain rvCSI. This ADR makes the *implementation* concrete: which crates exist, what each owns, where the two FFI seams are (the **napi-c** C shim below Rust, and the **napi-rs** Node addon above it), and the rules that keep `unsafe` confined and the boundary objects validated.","","The two seams:","","- **napi-c** — the *downward* seam to fragile vendor/firmware/driver code. Per ADR-095 D2, C is the only language allowed here, and only as a thin, allocation-free, bounds-checked shim. The Nexmon family is the first consumer.","- **napi-rs** — the *upward* seam to Node.js/TypeScript. Per ADR-095 D3/D4, the Rust runtime is exposed to JS via [napi-rs](https://napi.rs/); nothing crosses this seam that hasn't been validated (D6) and normalized (D5).","","Both seams are *narrow on purpose*: everything in between — parsing, validation, DSP, windowing, event extraction, RuVector export — is safe Rust (`#![forbid(unsafe_code)]` in every crate except `rvcsi-adapter-nexmon`, which needs `extern \"C\"`).","","---","","## 2. Decision","","### 2.1 Crate topology","","Eight new workspace members under `v2/crates/`:","","| Crate | `unsafe`? | Depends on | Owns |","|-------|-----------|------------|------|","| `rvcsi-core` | no (`forbid`) | — (serde, thiserror) | The normalized schema (`CsiFrame`/`CsiWindow`/`CsiEvent`), `AdapterProfile`, the `CsiSource` plugin trait, id newtypes + `IdGenerator`, `RvcsiError`, and the `validate_frame` pipeline + quality scoring. The shared kernel. |","| `rvcsi-dsp` | no (`forbid`) | `rvcsi-core` | Reusable DSP stages (DC removal, phase unwrap, smoothing, Hampel/MAD outlier filter, sliding variance, baseline subtraction) and scalar features (motion energy, presence score, confidence, heuristic breathing-band estimate), plus a non-destructive `SignalPipeline::process_frame`. |","| `rvcsi-events` | no (`forbid`) | `rvcsi-core` | `WindowBuffer` (frames → `CsiWindow`), the `EventDetector` trait + presence/motion/quality/baseline-drift state machines, and `EventPipeline` (windows → `CsiEvent`s). The baseline-drift detector measures drift **relative to the running baseline's RMS magnitude** (a fraction, not absolute amplitude units), so the same thresholds work for raw `int8` ESP32 CSI, `int16`-scaled Nexmon CSI, and baseline-subtracted streams alike — see ADR-095 D13. |","| `rvcsi-adapter-file` | no (`forbid`) | `rvcsi-core` | The `.rvcsi` capture format (JSONL: a header line + one `CsiFrame` per line), `FileRecorder`, and `FileReplayAdapter` (a `CsiSource`) — deterministic replay (D9). |","| `rvcsi-adapter-nexmon` | **yes** (FFI only) | `rvcsi-core` + the C shim | The **napi-c** seam: `native/rvcsi_nexmon_shim.{c,h}` compiled via `build.rs`+`cc`, a documented `ffi` module wrapping it, a pure-Rust libpcap reader (`pcap.rs`), the Nexmon-chip / Raspberry-Pi-model registry (`chips.rs` — `NexmonChip`, `RaspberryPiModel` incl. **Pi 5**, profile builders), and two `CsiSource`s — `NexmonAdapter` (rvCSI-record buffers) and `NexmonPcapAdapter` (real nexmon_csi UDP payloads inside a `.pcap`, with chip auto-detection). |","| `rvcsi-ruvector` | no (`forbid`) | `rvcsi-core` | The RuVector RF-memory bridge: deterministic `window_embedding`/`event_embedding`, `cosine_similarity`, the `RfMemoryStore` trait, and `InMemoryRfMemory` + `JsonlRfMemory` (a standin until the production RuVector binding lands). |","| `rvcsi-runtime` | no (`forbid`) | core, dsp, events, adapter-file, adapter-nexmon, ruvector | The composition layer (no FFI): `CaptureRuntime` (a `CsiSource` + `validate_frame` + `SignalPipeline` + `EventPipeline`) plus one-shot helpers (`summarize_capture`, `decode_nexmon_records`, `decode_nexmon_pcap`, `summarize_nexmon_pcap`, `events_from_capture`, `export_capture_to_rf_memory`). The shared layer under `rvcsi-node` and `rvcsi-cli`. |","| `rvcsi-node` | no (`deny(clippy::all)`) | `rvcsi-core`, `rvcsi-runtime`, `rvcsi-adapter-nexmon` | The **napi-rs** seam: the `.node` addon (cdylib + rlib) exposing a safe TS-facing surface (thin `#[napi]` wrappers over `rvcsi-runtime`); `build.rs` runs `napi_build::setup()`. |","| `rvcsi-cli` | no | core, adapter-file, adapter-nexmon, runtime | The `rvcsi` binary: `record` (Nexmon-dump or nexmon-pcap → `.rvcsi`), `inspect`, `inspect-nexmon`, `decode-chanspec`, `replay`, `stream`, `events`, `health`, `calibrate`, `export ruvector` (ADR-095 FR7). |","","`rvcsi-events` does **not** call into `rvcsi-dsp`: window statistics are simple enough to compute in `WindowBuffer` itself, and keeping the two leaves independent removes a coordination point. `rvcsi-cli` does **not** depend on `rvcsi-node` (a binary can't link a napi cdylib's undefined Node symbols) — the shared logic lives in `rvcsi-runtime`, which both build on. Higher layers wire `SignalPipeline::process_frame` → `WindowBuffer::push` when they want cleaned frames.","","The MCP tool server (`rvcsi-mcp`) and the long-running daemon (`rvcsi-daemon`) — and live radio capture — are *not* in this ADR's scope; they sit on top of `rvcsi-runtime` / the crates above and are tracked as follow-ups. The `@ruv/rvcsi` npm package ships alongside `rvcsi-node`.","","### 2.2 The napi-c shim — record formats and contract","","`native/rvcsi_nexmon_shim.{c,h}` is the only C in the runtime. It handles **two byte formats** (ABI `1.1`):","","**(1) The \"rvCSI Nexmon record\"** — a compact, self-describing record (`'RVNX'` magic, version, flags, RSSI/noise, channel, bandwidth, timestamp, then interleaved `int16` I/Q in Q8.8 fixed point; total `24 + 4*N`). Used by the `rvcsi capture`/`record` recorder, the file replay path, and tests. Functions: `rvcsi_nx_record_len`, `rvcsi_nx_parse_record`, `rvcsi_nx_write_record`.","","**(2) The *real* nexmon_csi UDP payload** — what the patched Broadcom firmware actually sends to the host (port 5500 by default): the 18-byte header `magic=0x1111 (2) · rssi int8 (1) · fctl (1) · src_mac (6) · seq_cnt (2) · core/stream (2) · chanspec (2) · chip_ver (2)`, followed by `nsub` complex CSI samples. The shim implements the **modern int16 I/Q export** (`nsub` pairs of little-endian `int16` `(real, imag)`, raw counts — what CSIKit / `csireader.py` read for the BCM43455c0 / 4358 / 4366c0); `nsub` is derived from the payload length, `(len − 18) / 4`. Functions: `rvcsi_nx_csi_udp_header` (just the 18-byte header), `rvcsi_nx_csi_udp_decode` (header + CSI body, `csi_format` selector), `rvcsi_nx_csi_udp_write` (synthesize a payload — tests/examples), and `rvcsi_nx_decode_chanspec` (decode a Broadcom d11ac chanspec word → `channel` = `chanspec \u0026 0xff`, bandwidth from bits `[13:11]` cross-checked against the FFT size, band from bits `[15:14]` cross-checked against the channel number). The legacy nexmon *packed-float* export used by some 4339/4358 firmwares is a documented follow-up (it sits behind the same `csi_format` selector).","","The `timestamp_ns` of a frame from format (2) comes from the **pcap packet timestamp**, not the wire (nexmon_csi doesn't carry one). The pcap file itself is parsed in **pure Rust** (`rvcsi-adapter-nexmon::pcap` — classic libpcap, all four byte-order/timestamp-resolution magics, Ethernet / raw-IPv4 / Linux-SLL link types; pcapng is a follow-up): peeling the Ethernet/IPv4/UDP headers down to the payload is not a vendor-fragility concern, so it doesn't belong in C.","","Contract (both formats):","","- **Allocation-free, global-free.** Every read is bounds-checked against the caller-supplied length; nothing can scribble outside caller buffers; no `malloc`, no statics.","- **Structured errors, never panics.** Functions return one of a small set of `RvcsiNxError` codes (`TOO_SHORT`, `BAD_MAGIC`, `BAD_VERSION`, `CAPACITY`, `TRUNCATED`, `ZERO_SUBCARRIERS`, `TOO_MANY_SUBCARRIERS`, `NULL_ARG`, `BAD_NEXMON_MAGIC`, `BAD_CSI_LEN`, `UNKNOWN_FORMAT`); `rvcsi_nx_strerror` maps each to a static string.","- **ABI versioned.** `rvcsi_nx_abi_version()` returns `major \u003c\u003c 16 | minor` (`0x0001_0001`); the Rust side `debug_assert`s the major matches the header it was compiled against. The minor was bumped from `1.0` → `1.1` when the format-(2) entry points landed (additive — format (1) is unchanged).","- The Rust `ffi` module wraps these in safe functions (`record_len`, `decode_record`, `encode_record`, `decode_chanspec`, `parse_nexmon_udp_header`, `decode_nexmon_udp`, `encode_nexmon_udp`, `shim_abi_version`); every `unsafe` block is limited to the FFI call (and reading back C-initialised structs) and carries a `// SAFETY:` comment, per the project rule.","","**Chip registry (`rvcsi-adapter-nexmon::chips`).** nexmon_csi runs on a handful of patched Broadcom/Cypress chips; `NexmonChip` names them, `RaspberryPiModel` maps Pi boards to their chip, and `nexmon_adapter_profile` / `raspberry_pi_profile` build the [`AdapterProfile`] (supported channels / bandwidths / expected subcarrier counts — 20→64, 40→128, 80→256, 160→512) `validate_frame` bounds CSI frames against. The **Raspberry Pi 5** carries the same **CYW43455 / BCM43455c0** 802.11ac wireless as the Pi 3B+ / Pi 4 / Pi 400 (20/40/80 MHz, 2.4 + 5 GHz) — the chip with the most mature nexmon_csi support — so `RaspberryPiModel::Pi5 → NexmonChip::Bcm43455c0`; the Pi Zero 2 W is `Bcm43436b0` (2.4 GHz, ≤40 MHz). `NexmonPcapAdapter` **auto-detects** the chip from each packet's `chip_ver` word (`0x4345` → `Bcm43455c0`, etc.) and uses the matching profile; `.with_chip(...)` / `.with_pi_model(...)` override it. `NexmonChip::from_chip_ver` and the `chip_ver` field are best-effort/preserved respectively — the c0/b0 revision suffix isn't carried by that word, and the int16-vs-packed-float export distinction is handled by the `csi_format` selector, not by chip-ver parsing.","","A real deployment captures with `tcpdump -i wlan0 dst port 5500 -w csi.pcap` on the Pi and feeds the `.pcap` to `NexmonPcapAdapter::open` (or `rvcsi record --source nexmon-pcap --in csi.pcap --out cap.rvcsi --chip pi5`, then the rest of the toolchain works on the `.rvcsi`; `rvcsi inspect-nexmon` reports the resolved chip, `rvcsi nexmon-chips` lists the matrix). Production *live* capture (binding the UDP socket, monitor mode, firmware patch hooks) is a later increment that reuses the same shim parse path — the shim's job is the *parse*, not the *socket*.","","### 2.3 The napi-rs surface — what crosses the seam","","`rvcsi-node` is a `[\"cdylib\", \"rlib\"]` crate (cdylib = the `.node` addon; rlib so `cargo test --workspace` can link and test the Rust side without Node). Rules:","","- **Only normalized/validated data crosses.** The boundary types are JS-friendly mirrors of `CsiFrame`/`CsiWindow`/`CsiEvent`/`AdapterProfile`/`SourceHealth`, or plain JSON strings — never raw pointers, never `Pending` frames. A frame is run through `rvcsi_core::validate_frame` before it is handed to JS.","- **Errors map to JS exceptions** via napi-rs's `Result` integration; `RvcsiError`'s `Display` is the message.","- **The build emits link args + `binding.js`/`binding.d.ts`** via `napi_build::setup()` in `build.rs`; the `@ruv/rvcsi` npm package's hand-written `index.js`/`index.d.ts` wrap that loader and `JSON.parse` the addon's returns into plain `CsiFrame`/`CsiWindow`/`CsiEvent`/`SourceHealth`/`CaptureSummary`/`NexmonPcapSummary`/`DecodedChanspec` objects.","- The free functions exposed are: `rvcsiVersion`, `nexmonShimAbiVersion` (the linked shim's ABI), `nexmonDecodeRecords`, `nexmonDecodePcap`, `inspectNexmonPcap`, `decodeChanspec`, `inspectCaptureFile`, `eventsFromCaptureFile`, `exportCaptureToRfMemory`; plus the `RvcsiRuntime` streaming class (`openCaptureFile` / `openNexmonFile` / `openNexmonPcap` factories + `nextFrameJson` / `nextCleanFrameJson` / `drainEventsJson` / `healthJson`).","","### 2.4 Build \u0026 test invariants","","- `cargo build --workspace` and `cargo test --workspace --no-default-features` (the repo's pre-merge gate) must stay green; the new crates add tests and don't regress the existing 1,031+.","- `rvcsi-node` stays a workspace *member* (not `exclude`d like `wifi-densepose-wasm-edge`): on Linux/macOS a napi cdylib links fine with Node symbols left undefined (resolved at addon-load time), so `cargo build`/`cargo test` work without a Node toolchain. Only `napi build` (npm packaging) needs Node.","- No new heavy dependencies in the rvCSI crates: `serde`, `serde_json`, `thiserror`, `cc` (build only), `napi`/`napi-derive`/`napi-build`, `clap` (CLI only), `tempfile` (dev only). DSP math is hand-rolled — no `ndarray`/`rustfft`.","","---","","## 3. Consequences","","**Positive**","","- The two FFI seams are small, audited, and independently testable: the C shim round-trips through Rust tests; the napi surface tests run under `cargo test` without Node.","- `unsafe` is confined to one crate (`rvcsi-adapter-nexmon`) and within it to one module (`ffi`), every block documented.","- Each leaf crate (`rvcsi-dsp`, `rvcsi-events`, `rvcsi-adapter-file`, `rvcsi-ruvector`) depends only on `rvcsi-core`, so they can evolve (and be reviewed, and be swarm-implemented) independently.","- The `.rvcsi` JSONL capture format and the `JsonlRfMemory` standin make the whole pipeline runnable and testable end-to-end before any hardware or the real RuVector binding exists.","","**Negative / costs**","","- A `cc`-built C library means a C toolchain is required to build `rvcsi-adapter-nexmon` (already true for many workspace crates via transitive `cc` deps; acceptable).","- The \"rvCSI Nexmon record\" is a *normalized* format, not byte-identical to any upstream nexmon_csi build — a thin demux/transcode step is needed when wiring real Nexmon output. This is intentional (we control the contract the shim parses) and documented.","- JSONL captures are larger than a packed binary format; fine for v0 (and the PRD already standardizes on JSON/WebSocket on the wire), revisit if capture size becomes a problem.","- `rvcsi-node` as a workspace member adds the `napi` dependency tree to `cargo build --workspace`; mitigated by it being a small, well-maintained crate.","","**Risks**","","- napi-rs major-version churn could change the macro/`build.rs` surface; pinned to `napi = \"2.16\"` in workspace deps, bumped deliberately.","- If a future platform can't link a napi cdylib under plain `cargo build`, `rvcsi-node` moves to the workspace `exclude` list (like `wifi-densepose-wasm-edge`) with a separate build command — same pattern, already established.","","---","","## 4. Alternatives considered","","| Alternative | Why not |","|-------------|---------|","| One mega-crate `rvcsi` instead of eight | Couples DSP/events/adapters/FFI; can't review or implement them independently; bloats compile units for downstream users who only want `rvcsi-core`. |","| `bindgen` for the C shim | Pulls in `libclang`; the shim's C API is six functions — hand-written `extern \"C\"` decls are clearer and dependency-free. |","| Binary `.rvcsi` capture format (bincode/custom) | Smaller, but not human-inspectable; JSONL is debuggable, append-friendly, and matches the PRD's on-the-wire JSON. Revisit if size matters. |","| Expose raw `CsiFrame` pointers / typed arrays across napi for zero-copy | Violates ADR-095 D6 (validate-before-FFI) and the \"no raw pointers to TS\" safety NFR; the per-frame copy cost is negligible at the target rates. |","| `wasm-bindgen` instead of napi-rs for the JS surface | WASM can't do live capture (no raw sockets/serial); great for offline parsing (a later target) but not the primary Node runtime. |","| `rvcsi-events` depending on `rvcsi-dsp` for window stats | Adds a coordination point for two leaf crates; the stats are a few lines — keep the leaves independent and let higher layers compose them. |","","---","","## 5. Status of the implementation","","- `rvcsi-core` — implemented, `forbid(unsafe_code)`, 29 unit tests.","- `rvcsi-adapter-nexmon` + the napi-c shim — implemented; C (ABI `1.1`) compiled via `build.rs`+`cc`; the `ffi` module wraps both record formats (rvCSI record **and** the real nexmon_csi UDP payload + chanspec decode); a pure-Rust `pcap` reader; the Nexmon-chip / Raspberry-Pi-model registry (`chips.rs` — incl. **Pi 5 → BCM43455c0** + chip auto-detection from `chip_ver`); `NexmonAdapter` + `NexmonPcapAdapter` `CsiSource`s; 28 tests, several round-tripping through the C shim and through synthetic libpcap files.","- `rvcsi-dsp` (28 tests), `rvcsi-events` (19 tests — incl. a scale-invariance regression for the baseline-drift detector), `rvcsi-adapter-file` (20 + 1 doctest), `rvcsi-ruvector` (20 + 1 doctest) — implemented.","- `rvcsi-runtime` (13 tests) — composition layer + the one-shot helpers, including `decode_nexmon_pcap` / `decode_nexmon_pcap_for` (per-chip) / `summarize_nexmon_pcap` / `nexmon_profile_for`.","- `rvcsi-node` (napi-rs surface — incl. `nexmonDecodePcap` (with `chip`) / `inspectNexmonPcap` / `decodeChanspec` / `nexmonChipName` / `nexmonProfile` / `nexmonChips` / `RvcsiRuntime.openNexmonPcap`) and `rvcsi-cli` (10 tests — incl. `record --source nexmon-pcap [--chip pi5]`, `inspect-nexmon`, `nexmon-chips`, `decode-chanspec`) — implemented; the `@ruv/rvcsi` npm package + a Node smoke test ship alongside.","- Totals: 169 rvcsi unit/integration tests + 2 doctests, 0 failures; all rvcsi crates build together and are clippy-clean.","- **Validated against real ESP32 CSI** (a 7,000-frame node-1 capture, transcoded to `.rvcsi` via `scripts/esp32_jsonl_to_rvcsi.py` — the stand-in for the not-yet-shipped `record --source esp32-jsonl`): `rvcsi inspect` / `replay` / `calibrate` / `events` all run end-to-end. This surfaced and fixed the baseline-drift over-trigger (absolute → relative thresholds, above).","- `rvcsi-adapter-esp32` (live serial/UDP ESP32 source — ADR-095 §1.2 / D15), `rvcsi-mcp` (MCP tool server), `rvcsi-daemon` (live capture + WebSocket), and the legacy nexmon *packed-float* CSI export — not in this PR; tracked as follow-ups.","","---","","## 6. References","","- [ADR-095 — rvCSI Edge RF Sensing Platform](ADR-095-rvcsi-edge-rf-sensing-platform.md)","- [rvCSI Platform PRD](../prd/rvcsi-platform-prd.md)","- [rvCSI Domain Model](../ddd/rvcsi-domain-model.md)","- napi-rs — https://napi.rs/","- nexmon_csi — the upstream Broadcom CSI extractor the record format normalizes"],"stylingDirectives":[[[0,80,"pl-mh"],[2,80,"pl-en"]],[],[[0,1,"pl-ml"],[8,9,"pl-ml"],[16,17,"pl-ml"]],[[0,1,"pl-ml"],[8,9,"pl-ml"],[16,17,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[10,12,"pl-s"],[13,14,"pl-ml"],[24,25,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[8,10,"pl-s"],[11,12,"pl-ml"],[24,25,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[12,14,"pl-s"],[15,16,"pl-ml"],[21,22,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[12,14,"pl-s"],[15,16,"pl-ml"],[17,19,"pl-s"],[24,26,"pl-s"],[72,73,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[14,16,"pl-s"],[17,18,"pl-ml"],[255,256,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[7,9,"pl-s"],[10,11,"pl-ml"],[12,13,"pl-s"],[31,32,"pl-s"],[32,33,"pl-s"],[33,61,"pl-corl"],[61,62,"pl-s"],[63,64,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[16,18,"pl-s"],[19,20,"pl-ml"],[21,22,"pl-s"],[40,41,"pl-s"],[41,42,"pl-s"],[42,70,"pl-corl"],[70,71,"pl-s"],[72,73,"pl-ml"]],[[0,1,"pl-ml"],[2,4,"pl-s"],[14,16,"pl-s"],[17,18,"pl-ml"],[19,20,"pl-s"],[20,40,"pl-c1"],[40,41,"pl-s"],[43,44,"pl-s"],[44,53,"pl-c1"],[53,54,"pl-s"],[56,57,"pl-s"],[57,69,"pl-c1"],[69,70,"pl-s"],[72,73,"pl-s"],[73,91,"pl-c1"],[91,92,"pl-s"],[94,95,"pl-s"],[95,115,"pl-c1"],[115,116,"pl-s"],[118,119,"pl-s"],[119,133,"pl-c1"],[133,134,"pl-s"],[136,137,"pl-s"],[137,147,"pl-c1"],[147,148,"pl-s"],[150,151,"pl-s"],[151,160,"pl-c1"],[160,161,"pl-s"],[162,163,"pl-ml"]],[],[[0,3,"pl-ms"]],[],[[0,13,"pl-mh"],[3,13,"pl-en"]],[],[[41,42,"pl-s"],[42,63,"pl-c1"],[63,64,"pl-s"],[132,133,"pl-s"],[147,148,"pl-s"],[228,230,"pl-s"],[236,238,"pl-s"],[266,268,"pl-s"],[275,277,"pl-s"],[324,325,"pl-s"],[325,331,"pl-c1"],[331,332,"pl-s"]],[],[],[],[[0,1,"pl-v"],[2,4,"pl-s"],[10,12,"pl-s"],[19,20,"pl-s"],[28,29,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[11,13,"pl-s"],[20,21,"pl-s"],[27,28,"pl-s"],[114,115,"pl-s"],[122,123,"pl-s"],[123,124,"pl-s"],[124,140,"pl-corl"],[140,141,"pl-s"]],[],[[15,16,"pl-s"],[33,34,"pl-s"],[147,148,"pl-s"],[148,171,"pl-c1"],[171,172,"pl-s"],[195,196,"pl-s"],[196,216,"pl-c1"],[216,217,"pl-s"],[231,232,"pl-s"],[232,242,"pl-c1"],[242,243,"pl-s"]],[],[[0,3,"pl-ms"]],[],[[0,14,"pl-mh"],[3,14,"pl-en"]],[],[[0,22,"pl-mh"],[4,22,"pl-en"]],[],[[34,35,"pl-s"],[35,45,"pl-c1"],[45,46,"pl-s"]],[],[[0,1,"pl-ml"],[8,9,"pl-ml"],[10,11,"pl-s"],[11,17,"pl-c1"],[17,18,"pl-s"],[20,21,"pl-ml"],[33,34,"pl-ml"],[40,41,"pl-ml"]],[[0,1,"pl-ml"],[8,9,"pl-ml"],[20,21,"pl-ml"],[33,34,"pl-ml"],[40,41,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[15,16,"pl-ml"],[21,22,"pl-s"],[22,28,"pl-c1"],[28,29,"pl-s"],[31,32,"pl-ml"],[54,55,"pl-ml"],[79,80,"pl-s"],[80,88,"pl-c1"],[88,89,"pl-s"],[90,91,"pl-s"],[91,100,"pl-c1"],[100,101,"pl-s"],[102,103,"pl-s"],[103,111,"pl-c1"],[111,112,"pl-s"],[115,116,"pl-s"],[116,130,"pl-c1"],[130,131,"pl-s"],[137,138,"pl-s"],[138,147,"pl-c1"],[147,148,"pl-s"],[177,178,"pl-s"],[178,189,"pl-c1"],[189,190,"pl-s"],[192,193,"pl-s"],[193,203,"pl-c1"],[203,204,"pl-s"],[214,215,"pl-s"],[215,229,"pl-c1"],[229,230,"pl-s"],[278,279,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,12,"pl-c1"],[12,13,"pl-s"],[14,15,"pl-ml"],[20,21,"pl-s"],[21,27,"pl-c1"],[27,28,"pl-s"],[30,31,"pl-ml"],[32,33,"pl-s"],[33,43,"pl-c1"],[43,44,"pl-s"],[45,46,"pl-ml"],[295,296,"pl-s"],[296,325,"pl-c1"],[325,326,"pl-s"],[328,329,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[17,18,"pl-ml"],[23,24,"pl-s"],[24,30,"pl-c1"],[30,31,"pl-s"],[33,34,"pl-ml"],[35,36,"pl-s"],[36,46,"pl-c1"],[46,47,"pl-s"],[48,49,"pl-ml"],[50,51,"pl-s"],[51,63,"pl-c1"],[63,64,"pl-s"],[75,76,"pl-s"],[76,85,"pl-c1"],[85,86,"pl-s"],[93,94,"pl-s"],[94,107,"pl-c1"],[107,108,"pl-s"],[176,177,"pl-s"],[177,190,"pl-c1"],[190,191,"pl-s"],[203,204,"pl-s"],[204,212,"pl-c1"],[212,213,"pl-s"],[260,262,"pl-s"],[310,312,"pl-s"],[393,394,"pl-s"],[394,398,"pl-c1"],[398,399,"pl-s"],[411,412,"pl-s"],[412,417,"pl-c1"],[417,418,"pl-s"],[495,496,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,21,"pl-c1"],[21,22,"pl-s"],[23,24,"pl-ml"],[29,30,"pl-s"],[30,36,"pl-c1"],[36,37,"pl-s"],[39,40,"pl-ml"],[41,42,"pl-s"],[42,52,"pl-c1"],[52,53,"pl-s"],[54,55,"pl-ml"],[60,61,"pl-s"],[61,67,"pl-c1"],[67,68,"pl-s"],[112,113,"pl-s"],[113,121,"pl-c1"],[121,122,"pl-s"],[134,135,"pl-s"],[135,147,"pl-c1"],[147,148,"pl-s"],[154,155,"pl-s"],[155,172,"pl-c1"],[172,173,"pl-s"],[177,178,"pl-s"],[178,187,"pl-c1"],[187,188,"pl-s"],[219,220,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,23,"pl-c1"],[23,24,"pl-s"],[25,26,"pl-ml"],[27,29,"pl-s"],[32,34,"pl-s"],[46,47,"pl-ml"],[48,49,"pl-s"],[49,59,"pl-c1"],[59,60,"pl-s"],[74,75,"pl-ml"],[80,82,"pl-s"],[88,90,"pl-s"],[97,98,"pl-s"],[98,128,"pl-c1"],[128,129,"pl-s"],[143,144,"pl-s"],[144,152,"pl-c1"],[152,153,"pl-s"],[154,155,"pl-s"],[155,157,"pl-c1"],[157,158,"pl-s"],[173,174,"pl-s"],[174,177,"pl-c1"],[177,178,"pl-s"],[227,228,"pl-s"],[228,235,"pl-c1"],[235,236,"pl-s"],[286,287,"pl-s"],[287,295,"pl-c1"],[295,296,"pl-s"],[299,300,"pl-s"],[300,310,"pl-c1"],[310,311,"pl-s"],[313,314,"pl-s"],[314,330,"pl-c1"],[330,331,"pl-s"],[338,340,"pl-s"],[344,346,"pl-s"],[375,376,"pl-s"],[376,385,"pl-c1"],[385,386,"pl-s"],[390,391,"pl-s"],[391,404,"pl-c1"],[404,405,"pl-s"],[433,434,"pl-s"],[434,451,"pl-c1"],[451,452,"pl-s"],[492,493,"pl-s"],[493,498,"pl-c1"],[498,499,"pl-s"],[528,529,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"],[19,20,"pl-ml"],[25,26,"pl-s"],[26,32,"pl-c1"],[32,33,"pl-s"],[35,36,"pl-ml"],[37,38,"pl-s"],[38,48,"pl-c1"],[48,49,"pl-s"],[50,51,"pl-ml"],[97,98,"pl-s"],[98,114,"pl-c1"],[114,115,"pl-s"],[116,117,"pl-s"],[117,132,"pl-c1"],[132,133,"pl-s"],[135,136,"pl-s"],[136,153,"pl-c1"],[153,154,"pl-s"],[160,161,"pl-s"],[161,174,"pl-c1"],[174,175,"pl-s"],[187,188,"pl-s"],[188,204,"pl-c1"],[204,205,"pl-s"],[208,209,"pl-s"],[209,222,"pl-c1"],[222,223,"pl-s"],[281,282,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,16,"pl-c1"],[16,17,"pl-s"],[18,19,"pl-ml"],[24,25,"pl-s"],[25,31,"pl-c1"],[31,32,"pl-s"],[34,35,"pl-ml"],[94,95,"pl-ml"],[128,129,"pl-s"],[129,143,"pl-c1"],[143,144,"pl-s"],[148,149,"pl-s"],[149,158,"pl-c1"],[158,159,"pl-s"],[162,163,"pl-s"],[163,177,"pl-c1"],[177,178,"pl-s"],[181,182,"pl-s"],[182,196,"pl-c1"],[196,197,"pl-s"],[200,201,"pl-s"],[201,214,"pl-c1"],[214,215,"pl-s"],[240,241,"pl-s"],[241,258,"pl-c1"],[258,259,"pl-s"],[261,262,"pl-s"],[262,283,"pl-c1"],[283,284,"pl-s"],[286,287,"pl-s"],[287,305,"pl-c1"],[305,306,"pl-s"],[308,309,"pl-s"],[309,330,"pl-c1"],[330,331,"pl-s"],[333,334,"pl-s"],[334,353,"pl-c1"],[353,354,"pl-s"],[356,357,"pl-s"],[357,384,"pl-c1"],[384,385,"pl-s"],[411,412,"pl-s"],[412,422,"pl-c1"],[422,423,"pl-s"],[428,429,"pl-s"],[429,438,"pl-c1"],[438,439,"pl-s"],[441,442,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[15,16,"pl-ml"],[21,22,"pl-s"],[22,39,"pl-c1"],[39,40,"pl-s"],[42,43,"pl-ml"],[44,45,"pl-s"],[45,55,"pl-c1"],[55,56,"pl-s"],[58,59,"pl-s"],[59,72,"pl-c1"],[72,73,"pl-s"],[75,76,"pl-s"],[76,96,"pl-c1"],[96,97,"pl-s"],[98,99,"pl-ml"],[104,106,"pl-s"],[113,115,"pl-s"],[126,127,"pl-s"],[127,132,"pl-c1"],[132,133,"pl-s"],[196,197,"pl-s"],[197,204,"pl-c1"],[204,205,"pl-s"],[220,221,"pl-s"],[221,234,"pl-c1"],[234,235,"pl-s"],[238,239,"pl-s"],[239,247,"pl-c1"],[247,248,"pl-s"],[254,255,"pl-s"],[255,274,"pl-c1"],[274,275,"pl-s"],[277,278,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,12,"pl-c1"],[12,13,"pl-s"],[14,15,"pl-ml"],[19,20,"pl-ml"],[65,66,"pl-ml"],[71,72,"pl-s"],[72,77,"pl-c1"],[77,78,"pl-s"],[87,88,"pl-s"],[88,94,"pl-c1"],[94,95,"pl-s"],[126,127,"pl-s"],[127,133,"pl-c1"],[133,134,"pl-s"],[137,138,"pl-s"],[138,145,"pl-c1"],[145,146,"pl-s"],[148,149,"pl-s"],[149,163,"pl-c1"],[163,164,"pl-s"],[166,167,"pl-s"],[167,182,"pl-c1"],[182,183,"pl-s"],[185,186,"pl-s"],[186,192,"pl-c1"],[192,193,"pl-s"],[195,196,"pl-s"],[196,202,"pl-c1"],[202,203,"pl-s"],[205,206,"pl-s"],[206,212,"pl-c1"],[212,213,"pl-s"],[215,216,"pl-s"],[216,222,"pl-c1"],[222,223,"pl-s"],[225,226,"pl-s"],[226,235,"pl-c1"],[235,236,"pl-s"],[238,239,"pl-s"],[239,254,"pl-c1"],[254,255,"pl-s"],[271,272,"pl-ml"]],[],[[0,1,"pl-s"],[1,13,"pl-c1"],[13,14,"pl-s"],[20,22,"pl-s"],[25,27,"pl-s"],[38,39,"pl-s"],[39,48,"pl-c1"],[48,49,"pl-s"],[101,102,"pl-s"],[102,114,"pl-c1"],[114,115,"pl-s"],[193,194,"pl-s"],[194,203,"pl-c1"],[203,204,"pl-s"],[210,212,"pl-s"],[215,217,"pl-s"],[228,229,"pl-s"],[229,239,"pl-c1"],[239,240,"pl-s"],[330,331,"pl-s"],[331,344,"pl-c1"],[344,345,"pl-s"],[387,388,"pl-s"],[388,417,"pl-c1"],[417,418,"pl-s"],[421,422,"pl-s"],[422,440,"pl-c1"],[440,441,"pl-s"]],[],[[21,22,"pl-s"],[22,31,"pl-c1"],[31,32,"pl-s"],[63,64,"pl-s"],[64,76,"pl-c1"],[76,77,"pl-s"],[110,111,"pl-s"],[114,115,"pl-s"],[156,157,"pl-s"],[157,170,"pl-c1"],[170,171,"pl-s"],[226,227,"pl-s"],[227,237,"pl-c1"],[237,238,"pl-s"],[267,268,"pl-s"],[268,278,"pl-c1"],[278,279,"pl-s"]],[],[[0,53,"pl-mh"],[4,53,"pl-en"]],[],[[0,1,"pl-s"],[1,31,"pl-c1"],[31,32,"pl-s"],[74,76,"pl-s"],[92,94,"pl-s"],[100,101,"pl-s"],[101,104,"pl-c1"],[104,105,"pl-s"]],[],[[0,2,"pl-s"],[31,33,"pl-s"],[71,72,"pl-s"],[72,78,"pl-c1"],[78,79,"pl-s"],[163,164,"pl-s"],[164,169,"pl-c1"],[169,170,"pl-s"],[202,203,"pl-s"],[203,211,"pl-c1"],[211,212,"pl-s"],[227,228,"pl-s"],[228,241,"pl-c1"],[241,242,"pl-s"],[243,244,"pl-s"],[244,250,"pl-c1"],[250,251,"pl-s"],[306,307,"pl-s"],[307,326,"pl-c1"],[326,327,"pl-s"],[329,330,"pl-s"],[330,351,"pl-c1"],[351,352,"pl-s"],[354,355,"pl-s"],[355,376,"pl-c1"],[376,377,"pl-s"]],[],[],[],[[4,5,"pl-s"],[5,17,"pl-c1"],[17,18,"pl-s"],[61,63,"pl-s"],[84,86,"pl-s"],[167,169,"pl-s"],[178,180,"pl-s"],[182,183,"pl-s"],[183,209,"pl-c1"],[209,210,"pl-s"]],[],[],[],[[0,1,"pl-v"],[2,4,"pl-s"],[33,35,"pl-s"],[149,150,"pl-s"],[150,156,"pl-c1"],[156,157,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[36,38,"pl-s"],[78,79,"pl-s"],[79,91,"pl-c1"],[91,92,"pl-s"],[100,101,"pl-s"],[101,110,"pl-c1"],[110,111,"pl-s"],[113,114,"pl-s"],[114,123,"pl-c1"],[123,124,"pl-s"],[126,127,"pl-s"],[127,138,"pl-c1"],[138,139,"pl-s"],[141,142,"pl-s"],[142,150,"pl-c1"],[150,151,"pl-s"],[153,154,"pl-s"],[154,163,"pl-c1"],[163,164,"pl-s"],[166,167,"pl-s"],[167,183,"pl-c1"],[183,184,"pl-s"],[186,187,"pl-s"],[187,207,"pl-c1"],[207,208,"pl-s"],[210,211,"pl-s"],[211,219,"pl-c1"],[219,220,"pl-s"],[222,223,"pl-s"],[223,239,"pl-c1"],[239,240,"pl-s"],[242,243,"pl-s"],[243,254,"pl-c1"],[254,255,"pl-s"],[257,258,"pl-s"],[258,272,"pl-c1"],[272,273,"pl-s"],[276,277,"pl-s"],[277,294,"pl-c1"],[294,295,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[18,20,"pl-s"],[21,22,"pl-s"],[22,44,"pl-c1"],[44,45,"pl-s"],[54,55,"pl-s"],[55,74,"pl-c1"],[74,75,"pl-s"],[77,78,"pl-s"],[78,89,"pl-c1"],[89,90,"pl-s"],[107,108,"pl-s"],[108,120,"pl-c1"],[120,121,"pl-s"],[203,204,"pl-s"],[204,207,"pl-c1"],[207,208,"pl-s"],[211,212,"pl-s"],[212,215,"pl-c1"],[215,216,"pl-s"]],[[0,1,"pl-v"],[11,12,"pl-s"],[12,15,"pl-c1"],[15,16,"pl-s"],[55,56,"pl-s"],[56,66,"pl-c1"],[66,67,"pl-s"],[69,70,"pl-s"],[70,83,"pl-c1"],[83,84,"pl-s"],[86,87,"pl-s"],[87,100,"pl-c1"],[100,101,"pl-s"],[103,104,"pl-s"],[104,119,"pl-c1"],[119,120,"pl-s"],[122,123,"pl-s"],[123,146,"pl-c1"],[146,147,"pl-s"],[149,150,"pl-s"],[150,167,"pl-c1"],[167,168,"pl-s"],[170,171,"pl-s"],[171,188,"pl-c1"],[188,189,"pl-s"],[191,192,"pl-s"],[192,208,"pl-c1"],[208,209,"pl-s"],[218,219,"pl-s"],[219,225,"pl-c1"],[225,226,"pl-s"],[315,316,"pl-s"],[316,326,"pl-c1"],[326,327,"pl-s"]],[],[],[],[[32,33,"pl-s"],[33,75,"pl-c1"],[75,76,"pl-s"],[101,102,"pl-s"],[102,107,"pl-c1"],[107,108,"pl-s"],[112,113,"pl-s"],[113,136,"pl-c1"],[136,137,"pl-s"],[142,143,"pl-s"],[143,217,"pl-c1"],[217,218,"pl-s"],[264,265,"pl-s"],[265,271,"pl-c1"],[271,272,"pl-s"],[274,275,"pl-s"],[275,295,"pl-c1"],[295,296,"pl-s"],[324,325,"pl-s"],[325,343,"pl-c1"],[343,344,"pl-s"],[375,376,"pl-s"],[380,381,"pl-s"],[533,534,"pl-s"],[539,540,"pl-s"],[550,551,"pl-s"],[557,558,"pl-s"]],[],[[0,51,"pl-mh"],[4,51,"pl-en"]],[],[[0,1,"pl-s"],[1,11,"pl-c1"],[11,12,"pl-s"],[18,19,"pl-s"],[19,37,"pl-c1"],[37,38,"pl-s"],[59,60,"pl-s"],[60,65,"pl-c1"],[65,66,"pl-s"],[82,83,"pl-s"],[83,105,"pl-c1"],[105,106,"pl-s"]],[],[[0,1,"pl-v"],[2,4,"pl-s"],[43,45,"pl-s"],[92,93,"pl-s"],[93,101,"pl-c1"],[101,102,"pl-s"],[103,104,"pl-s"],[104,113,"pl-c1"],[113,114,"pl-s"],[115,116,"pl-s"],[116,124,"pl-c1"],[124,125,"pl-s"],[126,127,"pl-s"],[127,141,"pl-c1"],[141,142,"pl-s"],[143,144,"pl-s"],[144,156,"pl-c1"],[156,157,"pl-s"],[209,210,"pl-s"],[210,217,"pl-c1"],[217,218,"pl-s"],[250,251,"pl-s"],[251,277,"pl-c1"],[277,278,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[31,33,"pl-s"],[48,49,"pl-s"],[49,55,"pl-c1"],[55,56,"pl-s"],[70,71,"pl-s"],[71,81,"pl-c1"],[81,82,"pl-s"],[85,86,"pl-s"],[86,93,"pl-c1"],[93,94,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[32,33,"pl-s"],[33,43,"pl-c1"],[43,44,"pl-s"],[45,46,"pl-s"],[46,58,"pl-c1"],[58,59,"pl-s"],[59,61,"pl-s"],[66,67,"pl-s"],[67,86,"pl-c1"],[86,87,"pl-s"],[91,92,"pl-s"],[92,100,"pl-c1"],[100,101,"pl-s"],[107,108,"pl-s"],[108,118,"pl-c1"],[118,119,"pl-s"],[147,148,"pl-s"],[148,156,"pl-c1"],[156,157,"pl-s"],[158,159,"pl-s"],[159,169,"pl-c1"],[169,170,"pl-s"],[192,193,"pl-s"],[193,203,"pl-c1"],[203,204,"pl-s"],[236,237,"pl-s"],[237,245,"pl-c1"],[245,246,"pl-s"],[247,248,"pl-s"],[248,257,"pl-c1"],[257,258,"pl-s"],[259,260,"pl-s"],[260,268,"pl-c1"],[268,269,"pl-s"],[270,271,"pl-s"],[271,283,"pl-c1"],[283,284,"pl-s"],[285,286,"pl-s"],[286,300,"pl-c1"],[300,301,"pl-s"],[302,303,"pl-s"],[303,320,"pl-c1"],[320,321,"pl-s"],[322,323,"pl-s"],[323,338,"pl-c1"],[338,339,"pl-s"]],[[0,1,"pl-v"],[34,35,"pl-s"],[35,47,"pl-c1"],[47,48,"pl-s"],[50,51,"pl-s"],[51,71,"pl-c1"],[71,72,"pl-s"],[98,99,"pl-s"],[99,118,"pl-c1"],[118,119,"pl-s"],[121,122,"pl-s"],[122,138,"pl-c1"],[138,139,"pl-s"],[141,142,"pl-s"],[142,159,"pl-c1"],[159,160,"pl-s"],[162,163,"pl-s"],[163,177,"pl-c1"],[177,178,"pl-s"],[180,181,"pl-s"],[181,199,"pl-c1"],[199,200,"pl-s"],[202,203,"pl-s"],[203,224,"pl-c1"],[224,225,"pl-s"],[227,228,"pl-s"],[228,251,"pl-c1"],[251,252,"pl-s"],[263,264,"pl-s"],[264,276,"pl-c1"],[276,277,"pl-s"],[295,296,"pl-s"],[296,311,"pl-c1"],[311,312,"pl-s"],[315,316,"pl-s"],[316,330,"pl-c1"],[330,331,"pl-s"],[334,335,"pl-s"],[335,349,"pl-c1"],[349,350,"pl-s"],[363,364,"pl-s"],[364,377,"pl-c1"],[377,378,"pl-s"],[381,382,"pl-s"],[382,400,"pl-c1"],[400,401,"pl-s"],[404,405,"pl-s"],[405,420,"pl-c1"],[420,421,"pl-s"],[424,425,"pl-s"],[425,435,"pl-c1"],[435,436,"pl-s"]],[],[[0,31,"pl-mh"],[4,31,"pl-en"]],[],[[0,1,"pl-v"],[2,3,"pl-s"],[3,26,"pl-c1"],[26,27,"pl-s"],[32,33,"pl-s"],[33,77,"pl-c1"],[77,78,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[33,34,"pl-s"],[40,41,"pl-s"],[47,48,"pl-s"],[48,55,"pl-c1"],[55,56,"pl-s"],[63,64,"pl-s"],[64,88,"pl-c1"],[88,89,"pl-s"],[199,200,"pl-s"],[200,211,"pl-c1"],[211,212,"pl-s"],[213,214,"pl-s"],[214,224,"pl-c1"],[224,225,"pl-s"],[262,263,"pl-s"],[263,273,"pl-c1"],[273,274,"pl-s"]],[[0,1,"pl-v"],[49,50,"pl-s"],[50,55,"pl-c1"],[55,56,"pl-s"],[58,59,"pl-s"],[59,69,"pl-c1"],[69,70,"pl-s"],[72,73,"pl-s"],[73,82,"pl-c1"],[82,83,"pl-s"],[85,86,"pl-s"],[86,88,"pl-c1"],[88,89,"pl-s"],[104,105,"pl-s"],[105,109,"pl-c1"],[109,110,"pl-s"],[111,112,"pl-s"],[112,123,"pl-c1"],[123,124,"pl-s"],[125,126,"pl-s"],[126,136,"pl-c1"],[136,137,"pl-s"],[139,140,"pl-s"],[140,144,"pl-c1"],[144,145,"pl-s"],[158,159,"pl-s"],[159,167,"pl-c1"],[167,168,"pl-s"],[210,211,"pl-s"],[211,218,"pl-c1"],[218,219,"pl-s"],[220,221,"pl-s"],[221,228,"pl-c1"],[228,229,"pl-s"]],[],[[0,3,"pl-ms"]],[],[[0,18,"pl-mh"],[3,18,"pl-en"]],[],[[0,2,"pl-s"],[10,12,"pl-s"]],[],[[0,1,"pl-v"],[144,145,"pl-s"],[145,155,"pl-c1"],[155,156,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,9,"pl-c1"],[9,10,"pl-s"],[37,38,"pl-s"],[38,58,"pl-c1"],[58,59,"pl-s"],[90,91,"pl-s"],[91,94,"pl-c1"],[94,95,"pl-s"]],[[0,1,"pl-v"],[19,20,"pl-s"],[20,29,"pl-c1"],[29,30,"pl-s"],[32,33,"pl-s"],[33,45,"pl-c1"],[45,46,"pl-s"],[48,49,"pl-s"],[49,67,"pl-c1"],[67,68,"pl-s"],[70,71,"pl-s"],[71,85,"pl-c1"],[85,86,"pl-s"],[104,105,"pl-s"],[105,115,"pl-c1"],[115,116,"pl-s"]],[[0,1,"pl-v"],[6,7,"pl-s"],[7,13,"pl-c1"],[13,14,"pl-s"],[44,45,"pl-s"],[45,58,"pl-c1"],[58,59,"pl-s"]],[],[[0,2,"pl-s"],[18,20,"pl-s"]],[],[[0,1,"pl-v"],[4,5,"pl-s"],[5,7,"pl-c1"],[7,8,"pl-s"],[66,67,"pl-s"],[67,87,"pl-c1"],[87,88,"pl-s"],[144,145,"pl-s"],[145,147,"pl-c1"],[147,148,"pl-s"]],[[0,1,"pl-v"],[33,34,"pl-s"],[44,45,"pl-s"]],[[0,1,"pl-v"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[46,47,"pl-s"],[47,51,"pl-c1"],[51,52,"pl-s"],[72,73,"pl-s"],[73,96,"pl-c1"],[96,97,"pl-s"]],[],[[0,2,"pl-s"],[7,9,"pl-s"]],[],[[0,1,"pl-v"],[53,54,"pl-s"],[54,62,"pl-c1"],[62,63,"pl-s"],[83,84,"pl-s"],[84,97,"pl-c1"],[97,98,"pl-s"]],[[0,1,"pl-v"],[60,61,"pl-s"],[61,72,"pl-c1"],[72,73,"pl-s"],[75,76,"pl-s"],[76,86,"pl-c1"],[86,87,"pl-s"],[111,112,"pl-s"],[112,119,"pl-c1"],[119,120,"pl-s"],[132,133,"pl-s"],[133,157,"pl-c1"],[157,158,"pl-s"]],[],[[0,3,"pl-ms"]],[],[[0,29,"pl-mh"],[3,29,"pl-en"]],[],[[0,1,"pl-ml"],[14,15,"pl-ml"],[24,25,"pl-ml"]],[[0,1,"pl-ml"],[14,15,"pl-ml"],[24,25,"pl-ml"]],[[0,1,"pl-ml"],[17,18,"pl-s"],[18,23,"pl-c1"],[23,24,"pl-s"],[42,43,"pl-ml"],[179,180,"pl-s"],[180,190,"pl-c1"],[190,191,"pl-s"],[193,194,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,10,"pl-c1"],[10,11,"pl-s"],[27,28,"pl-ml"],[38,39,"pl-s"],[39,47,"pl-c1"],[47,48,"pl-s"],[99,100,"pl-s"],[100,110,"pl-c1"],[110,111,"pl-s"],[151,152,"pl-ml"]],[[0,1,"pl-ml"],[9,10,"pl-s"],[10,16,"pl-c1"],[16,17,"pl-s"],[50,51,"pl-ml"],[191,192,"pl-ml"]],[[0,1,"pl-ml"],[13,14,"pl-s"],[14,22,"pl-c1"],[22,23,"pl-s"],[74,75,"pl-ml"],[221,222,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[55,56,"pl-ml"],[186,187,"pl-ml"]],[[0,1,"pl-ml"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[30,31,"pl-s"],[31,40,"pl-c1"],[40,41,"pl-s"],[59,60,"pl-ml"],[200,201,"pl-ml"]],[],[[0,3,"pl-ms"]],[],[[0,34,"pl-mh"],[3,34,"pl-en"]],[],[[0,1,"pl-v"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[30,31,"pl-s"],[31,50,"pl-c1"],[50,51,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,23,"pl-c1"],[23,24,"pl-s"],[65,66,"pl-s"],[66,69,"pl-c1"],[69,70,"pl-s"],[85,86,"pl-s"],[86,94,"pl-c1"],[94,95,"pl-s"],[96,97,"pl-s"],[97,99,"pl-c1"],[99,100,"pl-s"],[106,107,"pl-s"],[107,110,"pl-c1"],[110,111,"pl-s"],[159,161,"pl-s"],[164,166,"pl-s"],[231,232,"pl-s"],[232,236,"pl-c1"],[236,237,"pl-s"],[293,294,"pl-s"],[294,302,"pl-c1"],[302,303,"pl-s"],[312,314,"pl-s"],[331,333,"pl-s"],[361,362,"pl-s"],[362,370,"pl-c1"],[370,371,"pl-s"],[374,375,"pl-s"],[375,388,"pl-c1"],[388,389,"pl-s"],[392,393,"pl-s"],[393,410,"pl-c1"],[410,411,"pl-s"],[412,413,"pl-s"],[413,422,"pl-c1"],[422,423,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,12,"pl-c1"],[12,13,"pl-s"],[26,27,"pl-s"],[27,39,"pl-c1"],[39,40,"pl-s"],[123,124,"pl-s"],[124,142,"pl-c1"],[142,143,"pl-s"],[162,163,"pl-s"],[163,177,"pl-c1"],[177,178,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,16,"pl-c1"],[16,17,"pl-s"],[83,84,"pl-s"],[84,102,"pl-c1"],[102,103,"pl-s"],[106,107,"pl-s"],[107,129,"pl-c1"],[129,130,"pl-s"],[144,145,"pl-s"],[145,166,"pl-c1"],[166,167,"pl-s"],[170,171,"pl-s"],[171,189,"pl-c1"],[189,190,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[40,41,"pl-s"],[41,57,"pl-c1"],[57,58,"pl-s"],[65,66,"pl-s"],[66,70,"pl-c1"],[70,71,"pl-s"],[75,76,"pl-s"],[76,93,"pl-c1"],[93,94,"pl-s"],[97,98,"pl-s"],[98,112,"pl-c1"],[112,113,"pl-s"],[116,117,"pl-s"],[117,131,"pl-c1"],[131,132,"pl-s"],[135,136,"pl-s"],[136,149,"pl-c1"],[149,150,"pl-s"],[153,154,"pl-s"],[154,165,"pl-c1"],[165,166,"pl-s"],[169,170,"pl-s"],[170,197,"pl-c1"],[197,198,"pl-s"],[204,205,"pl-s"],[205,214,"pl-c1"],[214,215,"pl-s"],[234,235,"pl-s"],[235,275,"pl-c1"],[275,276,"pl-s"],[278,279,"pl-s"],[279,293,"pl-c1"],[293,294,"pl-s"],[296,297,"pl-s"],[297,309,"pl-c1"],[309,310,"pl-s"],[312,313,"pl-s"],[313,328,"pl-c1"],[328,329,"pl-s"],[350,351,"pl-s"],[351,361,"pl-c1"],[361,362,"pl-s"]],[[0,1,"pl-v"]],[[0,1,"pl-v"],[2,4,"pl-s"],[36,38,"pl-s"],[84,85,"pl-s"],[85,91,"pl-c1"],[91,92,"pl-s"],[97,98,"pl-s"],[98,129,"pl-c1"],[129,130,"pl-s"],[170,171,"pl-s"],[171,198,"pl-c1"],[198,199,"pl-s"],[202,203,"pl-s"],[203,216,"pl-c1"],[216,217,"pl-s"],[220,221,"pl-s"],[221,227,"pl-c1"],[227,228,"pl-s"],[231,232,"pl-s"],[232,241,"pl-c1"],[241,242,"pl-s"],[245,246,"pl-s"],[246,252,"pl-c1"],[252,253,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,22,"pl-c1"],[22,23,"pl-s"],[77,78,"pl-s"],[78,87,"pl-c1"],[87,88,"pl-s"],[108,109,"pl-s"],[109,121,"pl-c1"],[121,122,"pl-s"],[173,174,"pl-s"],[186,187,"pl-s"]],[],[[0,3,"pl-ms"]],[],[[0,16,"pl-mh"],[3,16,"pl-en"]],[],[[0,1,"pl-v"],[2,3,"pl-s"],[43,44,"pl-s"],[44,45,"pl-s"],[45,86,"pl-corl"],[86,87,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[21,22,"pl-s"],[22,23,"pl-s"],[23,51,"pl-corl"],[51,52,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[21,22,"pl-s"],[22,23,"pl-s"],[23,51,"pl-corl"],[51,52,"pl-s"]],[[0,1,"pl-v"],[12,28,"pl-corl"]],[[0,1,"pl-v"]]],"colorizedLines":null}},"title":"RuView/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md at main · Esbroro/RuView","appPayload":{},"meta":{"title":"RuView/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md at main · Esbroro/RuView"}}</script>
  <div data-target="react-app.reactRoot"><meta name="github-code-view-meta-stats" id="github-code-view-meta-stats" data-hydrostats="publish"/> <!-- --> <a hidden="" id="code-view-repo-link" href="/Esbroro/RuView" data-discover="true"></a> <div class="d-none"></div><div><div style="--spacing:var(--spacing-none)" class="prc-PageLayout-PageLayoutRoot--KH-d" data-component="SplitPageLayout" data-has-sidebar="true"><div class="prc-PageLayout-SidebarWrapper-kLG4B CopilotSidePanelSidebar-module__SidePanel__L3O0C CopilotSidePanelSidebar-module__HiddenSidePanel__TBRGn" style="--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="end" data-sticky="true" data-responsive-variant="fullscreen"><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-SidebarVerticalDivider-0Rl0V" data-component="PageLayout.VerticalDivider" data-variant="line" data-position="end" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="450" aria-valuemax="768" aria-valuenow="544" aria-valuetext="Pane width 544 pixels" tabindex="0"></div></div><div class="prc-PageLayout-Sidebar-iciWg" data-component="SplitPageLayout.Sidebar" data-resizable="true" style="--spacing:var(--spacing-normal);--pane-min-width:450px;--pane-max-width:768px;--pane-width-custom:544px;--pane-width-size:var(--pane-width-custom);--pane-width:544px"><div class="height-full" data-testid="copilot-code-view-side-panel"><div id="copilot-side-panel-content" class="height-full"></div></div></div></div><div class="prc-PageLayout-PageLayoutWrapper-2BhU2" data-width="full"><div class="prc-PageLayout-PageLayoutContent-BneH9"><div id="repos-file-tree-sidebar" class="CodeViewFileTreeLayout-module__sidebar__n_Aau" tabindex="0"><div class="prc-PageLayout-PaneWrapper-pHPop ReposFileTreePane-module__Pane__rBZpI ReposFileTreePane-module__HideTree__AYZnm ReposFileTreePane-module__HidePane__VHAVt" style="--offset-header:0px;--spacing-row:var(--spacing-none);--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="start" data-sticky="true"><div class="prc-PageLayout-HorizontalDivider-JLVqp prc-PageLayout-PaneHorizontalDivider-9tbnE" data-component="PageLayout.HorizontalDivider" data-variant-regular="none" data-variant-narrow="none" data-position="start" style="--spacing-divider:var(--spacing-none);--spacing:var(--spacing-none)"></div><div class="prc-PageLayout-Pane-AyzHK" data-component="SplitPageLayout.Pane" data-resizable="true" style="--spacing:var(--spacing-none);--pane-min-width:256px;--pane-max-width:calc(100vw - var(--pane-max-width-diff));--pane-width-size:var(--pane-width-large);--pane-width:320px"></div><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-PaneVerticalDivider-le57g" data-component="PageLayout.VerticalDivider" data-variant-narrow="none" data-variant-regular="line" data-variant-wide="line" data-position="start" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="256" aria-valuemax="600" aria-valuenow="320" aria-valuetext="Pane width 320 pixels" tabindex="0"></div></div></div></div><div data-component="SplitPageLayout.Content" class="prc-PageLayout-ContentWrapper-gR9eG"><div class="prc-PageLayout-Content-xWL-A" data-width="full" style="--spacing:var(--spacing-none)"><div class="SharedPageLayout-module__content__IwGAp" data-selector="repos-split-pane-content" id="repos-split-pane-content" tabindex="0"> <!-- --> <div class="container CodeViewHeader-module__Box__JkPOb"><div class="CodeViewHeader-module__StickyHeader__Qn7UN" id="StickyHeader"><div class="CodeViewHeader-module__Box_1__SbNDV"><div class="CodeViewHeader-module__Box_2__TB46f"><div class="react-code-view-header-wrap--narrow CodeViewHeader-module__Box_3__q1zUL"><div class="CodeViewHeader-module__treeToggleWrapper__RQ__9"><h2 class="use-tree-pane-module__Heading__s4QbZ prc-Heading-Heading-MtWFE" data-component="Heading"><button data-component="Button" type="button" aria-label="Expand file tree" data-testid="expand-file-tree-button-mobile" class="prc-Button-ButtonBase-9n-Xk ExpandFileTreeButton-module__Button_1__Svs95" data-loading="false" data-size="medium" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-left" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.78 12.53a.75.75 0 0 1-1.06 0L2.47 8.28a.75.75 0 0 1 0-1.06l4.25-4.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L4.81 7h7.44a.75.75 0 0 1 0 1.5H4.81l2.97 2.97a.75.75 0 0 1 0 1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Files</span></span></button><button data-component="IconButton" type="button" data-testid="expand-file-tree-button" aria-controls="repos-file-tree" class="prc-Button-ButtonBase-9n-Xk position-relative ExpandFileTreeButton-module__expandButton__hDOcv ExpandFileTreeButton-module__filesButtonBreakpoint__zEvz3 fgColor-muted prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-labelledby="_R_4lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sidebar-collapse" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.823 7.823a.25.25 0 0 1 0 .354l-2.396 2.396A.25.25 0 0 1 4 10.396V5.604a.25.25 0 0 1 .427-.177Z"></path><path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25H9.5v-13H1.75a.25.25 0 0 0-.25.25ZM11 14.5h3.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H11Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="se" data-component="Tooltip" aria-hidden="true" id="_R_4lla9lik5_">Expand file tree</span><div class="d-none"></div></h2></div><div class="react-code-view-header-mb--narrow mr-2"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector-wide"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="react-code-view-header-mb--narrow CodeViewHeader-module__Box_5__MQ0hL"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__lg__Rjz0A"><nav data-testid="breadcrumbs" aria-labelledby="repos-header-breadcrumb-heading" id="repos-header-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="repos-header-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/Esbroro/RuView/tree/main" data-discover="true">RuView</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/Esbroro/RuView/tree/main/docs" data-discover="true">docs</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/Esbroro/RuView/tree/main/docs/adr" data-discover="true">adr</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__lg__Rjz0A prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="file-name-id">ADR-096-rvcsi-ffi-crate-layout.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lla9lik5_">Copy path</span></div></div></div><div class="react-code-view-header-element--wide"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><div><div class="CodeViewHeader-module__FileResultsList__JDzUy"><span class="d-flex FileResultsList-module__FilesSearchBox__ivVkc TextInput-wrapper prc-components-TextInputWrapper-Hpdqi prc-components-TextInputBaseWrapper-wY-n0" data-no-trailing-action="true" data-component="TextInput" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id="_R_1cpla9lik5_" aria-hidden="true" data-component="TextInput.LeadingVisual"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellCheck="false" placeholder="Go to file" aria-describedby="_R_1cpla9lik5_ _R_1cpla9lik5H1_" data-component="input" class="prc-components-Input-IwWrt" value=""/><span class="TextInput-icon" id="_R_1cpla9lik5H1_" aria-hidden="true" data-component="TextInput.TrailingVisual"></span></span></div><div class="d-none"></div></div><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-wide" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_7p9la9lik5_" id="_R_99la9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_7p9la9lik5_">More file actions</span></div></div></div><div class="react-code-view-header-element--narrow"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-narrow" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_7pdla9lik5_" id="_R_9dla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_7pdla9lik5_">More file actions</span></div></div></div></div></div></div></div><div class="CodeView-module__contentWrapper__cG2JH"><div class="react-code-view-bottom-padding"><div class="BlobTopBanners-module__Box__v_nvx"></div></div> <div class="d-none"></div><div class="d-flex flex-column border rounded-2 tmp-mb-3 pl-1"><div class="LatestCommit-module__Box__B25ZT"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">History</h2><a data-component="LinkButton" href="/Esbroro/RuView/commits/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md" class="prc-Button-ButtonBase-9n-Xk d-none d-lg-flex LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><span class="fgColor-default">History</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><a data-component="LinkButton" aria-label="View commit history for this file." href="/Esbroro/RuView/commits/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby="_R_4mlala9lik5_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" role="tooltip" aria-hidden="true" id="_R_4mlala9lik5_">History</span></div></div></div></div></div><div class="d-flex flex-row"><div class="container BlobViewContent-module__blobContainer__DtH2d"><div class="react-code-size-details-banner BlobViewContent-module__codeSizeDetails__e5sUw"><div class="react-code-size-details-banner CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="18.6 KB" style="--truncate-max-width:100%"><span>144 lines (99 loc) · 18.6 KB</span></div></div></div></div><div class="react-blob-view-header-sticky BlobViewContent-module__stickyHeader__VwxB5" id="repos-sticky-header"><div class="BlobViewHeader-module__Box__yhm9u"><div class="react-blob-sticky-header"><div class="FileNameStickyHeader-module__outerWrapper__ZL4Xc FileNameStickyHeader-module__outerWrapperHidden__Zpynk"><div class="FileNameStickyHeader-module__Box_1__Hazu5"><div class="FileNameStickyHeader-module__Box_2__hoolP"><div class="FileNameStickyHeader-module__Box_3__MVKsk"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="FileNameStickyHeader-module__Box_4__FLhtt"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__md__Wb1Gs"><nav data-testid="breadcrumbs" aria-labelledby="sticky-breadcrumb-heading" id="sticky-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="sticky-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/Esbroro/RuView/tree/main" data-discover="true">RuView</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/Esbroro/RuView/tree/main/docs" data-discover="true">docs</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/Esbroro/RuView/tree/main/docs/adr" data-discover="true">adr</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__md__Wb1Gs prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="sticky-file-name-id">ADR-096-rvcsi-ffi-crate-layout.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lcpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lcpala9lik5_">Copy path</span></div></div></div><button data-component="Button" type="button" class="prc-Button-ButtonBase-9n-Xk FileNameStickyHeader-module__Button__LSEU_ FileNameStickyHeader-module__GoToTopButton__nxAFn" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-up" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.47 7.78a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0l4.25 4.25a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018L9 4.81v7.44a.75.75 0 0 1-1.5 0V4.81L4.53 7.78a.75.75 0 0 1-1.06 0Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Top</span></span></button></div></div></div><div class="BlobViewHeader-module__Box_1__VEmuQ"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">File metadata and controls</h2><div class="BlobViewHeader-module__Box_2__icUs2"><ul aria-label="File view" class="prc-SegmentedControl-SegmentedControl-lqIXp BlobTabButtons-module__SegmentedControl__jen2u" data-variant="default" data-size="small" data-component="SegmentedControl"><li class="prc-SegmentedControl-Item-tSCQh" data-selected="" data-component="SegmentedControl.Button"><button aria-pressed="true" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:transparent"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Preview">Preview</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Code">Code</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Blame">Blame</div></span></button></li></ul><div class="d-none"></div><div class="react-code-size-details-in-header CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="18.6 KB" style="--truncate-max-width:100%"><span>144 lines (99 loc) · 18.6 KB</span></div></div></div></div><div class="BlobViewHeader-module__Box_3__ng6v2"><div class="d-none"></div><div class="react-blob-header-edit-and-raw-actions BlobViewHeader-module__Box_4__J4Y4W"><div class="d-none"></div><div class="prc-ButtonGroup-ButtonGroup-vFUrY" data-component="ButtonGroup"><div class="prc-ButtonGroup-Item-PqvDl"><a data-component="LinkButton" href="https://github.com/Esbroro/RuView/raw/refs/heads/main/docs/adr/ADR-096-rvcsi-ffi-crate-layout.md" data-testid="raw-button" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov BlobViewHeader-module__LinkButton__X9kx2" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Raw</span></span></a></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="copy-raw-button" class="prc-Button-ButtonBase-9n-Xk prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_qaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_qaucpala9lik5_">Copy raw file</span></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="download-raw-button" class="prc-Button-ButtonBase-9n-Xk BlobViewHeader-module__downloadButton__ef459 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_eaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_eaucpala9lik5_">Download raw file</span></div></div></div><button data-component="IconButton" type="button" aria-pressed="false" class="prc-Button-ButtonBase-9n-Xk tmp-mr-2 TableOfContents-module__IconButton__jrlNM prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_3ucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_3ucpala9lik5_">Outline</span><div class="react-blob-header-edit-and-raw-actions-combined"><button data-component="IconButton" type="button" title="More file actions" data-testid="more-file-actions-button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click BlobViewHeader-module__IconButton__XrMQY prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_fkecpala9lik5_" id="_R_kecpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_fkecpala9lik5_">Edit and raw actions</span></div></div></div></div><div></div></div><div class="BlobViewContent-module__blobContentWrapper__JS0W6"><section aria-labelledby="file-name-id-wide file-name-id-mobile" class="BlobContent-module__blobContentSection__VOgZq BlobContent-module__blobContentSectionMarkdown__mPLOK" style="margin-top:46px"><div class="js-snippet-clipboard-copy-unpositioned BlobContent-module__markdownBlob__T8jpG" data-hpc="true" containertiming="hpc"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface</h1><a id="user-content-adr-096-rvcsi--crate-topology-the-napi-c-shim-and-the-napi-rs-node-surface" class="anchor" aria-label="Permalink: ADR-096: rvCSI — Crate Topology, the napi-c Shim, and the napi-rs Node Surface" href="#adr-096-rvcsi--crate-topology-the-napi-c-shim-and-the-napi-rs-node-surface"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Status</strong></td>
<td>Proposed</td>
</tr>
<tr>
<td><strong>Date</strong></td>
<td>2026-05-12</td>
</tr>
<tr>
<td><strong>Deciders</strong></td>
<td>ruv</td>
</tr>
<tr>
<td><strong>Codename</strong></td>
<td><strong>rvCSI</strong> — RuVector Channel State Information runtime</td>
</tr>
<tr>
<td><strong>Relates to</strong></td>
<td>ADR-095 (rvCSI platform — D1 Rust core, D2 C-at-the-boundary, D3 TS SDK, D4 napi-rs, D5 normalized schema, D6 validate-before-FFI, D15 plugin adapters), ADR-009/ADR-040 (WASM runtimes), ADR-049 (cross-platform WiFi interface detection)</td>
</tr>
<tr>
<td><strong>PRD</strong></td>
<td><a href="/Esbroro/RuView/blob/main/docs/prd/rvcsi-platform-prd.md">rvCSI Platform PRD</a></td>
</tr>
<tr>
<td><strong>Domain model</strong></td>
<td><a href="/Esbroro/RuView/blob/main/docs/ddd/rvcsi-domain-model.md">rvCSI Domain Model</a></td>
</tr>
<tr>
<td><strong>Implements</strong></td>
<td><code>v2/crates/rvcsi-core</code>, <code>rvcsi-dsp</code>, <code>rvcsi-events</code>, <code>rvcsi-adapter-file</code>, <code>rvcsi-adapter-nexmon</code>, <code>rvcsi-ruvector</code>, <code>rvcsi-node</code>, <code>rvcsi-cli</code></td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">1. Context</h2><a id="user-content-1-context" class="anchor" aria-label="Permalink: 1. Context" href="#1-context"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">ADR-095 set the platform-level invariant <code>C → Rust → TypeScript</code> and the fifteen decisions that constrain rvCSI. This ADR makes the <em>implementation</em> concrete: which crates exist, what each owns, where the two FFI seams are (the <strong>napi-c</strong> C shim below Rust, and the <strong>napi-rs</strong> Node addon above it), and the rules that keep <code>unsafe</code> confined and the boundary objects validated.</p>
<p dir="auto">The two seams:</p>
<ul dir="auto">
<li><strong>napi-c</strong> — the <em>downward</em> seam to fragile vendor/firmware/driver code. Per ADR-095 D2, C is the only language allowed here, and only as a thin, allocation-free, bounds-checked shim. The Nexmon family is the first consumer.</li>
<li><strong>napi-rs</strong> — the <em>upward</em> seam to Node.js/TypeScript. Per ADR-095 D3/D4, the Rust runtime is exposed to JS via <a href="https://napi.rs/" rel="nofollow">napi-rs</a>; nothing crosses this seam that hasn't been validated (D6) and normalized (D5).</li>
</ul>
<p dir="auto">Both seams are <em>narrow on purpose</em>: everything in between — parsing, validation, DSP, windowing, event extraction, RuVector export — is safe Rust (<code>#![forbid(unsafe_code)]</code> in every crate except <code>rvcsi-adapter-nexmon</code>, which needs <code>extern "C"</code>).</p>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">2. Decision</h2><a id="user-content-2-decision" class="anchor" aria-label="Permalink: 2. Decision" href="#2-decision"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">2.1 Crate topology</h3><a id="user-content-21-crate-topology" class="anchor" aria-label="Permalink: 2.1 Crate topology" href="#21-crate-topology"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Eight new workspace members under <code>v2/crates/</code>:</p>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>Crate</th>
<th><code>unsafe</code>?</th>
<th>Depends on</th>
<th>Owns</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>rvcsi-core</code></td>
<td>no (<code>forbid</code>)</td>
<td>— (serde, thiserror)</td>
<td>The normalized schema (<code>CsiFrame</code>/<code>CsiWindow</code>/<code>CsiEvent</code>), <code>AdapterProfile</code>, the <code>CsiSource</code> plugin trait, id newtypes + <code>IdGenerator</code>, <code>RvcsiError</code>, and the <code>validate_frame</code> pipeline + quality scoring. The shared kernel.</td>
</tr>
<tr>
<td><code>rvcsi-dsp</code></td>
<td>no (<code>forbid</code>)</td>
<td><code>rvcsi-core</code></td>
<td>Reusable DSP stages (DC removal, phase unwrap, smoothing, Hampel/MAD outlier filter, sliding variance, baseline subtraction) and scalar features (motion energy, presence score, confidence, heuristic breathing-band estimate), plus a non-destructive <code>SignalPipeline::process_frame</code>.</td>
</tr>
<tr>
<td><code>rvcsi-events</code></td>
<td>no (<code>forbid</code>)</td>
<td><code>rvcsi-core</code></td>
<td><code>WindowBuffer</code> (frames → <code>CsiWindow</code>), the <code>EventDetector</code> trait + presence/motion/quality/baseline-drift state machines, and <code>EventPipeline</code> (windows → <code>CsiEvent</code>s). The baseline-drift detector measures drift <strong>relative to the running baseline's RMS magnitude</strong> (a fraction, not absolute amplitude units), so the same thresholds work for raw <code>int8</code> ESP32 CSI, <code>int16</code>-scaled Nexmon CSI, and baseline-subtracted streams alike — see ADR-095 D13.</td>
</tr>
<tr>
<td><code>rvcsi-adapter-file</code></td>
<td>no (<code>forbid</code>)</td>
<td><code>rvcsi-core</code></td>
<td>The <code>.rvcsi</code> capture format (JSONL: a header line + one <code>CsiFrame</code> per line), <code>FileRecorder</code>, and <code>FileReplayAdapter</code> (a <code>CsiSource</code>) — deterministic replay (D9).</td>
</tr>
<tr>
<td><code>rvcsi-adapter-nexmon</code></td>
<td><strong>yes</strong> (FFI only)</td>
<td><code>rvcsi-core</code> + the C shim</td>
<td>The <strong>napi-c</strong> seam: <code>native/rvcsi_nexmon_shim.{c,h}</code> compiled via <code>build.rs</code>+<code>cc</code>, a documented <code>ffi</code> module wrapping it, a pure-Rust libpcap reader (<code>pcap.rs</code>), the Nexmon-chip / Raspberry-Pi-model registry (<code>chips.rs</code> — <code>NexmonChip</code>, <code>RaspberryPiModel</code> incl. <strong>Pi 5</strong>, profile builders), and two <code>CsiSource</code>s — <code>NexmonAdapter</code> (rvCSI-record buffers) and <code>NexmonPcapAdapter</code> (real nexmon_csi UDP payloads inside a <code>.pcap</code>, with chip auto-detection).</td>
</tr>
<tr>
<td><code>rvcsi-ruvector</code></td>
<td>no (<code>forbid</code>)</td>
<td><code>rvcsi-core</code></td>
<td>The RuVector RF-memory bridge: deterministic <code>window_embedding</code>/<code>event_embedding</code>, <code>cosine_similarity</code>, the <code>RfMemoryStore</code> trait, and <code>InMemoryRfMemory</code> + <code>JsonlRfMemory</code> (a standin until the production RuVector binding lands).</td>
</tr>
<tr>
<td><code>rvcsi-runtime</code></td>
<td>no (<code>forbid</code>)</td>
<td>core, dsp, events, adapter-file, adapter-nexmon, ruvector</td>
<td>The composition layer (no FFI): <code>CaptureRuntime</code> (a <code>CsiSource</code> + <code>validate_frame</code> + <code>SignalPipeline</code> + <code>EventPipeline</code>) plus one-shot helpers (<code>summarize_capture</code>, <code>decode_nexmon_records</code>, <code>decode_nexmon_pcap</code>, <code>summarize_nexmon_pcap</code>, <code>events_from_capture</code>, <code>export_capture_to_rf_memory</code>). The shared layer under <code>rvcsi-node</code> and <code>rvcsi-cli</code>.</td>
</tr>
<tr>
<td><code>rvcsi-node</code></td>
<td>no (<code>deny(clippy::all)</code>)</td>
<td><code>rvcsi-core</code>, <code>rvcsi-runtime</code>, <code>rvcsi-adapter-nexmon</code></td>
<td>The <strong>napi-rs</strong> seam: the <code>.node</code> addon (cdylib + rlib) exposing a safe TS-facing surface (thin <code>#[napi]</code> wrappers over <code>rvcsi-runtime</code>); <code>build.rs</code> runs <code>napi_build::setup()</code>.</td>
</tr>
<tr>
<td><code>rvcsi-cli</code></td>
<td>no</td>
<td>core, adapter-file, adapter-nexmon, runtime</td>
<td>The <code>rvcsi</code> binary: <code>record</code> (Nexmon-dump or nexmon-pcap → <code>.rvcsi</code>), <code>inspect</code>, <code>inspect-nexmon</code>, <code>decode-chanspec</code>, <code>replay</code>, <code>stream</code>, <code>events</code>, <code>health</code>, <code>calibrate</code>, <code>export ruvector</code> (ADR-095 FR7).</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto"><code>rvcsi-events</code> does <strong>not</strong> call into <code>rvcsi-dsp</code>: window statistics are simple enough to compute in <code>WindowBuffer</code> itself, and keeping the two leaves independent removes a coordination point. <code>rvcsi-cli</code> does <strong>not</strong> depend on <code>rvcsi-node</code> (a binary can't link a napi cdylib's undefined Node symbols) — the shared logic lives in <code>rvcsi-runtime</code>, which both build on. Higher layers wire <code>SignalPipeline::process_frame</code> → <code>WindowBuffer::push</code> when they want cleaned frames.</p>
<p dir="auto">The MCP tool server (<code>rvcsi-mcp</code>) and the long-running daemon (<code>rvcsi-daemon</code>) — and live radio capture — are <em>not</em> in this ADR's scope; they sit on top of <code>rvcsi-runtime</code> / the crates above and are tracked as follow-ups. The <code>@ruv/rvcsi</code> npm package ships alongside <code>rvcsi-node</code>.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">2.2 The napi-c shim — record formats and contract</h3><a id="user-content-22-the-napi-c-shim--record-formats-and-contract" class="anchor" aria-label="Permalink: 2.2 The napi-c shim — record formats and contract" href="#22-the-napi-c-shim--record-formats-and-contract"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>native/rvcsi_nexmon_shim.{c,h}</code> is the only C in the runtime. It handles <strong>two byte formats</strong> (ABI <code>1.1</code>):</p>
<p dir="auto"><strong>(1) The "rvCSI Nexmon record"</strong> — a compact, self-describing record (<code>'RVNX'</code> magic, version, flags, RSSI/noise, channel, bandwidth, timestamp, then interleaved <code>int16</code> I/Q in Q8.8 fixed point; total <code>24 + 4*N</code>). Used by the <code>rvcsi capture</code>/<code>record</code> recorder, the file replay path, and tests. Functions: <code>rvcsi_nx_record_len</code>, <code>rvcsi_nx_parse_record</code>, <code>rvcsi_nx_write_record</code>.</p>
<p dir="auto"><strong>(2) The <em>real</em> nexmon_csi UDP payload</strong> — what the patched Broadcom firmware actually sends to the host (port 5500 by default): the 18-byte header <code>magic=0x1111 (2) · rssi int8 (1) · fctl (1) · src_mac (6) · seq_cnt (2) · core/stream (2) · chanspec (2) · chip_ver (2)</code>, followed by <code>nsub</code> complex CSI samples. The shim implements the <strong>modern int16 I/Q export</strong> (<code>nsub</code> pairs of little-endian <code>int16</code> <code>(real, imag)</code>, raw counts — what CSIKit / <code>csireader.py</code> read for the BCM43455c0 / 4358 / 4366c0); <code>nsub</code> is derived from the payload length, <code>(len − 18) / 4</code>. Functions: <code>rvcsi_nx_csi_udp_header</code> (just the 18-byte header), <code>rvcsi_nx_csi_udp_decode</code> (header + CSI body, <code>csi_format</code> selector), <code>rvcsi_nx_csi_udp_write</code> (synthesize a payload — tests/examples), and <code>rvcsi_nx_decode_chanspec</code> (decode a Broadcom d11ac chanspec word → <code>channel</code> = <code>chanspec &amp; 0xff</code>, bandwidth from bits <code>[13:11]</code> cross-checked against the FFT size, band from bits <code>[15:14]</code> cross-checked against the channel number). The legacy nexmon <em>packed-float</em> export used by some 4339/4358 firmwares is a documented follow-up (it sits behind the same <code>csi_format</code> selector).</p>
<p dir="auto">The <code>timestamp_ns</code> of a frame from format (2) comes from the <strong>pcap packet timestamp</strong>, not the wire (nexmon_csi doesn't carry one). The pcap file itself is parsed in <strong>pure Rust</strong> (<code>rvcsi-adapter-nexmon::pcap</code> — classic libpcap, all four byte-order/timestamp-resolution magics, Ethernet / raw-IPv4 / Linux-SLL link types; pcapng is a follow-up): peeling the Ethernet/IPv4/UDP headers down to the payload is not a vendor-fragility concern, so it doesn't belong in C.</p>
<p dir="auto">Contract (both formats):</p>
<ul dir="auto">
<li><strong>Allocation-free, global-free.</strong> Every read is bounds-checked against the caller-supplied length; nothing can scribble outside caller buffers; no <code>malloc</code>, no statics.</li>
<li><strong>Structured errors, never panics.</strong> Functions return one of a small set of <code>RvcsiNxError</code> codes (<code>TOO_SHORT</code>, <code>BAD_MAGIC</code>, <code>BAD_VERSION</code>, <code>CAPACITY</code>, <code>TRUNCATED</code>, <code>ZERO_SUBCARRIERS</code>, <code>TOO_MANY_SUBCARRIERS</code>, <code>NULL_ARG</code>, <code>BAD_NEXMON_MAGIC</code>, <code>BAD_CSI_LEN</code>, <code>UNKNOWN_FORMAT</code>); <code>rvcsi_nx_strerror</code> maps each to a static string.</li>
<li><strong>ABI versioned.</strong> <code>rvcsi_nx_abi_version()</code> returns <code>major &lt;&lt; 16 | minor</code> (<code>0x0001_0001</code>); the Rust side <code>debug_assert</code>s the major matches the header it was compiled against. The minor was bumped from <code>1.0</code> → <code>1.1</code> when the format-(2) entry points landed (additive — format (1) is unchanged).</li>
<li>The Rust <code>ffi</code> module wraps these in safe functions (<code>record_len</code>, <code>decode_record</code>, <code>encode_record</code>, <code>decode_chanspec</code>, <code>parse_nexmon_udp_header</code>, <code>decode_nexmon_udp</code>, <code>encode_nexmon_udp</code>, <code>shim_abi_version</code>); every <code>unsafe</code> block is limited to the FFI call (and reading back C-initialised structs) and carries a <code>// SAFETY:</code> comment, per the project rule.</li>
</ul>
<p dir="auto"><strong>Chip registry (<code>rvcsi-adapter-nexmon::chips</code>).</strong> nexmon_csi runs on a handful of patched Broadcom/Cypress chips; <code>NexmonChip</code> names them, <code>RaspberryPiModel</code> maps Pi boards to their chip, and <code>nexmon_adapter_profile</code> / <code>raspberry_pi_profile</code> build the [<code>AdapterProfile</code>] (supported channels / bandwidths / expected subcarrier counts — 20→64, 40→128, 80→256, 160→512) <code>validate_frame</code> bounds CSI frames against. The <strong>Raspberry Pi 5</strong> carries the same <strong>CYW43455 / BCM43455c0</strong> 802.11ac wireless as the Pi 3B+ / Pi 4 / Pi 400 (20/40/80 MHz, 2.4 + 5 GHz) — the chip with the most mature nexmon_csi support — so <code>RaspberryPiModel::Pi5 → NexmonChip::Bcm43455c0</code>; the Pi Zero 2 W is <code>Bcm43436b0</code> (2.4 GHz, ≤40 MHz). <code>NexmonPcapAdapter</code> <strong>auto-detects</strong> the chip from each packet's <code>chip_ver</code> word (<code>0x4345</code> → <code>Bcm43455c0</code>, etc.) and uses the matching profile; <code>.with_chip(...)</code> / <code>.with_pi_model(...)</code> override it. <code>NexmonChip::from_chip_ver</code> and the <code>chip_ver</code> field are best-effort/preserved respectively — the c0/b0 revision suffix isn't carried by that word, and the int16-vs-packed-float export distinction is handled by the <code>csi_format</code> selector, not by chip-ver parsing.</p>
<p dir="auto">A real deployment captures with <code>tcpdump -i wlan0 dst port 5500 -w csi.pcap</code> on the Pi and feeds the <code>.pcap</code> to <code>NexmonPcapAdapter::open</code> (or <code>rvcsi record --source nexmon-pcap --in csi.pcap --out cap.rvcsi --chip pi5</code>, then the rest of the toolchain works on the <code>.rvcsi</code>; <code>rvcsi inspect-nexmon</code> reports the resolved chip, <code>rvcsi nexmon-chips</code> lists the matrix). Production <em>live</em> capture (binding the UDP socket, monitor mode, firmware patch hooks) is a later increment that reuses the same shim parse path — the shim's job is the <em>parse</em>, not the <em>socket</em>.</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">2.3 The napi-rs surface — what crosses the seam</h3><a id="user-content-23-the-napi-rs-surface--what-crosses-the-seam" class="anchor" aria-label="Permalink: 2.3 The napi-rs surface — what crosses the seam" href="#23-the-napi-rs-surface--what-crosses-the-seam"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>rvcsi-node</code> is a <code>["cdylib", "rlib"]</code> crate (cdylib = the <code>.node</code> addon; rlib so <code>cargo test --workspace</code> can link and test the Rust side without Node). Rules:</p>
<ul dir="auto">
<li><strong>Only normalized/validated data crosses.</strong> The boundary types are JS-friendly mirrors of <code>CsiFrame</code>/<code>CsiWindow</code>/<code>CsiEvent</code>/<code>AdapterProfile</code>/<code>SourceHealth</code>, or plain JSON strings — never raw pointers, never <code>Pending</code> frames. A frame is run through <code>rvcsi_core::validate_frame</code> before it is handed to JS.</li>
<li><strong>Errors map to JS exceptions</strong> via napi-rs's <code>Result</code> integration; <code>RvcsiError</code>'s <code>Display</code> is the message.</li>
<li><strong>The build emits link args + <code>binding.js</code>/<code>binding.d.ts</code></strong> via <code>napi_build::setup()</code> in <code>build.rs</code>; the <code>@ruv/rvcsi</code> npm package's hand-written <code>index.js</code>/<code>index.d.ts</code> wrap that loader and <code>JSON.parse</code> the addon's returns into plain <code>CsiFrame</code>/<code>CsiWindow</code>/<code>CsiEvent</code>/<code>SourceHealth</code>/<code>CaptureSummary</code>/<code>NexmonPcapSummary</code>/<code>DecodedChanspec</code> objects.</li>
<li>The free functions exposed are: <code>rvcsiVersion</code>, <code>nexmonShimAbiVersion</code> (the linked shim's ABI), <code>nexmonDecodeRecords</code>, <code>nexmonDecodePcap</code>, <code>inspectNexmonPcap</code>, <code>decodeChanspec</code>, <code>inspectCaptureFile</code>, <code>eventsFromCaptureFile</code>, <code>exportCaptureToRfMemory</code>; plus the <code>RvcsiRuntime</code> streaming class (<code>openCaptureFile</code> / <code>openNexmonFile</code> / <code>openNexmonPcap</code> factories + <code>nextFrameJson</code> / <code>nextCleanFrameJson</code> / <code>drainEventsJson</code> / <code>healthJson</code>).</li>
</ul>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">2.4 Build &amp; test invariants</h3><a id="user-content-24-build--test-invariants" class="anchor" aria-label="Permalink: 2.4 Build &amp; test invariants" href="#24-build--test-invariants"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li><code>cargo build --workspace</code> and <code>cargo test --workspace --no-default-features</code> (the repo's pre-merge gate) must stay green; the new crates add tests and don't regress the existing 1,031+.</li>
<li><code>rvcsi-node</code> stays a workspace <em>member</em> (not <code>exclude</code>d like <code>wifi-densepose-wasm-edge</code>): on Linux/macOS a napi cdylib links fine with Node symbols left undefined (resolved at addon-load time), so <code>cargo build</code>/<code>cargo test</code> work without a Node toolchain. Only <code>napi build</code> (npm packaging) needs Node.</li>
<li>No new heavy dependencies in the rvCSI crates: <code>serde</code>, <code>serde_json</code>, <code>thiserror</code>, <code>cc</code> (build only), <code>napi</code>/<code>napi-derive</code>/<code>napi-build</code>, <code>clap</code> (CLI only), <code>tempfile</code> (dev only). DSP math is hand-rolled — no <code>ndarray</code>/<code>rustfft</code>.</li>
</ul>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">3. Consequences</h2><a id="user-content-3-consequences" class="anchor" aria-label="Permalink: 3. Consequences" href="#3-consequences"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><strong>Positive</strong></p>
<ul dir="auto">
<li>The two FFI seams are small, audited, and independently testable: the C shim round-trips through Rust tests; the napi surface tests run under <code>cargo test</code> without Node.</li>
<li><code>unsafe</code> is confined to one crate (<code>rvcsi-adapter-nexmon</code>) and within it to one module (<code>ffi</code>), every block documented.</li>
<li>Each leaf crate (<code>rvcsi-dsp</code>, <code>rvcsi-events</code>, <code>rvcsi-adapter-file</code>, <code>rvcsi-ruvector</code>) depends only on <code>rvcsi-core</code>, so they can evolve (and be reviewed, and be swarm-implemented) independently.</li>
<li>The <code>.rvcsi</code> JSONL capture format and the <code>JsonlRfMemory</code> standin make the whole pipeline runnable and testable end-to-end before any hardware or the real RuVector binding exists.</li>
</ul>
<p dir="auto"><strong>Negative / costs</strong></p>
<ul dir="auto">
<li>A <code>cc</code>-built C library means a C toolchain is required to build <code>rvcsi-adapter-nexmon</code> (already true for many workspace crates via transitive <code>cc</code> deps; acceptable).</li>
<li>The "rvCSI Nexmon record" is a <em>normalized</em> format, not byte-identical to any upstream nexmon_csi build — a thin demux/transcode step is needed when wiring real Nexmon output. This is intentional (we control the contract the shim parses) and documented.</li>
<li>JSONL captures are larger than a packed binary format; fine for v0 (and the PRD already standardizes on JSON/WebSocket on the wire), revisit if capture size becomes a problem.</li>
<li><code>rvcsi-node</code> as a workspace member adds the <code>napi</code> dependency tree to <code>cargo build --workspace</code>; mitigated by it being a small, well-maintained crate.</li>
</ul>
<p dir="auto"><strong>Risks</strong></p>
<ul dir="auto">
<li>napi-rs major-version churn could change the macro/<code>build.rs</code> surface; pinned to <code>napi = "2.16"</code> in workspace deps, bumped deliberately.</li>
<li>If a future platform can't link a napi cdylib under plain <code>cargo build</code>, <code>rvcsi-node</code> moves to the workspace <code>exclude</code> list (like <code>wifi-densepose-wasm-edge</code>) with a separate build command — same pattern, already established.</li>
</ul>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">4. Alternatives considered</h2><a id="user-content-4-alternatives-considered" class="anchor" aria-label="Permalink: 4. Alternatives considered" href="#4-alternatives-considered"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>Alternative</th>
<th>Why not</th>
</tr>
</thead>
<tbody>
<tr>
<td>One mega-crate <code>rvcsi</code> instead of eight</td>
<td>Couples DSP/events/adapters/FFI; can't review or implement them independently; bloats compile units for downstream users who only want <code>rvcsi-core</code>.</td>
</tr>
<tr>
<td><code>bindgen</code> for the C shim</td>
<td>Pulls in <code>libclang</code>; the shim's C API is six functions — hand-written <code>extern "C"</code> decls are clearer and dependency-free.</td>
</tr>
<tr>
<td>Binary <code>.rvcsi</code> capture format (bincode/custom)</td>
<td>Smaller, but not human-inspectable; JSONL is debuggable, append-friendly, and matches the PRD's on-the-wire JSON. Revisit if size matters.</td>
</tr>
<tr>
<td>Expose raw <code>CsiFrame</code> pointers / typed arrays across napi for zero-copy</td>
<td>Violates ADR-095 D6 (validate-before-FFI) and the "no raw pointers to TS" safety NFR; the per-frame copy cost is negligible at the target rates.</td>
</tr>
<tr>
<td><code>wasm-bindgen</code> instead of napi-rs for the JS surface</td>
<td>WASM can't do live capture (no raw sockets/serial); great for offline parsing (a later target) but not the primary Node runtime.</td>
</tr>
<tr>
<td><code>rvcsi-events</code> depending on <code>rvcsi-dsp</code> for window stats</td>
<td>Adds a coordination point for two leaf crates; the stats are a few lines — keep the leaves independent and let higher layers compose them.</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">5. Status of the implementation</h2><a id="user-content-5-status-of-the-implementation" class="anchor" aria-label="Permalink: 5. Status of the implementation" href="#5-status-of-the-implementation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li><code>rvcsi-core</code> — implemented, <code>forbid(unsafe_code)</code>, 29 unit tests.</li>
<li><code>rvcsi-adapter-nexmon</code> + the napi-c shim — implemented; C (ABI <code>1.1</code>) compiled via <code>build.rs</code>+<code>cc</code>; the <code>ffi</code> module wraps both record formats (rvCSI record <strong>and</strong> the real nexmon_csi UDP payload + chanspec decode); a pure-Rust <code>pcap</code> reader; the Nexmon-chip / Raspberry-Pi-model registry (<code>chips.rs</code> — incl. <strong>Pi 5 → BCM43455c0</strong> + chip auto-detection from <code>chip_ver</code>); <code>NexmonAdapter</code> + <code>NexmonPcapAdapter</code> <code>CsiSource</code>s; 28 tests, several round-tripping through the C shim and through synthetic libpcap files.</li>
<li><code>rvcsi-dsp</code> (28 tests), <code>rvcsi-events</code> (19 tests — incl. a scale-invariance regression for the baseline-drift detector), <code>rvcsi-adapter-file</code> (20 + 1 doctest), <code>rvcsi-ruvector</code> (20 + 1 doctest) — implemented.</li>
<li><code>rvcsi-runtime</code> (13 tests) — composition layer + the one-shot helpers, including <code>decode_nexmon_pcap</code> / <code>decode_nexmon_pcap_for</code> (per-chip) / <code>summarize_nexmon_pcap</code> / <code>nexmon_profile_for</code>.</li>
<li><code>rvcsi-node</code> (napi-rs surface — incl. <code>nexmonDecodePcap</code> (with <code>chip</code>) / <code>inspectNexmonPcap</code> / <code>decodeChanspec</code> / <code>nexmonChipName</code> / <code>nexmonProfile</code> / <code>nexmonChips</code> / <code>RvcsiRuntime.openNexmonPcap</code>) and <code>rvcsi-cli</code> (10 tests — incl. <code>record --source nexmon-pcap [--chip pi5]</code>, <code>inspect-nexmon</code>, <code>nexmon-chips</code>, <code>decode-chanspec</code>) — implemented; the <code>@ruv/rvcsi</code> npm package + a Node smoke test ship alongside.</li>
<li>Totals: 169 rvcsi unit/integration tests + 2 doctests, 0 failures; all rvcsi crates build together and are clippy-clean.</li>
<li><strong>Validated against real ESP32 CSI</strong> (a 7,000-frame node-1 capture, transcoded to <code>.rvcsi</code> via <code>scripts/esp32_jsonl_to_rvcsi.py</code> — the stand-in for the not-yet-shipped <code>record --source esp32-jsonl</code>): <code>rvcsi inspect</code> / <code>replay</code> / <code>calibrate</code> / <code>events</code> all run end-to-end. This surfaced and fixed the baseline-drift over-trigger (absolute → relative thresholds, above).</li>
<li><code>rvcsi-adapter-esp32</code> (live serial/UDP ESP32 source — ADR-095 §1.2 / D15), <code>rvcsi-mcp</code> (MCP tool server), <code>rvcsi-daemon</code> (live capture + WebSocket), and the legacy nexmon <em>packed-float</em> CSI export — not in this PR; tracked as follow-ups.</li>
</ul>
<hr>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">6. References</h2><a id="user-content-6-references" class="anchor" aria-label="Permalink: 6. References" href="#6-references"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li><a href="/Esbroro/RuView/blob/main/docs/adr/ADR-095-rvcsi-edge-rf-sensing-platform.md">ADR-095 — rvCSI Edge RF Sensing Platform</a></li>
<li><a href="/Esbroro/RuView/blob/main/docs/prd/rvcsi-platform-prd.md">rvCSI Platform PRD</a></li>
<li><a href="/Esbroro/RuView/blob/main/docs/ddd/rvcsi-domain-model.md">rvCSI Domain Model</a></li>
<li>napi-rs — <a href="https://napi.rs/" rel="nofollow">https://napi.rs/</a></li>
<li>nexmon_csi — the upstream Broadcom CSI extractor the record format normalizes</li>
</ul>
</article></div><div class="d-none"></div></section></div></div></div> </div> <!-- --> </div></div></div></div></div></div><div class="ScrollMarksContainer-module__scrollMarksContainer__Eu7uU" id="find-result-marks-container"></div><div class="d-none"></div><div class="d-none"></div></div> <!-- --> <!-- --> </div>
</react-app>




  </div>

</turbo-frame>

    </main>
  </div>

  </div>

          <footer class="footer f6 color-fg-muted color-border-subtle tmp-pt-7 tmp-pb-6 p-responsive" role="contentinfo"  >
  <h2 class='sr-only'>Footer</h2>

  


  <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap">
    <div class="d-flex flex-items-center flex-shrink-0 mx-2">
      <a aria-label="GitHub Homepage" class="footer-octicon mr-2" href="https://github.com">
        <svg aria-hidden="true" data-component="Octicon" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github">
    <path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path>
</svg>
</a>
      <span>
        &copy; 2026 GitHub,&nbsp;Inc.
      </span>
    </div>

    <nav aria-label="Footer">
      <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3>

      <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading">


          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a>
          </li>


            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a>
            </li>

            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a>
            </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to community&quot;,&quot;label&quot;:&quot;text:community&quot;}" href="https://github.community/" data-view-component="true" class="Link--secondary Link">Community</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a>
          </li>

          
<li class="mx-2" >
  <cookie-consent-link>
    <button
      type="button"
      class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent"
      data-action="click:cookie-consent-link#showConsentManagement"
      data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}"
    >
      Manage cookies
    </button>
  </cookie-consent-link>
</li>

  <li class="mx-2">
    <cookie-consent-link>
      <button
        type="button"
        class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent text-left"
        data-action="click:cookie-consent-link#showConsentManagement"
        data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}"
      >
        Do not share my personal information
      </button>
    </cookie-consent-link>
  </li>

      </ul>
    </nav>
  </div>
</footer>



    <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999"
      data-locale="en"
      data-initial-cookie-consent-allowed=""
      data-cookie-consent-required="true"
    ></ghcc-consent>




  <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden>
    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
    <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    You can’t perform that action at this time.
  </div>

    <template id="site-details-dialog">
  <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open>
    <summary role="button" aria-label="Close dialog"></summary>
    <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal">
      <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog>
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
      </button>
      <div class="octocat-spinner tmp-my-6 js-details-dialog-spinner"></div>
    </details-dialog>
  </details>
</template>

    <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;">
  <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;">
  </div>
</div>

    <template id="snippet-clipboard-copy-button">
  <div class="zeroclipboard-container position-absolute right-0 top-0">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2 tmp-m-2">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2 tmp-m-2">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>
<template id="snippet-clipboard-copy-button-unpositioned">
  <div class="zeroclipboard-container">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>




    </div>
    <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div>
    <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div>
  </body>
</html>

