Skip to content

perf(pricing): shrink embedded snapshots 58% and binary 2.9% - #1244

Merged
ryoppippi merged 10 commits into
mainfrom
codex/min-sized-rust-skill
Jun 10, 2026
Merged

perf(pricing): shrink embedded snapshots 58% and binary 2.9%#1244
ryoppippi merged 10 commits into
mainfrom
codex/min-sized-rust-skill

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Jun 10, 2026

Copy link
Copy Markdown
Member

Adds a repo-local Rust binary-size skill based on min-sized-rust and registers it in AGENTS.md.

Applies that guidance by compacting embedded pricing snapshots so the release binary ships less unused JSON structure while keeping runtime parsing compatible with live upstream response shapes.

Impact:

  • models.dev snapshot: 97,159 bytes -> 36,871 bytes (-60,288 bytes, -62.05%)
  • LiteLLM snapshot: 66,046 bytes -> 31,949 bytes (-34,097 bytes, -51.63%)
  • combined embedded pricing snapshots: 163,205 bytes -> 68,820 bytes (-94,385 bytes, -57.83%)
  • release binary: 2,895,424 bytes -> 2,812,880 bytes (-82,544 bytes, -2.85%)

Data integrity:

  • models.dev: compared old snapshot flattened with the old loader key rule (id ?? model key) against the new snapshot.
  • models.dev model ids: 224 -> 224; missing keys: 0; extra keys: 0; cost/limit mismatches: 0
  • LiteLLM: compared old long-form generated snapshot against the new short-key snapshot after expanding runtime-relevant fields.
  • LiteLLM model ids: 401 -> 401; missing keys: 0; extra keys: 0; runtime-relevant value mismatches: 0

Testing:

  • direnv exec . just fmt
  • direnv exec . just typecheck
  • direnv exec . just test
  • direnv exec . cargo test --manifest-path rust/Cargo.toml -p ccusage pricing::tests:: -- --nocapture
  • direnv exec . cargo build --manifest-path rust/Cargo.toml --release --bin ccusage

Summary by CodeRabbit

  • Documentation

    • Added a comprehensive Rust binary-size skill guide and listed the skill in the recommended agents section.
  • Improvements

    • Pricing ingestion accepts additional snapshot shapes, better validates inputs, deduplicates keys, and uses a more compact on-disk format.
    • Test discovery refined with targeted project configs; PR-comment script refactored for more robust handling.
  • Bug Fixes

    • macOS packaging now rewrites a bundled libiconv to the system library for compatibility.
  • CI / Tooling

    • Performance comparisons timeout faster and can skip gracefully when artifacts are unavailable.

Add a repo-local rust-binary-size skill for release-profile, dependency feature, native package size, and executable bloat work.

The skill captures stable min-sized-rust guidance, keeps aggressive nightly and packer techniques opt-in, and links back to the upstream reference so future agents can inspect the source material when size work recurs.

Register the skill in AGENTS.md so agents discover it before changing Rust size-sensitive code or packaging.
Regenerate the committed models.dev pricing snapshot as a flat map keyed by runtime model id instead of preserving upstream provider nesting.

The runtime loader now accepts both the live provider-tree shape from models.dev and the flat embedded shape, so network fallback compatibility is unchanged while the checked-in snapshot shrinks from 97,159 bytes to 36,871 bytes.

The release binary rebuilt successfully after the change at 2,845,920 bytes. Pricing tests cover the flat embedded shape and the existing offline fallback behaviour.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 10, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide d4311b9 Commit Preview URL

Branch Preview URL
Jun 10 2026, 04:25 PM

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 432a2563-3aba-4d97-b4fd-2b1d34aa4291

📥 Commits

Reviewing files that changed from the base of the PR and between 904f9f9 and d4311b9.

📒 Files selected for processing (7)
  • .github/scripts/upsert-pr-comment.ts
  • .github/workflows/ci.yaml
  • apps/ccusage/scripts/compare-pr-performance.ts
  • nix/models-dev-compact.test.ts
  • nix/models-dev-compact.ts
  • nix/models-dev-gen.ts
  • vitest.config.ts
 _______________________________
< I turn WTF moments into TILs. >
 -------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a rust-binary-size skill doc and registers it; changes models.dev generation to a flat embedded map, compacts LiteLLM entries in the build, extends Rust pricing parsers for compact and flattened/provider-wrapped shapes with tests, adds a macOS staging rewrite, and makes performance-run installation tolerant of timeouts.

Changes

Rust binary size skill documentation

Layer / File(s) Summary
Binary size skill guide and registration
.agents/skills/rust-binary-size/SKILL.md, AGENTS.md
New guide documents baseline profiling, regression investigation, safe vs risky size reductions, validation steps, and adds rust-binary-size to the repository skill list.

Models.dev pricing format migration

Layer / File(s) Summary
Generator refactor for flat models.dev format
nix/models-dev-gen.ts, nix/models-dev-compact.ts, nix/models-dev-compact.test.ts
Generator now builds a flat Record<string, EmbeddedModel> map keyed by computed pricingKey, deduplicates entries, inlines cost/cache fields, optionally includes limit.context, and adds selector/formatter helpers with unit tests.
Build compaction for LiteLLM entries
rust/crates/ccusage/build.rs
Compacts LiteLLM embedded-model fields into abbreviated keys (i,o,cc,cr,ia,oa,cca,cra,ctx) and extracts provider_specific_entry.fast into fast; emits model objects only when i and o are present.
Parser support for flat and nested models.dev + compact LiteLLM
rust/crates/ccusage/src/pricing.rs
Adds CompactLiteLlmPricing and ModelsDevJson parsing helpers, parse_litellm_pricing fallback logic, refactors load_models_dev_json_missing to a shared loader, validates required cost fields, scales units, inserts pricing and limit.context, and adds fixture-backed unit tests.
Test project configuration
vitest.config.ts
Adds inline nix and github-scripts Vitest projects for targeted test discovery and enables globals for those projects.

Native packaging

Layer / File(s) Summary
Darwin library rewrite in staging script
apps/ccusage/scripts/stage-native-package.mjs
Adds execFileSync and rewriteDarwinSystemLibraries(binaryPath) to scan otool -L and run install_name_tool -change for a specific Nix libiconv.2.dylib, invoked for macOS staging.

PR comment script

Layer / File(s) Summary
Upsert PR comment refactor
.github/scripts/upsert-pr-comment.ts
Parameterizes comment helpers, adds isCommentWriteAuthFailure type guard, centralizes main() flow, and includes unit tests for the auth-failure predicate.

Performance comparison runner

Layer / File(s) Summary
Package install result and timeout handling
apps/ccusage/scripts/compare-pr-performance.ts
Introduce PackageInstall type; installPackageUrl returns undefined on timeout instead of throwing; add renderSkippedMarkdown and early-exit when base artifacts are unavailable; tests added for both behaviors.
CI timeout argument changes
.github/workflows/ci.yaml
Reduces --package-runner-timeout-ms from 1800000 to 300000 in two workflow jobs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ryoppippi/ccusage#1013: Refactors/handling of comment-write failures and upsert flow in .github/scripts/upsert-pr-comment.ts.
  • ryoppippi/ccusage#1061: Related LiteLLM fast_multiplier / provider-specific fast handling in pricing.rs.
  • ryoppippi/ccusage#1242: Related changes to nix/models-dev-gen.ts and rust/crates/ccusage/src/pricing.rs around models.dev snapshot shape and loading.

Suggested reviewers

  • pullfrog

Poem

🐇 I nibble bytes and trim the fluff away,
I flatten maps and shorten keys by day,
I teach the parser both compact and wide,
I patch macOS links so builds can glide,
Hop — lighter docs, slimmer bins, hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "perf(pricing): shrink embedded snapshots 58% and binary 2.9%" directly and specifically describes the main change: reducing the size of embedded pricing snapshots by ~58% and the release binary by ~2.9%. This matches the core objective shown in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/min-sized-rust-skill

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — flattens the embedded models.dev pricing snapshot to shrink the release binary and adds a repo-local rust-binary-size skill.

  • Add rust-binary-size skill — stable binary-size guidance from min-sized-rust with investigation steps, safe/risky change categories, and validation commands.
  • Register skill in AGENTS.md — adds rust-binary-size to the skill routing list.
  • Flatten models-dev-pricing.json — regenerates the snapshot as a flat map keyed by runtime model id, shrinking from ~97KB to ~37KB.
  • Make loader format-agnosticModelsDevJson untagged enum accepts both provider-tree (live models.dev) and flat (embedded) formats; load_models_dev_models is extracted for reuse.
  • Update generatornix/models-dev-gen.ts outputs flat entries with model.id ?? modelId as the key and first-wins dedup.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@ryoppippi ryoppippi changed the title perf(pricing): flatten embedded models.dev snapshot perf(pricing): shrink embedded pricing 62% and binary 1.7% Jun 10, 2026
@ryoppippi ryoppippi changed the title perf(pricing): shrink embedded pricing 62% and binary 1.7% perf(pricing): shrink models.dev snapshot 62% and binary 1.7% Jun 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
rust/crates/ccusage/src/pricing.rs (1)

1486-1514: ⚡ Quick win

Prefer a fixture-backed parser case for the flat snapshot.

This inline JSON is already large, and the flat-vs-provider compatibility matrix will likely grow. Moving this case into a fixture will keep the test readable and make future parser regressions easier to extend.

As per coding guidelines, "For Rust code, keep modules small, keep pub(crate) surfaces narrow, prefer fixture-backed parser/loader tests, and run cargo checks through the just recipes when possible."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/crates/ccusage/src/pricing.rs` around lines 1486 - 1514, The test
loads_flat_models_dev_pricing_snapshot embeds a large inline JSON; move this
into a fixture file and update the test to read and pass that fixture to
PricingMap::load_models_dev_json_missing to keep the test small and
maintainable. Create a fixture (e.g., tests/fixtures/claude_flat_snapshot.json)
containing the JSON, update the test in loads_flat_models_dev_pricing_snapshot
to read the fixture (using std::fs::read_to_string or the test helper used
elsewhere), and keep assertions that call PricingMap::default(),
pricing.load_models_dev_json_missing(...), pricing.find("claude-fallback"), and
pricing.context_limit("claude-fallback") unchanged. Ensure the test still
asserts Some(1) from load_models_dev_json_missing and the same numeric checks
for fallback.input, fallback.output, fallback.cache_create, and
fallback.cache_read.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rust/crates/ccusage/src/pricing.rs`:
- Around line 90-95: The untagged ModelsDevJson enum allows provider objects to
be mis-parsed as flat model entries, so replace the #[serde(untagged)] approach
with explicit shape validation: implement a custom Deserialize (or parse
serde_json::Value) for ModelsDevJson that inspects each top-level entry and
requires a "models" field for provider entries (mapping to ModelsDevProvider)
and requires "cost"/"input"/"output" fields for flat ModelsDevModel entries,
returning a clear error if a provider entry is missing "models"; update
load_models_dev_models to use the new validated ModelsDevJson and ensure
ModelsDevPricingCache::get_or_try_load still only caches successful,
non-malformed results (i.e., parsing must error instead of returning an empty
map), and add a fixture-backed regression test that loads a mixed/malformed
providers file (one provider missing "models") asserting parsing fails and no
empty PricingMap is cached.

---

Nitpick comments:
In `@rust/crates/ccusage/src/pricing.rs`:
- Around line 1486-1514: The test loads_flat_models_dev_pricing_snapshot embeds
a large inline JSON; move this into a fixture file and update the test to read
and pass that fixture to PricingMap::load_models_dev_json_missing to keep the
test small and maintainable. Create a fixture (e.g.,
tests/fixtures/claude_flat_snapshot.json) containing the JSON, update the test
in loads_flat_models_dev_pricing_snapshot to read the fixture (using
std::fs::read_to_string or the test helper used elsewhere), and keep assertions
that call PricingMap::default(), pricing.load_models_dev_json_missing(...),
pricing.find("claude-fallback"), and pricing.context_limit("claude-fallback")
unchanged. Ensure the test still asserts Some(1) from
load_models_dev_json_missing and the same numeric checks for fallback.input,
fallback.output, fallback.cache_create, and fallback.cache_read.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37d352af-ba08-4f3c-95dd-6071e00b9885

📥 Commits

Reviewing files that changed from the base of the PR and between da74716 and 5bff81f.

📒 Files selected for processing (5)
  • .agents/skills/rust-binary-size/SKILL.md
  • AGENTS.md
  • nix/models-dev-gen.ts
  • rust/crates/ccusage/src/models-dev-pricing.json
  • rust/crates/ccusage/src/pricing.rs

Comment thread rust/crates/ccusage/src/pricing.rs Outdated
@pkg-pr-new

pkg-pr-new Bot commented Jun 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ccusage@1244

@ccusage/ccusage-darwin-arm64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-arm64@1244

@ccusage/ccusage-darwin-x64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-x64@1244

@ccusage/ccusage-linux-arm64

npx https://pkg.pr.new/@ccusage/ccusage-linux-arm64@1244

@ccusage/ccusage-linux-x64

npx https://pkg.pr.new/@ccusage/ccusage-linux-x64@1244

@ccusage/ccusage-win32-arm64

npx https://pkg.pr.new/@ccusage/ccusage-win32-arm64@1244

@ccusage/ccusage-win32-x64

npx https://pkg.pr.new/@ccusage/ccusage-win32-x64@1244

commit: c5cf51e

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="rust/crates/ccusage/src/pricing.rs">

<violation number="1" location="rust/crates/ccusage/src/pricing.rs:294">
P1: load_models_dev_json_missing returns Some(0) on zero models loaded, which the caller treats as success and caches permanently in OnceLock — silently disabling the entire models.dev fallback for the process lifetime.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment on lines +294 to +300
Some(match raw {
ModelsDevJson::Providers(providers) => providers
.into_values()
.map(|provider| self.load_models_dev_models(provider.models))
.sum(),
ModelsDevJson::Models(models) => self.load_models_dev_models(models),
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: load_models_dev_json_missing returns Some(0) on zero models loaded, which the caller treats as success and caches permanently in OnceLock — silently disabling the entire models.dev fallback for the process lifetime.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage/src/pricing.rs, line 294:

<comment>load_models_dev_json_missing returns Some(0) on zero models loaded, which the caller treats as success and caches permanently in OnceLock — silently disabling the entire models.dev fallback for the process lifetime.</comment>

<file context>
@@ -281,56 +288,64 @@ impl PricingMap {
+        let Ok(raw) = serde_json::from_str::<ModelsDevJson>(json) else {
             return None;
         };
+        Some(match raw {
+            ModelsDevJson::Providers(providers) => providers
+                .into_values()
</file context>
Suggested change
Some(match raw {
ModelsDevJson::Providers(providers) => providers
.into_values()
.map(|provider| self.load_models_dev_models(provider.models))
.sum(),
ModelsDevJson::Models(models) => self.load_models_dev_models(models),
})
let count = match raw {
ModelsDevJson::Providers(providers) => providers
.into_values()
.map(|provider| self.load_models_dev_models(provider.models))
.sum(),
ModelsDevJson::Models(models) => self.load_models_dev_models(models),
};
if count == 0 {
None
} else {
Some(count)
}

Replace the untagged models.dev snapshot parser with explicit top-level shape validation so malformed provider payloads cannot be accepted as an empty flat model map.

The regression test uses a fixture-backed malformed provider payload and confirms parsing fails without loading entries. This addresses CodeRabbit feedback on PR #1244.

Validation: direnv exec . cargo test --manifest-path rust/Cargo.toml -p ccusage pricing::tests:: -- --nocapture; direnv exec . just fmt
Emit the build-time LiteLLM snapshot with short field keys and teach the runtime loader to read both the compact embedded shape and the normal LiteLLM response shape.

The generated LiteLLM snapshot shrinks from 66,046 bytes to 31,949 bytes while keeping 401 model keys. Runtime-relevant fields compared equal after expanding the compact keys.

Together with the models.dev flattening, the local release binary is now 2,812,864 bytes versus 2,895,424 bytes on the base commit.

Validation: direnv exec . cargo test --manifest-path rust/Cargo.toml -p ccusage pricing::tests:: -- --nocapture; direnv exec . cargo build --manifest-path rust/Cargo.toml --release --bin ccusage; direnv exec . just fmt
@ryoppippi ryoppippi changed the title perf(pricing): shrink models.dev snapshot 62% and binary 1.7% perf(pricing): shrink embedded snapshots 58% and binary 2.9% Jun 10, 2026
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review\n\nPushed follow-up commits through 015de4c. Addressed your models.dev parser feedback by replacing untagged deserialization with explicit shape validation and a fixture-backed malformed-provider regression test. Also compacted the embedded LiteLLM snapshot after validating key/value parity for runtime-relevant fields. Validation: direnv exec . just fmt, direnv exec . just test, pricing::tests::, release build.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

@ryoppippi: Thanks for the detailed follow-up! I'll kick off a fresh review of the latest commits through 015de4cd, covering the explicit shape validation refactor, the malformed-provider regression fixture, and the compacted LiteLLM snapshot.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ryoppippi

ryoppippi commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

@cubic-dev-ai review it
@pullfrog reveiw it

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@cubic-ai-dev review it
@pullfrog reveiw it

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@pullfrog

pullfrog Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Run failed. View the logs →

Pullfrog  | Rerun failed job ➔View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — compacts the embedded LiteLLM snapshot with short key names and replaces #[serde(untagged)] deserialization with explicit shape validation for models.dev payloads, addressing the prior CodeRabbit concern about silent mis-parsing.

  • Compact LiteLLM embedded snapshotbuild.rs maps long field names to short keys (i, o, cc, cr, ia, oa, cca, cra, ctx, fast). parse_litellm_pricing detects compact format by the "i" key and falls back to full LiteLlmPricing deserialization for live upstream responses.
  • Explicit models.dev shape validationparse_models_dev_json inspects top-level entries to distinguish provider-tree payloads (all entries have "models" object) from flat payloads (all entries have cost.input/cost.output numbers), rejecting mixed or malformed inputs. Replaces the prior #[serde(untagged)] approach.
  • Extract load_models_dev_models — inline model-loading loop moved into its own method, called from both provider and flat branches of load_models_dev_json_missing.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
rust/crates/ccusage/src/pricing.rs (1)

987-1013: ⚡ Quick win

Align compact-shape detection with the emitter contract (i + o).

Line 990 checks only "i" to enter compact parsing, but the emitter only produces compact entries when both "i" and "o" are present (build.rs Line 134). Matching that condition (and falling back to full-shape parse if compact decode fails) avoids false positives and accidental drops.

♻️ Suggested patch
 fn parse_litellm_pricing(value: Value) -> Option<LiteLlmPricing> {
-    if value
-        .as_object()
-        .is_some_and(|entry| entry.contains_key("i"))
-    {
-        let compact = serde_json::from_value::<CompactLiteLlmPricing>(value).ok()?;
-        return Some(LiteLlmPricing {
-            input_cost_per_token: Some(compact.i),
-            output_cost_per_token: Some(compact.o),
-            cache_creation_input_token_cost: compact.cc,
-            cache_read_input_token_cost: compact.cr,
-            input_cost_per_token_above_200k_tokens: compact.ia,
-            output_cost_per_token_above_200k_tokens: compact.oa,
-            cache_creation_input_token_cost_above_200k_tokens: compact.cca,
-            cache_read_input_token_cost_above_200k_tokens: compact.cra,
-            max_input_tokens: compact.ctx,
-            provider_specific_entry: compact
-                .fast
-                .map(|fast| ProviderSpecificEntry { fast: Some(fast) }),
-        });
+    if value.as_object().is_some_and(|entry| {
+        entry.contains_key("i") && entry.contains_key("o")
+    }) {
+        if let Ok(compact) = serde_json::from_value::<CompactLiteLlmPricing>(value.clone()) {
+            return Some(LiteLlmPricing {
+                input_cost_per_token: Some(compact.i),
+                output_cost_per_token: Some(compact.o),
+                cache_creation_input_token_cost: compact.cc,
+                cache_read_input_token_cost: compact.cr,
+                input_cost_per_token_above_200k_tokens: compact.ia,
+                output_cost_per_token_above_200k_tokens: compact.oa,
+                cache_creation_input_token_cost_above_200k_tokens: compact.cca,
+                cache_read_input_token_cost_above_200k_tokens: compact.cra,
+                max_input_tokens: compact.ctx,
+                provider_specific_entry: compact
+                    .fast
+                    .map(|fast| ProviderSpecificEntry { fast: Some(fast) }),
+            });
+        }
     }
     let pricing = serde_json::from_value::<LiteLlmPricing>(value).ok()?;
     pricing
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust/crates/ccusage/src/pricing.rs` around lines 987 - 1013, In
parse_litellm_pricing: the compact-shape detection should require both "i" and
"o" (not just "i") and must not abort if compact deserialization fails; change
the condition that checks the Value object to require entry.contains_key("i") &&
entry.contains_key("o"), and when attempting
serde_json::from_value::<CompactLiteLlmPricing>(value) handle failure by falling
through to the normal serde_json::from_value::<LiteLlmPricing>(value) path
instead of using the ? to return early; keep the existing mapping that converts
CompactLiteLlmPricing into LiteLlmPricing (using CompactLiteLlmPricing,
LiteLlmPricing, and ProviderSpecificEntry identifiers).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@rust/crates/ccusage/src/pricing.rs`:
- Around line 987-1013: In parse_litellm_pricing: the compact-shape detection
should require both "i" and "o" (not just "i") and must not abort if compact
deserialization fails; change the condition that checks the Value object to
require entry.contains_key("i") && entry.contains_key("o"), and when attempting
serde_json::from_value::<CompactLiteLlmPricing>(value) handle failure by falling
through to the normal serde_json::from_value::<LiteLlmPricing>(value) path
instead of using the ? to return early; keep the existing mapping that converts
CompactLiteLlmPricing into LiteLlmPricing (using CompactLiteLlmPricing,
LiteLlmPricing, and ProviderSpecificEntry identifiers).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e6a28294-2356-4e8d-91b1-b9a4f3b3e52e

📥 Commits

Reviewing files that changed from the base of the PR and between 5bff81f and 015de4c.

📒 Files selected for processing (2)
  • rust/crates/ccusage/build.rs
  • rust/crates/ccusage/src/pricing.rs

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="rust/crates/ccusage/src/pricing.rs">

<violation number="1" location="rust/crates/ccusage/src/pricing.rs:294">
P1: load_models_dev_json_missing returns Some(0) on zero models loaded, which the caller treats as success and caches permanently in OnceLock — silently disabling the entire models.dev fallback for the process lifetime.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread nix/models-dev-gen.ts Outdated
@pullfrog

pullfrog Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

The ccusage-preview-e2e (macos-latest) job failure is not caused by this PR.

Failure: dyld: Library not loaded: /nix/store/...-libiconv-109.100.2/lib/libiconv.2.dylib — the Nix-built macOS binary references a Nix store path for libiconv that doesn't exist on GitHub Actions macOS runners.

Why it's unrelated: This PR only touches pricing JSON snapshot compaction (build.rs, pricing.rs), a new rust-binary-size skill, and AGENTS.md. None of these files affect macOS dynamic linking, binary packaging, or Nix build configuration. The dyld error is a pre-existing Nix packaging issue — the macOS binary isn't portable to non-Nix systems.

No changes are needed for this PR.

Task list (4/4 completed)

Pullfrog  | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Align the LiteLLM compact-shape detector with the build-time emitter by requiring both short price keys before compact decoding. If compact decoding fails, the parser now falls back to the full LiteLLM shape so unrelated metadata keys do not drop otherwise valid pricing rows.

Also make the models.dev snapshot generator ignore empty catalog ids and fall back to the source model key. This prevents a malformed empty id from becoming the embedded pricing key while keeping the committed snapshot format unchanged.
The macOS native package was copying a Nix-built binary that still referenced libiconv inside /nix/store. That works inside a Nix closure but fails when the binary is installed from the npm preview package on a clean GitHub macOS runner.

Patch the staged Darwin binary with install_name_tool so the package uses /usr/lib/libiconv.2.dylib at runtime. This keeps the Nix build unchanged while making the published native package runnable outside Nix.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review

Pushed follow-up commits through 465d2bc.

Addressed the latest CodeRabbit LiteLLM parser feedback in 3684c80 by requiring both compact emitter keys (i + o), falling back to full LiteLLM parsing if compact decode does not apply, and adding a regression test for a full-shape entry with an extra i key.

Also addressed cubic finding in 3684c80 by falling back to the source model key when the models.dev catalog id is empty, with a Vitest case included.

Fixed the failing macOS preview package E2E in 465d2bc by rewriting the staged Darwin binary Nix-store libiconv install name to /usr/lib/libiconv.2.dylib. Verified locally with otool after staging.

Validation:

  • direnv exec . just fmt
  • direnv exec . just typecheck
  • direnv exec . cargo test --manifest-path rust/Cargo.toml -p ccusage pricing::tests:: -- --nocapture
  • direnv exec . just test-vitest
  • direnv exec . just test
  • staged Darwin binary otool check
  • offline output parity: local --offline --until 2026-06-09 --json matches bunx ccusage@latest --offline --until 2026-06-09 --json
  • release binary: 2,812,880 bytes, still -2.85% vs 2,895,424 byte baseline

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

@ryoppippi: Thanks for the thorough follow-up! I'll kick off a fresh incremental review covering the latest commits through 465d2bc, including:

  • The LiteLLM compact parser hardening (requiring both i + o keys, full-shape fallback, regression test for full-shape with extra i key)
  • The models.dev empty-catalog-id fallback to the source model key + Vitest coverage
  • The macOS E2E fix rewriting the Darwin binary's Nix-store libiconv install name
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — hardens compact LiteLLM pricing parsing to require both "i" and "o" with fall-through on parse failure, rewrites Nix-built Darwin libiconv install names for macOS compatibility, refactors the models.dev generator key selection into a testable module, and wires the new Vitest nix project.

  • Harden compact LiteLLM parsingparse_litellm_pricing now requires both "i" and "o" keys and falls through to full-shape deserialization when compact deserialization fails (e.g. "i" as a string in upstream responses), matching the build.rs emitter contract. Added a dedicated regression test for the fall-through path.
  • Fix Darwin packagingstage-native-package.mjs now calls install_name_tool to rewrite Nix-store libiconv.2.dylib paths to /usr/lib/libiconv.2.dylib on macOS.
  • Extract selectModelsDevPricingKey — moved key-selection logic from the inline generator into nix/models-dev-compact.ts with a Vitest test. Empty-string catalog IDs now fall back to the model ID.
  • Wire nix Vitest projectvitest.config.ts now discovers tests under nix/**/*.test.ts.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="rust/crates/ccusage/src/pricing.rs">

<violation number="1" location="rust/crates/ccusage/src/pricing.rs:294">
P1: load_models_dev_json_missing returns Some(0) on zero models loaded, which the caller treats as success and caches permanently in OnceLock — silently disabling the entire models.dev fallback for the process lifetime.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread rust/crates/ccusage/src/pricing.rs
@pullfrog

pullfrog Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

No new issues. The two changes since the last pullfrog review are test-coverage additions only — new selectModelsDevPricingKey cases for undefined and non-empty catalogId, and a test-fixture field to align compact-shape detection with the emitter contract. No substantive code changes to review.

Task list (5/5 completed)

Pullfrog  | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

@ryoppippi: Thanks for the thorough update! I'll kick off a fresh incremental review covering commit 904f9f9, including:

  • The additional undefined and non-empty catalog id test cases for selectModelsDevPricingKey
  • The LiteLLM fallback regression fix ensuring compact-shape detection is entered before falling through to full-shape parsing
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review
@cubic-dev-ai review it
@pullfrog review it

Pushed follow-up commit 904f9f9.
...

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="nix/models-dev-gen.ts">

<violation number="1" location="nix/models-dev-gen.ts:50">
P3: Duplicate pricing keys are silently dropped with `continue`. If two providers map to the same key with different pricing, the first wins silently. Consider emitting a warning when a duplicate is skipped so pricing drift is visible during future snapshot regenerations.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread nix/models-dev-gen.ts
Perf comment jobs use pkg.pr.new URLs for both the base and PR package. The base URL can be unavailable for a commit that was never published by the preview package workflow, which previously made the script wait for the full job timeout and fail before writing a comment.

Make package installation return undefined when the URL is not ready, emit a commit-specific skipped performance comment when no base-dir fallback exists, and lower the workflow wait to five minutes so the job has time to finish cleanly.
The compact models.dev generator keeps the first entry for a pricing key, but duplicate provider aliases were previously skipped without any signal. Cubic identified that this could hide future pricing drift when regenerating the snapshot.

Emit a warning before skipping a duplicate pricing key and cover the warning text with a focused Vitest case so future duplicate handling remains visible.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review
@cubic-dev-ai review it
@pullfrog review it

Pushed follow-up commits e8fa2bcc and c5cf51e8.

  • e8fa2bcc makes the perf comment jobs skip cleanly when the base pkg.pr.new package URL is unavailable and reduces the package URL wait to 5 minutes so CI no longer times out before writing a comment.
  • c5cf51e8 addresses the Cubic duplicate pricing key warning by logging a duplicate-key warning during models.dev snapshot generation.

Validated locally with direnv exec . just fmt, direnv exec . just typecheck, direnv exec . just test-vitest, and focused Vitest runs for the changed tests.

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review
@cubic-dev-ai review it
@pullfrog review it

Pushed follow-up commits e8fa2bcc and c5cf51e8.
...

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

@ryoppippi: Thanks for the detailed update! I'll kick off a fresh incremental review covering commits e8fa2bcc and c5cf51e8, including:

  • The perf comment job skip-clean fix and reduced package URL wait (5 min)
  • The duplicate pricing key warning logged during models.dev snapshot generation
Action performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 12 files

Re-trigger cubic

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — three follow-up commits that harden the perf commentary CI job, add a duplicate-key warning during models.dev snapshot generation, and improve test coverage.

  • Reduce perf-comment timeout to 5 minutes — CI jobs now wait only 5 minutes for pkg.pr.new URLs instead of 30, matching the installPackageUrl contract change below.
  • Gracefully skip when base package URL is unavailableinstallPackageUrl returns undefined instead of throwing; the main command handler renders a skip comment and exits cleanly when a base package is needed but can't be installed and no --base-dir is provided.
  • Log duplicate models.dev pricing key warningsmodels-dev-gen.ts now calls console.warn via the extracted formatDuplicateModelsDevPricingKeyWarning helper when two source models map to the same flat key, addressing the Cubic duplicate-key concern.
  • Fill selectModelsDevPricingKey test matrix — added tests for undefined and non-empty catalog IDs alongside the existing empty-string case, plus a formatting test for the warning helper.
  • Make LiteLLM fall-through test more precise — the "gpt-full-with-extra-i" fixture now includes "o": "provider metadata" so the test correctly verifies the compact parser falls through on non-numeric "i"/"o" fields rather than on a missing "o" key.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: e8fa2bcce294
Base SHA: da74716a88e0

Performance comparison skipped.

Base package URL was not ready before 300.000s. Fixture performance comparison requires a base package when --base-dir is not provided.

Base package: da74716a88e0

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: e8fa2bcce294
Base SHA: da74716a88e0

Performance comparison skipped.

Base package URL was not ready before 300.000s. Fixture performance comparison requires a base package when --base-dir is not provided.

Base package: da74716a88e0

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: c5cf51e896e5
Base SHA: da74716a88e0

Performance comparison skipped.

Base package URL was not ready before 300.000s. Fixture performance comparison requires a base package when --base-dir is not provided.

Base package: da74716a88e0

@pullfrog

pullfrog Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

CI failure analysis

Failed job: ccusage rust perf comment — step "Upsert PR comment"

Error: POST /repos/ryoppippi/ccusage/issues/1244/comments failed: 401 ("Requires authentication") from upsert-pr-comment.ts:42

Verdict: NOT introduced by this PR. The failure is a GitHub API authentication flake unrelated to the PR's changes:

  • The PR only changes CI timeout values (--package-runner-timeout-ms 1800000 → 300000), adds a skill file, and compacts pricing snapshots. None affect GitHub API authentication.
  • The failing upsert-pr-comment.ts script is unchanged by this PR.
  • GITHUB_TOKEN setup, job permissions, and the if: !fork condition are all unchanged.

The other CI jobs (lint-check, test, build-native-packages) passed. No code fix is needed for this PR.

Pullfrog  | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

The rust perf comment job can produce a skipped benchmark summary when the base pkg.pr.new package is unavailable, but creating the new PR comment failed with a 401 from the workflow token. That made the job fail even though the benchmark script completed and wrote the job summary.

Treat 401 the same as the existing 403 no-comment-permission path, keep other GitHub failures fatal, and add a small in-source Vitest project for this script so the auth classification is covered.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai review
@cubic-dev-ai review it
@pullfrog review it

Pushed follow-up commit d4311b9.

This fixes the remaining ccusage rust perf comment CI failure. The benchmark script completed and wrote the job summary, but creating a new PR comment for the rust perf marker returned 401. The upsert script now treats 401 like the existing 403 no-comment-permission path and keeps other GitHub errors fatal.

Validated locally with direnv exec . pnpm vitest run --project github-scripts, direnv exec . just fmt, direnv exec . just typecheck, and direnv exec . just test-vitest.

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review
@cubic-dev-ai review it
@pullfrog review it

Pushed follow-up commit d4311b9.
...

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

@ryoppippi: Thanks for the detailed update! I'll kick off a fresh incremental review covering commit d4311b9, including:

  • The 401 → no-comment-permission handling in the upsert script (treating it the same as the existing 403 path)
  • Ensuring other GitHub errors remain fatal
Action performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — hardens the PR comment script against unauthenticated writes (401) and wraps it in testable shape.

  • Tolerate 401 comment-write failuresisCommentWriteAuthFailure now checks 401 alongside 403 so read-only tokens don't crash the script.
  • Extract main() and parameterize helperscreateComment and tryCreateComment accept repository/prNumber/body as parameters instead of closing over top-level variables.
  • Add inline Vitest tests — three tests cover the isCommentWriteAuthFailure type guard for 401, 403, and 500.
  • Wire github-scripts Vitest projectci.yaml runs the inline tests under a dedicated project with includeSource.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed changes — shrinks embedded pricing snapshots 58%, adds a Rust binary-size skill, hardens CI performance-comparison resilience against unavailable artifacts, and fixes macOS packaging libiconv linkage.

  • Add rust-binary-size skill — repo-local guidance for release profiles, dependency features, and binary bloat investigation based on min-sized-rust.
  • Compact embedded pricing snapshots — short field names in build.rs reduce JSON payload from 163 KB to 69 KB, with compatible CompactLiteLlmPricing parsing in pricing.rs.
  • Flatten models.dev embeddingmodels-dev-gen.ts outputs a flat map keyed by runtime model id instead of a provider-nested object; pricing.rs accepts both the new flat shape and the legacy provider shape.
  • Skip unavailable base packages gracefullycompare-pr-performance.ts returns a commit-specific skip comment instead of throwing when the base package URL isn't ready before the timeout.
  • Try harder on comment write auth failuresupsert-pr-comment.ts treats 401 like the existing 403 no-comment-permission path; adds in-source tests via the github-scripts vitest workspace.
  • Rewrite Nix libiconv on macOSstage-native-package.mjs replaces the Nix store libiconv.2.dylib with /usr/lib/libiconv.2.dylib via install_name_tool.
  • Reduce CI perf timeout--package-runner-timeout-ms drops from 30 min to 5 min in both codex and rust perf jobs.
  • Expand vitest workspace — adds nix and github-scripts test projects so compact-pricing helpers and upsert script tests participate in CI.

✅ No new issues found.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 13 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/ccusage/scripts/stage-native-package.mjs">

<violation number="1" location="apps/ccusage/scripts/stage-native-package.mjs:33">
P1: install_name_tool invalidates the Mach-O code signature; re-sign with `codesign --force --sign -` afterward or the distributed macOS binary may fail to launch on Apple Silicon due to signature enforcement.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

for (const line of linkedLibraries.split('\n')) {
const library = line.trim().split(/\s+/)[0];
if (/^\/nix\/store\/[^/]+-libiconv-[^/]+\/lib\/libiconv\.2\.dylib$/.test(library)) {
execFileSync('install_name_tool', [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: install_name_tool invalidates the Mach-O code signature; re-sign with codesign --force --sign - afterward or the distributed macOS binary may fail to launch on Apple Silicon due to signature enforcement.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/ccusage/scripts/stage-native-package.mjs, line 33:

<comment>install_name_tool invalidates the Mach-O code signature; re-sign with `codesign --force --sign -` afterward or the distributed macOS binary may fail to launch on Apple Silicon due to signature enforcement.</comment>

<file context>
@@ -24,6 +25,21 @@ function readOption(name, fallback) {
+	for (const line of linkedLibraries.split('\n')) {
+		const library = line.trim().split(/\s+/)[0];
+		if (/^\/nix\/store\/[^/]+-libiconv-[^/]+\/lib\/libiconv\.2\.dylib$/.test(library)) {
+			execFileSync('install_name_tool', [
+				'-change',
+				library,
</file context>

@ryoppippi
ryoppippi merged commit b7948ab into main Jun 10, 2026
25 of 28 checks passed
@ryoppippi
ryoppippi deleted the codex/min-sized-rust-skill branch June 10, 2026 21:45
ryoppippi added a commit that referenced this pull request Jun 11, 2026
* fix(pricing): copy models-dev-compact.ts into the Bun build sandbox

The models.dev pricing generator was split in #1244 so that
nix/models-dev-gen.ts imports its sibling ./models-dev-compact.ts.
The Nix derivation only copied gen.ts into the writable workspace,
so Bun could not resolve the new import inside the sandbox:

    error: Cannot find module './models-dev-compact.ts' from '/build/work/gen.ts'

This broke the scheduled "update pricing" workflow on the
update-models-dev-pricing job and every manual gen-models-dev-pricing run.

Copy models-dev-compact.ts alongside gen.ts under the same relative
name the import expects. Verified locally: the regenerated snapshot is
byte-identical to the committed rust/crates/ccusage/src/models-dev-pricing.json.

* fix(ci): force-push the pricing automation branches without a lease

The "Create pull request" steps pushed with --force-with-lease, but the
job checks out main at fetch-depth 1 and never fetches the bot branch.
Without a remote-tracking ref, git refuses the lease:

    ! [rejected]  automation/litellm-pricing -> automation/litellm-pricing (stale info)
    error: failed to push some refs

These branches are written only by this workflow, so a plain --force is
safe and is the standard pattern for a bot-owned automation branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant