From aee868e65ad85384f52ec69130a57a80b8abd786 Mon Sep 17 00:00:00 2001
From: stv1024
Date: Fri, 16 Oct 2026 14:45:04 +0800
Subject: [PATCH 1/6] wip: usage-scope semantics, honest unknowns, and pricing
cleanup
Experimental checkpoint of usage/cost reporting accuracy work:
- shared: TurnRecord.tokenScope (turn/session/unknown), nullable token and cost fields, UsageSnapshot for late cumulative/unknown observations; v1 history stays readable
- semantics: only verified harness input conventions; no model-name fallback, freshInput stays unknown when counts are inconsistent
- pricing: no private gateway seed prices or fixed FX; full model identity plus explicit aliases, provider scopes no longer match model text, ambiguous entries surface pricingWarning instead of guessing
- tracker/turns/read-model: late idle usage refreshes a snapshot card instead of inventing turn deltas; a falling session-cost counter is not treated as a session reset
- UI (panel/pill/sidebar/overview/timeline): disclose incomplete usage, partial reference estimates and unknown-cost turns; session token snapshot in pill; old timeline cards label missing scope metadata
- tests: new server/read-model.test.ts; 66 tests pass, tsc clean
---
AGENTS.md | 14 +-
CHANGELOG.md | 10 ++
OVERVIEW.md | 17 +-
README.md | 65 ++++----
client/panel.tsx | 60 ++++---
client/pill.tsx | 46 ++++--
client/sidebar.tsx | 2 +-
client/timeline.tsx | 5 +-
client/ui.tsx | 50 +++---
docs/compatibility.md | 29 ++++
docs/paseo-usage-api.md | 31 +++-
images/screenshot-overview.png | Bin 82306 -> 50395 bytes
images/screenshot-panel.png | Bin 47644 -> 29172 bytes
images/screenshot-pill.jpg | Bin 37405 -> 2428 bytes
server/pricing.test.ts | 110 +++++++++----
server/pricing.ts | 275 ++++++++++++---------------------
server/read-model.test.ts | 36 +++++
server/read-model.ts | 24 ++-
server/tracker.ts | 91 +++++------
server/turns.test.ts | 21 +++
server/turns.ts | 28 ++--
shared/aggregate.test.ts | 14 +-
shared/aggregate.ts | 12 +-
shared/ledger.ts | 54 +++++--
shared/pricing.test.ts | 37 +++--
shared/pricing.ts | 83 +++++-----
shared/semantics.test.ts | 53 +++----
shared/semantics.ts | 86 +++++------
shared/timeline.ts | 3 +-
29 files changed, 743 insertions(+), 513 deletions(-)
create mode 100644 server/read-model.test.ts
diff --git a/AGENTS.md b/AGENTS.md
index f17fc52..56dd6e5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -29,8 +29,8 @@ paseo agent archive # 测完归档,别
- 服务端 contribute 拿到 `handle/on/before`,`paseo` 在 RPC 和生命周期回调中提供。`before(agent.session_open)` 启动订阅,`on(agent.turn_started)` 覆盖 reload 后已有会话;客户端 ensure 尽早连接已有会话。**新建 agent 在 session_open 时尚未进入目录,不能在此 refresh 新 agent。**
- **wire 层 `agent_stream` 没有 `usage_updated`**:轮中 usage 走 `agent_update` upsert 快照(`lastUsage`/`activeTurn`),且必须先 `paseo.agents.list({ subscribe: {} })` 才会推送。turn 生命周期(started/completed/failed/canceled + turnId + 轮末 usage)走 `agents.ref(id).timeline.subscribe`。
- usage 语义(2026-09-04 实测):Claude 轮末 usage 是**逐轮**汇总、`totalCostUsd` 是**会话累计**(所以记录里存 delta + raw 两份);Codex 每次模型请求报一次 `last` 值,多请求轮靠去重求和。快照会把上一轮旧 usage 回放进新一轮——tracker 用 agent 级 `lastObservation` 基线挡掉。
-- **Paseo 丢弃 `cache_creation_input_tokens`**(2026-09-05 从 app.asar 的 `providers/claude/agent.js` `buildResultUsage` ~1424 行验证):`cachedInputTokens` 只映射 `cache_read_input_tokens`,cache write 只用于上下文窗口内部估算、不进 `AgentUsage`。后果:用户输入和工具结果(几乎全是 cache write,计费 1.25× input 价)在 IN 和 CACHE 两列都不可见,IN 通常只有零头(个位数~几十);`costUsd` 仍准确(上游总额含 write)。pricing.ts 的分项估算按牌价直算,总额与估算的差额单列为 `otherUsd`(COST 列下方显示 `+$x.xx`)——不再 rescale 摊进分项。token 数本身的缺口需上游 Paseo 加字段,插件侧无法拿到。
-- **input 语义因 provider 而异**(2026-09-05 从落库记录实测):codex/OpenAI 系的 `inputTokens` **含** cached(如 input 213818 / cached 213252,真实新增仅 566);Claude 的 input **不含** cache read。`semantics.ts` 维护按 provider(回退 model)匹配的语义表,归一化到"input = 未命中缓存的新输入"(Anthropic 式,信息不丢失)。磁盘 ledger.jsonl 永远存上游原始值,归一化只在读取/服务层做(store 的 summary、tracker 的 handleSync 和 inFlightFor),历史记录自动被正确重解读。新接 provider:跑一轮真实 turn → 看落库记录判断 input 是否含 cached → 往 SEMANTICS_TABLE 加一行 + 测试。未知 provider 原样透传,不猜。
+- **Paseo 0.11.2 仍丢弃 cache creation**:Claude `buildResultUsage` 只映射普通输入、cache read、输出与 SDK 报告费用。缺失不等于零;命中率必须有完整分母。`costUsd` 只是运行器报告费用,不保证等于网关实际扣款;分项估算残差不得反推 write token。
+- **输入口径只按已验证 harness,不按模型回退**:Codex input 包含 read/write;Claude 和 OMP input 已与缓存分开。`usageSemantics(provider)` 不接受 model。RPC 的 IN 是减掉 read 和已知 write 的未缓存输入,write 缺失时 Codex IN 仍可能含未分类写入;未知 provider 原样显示并排除轮次合计。磁盘原始值不重写。
- **turnId 不是全局唯一的**(2026-09-07 从 ledger.jsonl 实测):Paseo 的 turnId 形如 `foreground-turn-N`,agent/daemon 会话重启后从 1 重新计数。任何以 `agentId:turnId` 当唯一键的地方都会跨会话冲突——曾导致面板 React key 重复、渲染出幽灵重复行。现在记录 id 拼入 `endedAt`(aggregate.ts),面板行 key 用 `seq`(兼容旧格式的历史记录)。新代码需要唯一键时同样别只用 turnId。
- **终止事件后快照可能回放 activeTurn**(同日实测,曾造成 3ms 内同一 turn 落库两条):turn_completed 之后紧跟的 agent_update 快照仍带着刚结束的 turn,noteUsage 若据此重开 open turn,下个终止事件就会重复落库。tracker 用 `lastClosedTurnId` 挡掉(新轮保留旧 ID 以屏蔽迟到事件;provider session 确认改变时重置)。改 turn 生命周期逻辑时注意 timeline 事件流和快照流是两条异步通道,顺序无保证。
@@ -48,8 +48,8 @@ paseo agent archive # 测完归档,别
- `server/journal.ts` 保存 open turn、session/cost 基线及 pending records;先写 journal 再 append JSONL,open.key 是稳定 UUID。结束 hook 无 usage,短暂等待 timeline 终值后按已观测数据结算;清理时完成已知的结束 hook。
- `server/read-model.ts` 按 store/pricing revision 缓存归一化行与汇总;`client/data.ts` 共享 panel/pill 查询并合并未变化的 records。RPC 的空 records 配合相同 recordsRevision 表示未变化,不表示历史清空。
- `server/catalog.ts` 复用完整 agent 目录并订阅分页 workspace 目录;总览不再每次查询只取前 200 个 agent。
-- `providerSemantics` 只按已验证 harness 匹配:Claude whole-turn + session cost;Codex request observations;未知取最新观察且标 partial,原始费用保留但不推断累计差值。model fallback 仅用于 input/cache 口径。
-- 新 Codex 记录的 requests 保留原始逐请求 token,用于逐请求价格档位;旧记录没有请求明细,只能近似。pricing.json 最后档必须无上限,档位递增;运行时重新读取无效文件会保留上一份有效价格。
+- `providerSemantics` 区分 Claude turn、Codex request、OMP session/branch 和 unknown;`tokenScope` 在读取旧账本时按已验证 harness 补足解释。session/unknown 只作为快照显示,不做轮差、不计入轮次或日期范围合计、不估算单轮费用。`ledger.sync.usageSnapshot` 保留迟到的闭轮/idle 观察,不能据此重开一轮;无 epoch/终值归属时不猜测真实轮增量。
+- Codex `requests` 用于逐请求价格档位;缺字段时整个对应分项保持未知,原请求仍保留。价格匹配保留完整 ID,标准 Claude 纯数字版本仅兼容点号/连字符,其他差异使用显式 aliases。旧的 namespace/context/provider 折叠只用于提示迁移,不能选价;可能的旧覆盖价失配或多义匹配阻止参考价回退,并通过 pricingWarning/pricingWarningTurns 在 UI 提示。provider scope 仅匹配 provider,配置读回后自动清除已解决的提示。用户文件不重写,无内部价格种子或固定汇率。
- Timeline 使用 append + addTimelineRenderer:先落盘、每轮一次、稳定 ID、最多重试一次。不要高频更新或全历史回填;append 会改变 agent.updatedAt,且 plugin rows 不保证 daemon 重启后保留。JSONL 是权威账本。
## 0.9.1 适配约束
@@ -64,17 +64,17 @@ paseo agent archive # 测完归档,别
## 0.11 适配约束
- **发布代码禁止 import `@getpaseo/client` / `@getpaseo/protocol`**(含 type-only)。宿主编译插件时会解析 type-only import,但只提供 SDK specifier、zod、react、react-native、@tanstack/react-query、@types/node。git 安装不跑 `npm install`(只跑 manifest `build`),npm 安装不装 devDependencies,所以其他类型依赖会让安装失败(0.11.1 实测 `Could not resolve type dependency`)。客户端类型从 `client/paseo-types.ts` 取,服务端从 `server/paseo-types.ts` 取(都由宿主 `PaseoApi` 推导)。`shared/` 不能 import `/client` 或 `/server` SDK,用结构类型和泛型。测试文件不进 bundle,可以继续用 devDependencies。
-- 改动依赖或 import 后,用无 `node_modules` 的副本验证:复制源码到临时目录、改 manifest id、让 contribute 提前返回,`paseo plugin add <目录>`,看到 "Plugin ready" 后 `paseo plugin remove` 并删除目录。
+- 改动依赖或 import 后,用无 `node_modules` 的副本验证:复制源码到临时目录、改 manifest id、让两端 contribute 提前返回 `() => {}`(宿主要求 cleanup 函数,裸 return 会被拒绝),`paseo plugin add <目录>`,看到 "Plugin ready" 后 `paseo plugin remove` 并删除目录。
- 总览是 `addScreen`(id `ledger-overview` 不变),`range` 放在 screen params 里(`today`/`7d`/`30d`/`all`,缺省 all)。screen props 没有 setParams;切换范围用 `client.openScreen`(宿主 router.push,会产生历史记录),标题函数随 params 变化。
- 侧边栏是 `addSidebarFooterItem` + `SidebarRow`,trailing 显示今日费用。"今天"按客户端本地午夜计算,以 ISO `since` 传给 `ledger.overview`;服务端按 `Date.parse(endedAt)` 过滤 read-model 行,不在服务端猜时区。
- `addSurface` / `addSidebarItem` / `openSurface` 已弃用,不要再用。不接 `registerUsageSource`(那是订阅额度窗口,不是逐轮 usage;用户已决定不放进 Usage 面板)。
-- 0.11.1 仍未公开 cache-write 和 provider 内部子代理 usage。
+- 0.11.2 的 cache-write、Codex 内部子代理 usage、OMP final-drain/branch epoch 缺口仍在。OMP 统计已包含部分子代理,不能无条件再叠加。徽标使用 Session token snapshot,不以 unknown 代替已知快照;未知 scope 不求 token 总数。历史 Timeline 缺少 scope 元数据时只声明元数据缺失,不声明账本排除。更新后重载客户端以使用新字段。
## 截图
发布用截图不能出现真实 agent 标题、workspace 或项目名。用独立 demo daemon 和合成数据:
-- 新建 home 目录,config 只写 `daemon.listen`(换端口)、`relay.enabled: false`、`cors.allowedOrigins`(静态服务的 origin)、`pluginsEnabled: true`。**不要**复制 `~/.paseo/config.json`(含 provider 密钥)。`paseo daemon run --home ` 前台运行,用 `paseo daemon stop --home ` 只停它,不碰主 daemon。
+- 新建 home 目录,config 只写 `daemon.listen`(换端口)、`daemon.relay.enabled: false`、`daemon.cors.allowedOrigins`(静态服务 origin)、`pluginsEnabled: true`。0.11.2 的 relay/cors 在 daemon 下,不在根级。**不要**复制 `~/.paseo/config.json`(含 provider 密钥)。`paseo daemon run --home ` 前台运行,用 `paseo daemon stop --home ` 只停它,不碰主 daemon。演示 OMP 需在隔离配置中启用,并用 provider.env.PI_CODING_AGENT_DIR 指向临时目录,避免继承用户的 disabledProviders。
- `paseo project create --home `、`paseo workspace create --path --isolation local --title --home ` 建项目和 workspace。agent 记录直接写 `agents//.json`(daemon 启动时读),账本写 `plugins/token-ledger/ledger.jsonl`,然后 `paseo plugin add <仓库目录> --home `。
- Web 客户端在桌面安装目录的 `resources/app-dist`。静态服务时往 index.html 注入 `globalThis.__PASEO_INITIAL_DAEMON_CONNECTION__={listen:"127.0.0.1:",useTls:false}`,用 puppeteer-core 截图。总览可直接打开 `/h//plugin/token-ledger/surface/ledger-overview?param.range=7d`。
- 截完停 demo daemon,删除 demo 目录。
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ab508e..94037ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,16 @@
## Unreleased
- Add an overview screenshot (demo data, with the sidebar footer row) to the README and as the first manifest media image.
+- Fix harness input semantics: OMP exclusive input is no longer reduced again by a GPT-model fallback; unverified providers are never inferred from model names.
+- Separate per-turn usage from OMP current-session/branch totals and unknown-scope snapshots, including historical v1 records. Snapshots remain visible but are excluded from turn/date-range sums and estimates. Late idle usage updates refresh a separate latest-snapshot card, not an invented turn delta.
+- Preserve unknown counts and cache rates rather than displaying zero. Only show a cache hit rate with a complete prompt denominator; keep partial request fields incomplete.
+- Disclose incomplete usage, partial reference estimates and unknown-cost turns in the panel, pill, sidebar and overview. Runtime-reported amounts are not verified bills. Keep cost cells within narrow panel widths.
+- Remove private gateway seed prices and fixed currency conversion. Start new price files empty without rewriting existing custom files. Match full model identities and explicit aliases; provider scopes no longer match model text, and ambiguous overrides are unpriced.
+- Do not guess cache-read/write rates from ordinary-input rates, select tiers with an unknown prompt size, or interpret a falling session-cost counter as proof of a new session.
+- Follow up upstream with public synthetic evidence for cache writes, request/branch/descendant attribution and OMP final-drain ordering; see [usage API requirements](docs/paseo-usage-api.md). Missing upstream data is not restored by this change.
+- Preserve standard Claude dotted/hyphenated numeric-version aliases for custom prices. Block reference-price fallback and surface a pricing.json migration warning for ambiguous entries or matches that previously depended on unsafe namespace/context/provider folding; valid explicit aliases clear it without rewriting the file.
+- Distinguish session token snapshots, unknown-scope snapshots, waiting for usage and no reported usage in the composer pill. Live per-turn token observations remain visible even without a price.
+- Label old Timeline cards as missing scope metadata rather than falsely claiming they were excluded from ledger totals. Refresh the support matrix and screenshots with isolated synthetic data.
## v0.7.0 (2026-10-09) — Paseo 0.11 screens and sidebar
diff --git a/OVERVIEW.md b/OVERVIEW.md
index 5a13647..479cb3c 100644
--- a/OVERVIEW.md
+++ b/OVERVIEW.md
@@ -2,7 +2,9 @@ TokenLedger records the tokens and cost of each agent turn and keeps the history
The agent panel shows session totals, the turn in progress with its context window, and one row per finished turn with status, time, duration, input, cache and output tokens, cost, and a data quality mark. The pill shows the session cost and context use, with an activity icon while a turn runs, and opens the panel. The sidebar row opens the overview, which groups agents by workspace and filters to today, the last 7 days, the last 30 days, or all time. Day ranges start at local midnight on the device that shows them. After each finished turn, the plugin can add one short usage summary to the timeline.
-Token counts come from the provider and are never invented. Claude reports a total for each turn, which is marked exact. Codex reports each model request, so the plugin adds the requests and marks the total as approximate. Other providers show the latest report, marked partial. When the provider reports a cost, that cost is shown. Otherwise the plugin estimates the cost, marked with ≈, from your prices in `pricing.json`, then OpenRouter reference prices, then a small built-in price table.
+Token counts come from the provider. Claude terminal aggregates and observed Codex requests contribute to turn subtotals. OMP current-session/branch totals and unverified-harness observations remain visible as snapshots but are excluded from turn sums and prices. A separate latest-snapshot card retains late updates without inventing turn attribution. Missing counts/rates display as unknown; cache hit rates require a complete prompt denominator. Partial estimates and unknown-cost turns are explicit in the panel, pill and overview. Runtime-reported costs take priority over your reference prices, OpenRouter references and built-in prices, but are not verified bills.
+
+The pill distinguishes known session snapshots (`Session ≈4.12M tok`), unknown-scope snapshots, waiting for usage and no reported usage. Old timeline cards without scope metadata are labelled as legacy; their ledger inclusion is not guessed from the card.
The plugin settings page on each host has four options:
@@ -11,11 +13,14 @@ The plugin settings page on each host has four options:
- **Built-in fallback prices** controls estimates when no custom or OpenRouter price matches a model.
- **Refresh frequency** selects normal or relaxed polling. Live updates still refresh the views immediately.
-The ledger is a JSON Lines file in the plugin data folder on the daemon host, `~/.paseo/plugins/token-ledger/` (or the same path under `PASEO_HOME`). It keeps the last 2,000 turns. Each record holds timestamps, agent ID, provider, model, token counts, cost, status, duration, and quality. Prompts, responses, tool arguments, file paths, and credentials are not recorded. A `pricing.json` file in the same folder holds your own prices per million tokens. History does not sync between hosts.
+The ledger is a JSON Lines file on the daemon host, `~/.paseo/plugins/token-ledger/` (or under `PASEO_HOME`), retaining 2,000 records. It stores observed usage, timestamps, identity, scope and quality, not prompts, responses, tool arguments or credentials. Older records remain readable and are reinterpreted without rewriting them. `pricing.json` starts empty and preserves your existing prices. Full model IDs and explicit aliases prevent unrelated routes from sharing a guessed price. History does not sync between hosts.
+
+Standard Claude numeric-version spellings such as `5.5` and `5-5` retain custom-price compatibility. Other old lossy matches or ambiguous entries show a pricing configuration warning and block reference-price fallback until an explicit alias/provider scope is reviewed. Existing files are not rewritten, and valid edits clear the warning automatically.
Known limits:
-- Paseo does not report cache write tokens, so Claude cache writes are missing from the token columns. The reported cost stays correct, and the difference shows as a residual under the cost.
-- Paseo does not report the usage of subagents that run inside a provider, so totals can be lower than the provider bill.
-- Usage during a time when the plugin or daemon is offline cannot be recovered. Affected turns are marked as a gap or as unknown.
-- Estimated costs use reference prices and can differ from your actual contract.
+- Missing cache writes are not zero; setting prices cannot recover omitted token counts. A reported-cost residual does not prove a cache-write charge.
+- Child coverage differs by harness. Codex child usage can be omitted; OMP already includes some child usage. Blindly adding children can double-count.
+- Session snapshots cannot safely become per-turn deltas without branch epochs and final usage attribution; they are not included in date-range totals.
+- Offline observations and missing request identities cannot be reconstructed. Affected usage stays incomplete or unknown.
+- Runtime and reference prices can differ from actual contracts. No private gateway rate table or fixed exchange rate is built in.
diff --git a/README.md b/README.md
index 7b5e990..a56bc8c 100644
--- a/README.md
+++ b/README.md
@@ -13,21 +13,21 @@ Per-turn LLM token usage and cost for [Paseo](https://paseo.sh) agents — an ag
-
+
## What it shows
**Per-agent panel** (workspace/explorer, bound to one session — the header names the agent and model it is tracking):
-- **Session summary** — total turns, input / cache / output tokens, and reported or estimated cost. Estimated totals use `≈`; missing-price turns are counted explicitly.
-- **Turn in progress** — elapsed time, running token counts and estimated cost when available, and a context-window bar. When idle, the last known context-window usage is still shown.
-- **Turn history** — one row per finished turn: status, time, duration, tokens, cost, and a data-quality mark.
+- **Session summary** — known per-turn input / cache / output subtotals and runtime-reported or reference cost. Missing counts stay `–`; partial estimates and unknown-cost turns are counted explicitly.
+- **Turn in progress** — elapsed time, observed token counts and cost when attributable to the turn, plus a context-window bar. Idle context usage remains visible.
+- **Turn history** — one row per finished turn with accounting scope and coverage. OMP session/branch totals and unverified-harness observations are snapshots, not turn usage, and are excluded from totals. A separate latest-snapshot card also reflects late idle updates.
-**Composer pill** — every live agent gets a compact pill next to its composer (`$0.43 · ctx 47%`, with an activity icon while a turn is running). The total includes the current turn's estimated cost when available and uses `≈` whenever estimates contribute. Pressing it opens that agent's panel. With split views, each session carries its own pill, so the session↔usage binding is always visible.
+**Composer pill** — shows attributable current-turn totals when available. For OMP, `Session ≈4.12M tok` means the known tokens in the latest session/branch snapshot, not a per-turn total; `≈` marks missing components. Unknown-scope snapshots are named without summing potentially overlapping counts. No data shows **Waiting for usage** while running or **No usage reported** when idle. Reference estimates, partial costs and pricing configuration warnings remain explicit. Pressing the pill opens that agent's panel.
-
+
**Sidebar** — a **TokenLedger** row in the sidebar footer shows today's cost (or tokens when no price is known), with an activity icon while a turn is running. "Today" starts at local midnight on the device that shows it.
@@ -35,10 +35,10 @@ Per-turn LLM token usage and cost for [Paseo](https://paseo.sh) agents — an ag
**Overview** (sidebar footer → TokenLedger, or the command center) — all sessions in one place: grand totals, then per-agent rows grouped by workspace with live-turn indicator, last activity, cost/tokens, and turn count. Pick **Today**, **Last 7 days**, **Last 30 days**, or **All time**; the range is part of the screen link and its title. A range lists agents with turns that ended in it, plus agents with a turn in flight. Tapping a row jumps to that agent.
-
+
-**Timeline** — each newly finished turn gets one passive usage summary after its ledger record is saved. It uses the same normalized counts, cost source and quality marks as the panel. No polling or message replacement is involved.
+**Timeline** — each newly finished turn gets one passive usage summary after its ledger record is saved. Older cards without scope metadata say **legacy scope metadata unavailable**; they do not claim exclusion from totals. The ledger remains authoritative. No polling or message replacement is involved.
## Compatibility
@@ -46,6 +46,8 @@ TokenLedger **v0.7.0** requires **Paseo 0.11.0 or newer**, on both the daemon an
Paseo 0.9.1–0.10.x users should stay on `v0.6.3`; Paseo 0.8 users on `v0.5.1`; Paseo 0.7 users on `v0.3.1`. Existing `ledger.jsonl` records remain readable; no migration or deletion is required. See the [v0.6.0 release notes](docs/releases/v0.6.0.md) for the 0.9.1 migration details.
+The unreleased accounting fixes were also exercised on Paseo 0.11.2. After updating, reload/reopen the client so it uses the new nullable summary fields, scope metadata and pricing warnings. Existing JSONL records are reinterpreted on read, not rewritten. The screenshots above use synthetic data on an isolated host.
+
## Install
Install from the [Paseo plugin registry](https://paseo.sh/plugins/stv1024/token-ledger) (Paseo 0.11.0 or newer):
@@ -102,20 +104,23 @@ All three switches default to on, and refresh frequency defaults to normal.
A "turn" is one user message through to `turn_completed`, `turn_failed`, or `turn_canceled` — potentially spanning many model calls. Token counts always come from the provider; TokenLedger never invents missing usage:
-| Situation | Value used | Quality |
+| Situation | Value used | Accounting scope |
| --- | --- | --- |
-| Provider reports a whole-turn aggregate at turn end (Claude) | used as-is | `exact` |
-| Provider reports per-request usage during the turn (Codex) | distinct observations summed | `partial` (shown as `≈`) |
-| Only a single mid-turn observation | that observation | `partial` |
-| Nothing reported | nothing shown | `unavailable` |
+| Whole-turn terminal aggregate (Claude) | reported counts | turn; coverage can still be incomplete |
+| Per-request observations (Codex) | observed requests summed | turn; approximate without stable request IDs |
+| Current-session/branch aggregate (OMP) | latest reported snapshot | session; excluded from per-turn totals and prices |
+| Unverified harness | latest reported snapshot | unknown; excluded from per-turn totals and prices |
+| Nothing reported | unknown, not zero | unavailable |
+
+Counting conventions are selected by verified harness/provider identity, never by the model name. OMP input is already exclusive of cache; Codex input is inclusive. “IN” is uncached input after subtracting cache reads and known writes; if writes are omitted, Codex IN may still include unclassified writes. Unknown provider values stay as reported, without guessed normalization.
-Cost uses the first available source: upstream reported cost, local override, OpenRouter reference pricing, then the small built-in fallback table. Claude reports cumulative session cost, so its per-turn delta is attributed to the turn. For unverified harnesses, raw cost is retained in `sessionCostUsd` but is not treated as a known per-turn charge. Model names do not establish aggregation or cost scope.
+For attributable turn costs, the order is runtime-reported cost, local override, OpenRouter reference, then built-in fallback. Claude session-cost deltas use the known baseline; a lower counter alone does not prove a session reset. A runtime's reported cost can itself be an estimate: it is not a verified invoice, and custom reference pricing does not replace it. Residuals do not identify missing tokens or billing categories.
-Estimated costs are marked `≈`. OpenRouter prices are references and may differ from the actual route or contract. New Codex records retain observed request counts, so tiered prices are chosen separately for each request. Historical records without request detail use the aggregate prompt as an approximate fallback.
+Estimated costs are marked `≈`; missing components/rates or uncertain request coverage add `partial`. Summaries expose unknown-cost turns rather than presenting the known subtotal as a complete bill. Codex request observations are priced separately; legacy records without requests use the aggregate as an explicitly partial estimate. A tiered price cannot be selected when the complete prompt size is unknown. Per-request routed model identities are not exposed, so reference pricing uses the recorded selected model, not a claim of the actual billed model.
-Paseo 0.9.1 still does not expose cache-write token counts through its public usage API. TokenLedger can retain and price them separately when supplied, but the current Claude and Codex adapters omit them. Missing counts stay unknown; historical writes are not inferred. Claude's reported total can include charges absent from the token counts, producing a positive residual under COST. Codex input includes cache reads (and cache writes when supplied); the UI separates known cache counts while the ledger retains raw counts.
+Paseo 0.11.2 still omits cache-write counts from the public Claude, Codex and OMP usage paths. Missing counts remain unknown; setting a price cannot recover them. Cache hit rate is read tokens divided by the complete prompt size: Codex's inclusive input supplies that denominator, while Claude/OMP need input + read + write. Without a complete denominator the panel shows `?`, not a near-100% rate. If input/cache counts are inconsistent, the plugin does not clamp them into a fabricated zero.
-Provider-internal subagents are not ordinary Paseo catalog agents. The public plugin API does not expose their usage; the Codex adapter discards child usage notifications. Session and overview totals therefore **may omit descendant usage**. TokenLedger uses only public Paseo APIs; it does not inspect provider logs or gateway billing endpoints. The [upstream API requirements](docs/paseo-usage-api.md) describe the missing fields, lineage, stable request IDs, and accounting scopes needed to close these gaps without double billing.
+Provider-internal subagents are not ordinary Paseo catalog agents. The Codex adapter discards child usage notifications; OMP session stats already include some task-child usage. Neither just traversing the catalog nor blindly adding children fixes accounting. OMP's branch-view totals can decrease, and its final usage can arrive after completion or be superseded by the next turn. Without epochs and turn attribution the plugin does not invent per-turn deltas: cumulative history is shown as snapshots and late observations refresh the separate latest-snapshot card. These snapshots do not enter date-range totals. TokenLedger uses only public Paseo APIs, not provider logs or gateway billing endpoints. See the [upstream API requirements](docs/paseo-usage-api.md).
Identical consecutive usage snapshots cannot be distinguished from separate equal-size model calls, so Codex totals remain `partial`. Open-turn observations, session identity and billing baselines are checkpointed locally, and graceful plugin reloads preserve them. A crash can lose observations since the last checkpoint; events missed while the plugin was offline cannot be reconstructed. Interrupted recovered turns are marked as partial/unavailable rather than claiming an exact offline outcome. `exact` describes the reported turn aggregate, not proof that every descendant or billing category was included.
@@ -125,7 +130,7 @@ After a subscription error or reconnect, the tracker refreshes the affected agen
### Pricing overrides
-On first use, TokenLedger creates `~/.paseo/plugins/token-ledger/pricing.json` (or under `PASEO_HOME`). It is a USD-per-million-token table and has highest priority among estimates. Entries can be scoped by provider substring and can contain prompt-size tiers. Changes to the file are picked up on the next usage request after a 30-second recheck interval; a reload also applies them immediately:
+On first use, TokenLedger creates an **empty** `~/.paseo/plugins/token-ledger/pricing.json` (or under `PASEO_HOME`). No internal gateway prices or currency conversion are shipped. Existing files are preserved. Overrides are USD per million tokens and have highest priority among estimates. Provider substring scopes match only the provider, not the model string. Full model IDs are matched case-insensitively, with one safe spelling equivalence: standard Claude numeric versions such as `claude-opus-5.5` and `claude-opus-5-5` match each other. Namespaces, context/mode suffixes, arbitrary model punctuation and model arrays are not collapsed. Add explicit `aliases` for other verified identities. Scoped matches take priority over global ones; ambiguous matches are unpriced. Valid edits take effect after the next 30-second recheck, or a reload:
```json
{
@@ -135,6 +140,7 @@ On first use, TokenLedger creates `~/.paseo/plugins/token-ledger/pricing.json` (
{
"providers": ["my-provider"],
"model": "my-model",
+ "aliases": ["my-provider/my-model"],
"tiers": [
{ "input": 1.5, "cacheRead": 0.15, "cacheWrite": 1.875, "output": 6 }
]
@@ -143,11 +149,13 @@ On first use, TokenLedger creates `~/.paseo/plugins/token-ledger/pricing.json` (
}
```
-`cacheWrite` is an optional, independent USD/MTok rate; the example is illustrative, not a universal write multiplier. Old files remain valid: when a write count is known but its price is omitted, it uses the ordinary input rate as an estimate. An explicit zero is a free write rate. Missing write counts cannot be recovered by setting a price. Prompt-size tiers include ordinary input, cache reads, and known writes; reported total cost stays authoritative and is never increased by adding the estimated components again.
+**Upgrading old custom prices:** if a model would only have matched through the old namespace/context/provider folding, TokenLedger blocks OpenRouter/built-in fallback and shows **price config**. Review that model's full ID and provider scope, then add a verified alias or correct the entry; the warning clears after the valid configuration is re-read. The plugin does not edit your file or silently replace an intended override with a reference rate. Runtime-reported costs remain visible, but their reference breakdown can still require review.
+
+`cacheRead` and `cacheWrite` are optional independent USD/MTok rates. Missing rates are unknown; an explicit zero is free. A measured zero token count costs zero even when its rate is unknown. Missing rates no longer fall back to ordinary-input pricing. The example's write multiplier is illustrative, not universal. Tiers use the full prompt count when available. Runtime-reported totals are never increased by adding the estimated components again.
OpenRouter's public model catalog, including `input_cache_write` when provided, is cached locally for 24 hours in `openrouter-pricing.json`. Local/cache prices are served before network refresh completes. If refresh fails, the last cache remains active, with retries no more often than every five minutes while the plugin is in use.
-Built-in Claude rates were checked against [Anthropic's pricing table](https://platform.claude.com/docs/en/about-claude/pricing) on 2026-09-23. Opus 5.5 standard rates are input $4, cache read $0.20, output $20 per million tokens; the cache-write reference is $5 for the 5-minute lifetime. Other lifetimes, Fast Mode, discounts and gateway contracts can differ. The public usage API does not identify cache lifetimes or the billed service tier. Unknown model versions and explicit Fast/Batch suffixes do not receive a guessed built-in price. Configure a matching override when needed; no new TokenRouter contract prices are assumed.
+Built-in Claude rates were checked against [Anthropic's pricing table](https://platform.claude.com/docs/en/about-claude/pricing) on 2026-09-23. Opus 5.5 standard rates are input $4, cache read $0.20, output $20 per million tokens; the cache-write reference is $5 for the 5-minute lifetime. Other lifetimes, Fast Mode, discounts and gateway contracts can differ. The public usage API does not identify cache lifetimes or the billed service tier. Unknown model versions and explicit Fast/Batch suffixes do not receive a guessed built-in price. Configure a matching override when needed; private contract prices are never assumed.
## Data & privacy
@@ -160,19 +168,20 @@ Built-in Claude rates were checked against [Anthropic's pricing table](https://p
## Limitations
-- Paseo 0.9.1 does not expose cache-write token counts; Claude cache writes are invisible in token columns (reported cost stays accurate, the gap shows as a `+$x.xx` residual).
-- Usage of provider-internal subagents is not exposed by Paseo, so session and overview totals may omit it.
-- Codex totals are summed per request and marked `partial` (`≈`); estimated costs use reference prices and may differ from your actual contract.
-- Events missed while the plugin or daemon was offline cannot be reconstructed; affected turns are marked `gap` / `unknown`.
-- Desktop and mobile UI were verified less thoroughly than the daemon side.
+- Paseo 0.11.2 omits cache-write counts on current Claude/Codex/OMP usage paths. Missing writes are unknown, and may make the cache-rate denominator unavailable. A reported-cost residual is not proof of missing token charges.
+- Child coverage differs by harness: Codex child usage can be omitted, while OMP already includes some child usage. Blindly adding children can double-count.
+- OMP session/branch snapshots have no reliable per-turn boundary. They stay separate from per-turn and date-range sums; unknown providers are not priced by guessing semantics from model names.
+- Codex request observations and reference estimates remain partial. Runtime-reported costs are not verified invoices.
+- Events missed offline cannot be reconstructed; affected turns retain gap/unknown status. Mobile-device testing is more limited than desktop/web verification.
## Support matrix
| Provider | Tokens | Cost |
| --- | --- | --- |
-| Claude / claude-* variants | per-turn aggregate (`exact`) | reported when available; estimate fallback |
-| Codex / codex-* variants | summed per-request (`partial`) | estimate fallback when absent |
-| Other providers (OpenCode, Pi, ACP harnesses) | latest observation, `partial`; `unavailable` when silent | raw cost retained; estimate when model pricing matches |
+| Claude / claude-* variants | per-turn terminal aggregate; missing categories stay incomplete | runtime-reported when attributable; reference fallback |
+| Codex / codex-* variants | summed request observations (`partial`) | partial reference estimate with known prices |
+| OMP / omp-* variants | latest session/branch snapshot, excluded from turn totals | raw session cost displayed separately; no guessed turn cost |
+| Other providers (OpenCode, Pi, ACP harnesses) | latest unknown-scope snapshot; no guessed aggregation | raw cost retained separately; no turn estimate |
## Development
diff --git a/client/panel.tsx b/client/panel.tsx
index 072e07b..d6ad903 100644
--- a/client/panel.tsx
+++ b/client/panel.tsx
@@ -58,7 +58,7 @@ function CtxBar({ ctx, theme }: { ctx: Ctx; theme: PluginTheme }) {
function InFlightCard({ inFlight, seq, theme }: { inFlight: InFlight; seq: number; theme: PluginTheme }) {
const elapsed = useElapsed(inFlight.startedAt);
const tokens = tokensLine(inFlight.input, inFlight.cached, inFlight.output, inFlight.cacheWrite);
- const pct = fmtPct(cacheRatio(inFlight.input, inFlight.cached, inFlight.cacheWrite));
+ const pct = fmtPct(cacheRatio(inFlight.cached, inFlight.promptTokens));
const ctx = inFlight.ctxUsed !== null && inFlight.ctxMax !== null ? { used: inFlight.ctxUsed, max: inFlight.ctxMax } : null;
return (
{tokens}
- {pct ? ` (${pct} cached)` : ""}
- {inFlight.modelCalls > 0 ? ` · ${inFlight.modelCalls} call${inFlight.modelCalls > 1 ? "s" : ""}` : ""}
+ {pct ? ` (${pct} cached)` : ' (cache rate unknown)'}
+ {inFlight.modelCalls > 0 ? ` · ${inFlight.modelCalls} observation${inFlight.modelCalls > 1 ? 's' : ''}` : ''}
) : (
tokens & cost reported at turn end
)}
+ {inFlight.tokenScope !== 'turn' ?
+ {inFlight.tokenScope} snapshot, not current-turn usage. Excluded from totals.
+ : null}
{inFlight.effectiveCostUsd !== null ? (
- ≈{fmtCost(inFlight.effectiveCostUsd)} current turn
+ {inFlight.costSource === 'reported' ? '' : '≈'}{fmtCost(inFlight.effectiveCostUsd)} {inFlight.partialCost ? 'partial estimate' : 'current turn'}
) : null}
+ {inFlight.pricingWarning ? {inFlight.pricingWarning} : null}
{ctx ? : null}
{inFlight.usageGap ? Connection interrupted · usage may be incomplete. : null}
@@ -115,9 +119,9 @@ function TurnCell({
theme: PluginTheme;
}) {
return (
-
+
{top}
-
+
{bottom}
@@ -128,16 +132,16 @@ function RecordRow({ record, theme, dense }: { record: TurnRow; theme: PluginThe
const cols = turnColumns(dense);
const hasUsage = record.input !== null || record.cached !== null || record.output !== null || record.cacheWrite != null;
const split = record.costBreakdown;
- const pct = fmtPct(cacheRatio(record.input, record.cached, record.cacheWrite));
+ const pct = fmtPct(cacheRatio(record.cached, record.promptTokens));
const cacheCost = split ? fmtCostSmall(split.cacheUsd) : "–";
- const costDetail =
+ const costDetail = record.pricingWarning ? 'price config' :
record.costSource === "override"
? "override"
: record.costSource === "openrouter"
? "OR ref"
: record.costSource === "builtin"
? "list"
- : fmtResidual(split?.otherUsd ?? null);
+ : record.tokenScope !== 'turn' ? 'not turn' : `runtime ${fmtResidual(split?.otherUsd ?? null).trim()}`;
const seqWidth = dense ? 20 : 24;
return (
{fmtDuration(record.durationMs)}
- {record.usageGap ? ' · gap' : record.quality === "partial" ? " ≈" : ""}
+ {record.tokenScope !== 'turn' ? ` · ${record.tokenScope} snapshot` : record.usageGap ? ' · gap' : record.incompleteUsage ? ' · incomplete' : ''}
{hasUsage ? (
@@ -187,14 +191,12 @@ function RecordRow({ record, theme, dense }: { record: TurnRow; theme: PluginThe
- {record.cacheWrite != null ? (
-
- ) : null}
+
@@ -229,6 +231,7 @@ function RecordRow({ record, theme, dense }: { record: TurnRow; theme: PluginThe
export function TokenLedgerPanel({ theme, layout, agentId }: PluginAgentPanelProps) {
const { dense, setWidth } = useDenseLayout(layout.compact);
const { data, error } = useLedger(agentId);
+ const pricingWarnings = [...new Set(data?.records.flatMap((record) => record.pricingWarning ? [record.pricingWarning] : []) ?? [])];
// Make the panel↔agent binding visible: which session is this ledger for?
const agentLabel = useAgent(agentId, (agent) => {
const name = agent.title ?? agentId.slice(0, 8);
@@ -269,8 +272,24 @@ export function TokenLedgerPanel({ theme, layout, agentId }: PluginAgentPanelPro
+ {pricingWarnings.map((warning) => {warning})}
{!data.inFlight && data.ctx ? : null}
+ {data.usageSnapshot ?
+
+ Latest {data.usageSnapshot.scope === 'session' ? 'session / branch' : 'unknown-scope'} snapshot
+
+
+ {tokensLine(data.usageSnapshot.input, data.usageSnapshot.cached, data.usageSnapshot.output, data.usageSnapshot.cacheWrite)}
+
+ {data.usageSnapshot.reportedCostUsd !== null ?
+ Runtime-reported cost: {fmtCost(data.usageSnapshot.reportedCostUsd)} · not a verified bill
+ : null}
+
+ Not per-turn usage; excluded from totals. Late updates refresh this snapshot, not closed turns.
+ {data.usageSnapshot.observedAt ? ` Observed ${fmtTime(data.usageSnapshot.observedAt)}.` : ''}
+
+ : null}
{data.inFlight ? : null}
@@ -286,10 +305,13 @@ export function TokenLedgerPanel({ theme, layout, agentId }: PluginAgentPanelPro
// restarts (turnId reuse), which made React render ghost rows.
))}
+
+ IN is uncached input; it may include unclassified writes. “?” means the cache-rate denominator is unknown.
+ Session/unknown snapshots are observations at settlement, not final turn totals.
+
{data.records.some((record) => fmtResidual(record.costBreakdown?.otherUsd ?? null).trim() !== "") ? (
- ± under COST: difference between reported cost and the token-based estimate, including charges
- for usage Paseo does not expose.
+ ± under COST: runtime-reported cost minus known component estimates. A residual does not identify missing tokens or actual charges.
) : null}
{data.records.some((record) => record.costSource && record.costSource !== "reported") ? (
diff --git a/client/pill.tsx b/client/pill.tsx
index efc785d..d761ccb 100644
--- a/client/pill.tsx
+++ b/client/pill.tsx
@@ -5,23 +5,47 @@ import { useLedger } from "./data.ts";
import { useEffect } from "react";
import { subscribeAgents } from "../shared/agents.ts";
import { ledgerEnsure, type SyncResult } from "../shared/ledger.ts";
-import { fmtCost, fmtTokens } from "./ui.tsx";
+import { costOrTokens, fmtTokens } from "./ui.tsx";
import type { PanelPlacement } from "./layout.ts";
-function pillLabel({ summary, inFlight, ctx }: SyncResult): string {
- const combinedCost = summary.effectiveCostUsd === null && inFlight?.effectiveCostUsd == null
- ? null
- : (summary.effectiveCostUsd ?? 0) + (inFlight?.effectiveCostUsd ?? 0);
- const cost = fmtCost(combinedCost);
- const estimated = summary.estimatedTurns > 0 || inFlight?.effectiveCostUsd != null;
- const parts = [cost
- ? `${estimated ? "≈" : ""}${cost}`
- : `${fmtTokens(summary.input + summary.cached + (summary.cacheWrite ?? 0) + summary.output)} tok`];
+function pillLabel({ summary, inFlight, ctx, usageSnapshot }: SyncResult): string {
+ let label: string;
+ const snapshotHasTokens = usageSnapshot && (usageSnapshot.input !== null || usageSnapshot.cached !== null
+ || usageSnapshot.cacheWrite !== null || usageSnapshot.output !== null);
+ if (usageSnapshot && (snapshotHasTokens || usageSnapshot.reportedCostUsd !== null)) {
+ if (usageSnapshot.scope === 'session' && snapshotHasTokens) {
+ const partial = usageSnapshot.input === null || usageSnapshot.cached === null
+ || usageSnapshot.cacheWrite === null || usageSnapshot.output === null;
+ const total = (usageSnapshot.input ?? 0) + (usageSnapshot.cached ?? 0)
+ + (usageSnapshot.cacheWrite ?? 0) + (usageSnapshot.output ?? 0);
+ label = `Session ${partial ? '≈' : ''}${fmtTokens(total)} tok`;
+ } else label = usageSnapshot.scope === 'session' ? 'Session snapshot' : 'Usage snapshot · scope unknown';
+ } else {
+ const live = inFlight?.tokenScope === 'turn' ? inFlight : null;
+ const liveCost = live?.effectiveCostUsd;
+ const combined = { ...summary,
+ effectiveCostUsd: summary.effectiveCostUsd === null && liveCost == null ? null
+ : (summary.effectiveCostUsd ?? 0) + (liveCost ?? 0),
+ estimatedTurns: summary.estimatedTurns + (liveCost != null && live?.costSource !== 'reported' ? 1 : 0),
+ partialCostTurns: summary.partialCostTurns + (liveCost != null && live?.partialCost ? 1 : 0),
+ unpricedTurns: summary.unpricedTurns + (live && liveCost == null ? 1 : 0),
+ pricingWarningTurns: summary.pricingWarningTurns + (live?.pricingWarning ? 1 : 0),
+ incompleteTurns: summary.incompleteTurns + (live ? 1 : 0),
+ };
+ if (live) for (const field of ['input', 'cached', 'cacheWrite', 'output'] as const) {
+ if (live[field] != null) combined[field] = (combined[field] ?? 0) + live[field];
+ }
+ const hasUsage = combined.effectiveCostUsd !== null || combined.input !== null || combined.cached !== null
+ || combined.cacheWrite != null || combined.output !== null;
+ label = hasUsage || combined.pricingWarningTurns > 0 ? costOrTokens(combined)
+ : inFlight ? 'Waiting for usage' : 'No usage reported';
+ }
+ const parts = [label];
const liveCtx = inFlight?.ctxUsed != null && inFlight.ctxMax != null
? { used: inFlight.ctxUsed, max: inFlight.ctxMax } : ctx;
if (liveCtx && liveCtx.max > 0) parts.push(`ctx ${Math.round(liveCtx.used / liveCtx.max * 100)}%`);
- return parts.join(" · ");
+ return parts.join(' · ');
}
export function contributePills(client: PluginClientContext, placement: PanelPlacement): () => Promise {
diff --git a/client/sidebar.tsx b/client/sidebar.tsx
index 1f11f74..284feed 100644
--- a/client/sidebar.tsx
+++ b/client/sidebar.tsx
@@ -9,7 +9,7 @@ import { costOrTokens } from "./ui.tsx";
export function LedgerSidebarItem({ theme, currentScreen, openScreen }: PluginSidebarItemProps) {
const { data } = useOverview(useRangeStart("today"));
const working = !!data?.groups.some((group) => group.agents.some((agent) => agent.active));
- const label = !data ? null : data.totals.turns === 0 ? "$0.00" : costOrTokens(data.totals);
+ const label = data ? costOrTokens(data.totals) : null;
return (
= 0.01 ? `$${value.toFixed(2)}` : `$${value.toFixed(4)}`;
}
-/** Cost when priced, else total tokens. "≈" marks a cost that includes estimates. */
+/** Compact totals always disclose omitted costs or incomplete token coverage. */
export function costOrTokens(summary: Summary): string {
const cost = fmtCost(summary.effectiveCostUsd);
- if (cost) return `${summary.estimatedTurns > 0 ? "≈" : ""}${cost}`;
- return `${fmtTokens(summary.input + summary.cached + (summary.cacheWrite ?? 0) + summary.output)} tok`;
+ const unknown = summary.pricingWarningTurns > 0 ? ' · price config'
+ : summary.unpricedTurns > 0 ? ` · ${summary.unpricedTurns} unknown` : '';
+ if (cost) return `${summary.estimatedTurns > 0 ? '≈' : ''}${cost}${summary.partialCostTurns > 0 ? ' partial' : ''}${unknown}`;
+ if (summary.input === null && summary.cached === null && summary.output === null && summary.cacheWrite == null) {
+ return summary.unmeasuredTurns > 0 ? `turn usage unavailable${unknown}` : `no usage reported${unknown}`;
+ }
+ const total = (summary.input ?? 0) + (summary.cached ?? 0) + (summary.cacheWrite ?? 0) + (summary.output ?? 0);
+ return `${fmtTokens(total)} tok${summary.incompleteTurns > 0 ? ' partial' : ''}${unknown}`;
}
/** Compact cost for per-component cells; "–" when unknown. */
@@ -29,12 +35,7 @@ export function fmtCostSmall(value: number | null): string {
return `$${value.toPrecision(1)}`;
}
-/**
- * Signed cost residual (reported total minus list-price component estimate)
- * for the COST cell; blank when unknown or negligible. On Claude turns a
- * positive residual is mostly cache writes, which upstream never reports as
- * tokens.
- */
+/** Reported runtime cost minus known component estimates, not missing-token attribution. */
export function fmtResidual(value: number | null): string {
if (value === null || Math.abs(value) < 0.005) return " ";
return `${value > 0 ? "+" : "−"}${fmtCostSmall(Math.abs(value))}`;
@@ -72,7 +73,7 @@ export function statusColor(status: TurnRecord["status"], theme: PluginTheme): s
export function tokensLine(input: number | null, cached: number | null, output: number | null, cacheWrite?: number | null): string | null {
if (input === null && cached === null && output === null && cacheWrite == null) return null;
- return `in ${fmtTokens(input)} · cache ${fmtTokens(cached)}${cacheWrite != null ? ` · write ${fmtTokens(cacheWrite)}` : ''} · out ${fmtTokens(output)}`;
+ return `in ${fmtTokens(input)} · cache ${fmtTokens(cached)} · write ${fmtTokens(cacheWrite ?? null)} · out ${fmtTokens(output)}`;
}
/** Column widths for the TURNS table; shared by the header and data rows. */
@@ -120,16 +121,25 @@ export function Stat({ label, value, theme, dense }: { label: string; value: str
export function SummaryRow({ summary, theme, dense }: { summary: Summary; theme: PluginTheme; dense?: boolean }) {
const cost = fmtCost(summary.effectiveCostUsd);
- const costValue = cost ? `${summary.estimatedTurns > 0 ? "≈" : ""}${cost}` : null;
- const costLabel = summary.unpricedTurns > 0 ? `cost · ${summary.unpricedTurns} unknown` : summary.estimatedTurns > 0 ? "cost · estimated" : "cost";
+ const costValue = cost ? `${summary.estimatedTurns > 0 ? '≈' : ''}${cost}` : 'unknown';
+ const costLabel = ['known cost', summary.partialCostTurns > 0 ? `${summary.partialCostTurns} partial` : null,
+ summary.unpricedTurns > 0 ? `${summary.unpricedTurns} unknown` : null].filter(Boolean).join(' · ');
return (
-
-
-
-
- {summary.cacheWrite != null ? : null}
-
- {costValue ? : null}
+
+
+
+
+
+
+
+
+
+ {summary.incompleteTurns > 0 ?
+ {summary.incompleteTurns} turn(s) with incomplete usage{summary.unmeasuredTurns > 0 ? ` · ${summary.unmeasuredTurns} snapshot(s) excluded from totals` : ''}.
+ : null}
+ {summary.pricingWarningTurns > 0 ?
+ {summary.pricingWarningTurns} turn(s) need pricing.json review. Reference-price fallback is blocked for ambiguous or unsafe old matches.
+ : null}
);
}
@@ -137,7 +147,7 @@ export function SummaryRow({ summary, theme, dense }: { summary: Summary; theme:
export function UsageCoverageNote({ theme }: { theme: PluginTheme }) {
return (
- Totals reflect usage available from Paseo; subagent usage and cache writes may be missing.
+ Known usage only. “–” means unknown, not zero. Runtime-reported and reference costs are not verified bills; descendant usage may be missing.
);
}
diff --git a/docs/compatibility.md b/docs/compatibility.md
index f152bad..837d42f 100644
--- a/docs/compatibility.md
+++ b/docs/compatibility.md
@@ -46,6 +46,7 @@ exclude beta builds.
| 0.10.2 | Installed desktop/daemon, published SDK, typecheck, 65 tests, plugin reload, real Claude/Codex turns on 2026-09-30 | Compatible with v0.6.3 |
| 0.11.0 | Published SDK (plugin dist identical to 0.11.1), typecheck and 65 tests on 2026-10-09 | Minimum for v0.7.0; no installed host tested |
| 0.11.1 | Installed desktop/daemon, published SDK, typecheck, 65 tests, dependency-free compile probe, plugin reload, real Claude/Codex turns, manual sidebar and overview check on 2026-10-09 | Supported by v0.7.0 |
+| 0.11.2 | Unreleased accounting fixes: pinned-SDK typecheck, 66 tests, installed-plugin reload, replay of existing Claude/OMP records, real host Web UI overview/pill/panel and live OMP snapshots on 2026-10-14 | Harness scopes and incomplete coverage verified; missing upstream data remains unavailable |
The 0.11.1 investigation found:
@@ -75,3 +76,31 @@ This review checked client types, bundle compilation, and the desktop sidebar
row and overview ranges by hand; mobile UI was not checked. It does not certify
other providers or future Paseo releases. Test agents were archived after
verification.
+
+The 0.11.2 accounting review found two plugin errors: model-based input
+normalization subtracted OMP cache twice, and session/branch snapshots were
+added as turn counts. Historical snapshots are now excluded from turn totals,
+while retaining their raw facts and showing late updates separately. Cache
+hit rates require a complete denominator; costs disclose unknown/partial
+coverage. Existing local prices and JSONL files were not rewritten.
+
+The UI check used the installed app-dist against the running daemon in an
+isolated Chromium, including the narrow ledger panel. Local-network browser
+policy was disabled only for that disposable verification process; document
+assets were served locally at the daemon origin without changing its CORS or
+auth configuration. No mobile device or new paid model probe was used.
+
+A copy without `node_modules` also compiled and reached "Plugin ready" on
+0.11.2 under a disposable plugin ID. Its contributions returned cleanup
+functions without registering tracking/UI; the probe was then removed.
+
+The local-trial follow-up retained 66 passing tests and added upgrade cases
+for dotted/hyphenated Claude custom prices, unsafe legacy-match warnings,
+reported-cost preservation and warning removal after a corrected alias.
+The actual Timeline renderer was also exercised with legacy and scoped data:
+legacy cards no longer assert exclusion. Native Text/View were represented
+as leaf components for that render-branch smoke, not a full Timeline UI run.
+An isolated 0.11.2 daemon with synthetic data verified the overview warning,
+the `Session ≈4.12M tok` pill and its snapshot panel, and supplied the refreshed
+screenshots. No model prompt was sent. The production plugin was reloaded
+for local trial only; no package version was published.
diff --git a/docs/paseo-usage-api.md b/docs/paseo-usage-api.md
index ef313a1..49e975f 100644
--- a/docs/paseo-usage-api.md
+++ b/docs/paseo-usage-api.md
@@ -5,6 +5,8 @@ Status: submitted as follow-up comments in existing upstream Discussions on
- [Cache creation counts — discussion #4623](https://github.com/getpaseo/paseo/discussions/4623#discussioncomment-18550901).
- [Descendant usage and attribution — discussion #4660](https://github.com/getpaseo/paseo/discussions/4660#discussioncomment-18550906).
+- [2026-10-14 follow-up: OMP cache creation and input conventions](https://github.com/getpaseo/paseo/discussions/4623#discussioncomment-18924605).
+- [2026-10-14 follow-up: final drain, branch epochs and attribution](https://github.com/getpaseo/paseo/discussions/4660#discussioncomment-18924607).
Paseo's [contribution policy](https://github.com/getpaseo/paseo/blob/b2ce2bcb83dd40bd91c32098c59221f0b52d7ffd/CONTRIBUTING.md)
directs missing extension points to Discussions. Existing threads covered both
@@ -32,6 +34,27 @@ Rechecked on 2026-09-30 against the installed Paseo 0.10.2 provider source and
published SDK: the same cache-creation and Codex child-usage gaps remain. See
the [compatibility review](compatibility.md) for the scope of this verification.
+Rechecked on 2026-10-14 against installed 0.11.2, separately from public `main`
+at `cafa04d3fbdbc7e4a3fe8f4d4bea80f15cd4a1d0`. The follow-ups above were posted
+as `stv1024` and read back through GitHub; submission does not imply acceptance.
+The public OMP usage poller was exercised in memory with synthetic statistics
+and controlled promises, not by running the full upstream daemon:
+
+- OMP maps `getSessionStats()` input/read/output/cost but drops `cacheWrite`.
+ The installed OMP statistics are already cache-exclusive and aggregate the
+ current session/branch, including some task-child usage.
+- Completion can precede final usage; starting another turn can invalidate
+ the pending final sample. Public snapshots do not preserve its turn identity.
+ Require terminal drain or attributable late corrections, plus branch/reset
+ epochs; subtracting adjacent snapshots is not a reliable per-turn contract.
+- Context-only OMP stats become zero token/cost values in the current mapper.
+ The plugin cannot distinguish those fabricated zeros from measured zero.
+- Claude cache creation and Codex child usage remain omitted. Merged
+ [#6703](https://github.com/getpaseo/paseo/pull/6703) and
+ [#6106](https://github.com/getpaseo/paseo/pull/6106) improve context accounting,
+ not the missing billing/usage contract. They are not duplicate bug reports.
+
+
## 1. Preserve cache creation usage
`@getpaseo/protocol/dist/agent-types.d.ts`, `AgentUsage`, currently exposes
@@ -137,6 +160,8 @@ history/subscription. Persist identities before acknowledging ingestion, price
each request with its own model, and select one accounting scope for each
total. Keep the current snapshot path as an explicitly partial fallback.
-Until then, TokenLedger's ordinary snapshot/terminal tracking remains active.
-Historical missing counts and descendant charges cannot be reconstructed from
-the current public API, and this change does not claim to restore them.
+Until then, verified turn/request tracking remains active. OMP session/branch
+and unknown-scope observations are displayed separately and excluded from
+per-turn costs and sums; late observations refresh the latest-snapshot card.
+Coverage and unknown prices are explicit. Historical missing counts and
+descendant charges cannot be reconstructed from the current public API.
diff --git a/images/screenshot-overview.png b/images/screenshot-overview.png
index 947cc2a9e8e1bd3407968c0b3111a040af475e3e..034ec569160875d82c7c973bb14fe225dd1272ab 100644
GIT binary patch
literal 50395
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