Commit graph

1572 commits

Author SHA1 Message Date
iamtoruk
fa8c008f71 revert(codex): retract the BUG-2 partial-dedup timing fix
Re-instrumenting this exact head over the full corpus traced the
original 12.5%/46% figures to a replication gap: the earlier
prevCumulativeTotal guard (codex.ts) already discards any token_count
event whose running total exactly repeats the previous kept one, so a
drop at the seenKeys dedup site is always a byte-identical replay of
already-counted tokens -- never a real loss. The condition BUG-2's fix
guarded against does not occur in real Codex output.

Removes taskDedupedTokens, its increment at the dedup site, the
active-time scaling at task_complete, and the now-unexercisable unit
test (its fixture forces a dedup collision that is not also a
cumulative-total repeat, a state the real writer never produces). The
dedup site keeps a short comment recording why no rescaling is needed,
so the next investigator doesn't retrace this.

Keeps: the reasoning double-count fix, the harness-startup exclusion
(BUG-1, confirmed to the decimal), the shared mergeToolIntervals
helper and permissive duration parsing (BUG-8), and the legend rename.
The real-corpus table is unchanged -- BUG-2 measured zero effect on it
before this revert too.
2026-08-21 15:37:57 -07:00
iamtoruk
c7e754d3c0 fix(codex): exclude harness startup and fix partial-dedup timing in Tok/s
Extends #1079 (reasoning double-count) with three more findings from an
exactness pass over the same throughput path:

- BUG-1: task_started fires before Codex assembles the request, so the
  gap to the first request-context event (turn_context, world_state,
  event_msg/user_message, or response_item/message) was counted as
  active model time. The active window now starts at that event instead.

- BUG-2: a token_count event dropped by fork-replay dedup lost its
  tokens from the numerator while the task's real duration still spanned
  it in the denominator, understating Tok/s for a partially (not fully)
  deduped task. The active window is now scaled down by the dropped
  tokens' proportional share.

- BUG-8: the tool-interval clip/merge/cap logic was duplicated between
  providers/codex.ts and codex-throughput.ts and had already drifted
  (task_complete only read a plain-number duration, unlike
  mcp_tool_call_end). Now one shared mergeToolIntervals, and
  task_complete's duration parses the same permissive forms.

Cost and every token count remain byte-identical. activeGeneratedTokens/
activeDurationMs/toolWaitMs are stored verbatim in both Codex caches, so
none of this self-heals -- but the CODEX_CACHE_VERSION 13 bump already
shipped for #1079 covers the same fields, so no further bump is needed.

Dashboard's per-model column keeps the "Tok/s" header (zero width slack
at the standard layout, verified against a real test); the legend now
spells out "Effective Tok/s" with a decode-speed disclaimer.
2026-08-21 15:29:14 -07:00
iamtoruk
bfcf63ce3a fix(codex): stop double-counting reasoning tokens in Tok/s throughput
The same reasoning-inclusion bug #1075/#1078 fixed for cost also affected
the throughput display: activeGeneratedTokens/taskGeneratedTokens in the
Codex parser and generatedTokens in the live codex-tps reader summed
outputTokens + reasoningTokens, but reasoning is already inside output.
All three sites now route through the billableOutputTokens('codex', ...)
helper #1078 introduced, so the throughput numerator can never drift from
the billed one.

Cost and every token count are unchanged (verified byte-identical on a
real 51,753-call corpus); Tok/s drops 20-42% depending on how
reasoning-heavy the model is.

activeGeneratedTokens/activeDurationMs/toolWaitMs are stored verbatim in
both the Codex result cache and the session cache rather than re-derived
on read, so neither self-heals: CODEX_CACHE_VERSION moves 11 -> 13 (12 is
claimed by feat/core-extraction's own port of this feature) and
PROVIDER_PARSE_VERSIONS.codex gains a codex-tps-v1 suffix, forcing Codex
sessions to re-parse once.

Closes #1079
2026-08-21 14:42:04 -07:00
ozymandiashh
aaf9a4b780
Merge pull request #1085 from avs-io/fix/result-cache-version-suffix
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
fix(cache): version-suffix provider result caches
2026-08-21 23:34:53 +03:00
ozymandiashh
67f085a3c2
Merge pull request #1054 from avs-io/fix/1051-copilot-rollup-dedup
fix(copilot): prefer lastEventTimestamp for stampless shutdown calls
2026-08-21 23:34:19 +03:00
ozymandiashh
d1d2ecda27
Merge pull request #1073 from avs-io/fix/sync-drop-cleartext-session-id
fix(sync): drop cleartext session id from attribution spans
2026-08-21 23:33:34 +03:00
ozymandiashh
06b297c885
Merge pull request #1072 from avs-io/fix/json-report-require-durable
fix(report): require durable period; drop unreachable dailyMap
2026-08-21 23:32:53 +03:00
ozymandiashh
3ec96d3a1f
Merge pull request #1071 from avs-io/fix/cache-lock-loser-outcome
fix(cache): accept completed-by-other as the stale-lock loser
2026-08-21 23:32:03 +03:00
ozymandiashh
f697cce53b
Merge pull request #1069 from avs-io/fix/chart-session-title-legend
fix(web): lead session chart legends with title when unique
2026-08-21 23:29:15 +03:00
Aditya Vikram Singh
add21524da fix(cache): treat a present versioned result file as exclusive 2026-08-22 01:49:39 +05:30
Aditya Vikram Singh
5ec82ea18c fix(cache): version-suffix provider result caches
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.
2026-08-22 01:36:15 +05:30
Resham Joshi
cfba136e91
Merge pull request #1084 from getagentseal/fix/codex-pricing-polish
fix(pricing): harden the #1078 follow-ups — cache-flag survival, credits trap, harness cost bound
2026-08-21 12:56:28 -07:00
iamtoruk
f92949c081 docs(pricing): bound the codex repricing drift in verify:upgrade, fix stale comments
The COST_CHANGED_BY_DESIGN carve-out in compare.mjs left codex cost entirely
unasserted after #1075/#1078. It now requires the upgraded cost to be strictly
lower than baseline and within 25% of it, and the row verdict says "repriced"
instead of the misleading "identical (cost N% drift)".

grok.ts's comment on the reasoning/output split still claimed provider-side
splitting was the repo's only mechanism; it now also names
billableOutputTokens/REASONING_INCLUDED_IN_OUTPUT (models.ts), which is the
other half since #1078. usage-aggregator.ts's "folds reasoning into output"
comment was true pre-#1078 but is backwards for codex now (reasoning is
already inside output, not added to it).

Test exemplars for the "reasoning is additive" case used hermes, whose
upstream is OpenAI-shaped and may not stay a safe example; swapped to gemini,
which documents "thoughts" as genuinely separate output.

CHANGELOG's #1075 entry gets one line noting days whose codex transcripts
have aged out keep their pre-fix totals via the daily-cache never-lose guard,
matching the disclosure already given for #1040.
2026-08-21 12:49:05 -07:00
iamtoruk
7876c8e9d7 fix(pricing): version the pricing cache and drop codex-credits' dead reasoning param
The pricing cache written to disk had no schema version, so a cache written
by a pre-#1078 binary lacked cacheWriteCostIsExplicit on every entry. Reading
it back resolved the missing key to undefined (falsy), silently reintroducing
the surcharge-fabrication bug #1078 killed for up to CACHE_TTL_MS after an
upgrade. loadCachedPricing now rejects any cache whose version doesn't match
the current schema instead of reading it verbatim.

codexCredits() still accepted an optional reasoningTokens param that added it
to output - the exact double-count #1078 removed from every real caller. The
only caller never passed it; deleted it so it can't be reintroduced by
accident.

parser.ts's activeGeneratedTokens fallback went through billableOutputTokens
in #1078, but codex is the only caller of activeDurationMs/activeGeneratedTokens
and always sets both together, so the fallback branch is unreachable for it.
Reverted to reduce diff noise.
2026-08-21 12:48:55 -07:00
Resham Joshi
91ddf58d15
Merge pull request #1078 from getagentseal/fix/codex-pricing-1075
fix(codex): stop double-billing reasoning output, price cache writes at the explicit rate only
2026-08-21 12:37:08 -07:00
iamtoruk
fda7e8024d fix(codex): stop double-billing reasoning output, price cache writes at the explicit rate only
Reasoning tokens are a subset of output_tokens for OpenAI models, not an
extra bucket: on a 1,396-rollout corpus all 134,316 token_count events
carrying a total satisfy input + output == total. CodeBurn added
reasoning_output_tokens on top when pricing a codex call, in the
cache-rehydration re-price, and in the models/audit display sums. That
overstated codex cost by $166.03 (3.5%) and displayed output tokens by
34.6% on that corpus. Both cost sites and the display sums now go through
one shared billableOutputTokens() so a cold parse and a warm read cannot
drift apart.

cache_write_input_tokens (codex PR #33454) was never read and
cacheCreationInputTokens was hardcoded to 0. It is now carved out of the
uncached-input bucket and clamped to it, but routed to the cache-write
bucket ONLY when the pricing source publishes an explicit cache-write rate.
buildCosts fabricates 1.25x input when a source omits one, which is correct
for Anthropic and would have invented a surcharge OpenAI never charged on
gpt-5.5 / 5.4 / 5.3-codex / gpt-5. ModelCosts now carries
cacheWriteCostIsExplicit so that distinction survives getModelCosts.

A cost change invalidates persisted output: codex-results.json v10 -> v11
(stores costUSD verbatim), the codex parse version moves (the token-bucket
change does not self-heal on read), and the daily cache goes 20 -> 23 (21 is
claimed by the #946 landing branch and 22 by PR #1056). The upgrade-path
corpus asserts codex tokens and calls exactly and reports the repricing.

Closes #1075
2026-08-21 11:50:23 -07:00
Aditya Vikram Singh
e96aa39853 test: daily[] rows consume durable.days, not headlines
Extra High MERGE AFTER FIX on 7e51413. JSON-report headlines
come from durable.data; daily[] is the durable.days consumer.
Oracle helper and assertions unchanged.
2026-08-21 22:55:51 +05:30
Aditya Vikram Singh
dd25a39027 docs(sync): upsert by traceId without overclaiming privacy
#1070 is hygiene, not a leak. User docs no longer name
deriveTraceId or list session ids under What is NOT sent.
Code comment matches the wire key. Class test pins every
attribution span: no ai.session_id, join is shared traceId.
2026-08-21 22:50:08 +05:30
Aditya Vikram Singh
06fa57b155 fix(sync): drop cleartext ai.session_id from attribution spans
Attribution spans already share deriveTraceId(sessionId) with
usage spans. Emitting the raw session id was redundant and
undid the pre-attribution wire rule that session id is hash
input only. Receivers upsert session spans by that keyed
traceId. Usage spans never had the field. Docs match.
2026-08-21 22:48:03 +05:30
Aditya Vikram Singh
7e51413e21 test: describe reportDailyByDate as the durable.days oracle
Extra High MERGE AFTER FIX on 1fa284f. The parity helper is an
independent per-call oracle for durable.days, not a mirror of a
live dailyMap fallback that no longer exists. Helper and test
unchanged.
2026-08-21 22:45:29 +05:30
Aditya Vikram Singh
1fa284fff8 fix(report): require durable period; drop unreachable dailyMap
buildJsonReport always received a DurablePeriod from both JSON
call sites, so the live dailyMap fallback could never run (#1067).
Make durable required and take headlines + daily rows only from
durable.days. Proxied/net split stays live-session. No fallback.
2026-08-21 22:35:52 +05:30
Aditya Vikram Singh
f718077a9b ci: gate the serial cache-lock suite after #904
Extra High MERGE AFTER FIX on a3beafb. The process tests admitted
completed-by-other as a non-owner outcome, but the workflow still
had continue-on-error and a quarantined step name. The suite now
gates. Still serial (parallelism-sensitive). No tryTakeover rewrite.
2026-08-21 22:09:47 +05:30
Aditya Vikram Singh
a3beafba50 fix(cache): accept completed-by-other as the stale-lock loser
The process suite required the loser of a stale-lock contest to
be timed-out. On a slow runner the winner's unlink-guard /
create-successor gap is missing+missing, which the lock honestly
reports as completed-by-other (#904).

Exactly one owner still publishes. The loser may be timed-out,
completed-by-other, or unavailable — never parsed. Do not delay
the clean-release path by treating missing+missing as wait-out.
2026-08-21 21:59:54 +05:30
Aditya Vikram Singh
4065255733 fix(web): count legend title uniqueness in code points
The visible prefix that decides title-vs-id order must match the
title cap. A UTF-16 slice can split an emoji and treat two distinct
titles as the same truncated series.
2026-08-21 21:59:13 +05:30
Aditya Vikram Singh
088d264968 fix(web): lead session chart legends with title when unique
Hourly session series still opened with a truncated UUID, so a
monorepo's legend was six identical hex fragments. Sessions
report already prefers title; the chart did not.

Lead with the cleaned title when that prefix is unique in the
visible ~24-glyph budget. Fall back to short-id-first when
titles collide or share a long prefix. Untitled sessions stay
project fallback. No full session ids on the happy path.
2026-08-21 21:48:09 +05:30
Resham Joshi
e12fb39e3f
Merge pull request #1064 from avs-io/fix/test-isolate-provider-homes
Some checks are pending
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
test: isolate provider-home env vars so developer shells cannot leak sessions
2026-08-21 06:48:47 -07:00
Aditya Vikram Singh
094f9f1d43 test: consume runtime CLEARED/REDIRECTED arrays in the isolation guard
Extra High MERGE AFTER FIX: source-scraping the setup file treated a
comment containing 'HERMES_HOME' as isolation. The lists now live in a
side-effect-free module that applyIsolation and the declaration test
both import. Comment-only sabotage fails with hermes:HERMES_HOME.
2026-08-21 18:58:21 +05:30
Aditya Vikram Singh
f55f98726d test: isolate provider-home env vars so developer shells cannot leak sessions
HERMES_HOME and eight sibling PROVIDER_ENV_VARS data-dir overrides were
fingerprinted for cache invalidation but never CLEARED by the vitest
setup file, so a Hermes-shell laptop parsed real sessions in fixtures.
A static guard fails closed when the map grows another undeclared home.
2026-08-21 18:45:15 +05:30
Aditya Vikram Singh
9c8727d94f fix(copilot): prefer lastEventTimestamp for stampless shutdown calls
Maintainer review on #1054: two-journal collision is unreachable
through discovery. Keying by timestamp+journal collapsed a 3-leg
stampless journal onto one row, and the :n strip re-sent ledger
keys. Keep occurrence keys. Take lastEventTimestamp before
sessionStartTime for the call timestamp only. No migration.
2026-08-21 18:04:28 +05:30
Resham Joshi
f0c6e58008
Merge pull request #1049 from avs-io/fix/optimize-provider-remediation-copy
fix(optimize): scope remediation copy to --provider
2026-08-21 05:23:03 -07:00
Resham Joshi
52714d6241
Merge pull request #1063 from getagentseal/snap/scope-personal-files-main
snap: scope personal-files to the log subdirectories each provider actually reads
2026-08-21 03:57:36 -07:00
iamtoruk
c73d8ff6c8 snap: scope the entries main gained after the tightening
The ported declaration was written against main as of c9e6e2ec. Main has since
added dsh and carries five entries that commit never saw, all of them still bare
tool roots, so the port dropped them rather than reintroduce what the store
rejected. Each is restored at the path its provider opens:

  .dsh/sessions                          dsh.ts reads <DSH_HOME>/sessions only
  .kiro/sessions                         CLI store at sessions/cli, v2 IDE store
                                         at sessions/<hash> — siblings
  .quickwork/{profiles.json,sessions,metrics}
                                         profiles.json names the profile bases;
                                         the legacy layout is sessions/sessions.db
                                         plus metrics/
  .config/Claude/local-agent-mode-sessions
                                         Claude Desktop's local-agent-mode store
  .config/Open Design/{runs,data/runs,namespaces}
                                         the three discovery roots open-design.ts
                                         probes under its data dir

.lingtai and .lingtai-tui stay dropped. A LingTai ledger lives at
.lingtai/<agent>/logs/token_ledger.jsonl, and personal-files has no wildcard for
the agent segment; .lingtai-tui only exists to enumerate project homes that could
not be read anyway. Goose is narrowed to .local/share/goose/sessions, which holds
the only file it opens.

Four entries stay whole roots because the provider reads a file sitting directly
in the root: .config/github-copilot (JetBrains stores nest under a variable
<ide>/<kind>/<storeId>) and .local/share/{opencode,crush,kilo}. The new
app/scripts/snap-grants.test.ts asserts every other entry is at least one level
below its tool root, so a bare root cannot come back unnoticed.
2026-08-21 03:42:09 -07:00
iamtoruk
3168699927 snap: scope personal-files to log subdirectories
Snap Store review found the declaration requested each tool's entire root
directory. Those roots hold configuration and, in several cases, credentials,
and personal-files read is recursive, so the request granted read of every AI
tool's credential store.

Every path is now the subdirectory the provider actually opens: .claude/projects,
.codex/sessions, .cline/data, .vibe/logs/session, .hermes/profiles, .mux/sessions
and so on; two are single files (.forge/.forge.db, .zcode/cli/db/db.sqlite). The
editor entries name only the extension folders that hold transcripts rather than
the editor's whole configuration. No bare tool root remains.

One credential file is requested openly instead of implicitly: .claude/.credentials.json,
read-only, used to call Anthropic's usage endpoint for the live plan gauge.

Codex's equivalent needs read-write on the Codex CLI's auth.json to rotate the
token, so neither that file nor a Codex root is declared and the Codex live
gauge is disabled under $SNAP. Codex usage and cost analytics are unaffected;
they come from the session rollouts.

Also declares five providers that were missing entirely and would have shown no
data under the snap: opencode, crush, goose, kilo, kimi-code. Drops .lingtai,
whose per-agent directory sits above the log folder and cannot be expressed
without wildcards.

Ports 4fe760aafe0492a674476c1ca64bf0dbdc673dde onto current main; the entries
main gained since that commit are reconciled separately.
2026-08-21 03:38:25 -07:00
Aditya Vikram Singh
c12c1c6267 fix(optimize): do not claim a session scan for non-Claude providers
Maintainer review on #1049: empty-state copy under --provider codex
named detectors that scanSessions never ran. Say the session-scan
detectors do not cover that provider yet. Drop the dead TUI provider
threading; optimize view is still gated to all|claude.
2026-08-21 15:58:05 +05:30
Resham Joshi
ed02748063
Merge pull request #1055 from avs-io/fix/1045-session-meta-depth
fix(codex): read session_meta string fields at payload depth 1
2026-08-21 02:53:14 -07:00
Resham Joshi
be86a4bf95
Merge pull request #1060 from getagentseal/test/hermetic-deepseek-pricing
test: make pricing and FX hermetic so upstream reprices can't turn CI red
2026-08-21 02:32:24 -07:00
iamtoruk
577ff0b9ee test: skip the live Frankfurter fetch so FX moves can't shift assertions
Mirrors the pricing guard: CODEBURN_FX_NO_FETCH short-circuits getExchangeRate
after the cache read and before the fetch, returning the same USD-equivalent
rate an unreachable network already yields. Tests that seed their own
exchange-rate.json (serve-stdio's EUR case) keep working unchanged.
2026-08-21 02:23:41 -07:00
iamtoruk
4866332b91 test: price off the bundled snapshot so upstream reprices can't turn tests red
loadPricing() fetched the live LiteLLM table during tests and live data wins
over the bundled snapshot, so DeepSeek v4 assertions went red when upstream
dropped the off-peak discount. CODEBURN_PRICING_SNAPSHOT_ONLY skips the fetch;
env-isolation sets it for the whole suite.
2026-08-21 02:21:31 -07:00
Aditya Vikram Singh
a3ea24859e fix(copilot): journal-scope shutdown keys without a fingerprint bump
Extra High HOLD on #1054: timestamp-only keys still collided across
journals, and the provider-wide rollup-ts-v1 bump dropped present
OTel sources, erasing conversations already pruned from the DB.
Identity is now (session, model, timestamp, journal basename).
Legacy :n keys migrate on that JSONL file only.
2026-08-20 09:52:56 +05:30
Aditya Vikram Singh
497f655623 fix(codex): read session_meta string fields at payload depth 1
#1040 fixed nested provenance.model. The compact Buffer path still
took the first cwd/session_id/originator/name anywhere in the payload.
Same depth-1 window for every session_meta string field. Bump parse
fingerprint and CODEX_CACHE_VERSION so present sources re-parse.
2026-08-20 08:52:30 +05:30
Aditya Vikram Singh
a5ed4535cd fix(copilot): key shutdown rollups by timestamp, not per-file index
Two journals for one session both emitted :1 and the shared seenKeys
set dropped the second file's first leg. Identity is now
(session, model, shutdown timestamp). Bump the Copilot parse
fingerprint so present sources re-parse; durable orphans stay.
2026-08-20 08:13:35 +05:30
Resham Joshi
a48d78f9d2
Merge pull request #1040 from timdp/codex-model-attribution-fix
Some checks failed
CI / semgrep (push) Has been cancelled
Tests / test (22) (push) Has been cancelled
macOS Menubar CI / test (push) Has been cancelled
Tests / test (22.13.0) (push) Has been cancelled
Fix Codex model attribution after session metadata
2026-08-19 13:49:52 -07:00
iamtoruk
134e662013 Merge remote-tracking branch 'origin/main' into pr1040-rebase 2026-08-19 13:46:28 -07:00
Resham Joshi
c42de88f74
Merge pull request #1052 from getagentseal/ci/lock-suite-step-timeout
ci: give the quarantined cache-lock step its own timeout
2026-08-19 13:46:25 -07:00
iamtoruk
5130041839 ci: give the quarantined lock suite its own timeout
The step is continue-on-error, but when it stalls it runs into the job's
15-minute budget and the whole job is reported cancelled, hiding the
parallel suite's result (#1040 three times in a row).
2026-08-19 13:35:35 -07:00
iamtoruk
f9f79b0660 Merge remote-tracking branch 'origin/main' into pr1040-rebase
# Conflicts:
#	CHANGELOG.md
2026-08-19 13:18:09 -07:00
Resham Joshi
7862aabd47
Merge pull request #1039 from avs-io/fix/hermes-glm53-pr-links
fix(hermes): unwrap known routers; fail closed on unknown models
2026-08-19 12:29:21 -07:00
Resham Joshi
496b3f258e
Merge pull request #1041 from avs-io/fix/plan-budget-not-live-quota
fix(plans): call sticker-price bars a budget, not live quota
2026-08-19 12:27:34 -07:00
iamtoruk
fec3519ff1 Merge remote-tracking branch 'origin/main' into pr1041-rebase
# Conflicts:
#	CHANGELOG.md
2026-08-19 12:08:25 -07:00
iamtoruk
9ae4250ef3 changelog: resolve merge markers 2026-08-19 12:08:22 -07:00