bug: Ring and ledger count errors and coverage differently, cost reads slow down over time, and cost comments are stale
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 49/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- go
- 領域
- backend, databases, performance
調査の方向性
Start with core/cost/usage/usage.go and core/cost/ledger/writer.go to compare the error and priceability rules, then inspect the archive read and write paths in core/session/archive and ledger queries in core/cost/ledger. Add or update focused tests for zero-usage successful responses, excluded errors, archive rotation and reads, and past-day caching. Done means the ledger and ring agree, archive reads avoid repeatedly decoding growing segments, and stale comments match the code.
索引モデルが issue の本文から書いたものです。
説明
Problem
The cost and session read paths have three problems. The ring (which serves the duration windows) and the ledger (which serves today/7d/month) count the same traffic by different rules. Two read paths get slower the longer the proxy runs. And several comments in core/cost describe code that has since changed. Line numbers are at ab5f01f26.
1. The ledger hides a coverage gap that the ring reports
- Ledger (
core/cost/ledger/writer.go:519-521): a request counts as priceable only ifr.Model != "" && r.Tokens > 0. - Ring (
core/cost/usage/usage.go:812-840): any successful response with a model counts as priceable, even with zero usage, and it is named inUnpricedBy.
Case: a truncated OpenAI-dialect stream returns 200, the model is set, and there is no usage block. inference-parser publishes no cost record for it. With 9 priced requests plus one of these:
window=todayshows 9/9, which looks fully priced.window=1hshows 9/10 and names the gap.
The ring's own comment (usage.go:821-825) calls the 9/9 result a bug it fixed. There is no ledger test for a successful response with zero usage.
2. The error rule is written twice, and only one copy was updated
countsAsError(usage.go:1279-1285) excludesErrorKindUpgradeDeclinedandErrorKindDestinationPrivate. The latter was added in ab5f01f26.- The ledger (
writer.go:514-516) still counts anyStatusCode >= 400 || Denied.
So a parsed inference request refused with 403 destination_private counts as an error on today but not on 1h.
Fix for 1 and 2: export usage.CountsAsError and a single "priceable" check, and call both from the ledger writer.
3. Archive segments never rotate, and every read decodes from the start
core/session/archive/archive.go: a segment closes only after 60 minutes idle (:736), at the open-writer cap, or on delete, clear, rename or a write failure. There is no size or event-count limit.
planPrunenever deletes an open segment (retention.go:54-63). A session busy all day therefore keeps one segment growing without limit, andmaxBytes(2 GiB) can stay exceeded.PageandEventdecode the segment from its first event up to the cursor, andEarliercallsPageonce per 500 events (read.go:44-81, 189-203). inference-router'swentTocallsEarlieron the request path withhistoryLimit = 2000. With 20k events in the segment, that is 4 page calls, each decompressing and decoding most of the segment, per request.
Fix: rotate in write after N events or M bytes, by calling closeWriter when s.w.info() passes the cap.
4. Every ledger query re-reads every day file in the window
core/cost/ledger/query.go:183-250 / store.go:493-530 open and fully decode each day file on every request, with no cache.
- agentop polls
todayevery minute and7d/monthevery 5 minutes (cmd/agentop/tui/spend.go:211-217). On the 31st,monthdecodes 31 files per poll, and past days almost never change. - The endpoint has no auth.
Fix: cache decoded past days keyed by (path, size, mtime). Only today's file needs re-reading.
5. Comments that contradict the code
core/cost/pricing/cost.go:20-25calls the accumulation wrap "an open defect", butCounts.Addsaturates (usage.go:349-405).cost.go:93-99saysMaxPlausibleTokenshas "NO IMPORTER ON THIS BRANCH". The ledger writer imports it (writer.go:288-324).cost.go:202-204saysplausibleTokenReportandRefusedTokenRequestsdon't exist. They do (usage.go:438, :122).ledger/writer.go:929-933saysDropped()has "No non-test caller today".sessionapi/usage.go:404calls it.
These read like notes from the middle of a PR stack. A reader trusting them would conclude that sums can still wrap and that the token bounds are not enforced.
Fix: delete or correct them.
Found by a code audit of main at ab5f01f26. Items 3 and 4 were verified by reading the code; the decode cost was not measured.
Assisted-By: Claude (Anthropic AI) [email protected]
- 主要言語
- Go
- スター
- 21
- フォーク
- 43
- 平均マージ
- 14時間 25分
- マージ済み PR(30日)
- 245
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
rossoctl/cortex のほかの issue
-
aiac enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
rossoctl/cortex#1546 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
UI shows costs for all sessions even when drilled into a session対応中かも @esnible が 16 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
rossoctl/cortex#1116 · コメント 2 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
bug: agentop's plugin-order check misses RequiresLater, the live stream degrades, and TUI comments are stale対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープンbug laptop
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
メンテナーはふだん 1 日以内に返信
-
bug: Copied listener and parser code has drifted (hop-by-hop response headers, SSE BOM/CR handling)オープンbug
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
rossoctl/cortex の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信
-
schema-drift
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
stefanhoth/paperless-ngx-cli#61 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
slavakurilyak/awesome-ai-agents#888 ·
メンテナーはふだん 1 日以内に返信
-
enhancement nav-pilot
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
kind/enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 64/100
メンテナーはふだん 1 日以内に返信