* fix(codex): price Fast (priority tier) turns at priority rates
Codex bills turns run under the Fast speed setting through the priority
service tier, which the rollout files record per thread in
thread_settings_applied events. Track that tier through the parse (and
across append resumes and fork replays), mark the affected turns as
fast, and derive a fast multiplier from the LiteLLM priority rate keys
so those turns are priced at the priority rates instead of the standard
ones. Cache versions are bumped so already-cached Codex results are
re-priced.
* snapshot: priority slots only, no upstream drift
---------
Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
Mixed-version binaries were clobbering the unsuffixed Codex, Cursor,
and Antigravity result files and each re-parsed the whole corpus.
Write *-results.v<n>.json like the daily cache. Leave the unsuffixed
file for older binaries; adopt a matching-version copy once.
A warm launch rewrote the entire session cache whenever any provider
appended a few KB: on a 6 GB corpus that is a 155 MB stringify + fsync
every run. The on-disk cache is now a version-suffixed directory holding
one shard per provider plus a small envelope, and a save rewrites only
the providers marked dirty.
- Dirtiness is tracked per provider (markCacheDirty) instead of one
global flag, so an appended Claude session no longer republishes
Codex, Copilot and the rest.
- Shards carry a nonce in their filename and the envelope is renamed
last, so a save is published at a single point: readers never see a
half-updated set, and a writer that loses the refresh ownership fence
leaves the canonical shards untouched.
- A shard that fails validation is treated as an absent provider rather
than rejecting the whole cache, so one malformed turn costs one
provider's re-parse instead of every provider's history.
- v7 migrates losslessly: the blob is re-laid-out into shards and
removed only once that save publishes. Nothing re-parses.
- Cold-parse progress saves now trigger every N files parsed rather than
every 5s, so a slow cold parse no longer rewrites the growing cache on
a wall clock.
Performance and coherence:
- Settings > General 'Refresh every' (Manual/30s/1m/3m/5m/10m), live via
RefreshCadenceContext; Manual polls only on demand
- usePolled memoKey LRU: provider/period switches paint the last-good
result instantly with a switching hairline while refreshing quietly
- quota TTL 5min + honest rate-limited copy on 429 backoff
- version-suffixed cache files (session-cache.v5.json, daily-cache.v12,
auto-minted on future bumps); legacy files never written or deleted,
adopted once when versions match: old and new binaries coexist
without clobbering (field-observed menubar-vs-desktop ping-pong)
- advisory hydration lock: concurrent cold starts share one scan
(wait-then-read-warm), stale/dead locks self-heal, never a
correctness gate
Telemetry v1 + onboarding (desktop only, per owner decisions):
- first-launch onboarding (3 feature screens + consent); region-split
default (EU/EEA/UK/CH off, elsewhere on, unknown off); nothing sends
before consent completion or while off; dev builds never send
- anonymous install UUID, rotated on opt-out; day-granularity events,
cost buckets only; whitelisted names; 200-event queue, 5min flush
- Settings > Privacy live toggle replaces the static claim
Zero computed-number changes. App 316/316, root 1805.
Wire contract targets api.codeburn.app/v1/telemetry (Worker follows).
Users who run MCP tools through a CLI wrapper (e.g. philschmid/mcp-cli)
instead of registering servers natively don't produce Codex
mcp_tool_call_end events; Codex logs a plain exec_command. So their MCP
usage showed only as a shell command and was absent from the MCP
breakdown, even after #513 fixed the native path.
- Recognize `mcp-cli [options] call <server> <tool>` in the exec command
and also attribute it as mcp__<server>__<tool>. The exec still counts as
Bash since it genuinely is a shell exec. Flag-tolerant, quote/path/bash-lc
tolerant, and scoped to the mcp-cli binary (not foo-mcp-cli); only the
`call` subcommand (a real execution) matches, not info/grep/listing.
- Register `codex` in PROVIDER_PARSE_VERSIONS. session-cache.json serves
unchanged session files without invoking the provider parser, so the
codex-cache version bump alone would never re-attribute already-cached
sessions. This also retroactively repairs #513's native-MCP fix for
users whose files were cached before it shipped.
- Bump CODEX_CACHE_VERSION 4->5 for the provider-internal layer.
Tested: parse cases (bash -lc wrapper, flags-before-call, argv array,
plus info/grep/foo-mcp-cli negatives), and a mutation-verified cache
regression test that fails without the PROVIDER_PARSE_VERSIONS entry.
ReDoS-checked. Reviewed with a Fable 5 adversarial pass (Codex is down);
its two must-fixes (the cache gap and the flags-before-call miss that
would have missed the reporter's own sessions) are folded in.
Fixes#478