hf2q 0.1.10

Pure Rust CLI for converting HuggingFace models to hardware-optimized formats and serving them over an OpenAI-compatible API on Apple Silicon
name: CI

# Per-PR and per-push-to-main build + test gate.
#
# Runs on macOS because hf2q's inference path depends on mlx-native,
# which is Metal-only (Apple Silicon). The release-check.sh parity +
# perf gate is wired in a separate workflow (release-check.yml) that
# needs a self-hosted runner with the Gemma-4 26B DWQ GGUF.
#
# Lint strictness policy:
#   * cargo check + build --release + hosted-safe tests — BLOCKING.
#     GitHub's hosted macOS VM compiles Metal, but does not expose a usable
#     residency set. Real Metal tests require a self-hosted Apple Silicon gate.
#   * cargo clippy — INFORMATIONAL. The legacy tree has a broad lint backlog;
#     check/build/test remain the blocking correctness gates.
#   * cargo fmt --check — INFORMATIONAL (continue-on-error). The
#     baseline carries ~700 rustfmt diffs from earlier style drift;
#     running `cargo fmt --all` against the whole tree is a separate
#     policy decision (touches wide swaths of legacy code). Kept in
#     the log so new drift is visible.
#   * activate() warning-matrix smoke — BLOCKING; confirms the
#     HF2Q_UNSAFE_EXPERIMENTS ack gate (docs/shipping-contract.md)
#     still refuses/activates/warns correctly.

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always

jobs:
  peer-ref-ratchet:
    name: peer reference ratchet
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
      # Fail-closed ratchet: literal llama.cpp references outside the
      # whitelist must never rise above data/peer_ref_baseline.txt.
      # Attribution policy lives in NOTICE; prose says "the peer".
      - name: peer_ref_ratchet
        run: sh scripts/peer_ref_ratchet.sh

  build-and-test:
    name: build + test (macos-latest)
    runs-on: macos-latest
    # This covers a cold locked build, audit, serialized hosted-safe contracts,
    # and post-job cache cleanup. It is a fail-closed ceiling, not the expected
    # duration; build-script invalidation must leave enough margin for cleanup.
    timeout-minutes: 60

    steps:
      - name: Checkout
        uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
        with:
          persist-credentials: false

      - name: Install Rust toolchain (1.88.0, as pinned in Cargo.toml)
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master
        with:
          toolchain: "1.88.0"
          components: rustfmt, clippy

      - name: Cache cargo registry + target
        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
          restore-keys: cargo-${{ runner.os }}-

      # --- fmt: informational (baseline drift, see header) ---
      - name: cargo fmt --check (informational)
        continue-on-error: true
        run: cargo fmt --all -- --check

      # --- clippy: informational until the legacy lint backlog is retired ---
      - name: cargo clippy (informational)
        continue-on-error: true
        run: cargo clippy --locked --all-targets --all-features

      # --- Blocking compile + test ---
      - name: Require canonical mlx-native build environment
        shell: bash
        run: |
          if [[ ${MLX_NATIVE_SKIP_METALLIB+x} ]]; then
            echo "MLX_NATIVE_SKIP_METALLIB is forbidden for release-capable builds" >&2
            exit 1
          fi

      - name: Standalone distribution package contract
        shell: bash
        run: |
          set -euo pipefail
          package_list="$(cargo +1.88.0 package --locked --list)"
          for required in \
            src/distribution/mod.rs \
            src/distribution/standalone.rs \
            src/distribution/standalone/update.rs \
            src/distribution/standalone_tests.rs \
            src/cli/complete.rs \
            src/cli/completion_install.rs \
            src/cli/completion_install_tests.rs \
            src/cli/completion_receipt.rs \
            src/cli/completion_startup.rs \
            src/cli/completion_startup_tests.rs \
            scripts/install.sh.in \
            scripts/sign_notarize_standalone_release.sh \
            scripts/test_standalone_installer.sh \
            scripts/test_standalone_release_signing_contract.sh \
            docs/shell-completion.md \
            docs/adr/ADR-045-frictionless-distribution-updates-and-onboarding.md
          do
            grep -Fqx -- "$required" <<<"$package_list"
          done

      - name: cargo check
        run: cargo check --locked --all-targets --all-features

      - name: cargo build --release
        run: cargo build --release --locked

      - name: cargo audit
        run: |
          cargo install cargo-audit --locked --version 0.22.2 --no-default-features
          cargo audit

      # GitHub's hosted macOS VM returns nil from Metal residency-set
      # creation. Keep the hosted gate blocking and deterministic by running
      # the library, native conversion, and non-Metal DeepSeek contracts here.
      # Metal execution is validated on real Apple Silicon; the declarative
      # parity/performance procedure lives in release-check.yml.
      - name: cargo test (hosted-safe contracts)
        run: |
          set -euo pipefail
          cargo test --locked --lib --all-features
          cargo test --locked --test build_script_contract --all-features
          cargo test --locked --test completions --all-features
          cargo test --locked --test convert_integration --all-features
          cargo test --locked --test lcp_registry_unit --all-features
          cargo test --locked --bin hf2q --all-features convert::orchestrator::tests::
          cargo test --locked --bin hf2q --all-features distribution::standalone:: -- --test-threads=1
          scripts/test_standalone_installer.sh
          scripts/test_standalone_release_signing_contract.sh
          cargo test --locked --bin hf2q --all-features setup:: -- --test-threads=1
          cargo test --locked --bin hf2q --all-features tests::convert_config_quant_is_used_and_explicit_quant_wins -- --exact
          cargo test --locked --bin hf2q --all-features tests::invalid_operator_config_fails_before_convert_source_or_serve_bind -- --exact
          cargo test --locked --bin hf2q --all-features serve::tests::serve_config_defaults_are_used_and_cli_env_override_them -- --exact
          cargo test --locked --bin hf2q --all-features serve::tests::configured_lan_requires_runtime_auth -- --exact
          cargo test --locked --bin hf2q --all-features serve::tests::c4_scheduler_cli_wins_over_env -- --exact
          cargo test --locked --bin hf2q --all-features serve::tests::c4_max_slots_cli_wins_over_env -- --exact
          hf_source_tests="$(cargo test --locked --bin hf2q --all-features -- --list)"
          for required_test in \
            cli::tests::getting_started_qwen38_commands_parse_exactly \
            distribution::standalone::tests::standalone_lifecycle_installs_updates_rolls_back_and_preserves_operator_state \
            distribution::standalone::tests::standalone_installer_bootstrap_surface_is_hidden_bounded_and_parseable \
            distribution::standalone::update::tests::stable_release_record_is_small_canonical_and_exact \
            distribution::standalone::update::tests::standalone_candidate_architecture_is_exactly_thin_arm64 \
            setup::defaults_contract_tests::operator_config_v2_is_canonical_strict_and_uses_the_guide_defaults \
            setup::defaults_contract_tests::operator_config_v2_rejects_incoherent_fifo_slots_and_invalid_quant \
            setup::defaults_contract_tests::absent_operator_config_preserves_existing_command_behavior_without_claiming_root_authority \
            setup::defaults_contract_tests::selected_state_root_loads_the_exact_operator_config \
            setup::tests::cli_parses_the_closed_noninteractive_surface \
            setup::tests::fresh_and_repeated_noninteractive_setup_are_idempotent \
            setup::tests::interactive_setup_uses_current_values_and_records_explicit_operator_choices \
            setup::tests::cancelled_or_interrupted_interactive_setup_creates_nothing \
            setup::tests::noninteractive_setup_requires_complete_choices_or_accept_defaults \
            setup::tests::named_performance_levels_accept_one_or_more_levels_and_reject_incoherent_facts \
            tests::convert_config_quant_is_used_and_explicit_quant_wins \
            tests::invalid_operator_config_fails_before_convert_source_or_serve_bind \
            serve::tests::serve_config_defaults_are_used_and_cli_env_override_them \
            serve::tests::configured_lan_requires_runtime_auth \
            serve::tests::c4_scheduler_cli_wins_over_env \
            serve::tests::c4_max_slots_cli_wins_over_env \
            setup::tests::lock_contention_is_busy_and_mints_no_config \
            setup::tests::exact_read_rejects_leaf_replacement_after_reading_the_open_inode \
            setup::tests::partial_leaf_replacement_before_rename_is_rejected_without_publication \
            setup::tests::config_lock_and_partial_leaf_replacements_never_return_success \
            setup::tests::stale_prompt_snapshot_and_partial_prefix_replacement_fail_closed \
            setup::tests::sigabrt_at_every_publication_barrier_recovers_in_a_fresh_process \
            input::hf_reference_tests::equivalent_model_references_share_one_canonical_identity \
            input::hf_download_plan_tests::file_specific_resolution_fails_before_any_hub_lookup \
            input::hf_download_plan_tests::repository_info_seals_a_mutable_request_to_the_returned_exact_commit \
            input::hf_download_plan_tests::immutable_file_metadata_is_checked_before_transfer \
            input::hf_download_plan_tests::metadata_transfer_caps_are_explicit_and_exact \
            inference::models::qwen35::source_precision::operator::tests::embedded_qwen38_source_manifest_projects_exact_offline_inventory \
            convert::cli_driver::tests::deepseek_tiny_official_layout_converts_to_q2_k_s_end_to_end \
            input::integrity::tests::safetensors_index_entry_cap_is_exact \
            convert::receipt::tests::prepared_success_receipt_binds_output_and_replaces_stale_atomically \
            convert::receipt::tests::explicit_receipt_destination_cannot_replace_the_artifact \
            tests::convert_source_classifier_reconciles_revision_and_rejects_ambiguity
          do
            grep -Fq -- "$required_test: test" <<<"$hf_source_tests"
          done
          cargo test --locked --bin hf2q --all-features input::hf_reference_tests::
          cargo test --locked --bin hf2q --all-features input::hf_download_plan_tests::
          cargo test --locked --bin hf2q --all-features inference::models::qwen35::source_precision::operator::tests::embedded_qwen38_source_manifest_projects_exact_offline_inventory -- --exact
          cargo test --locked --bin hf2q --all-features input::integrity::tests:: -- --test-threads=1
          cargo test --locked --bin hf2q --all-features convert::cli_driver::tests::deepseek_tiny_official_layout_converts_to_q2_k_s_end_to_end -- --exact
          cargo test --locked --bin hf2q --all-features convert::receipt::tests::
          cargo test --locked --bin hf2q --all-features tests::convert_source_classifier
          cargo test --locked --bin hf2q --all-features qwen38 -- --test-threads=1
          cargo test --locked --bin hf2q --all-features qwen_thinking_budget -- --test-threads=1
          cargo test --locked --bin hf2q --all-features gqa_q2_policy::tests -- --test-threads=1
          cargo test --locked --bin hf2q --all-features iter230_a2_lock_discipline -- --test-threads=1
          cargo test --locked --bin hf2q --all-features loaded_registration_overrides -- --test-threads=1
          cargo test --locked --bin hf2q --all-features serve::operator_ui::tests:: -- --test-threads=1
          cargo test --locked --bin hf2q --all-features qwen35_serving_tokenizer_is_sidecar_free_and_detects_vision_markers -- --test-threads=1
          cargo test --locked --bin hf2q --all-features vision_projector_binding -- --test-threads=1
          cargo test --locked --bin hf2q --all-features model_advertisement_contract_ -- --test-threads=1
          cargo test --locked --bin hf2q --all-features qwen35_startup_warmup_primes_gpu_for_serial_and_slot_aware -- --test-threads=1
          cargo test --locked --bin hf2q --all-features qwen35_bounded_prefill_watchdog_tests -- --test-threads=1
          cargo test --locked --bin hf2q --all-features prompt_cache_ -- --test-threads=1
          cargo test --locked --bin hf2q --all-features agentic_grammar_contract_ -- --test-threads=1
          cargo test --locked --bin hf2q --all-features gemma4_bounded_prefill_tests -- --test-threads=1
          cargo test --locked --bin hf2q --all-features slotaware_fail_stop_tests -- --test-threads=1
          cargo test --locked --bin hf2q --all-features engine_supervisor::tests -- --test-threads=1
          cargo test --locked --bin hf2q --all-features public_watchdog_fixture_bytes_are_stable_without_a_model -- --test-threads=1
          cargo test --locked --bin hf2q --all-features public_watchdog_fixture_consumers_share_the_canonical_digests -- --test-threads=1
          cargo test --locked --bin hf2q --all-features readiness_guard_tests -- --test-threads=1
          bash -n scripts/qwen36_watchdog_validate.sh \
            scripts/test_shipping_contract.sh \
            scripts/serve_qwen38_opencode.sh \
            scripts/test_qwen36_prefill_watchdog.sh \
            scripts/test_qwen36_prefill_cancellation.sh \
            scripts/test_qwen36_cumulative_release.sh \
            scripts/test_deepseek4_agentic.sh \
            scripts/test_deepseek4_structured_tools.sh \
            scripts/test_deepseek4_agentic_fixture_contract.sh \
            scripts/test_deepseek4_cooperative_prefill_receipt_contract.sh \
            scripts/test_deepseek4_decode_cohort_receipt_contract.sh \
            scripts/test_deepseek4_peer_cold_wave.sh \
            scripts/test_deepseek4_peer_cold_wave_contract.sh \
            scripts/run_deepseek4_matched_peer.sh \
            scripts/macos_thermal_guard.sh \
            scripts/verify_macos_thermal_receipt.sh \
            scripts/verify_deepseek4_cooperative_prefill_receipt.sh \
            scripts/verify_deepseek4_decode_cohort_receipt.sh \
            scripts/run_deepseek4_decode_cohort_gate.sh \
            scripts/verify_gemma4_wave_thermal_receipt.sh \
            scripts/verify_gemma4_parity_receipt.sh \
            scripts/qwen38_long_decode_ab.sh \
            scripts/verify_qwen38_long_decode_receipt.sh \
            scripts/test_qwen38_long_decode_receipt_contract.sh \
            scripts/test_qwen38_artifact_binding_contract.sh \
            scripts/test_macos_thermal_guard_contract.sh \
            scripts/test_gemma4_wave_thermal_contract.sh \
            scripts/test_gemma4_eight_slot_receipt_contract.sh \
            scripts/seal_release_binary.sh \
            scripts/test_release_binary_seal_contract.sh \
            scripts/sign_notarize_standalone_release.sh \
            scripts/verify_standalone_candidate.sh \
            scripts/test_standalone_release_signing_contract.sh \
            scripts/verify_release_dependency_provenance.sh \
            scripts/test_release_dependency_provenance_contract.sh \
            scripts/run_release_gate_process_group.sh \
            scripts/test_release_gate_process_group_contract.sh \
            scripts/ensure_github_release_tag.sh \
            scripts/test_release_tag_recovery_contract.sh \
            scripts/test_deepseek4_cached_suffix.sh \
            scripts/test_deepseek4_cached_suffix_contract.sh \
            scripts/test_deepseek4_interactive_overlap.sh \
            scripts/test_agentic_cache_lifecycle.sh \
            scripts/test_gemma4_long_short_overlap.sh \
            scripts/test_gemma4_long_short_overlap_contract.sh \
            scripts/run_agentic_cache_release_gate.sh
          bash scripts/test_qwen36_watchdog_harness_contract.sh
          bash scripts/test_shipping_contract.sh
          bash scripts/test_deepseek4_cached_suffix_contract.sh
          bash scripts/test_deepseek4_agentic_fixture_contract.sh
          bash scripts/test_deepseek4_cooperative_prefill_receipt_contract.sh
          bash scripts/test_deepseek4_decode_cohort_receipt_contract.sh
          bash scripts/test_deepseek4_peer_cold_wave_contract.sh
          bash scripts/test_macos_thermal_guard_contract.sh
          bash scripts/test_gemma4_wave_thermal_contract.sh
          bash scripts/test_gemma4_eight_slot_receipt_contract.sh
          bash scripts/test_qwen38_long_decode_receipt_contract.sh
          bash scripts/test_qwen38_artifact_binding_contract.sh
          bash scripts/test_release_binary_seal_contract.sh
          bash scripts/test_standalone_release_signing_contract.sh
          bash scripts/test_release_dependency_provenance_contract.sh
          bash scripts/test_release_gate_process_group_contract.sh
          bash scripts/test_release_tag_recovery_contract.sh
          bash scripts/test_gemma4_long_short_overlap_contract.sh
          cargo test --locked --bin hf2q --all-features deepseek4 -- \
            --skip attention_forward_tests \
            --skip allocator_materializes_the_plan_as_zeroed_bf16_buffers \
            --skip cache_steps_publish_only_complete_groups_and_commit_transactionally \
            --skip partial_token_poison_requires_reset_before_replay \
            --skip start_zero_prefill_span_counts_complete_groups_and_publishes_once \
            --skip ffn_forward_tests \
            --skip raw_matmul_accepts_quality_sensitive_f32_weights \
            --skip embedding_forward_rejects_empty_input \
            --skip q2_k_embeddings_expand_to_four_identical_hc_streams \
            --skip native_model_load_keeps_weights_and_cache_on_one_device \
            --skip native_output_head_produces_finite_vocab_logits_and_rejects_shape_drift \
            --skip loader_preserves_raw_blocks_and_expands_only_elementwise_state \
            --skip loader_rejects_catalog_and_i32_storage_before_residency

      # --- Blocking: activate() matrix matches the shipping contract ---
      - name: activate() matrix smoke (clean / REFUSED / UNSAFE)
        shell: bash
        run: |
          set -euo pipefail

          echo "--- clean env should produce no investigation output ---"
          ./target/release/hf2q --help > /dev/null 2>/tmp/stderr_clean.log
          if [[ -s /tmp/stderr_clean.log ]]; then
            echo "FAIL: clean-env run produced stderr:" >&2
            cat /tmp/stderr_clean.log >&2
            exit 1
          fi
          echo "  OK"

          echo "--- HF2Q_F16_KV=1 without ack must REFUSE ---"
          HF2Q_F16_KV=1 ./target/release/hf2q --help \
              > /dev/null 2>/tmp/stderr_refused.log
          grep -q "REFUSED" /tmp/stderr_refused.log
          grep -q "HF2Q_F16_KV=1" /tmp/stderr_refused.log
          echo "  OK"

          echo "--- HF2Q_F16_KV=1 + HF2Q_UNSAFE_EXPERIMENTS=1 must ACTIVATE ---"
          HF2Q_F16_KV=1 HF2Q_UNSAFE_EXPERIMENTS=1 \
              ./target/release/hf2q --help \
              > /dev/null 2>/tmp/stderr_unsafe.log
          grep -q "UNSAFE (ack-required, activated)" /tmp/stderr_unsafe.log
          if grep -q "REFUSED" /tmp/stderr_unsafe.log; then
            echo "FAIL: explicitly acknowledged unsafe activation was refused" >&2
            exit 1
          fi
          echo "  OK"