fix Codex parser + sharpen instructions + add ./sigrank --all
Browse files- Codex parser: unify Alpha/Beta into one _codex_input_estimate helper
(removes the two divergent hardcoded /9.0 copies). Beta now uses the
operator's REAL Claude input/output ratio; Alpha uses the AA 2:1 baseline.
- ./sigrank --all: run every provider in turn (claude, then codex); Codex
reuses Claude's measured ratio for the Beta pathway; one failing provider
doesn't stop the others.
- Instructions (app.py Clock Your Signal tab + README How-to-measure):
measure each provider separately, never bare `ccusage --json`; what data /
where to get it / where to input it; accurate two-pathway Codex description.
- Drop duplicate claudetodolist.md (content lives in SUPABASE_MIGRATION.md).
Supabase migration (submitted_at, hf_user, sigrank_sessions + RLS) applied
live via MCP and verified end-to-end. Canonical MO§ES Υ 18436.98 unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- README.md +45 -6
- app.py +20 -11
- claudetodolist.md +0 -147
- ingest.py +33 -27
- sigrank.py +33 -3
|
@@ -47,12 +47,45 @@ is the token-domain expression of the same conservation law.
|
|
| 47 |
- *[Word-based operator ranking — link placeholder]*
|
| 48 |
|
| 49 |
## What it does
|
| 50 |
-
Paste `
|
| 51 |
or four numbers →
|
| 52 |
- **operator profile** — a 0.5B MiniCPM model narrates your architecture, plus
|
| 53 |
raw ledger, composition, full metrics, cascade breakdown
|
| 54 |
- **leaderboard placement** vs real operators, ranked by Υ, with blended **$/1M cost**
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
## The model (Tiny Titan / MiniCPM)
|
| 57 |
`openbmb/MiniCPM4-0.5B` (0.5B params, well under the 4B cap) runs on ZeroGPU and
|
| 58 |
narrates the operator read. It is **non-blocking**: if unavailable, a deterministic
|
|
@@ -152,11 +185,17 @@ benchmarks on one side, real user token ledgers on the other — landing on the
|
|
| 152 |
same architecture is the validation.
|
| 153 |
|
| 154 |
## Codex support
|
| 155 |
-
Codex
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
## Cost
|
| 162 |
For Claude Code, ccusage supplies real cost → exact $/1M. For manual/wild rows
|
|
|
|
| 47 |
- *[Word-based operator ranking — link placeholder]*
|
| 48 |
|
| 49 |
## What it does
|
| 50 |
+
Paste `ccusage claude --json` (Claude Code), `ccusage codex --json` (Codex),
|
| 51 |
or four numbers →
|
| 52 |
- **operator profile** — a 0.5B MiniCPM model narrates your architecture, plus
|
| 53 |
raw ledger, composition, full metrics, cascade breakdown
|
| 54 |
- **leaderboard placement** vs real operators, ranked by Υ, with blended **$/1M cost**
|
| 55 |
|
| 56 |
+
## How to measure yourself
|
| 57 |
+
Three things: **what data, where to get it, where to put it.**
|
| 58 |
+
|
| 59 |
+
**1 — What / where to get it.** SigRank needs four integers — `input`, `output`,
|
| 60 |
+
`cache_create`, `cache_read`. [`ccusage`](https://github.com/ryoppippi/ccusage) reads
|
| 61 |
+
them from your local logs. Run **one command per provider** — Claude and Codex are
|
| 62 |
+
different operators, so measure them **separately**:
|
| 63 |
+
|
| 64 |
+
```
|
| 65 |
+
ccusage claude --json # Claude Code
|
| 66 |
+
ccusage codex --json # Codex
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
> ⚠️ Don't use bare `ccusage --json` (no subcommand): it merges every agent into one
|
| 70 |
+
> total, which inflates input and distorts the architecture read.
|
| 71 |
+
|
| 72 |
+
**2 — Where to put it.** Either:
|
| 73 |
+
|
| 74 |
+
- **Local importer (no paste):** `./sigrank` (Claude), `./sigrank --codex` (Codex),
|
| 75 |
+
or `./sigrank --all` (each provider in turn). Reads your usage on your machine and
|
| 76 |
+
prints your profile + board rank. Nothing leaves your computer.
|
| 77 |
+
- **Hosted Space:** paste one provider's JSON into the **Clock Your Signal** box, or type
|
| 78 |
+
the four numbers `input output cache_create cache_read`.
|
| 79 |
+
|
| 80 |
+
**3 — Saving (optional).** On the Space, sign in with HuggingFace to earn one persistent
|
| 81 |
+
board entry + session history (Greatest Hits). Without login, your read is a live
|
| 82 |
+
snapshot only — scored against the field but not saved.
|
| 83 |
+
|
| 84 |
+
**Codex note.** Codex doesn't report a fresh-vs-cache input split, so its input is
|
| 85 |
+
*estimated*: on its own it uses the AA-backed **2:1** baseline; if you also have a Claude
|
| 86 |
+
profile (e.g. `./sigrank --codex`, which reads your Claude ratio first) it calibrates with
|
| 87 |
+
**your own Claude input:output ratio**. Estimated rows are flagged with `*`.
|
| 88 |
+
|
| 89 |
## The model (Tiny Titan / MiniCPM)
|
| 90 |
`openbmb/MiniCPM4-0.5B` (0.5B params, well under the 4B cap) runs on ZeroGPU and
|
| 91 |
narrates the operator read. It is **non-blocking**: if unavailable, a deterministic
|
|
|
|
| 185 |
same architecture is the validation.
|
| 186 |
|
| 187 |
## Codex support
|
| 188 |
+
Codex never itemizes cache writes, so SigRank estimates the high-signal user input
|
| 189 |
+
from output via two pathways (`_codex_input_estimate` in `ingest.py`):
|
| 190 |
+
|
| 191 |
+
- **Alpha — Codex alone:** the AA-backed **2:1** baseline — `est_input = 2 × output`.
|
| 192 |
+
- **Beta — Codex + a Claude profile:** the operator's **own** measured Claude
|
| 193 |
+
`input:output` ratio — `est_input = output × (claude_input / claude_output)`. The
|
| 194 |
+
CLI builds this automatically (`./sigrank --codex` reads your Claude usage first).
|
| 195 |
+
|
| 196 |
+
`cache_create` is the remainder (`raw_input − est_input`, clamped ≥0); `cache_read` is
|
| 197 |
+
measured directly. Every Codex-derived row is **flagged with `*`** and names the exact
|
| 198 |
+
pathway used in its caveat.
|
| 199 |
|
| 200 |
## Cost
|
| 201 |
For Claude Code, ccusage supplies real cost → exact $/1M. For manual/wild rows
|
|
@@ -327,25 +327,34 @@ def _build_demo():
|
|
| 327 |
gr.HTML(board_html())
|
| 328 |
|
| 329 |
with gr.Tab("Clock Your Signal"):
|
| 330 |
-
gr.Markdown("""**Get your operator profile \u2014
|
| 331 |
|
| 332 |
-
**\u2460
|
| 333 |
```
|
| 334 |
-
ccusage claude --json # Claude Code
|
| 335 |
-
ccusage codex --json # Codex
|
| 336 |
-
ccusage --json # ALL providers combined
|
| 337 |
```
|
| 338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
```
|
| 340 |
-
./sigrank
|
| 341 |
-
./sigrank --codex
|
|
|
|
| 342 |
```
|
| 343 |
|
| 344 |
-
**\u2461 Paste
|
|
|
|
|
|
|
| 345 |
|
| 346 |
-
*Codex
|
|
|
|
|
|
|
| 347 |
|
| 348 |
-
**\u2462 Sign in to save.** HuggingFace
|
|
|
|
| 349 |
if _ON_SPACE:
|
| 350 |
gr.LoginButton(elem_id="hf-login-btn")
|
| 351 |
else:
|
|
|
|
| 327 |
gr.HTML(board_html())
|
| 328 |
|
| 329 |
with gr.Tab("Clock Your Signal"):
|
| 330 |
+
gr.Markdown("""**Get your operator profile \u2014 measure each provider separately.**
|
| 331 |
|
| 332 |
+
**\u2460 Get your numbers.** Run one command per provider in your terminal:
|
| 333 |
```
|
| 334 |
+
ccusage claude --json # Claude Code
|
| 335 |
+
ccusage codex --json # Codex (estimated *)
|
|
|
|
| 336 |
```
|
| 337 |
+
\u26a0\ufe0f **Run each provider on its own \u2014 never bare `ccusage --json`.** With no
|
| 338 |
+
subcommand it merges every agent into one total, inflating input and distorting your
|
| 339 |
+
architecture. Claude and Codex are different operators \u2014 measure them separately.
|
| 340 |
+
|
| 341 |
+
Prefer zero copy-paste? Use the local importer (reads your usage on your machine):
|
| 342 |
```
|
| 343 |
+
./sigrank # Claude Code (measured)
|
| 344 |
+
./sigrank --codex # Codex (calibrated *)
|
| 345 |
+
./sigrank --all # each provider, one after another
|
| 346 |
```
|
| 347 |
|
| 348 |
+
**\u2461 Paste it below.** Drop one provider's `ccusage` JSON in the box \u2014 we route it
|
| 349 |
+
automatically. No JSON handy? Type four numbers in order:
|
| 350 |
+
`input output cache_create cache_read`.
|
| 351 |
|
| 352 |
+
*Codex reports no fresh-vs-cache input split, so its input is **estimated**: on its own it
|
| 353 |
+
uses the AA-backed **2:1** baseline; if you also have a Claude profile it uses **your own
|
| 354 |
+
Claude input:output ratio**. Estimated rows are flagged with \\*.*
|
| 355 |
|
| 356 |
+
**\u2462 Sign in to save.** A HuggingFace login earns one persistent board entry + session
|
| 357 |
+
history (Greatest Hits). Pasting without login is a live snapshot only.""")
|
| 358 |
if _ON_SPACE:
|
| 359 |
gr.LoginButton(elem_id="hf-login-btn")
|
| 360 |
else:
|
|
@@ -1,147 +0,0 @@
|
|
| 1 |
-
2 items... i had devin build the instructions for the following...
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
1) i dont feel like we covered enough on instructions and detailing what information we need, where to get it... and where to imput it
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
2) # Supabase Migration — SigRank Importer Overhaul
|
| 9 |
-
|
| 10 |
-
Run these in the Supabase SQL Editor (Dashboard → SQL Editor → New Query).
|
| 11 |
-
|
| 12 |
-
---
|
| 13 |
-
|
| 14 |
-
## 1. Add columns to `sigrank_operators`
|
| 15 |
-
|
| 16 |
-
```sql
|
| 17 |
-
-- Timestamp for when the entry was last submitted/updated
|
| 18 |
-
ALTER TABLE sigrank_operators
|
| 19 |
-
ADD COLUMN IF NOT EXISTS submitted_at TIMESTAMPTZ DEFAULT now();
|
| 20 |
-
|
| 21 |
-
-- HuggingFace username — only authenticated users can persist
|
| 22 |
-
ALTER TABLE sigrank_operators
|
| 23 |
-
ADD COLUMN IF NOT EXISTS hf_user TEXT;
|
| 24 |
-
|
| 25 |
-
-- Index for fast lookups by HF user
|
| 26 |
-
CREATE INDEX IF NOT EXISTS idx_sigrank_operators_hf_user
|
| 27 |
-
ON sigrank_operators (hf_user);
|
| 28 |
-
```
|
| 29 |
-
|
| 30 |
-
---
|
| 31 |
-
|
| 32 |
-
## 2. Create `sigrank_sessions` table (session history / Greatest Hits)
|
| 33 |
-
|
| 34 |
-
```sql
|
| 35 |
-
CREATE TABLE IF NOT EXISTS sigrank_sessions (
|
| 36 |
-
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
| 37 |
-
name TEXT NOT NULL,
|
| 38 |
-
input BIGINT NOT NULL DEFAULT 0,
|
| 39 |
-
output BIGINT NOT NULL DEFAULT 0,
|
| 40 |
-
cache_create BIGINT NOT NULL DEFAULT 0,
|
| 41 |
-
cache_read BIGINT NOT NULL DEFAULT 0,
|
| 42 |
-
cost_usd DOUBLE PRECISION,
|
| 43 |
-
source TEXT DEFAULT 'manual',
|
| 44 |
-
estimated BOOLEAN DEFAULT FALSE,
|
| 45 |
-
caveat TEXT,
|
| 46 |
-
hf_user TEXT,
|
| 47 |
-
submitted_at TIMESTAMPTZ DEFAULT now()
|
| 48 |
-
);
|
| 49 |
-
|
| 50 |
-
-- Index for loading a user's session history
|
| 51 |
-
CREATE INDEX IF NOT EXISTS idx_sigrank_sessions_name
|
| 52 |
-
ON sigrank_sessions (name, submitted_at DESC);
|
| 53 |
-
```
|
| 54 |
-
|
| 55 |
-
---
|
| 56 |
-
|
| 57 |
-
## 3. RLS policies (keep anon read-only, service key for writes)
|
| 58 |
-
|
| 59 |
-
```sql
|
| 60 |
-
-- Enable RLS on the new table
|
| 61 |
-
ALTER TABLE sigrank_sessions ENABLE ROW LEVEL SECURITY;
|
| 62 |
-
|
| 63 |
-
-- Anon can read session history
|
| 64 |
-
CREATE POLICY "anon_read_sessions" ON sigrank_sessions
|
| 65 |
-
FOR SELECT USING (true);
|
| 66 |
-
|
| 67 |
-
-- Service role can insert (writes come from the app backend)
|
| 68 |
-
CREATE POLICY "service_insert_sessions" ON sigrank_sessions
|
| 69 |
-
FOR INSERT WITH CHECK (true);
|
| 70 |
-
|
| 71 |
-
-- Same pattern for the new columns on sigrank_operators
|
| 72 |
-
-- (existing policies should already cover SELECT/INSERT;
|
| 73 |
-
-- verify the existing INSERT policy allows the new columns)
|
| 74 |
-
```
|
| 75 |
-
|
| 76 |
-
---
|
| 77 |
-
|
| 78 |
-
## 4. Verify
|
| 79 |
-
|
| 80 |
-
After running the above, check:
|
| 81 |
-
|
| 82 |
-
```sql
|
| 83 |
-
-- Should show submitted_at and hf_user columns
|
| 84 |
-
SELECT column_name, data_type
|
| 85 |
-
FROM information_schema.columns
|
| 86 |
-
WHERE table_name = 'sigrank_operators'
|
| 87 |
-
ORDER BY ordinal_position;
|
| 88 |
-
|
| 89 |
-
-- Should exist with all columns
|
| 90 |
-
SELECT column_name, data_type
|
| 91 |
-
FROM information_schema.columns
|
| 92 |
-
WHERE table_name = 'sigrank_sessions'
|
| 93 |
-
ORDER BY ordinal_position;
|
| 94 |
-
```
|
| 95 |
-
|
| 96 |
-
---
|
| 97 |
-
|
| 98 |
-
## Notes
|
| 99 |
-
|
| 100 |
-
- `sigrank_operators` still upserts on `name` (one board entry per operator)
|
| 101 |
-
- `sigrank_sessions` is append-only — every submission creates a new row
|
| 102 |
-
- The app reads sessions via `load_session_history(name, limit=5)` for the Greatest Hits display
|
| 103 |
-
- `hf_user` is populated only when the user is authenticated via HuggingFace OAuth on the Space
|
| 104 |
-
- Without the `SUPABASE_SERVICE_KEY` env var, all writes are no-ops (safe for public demo)
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
3)Here's the spec for ./sigrank --all that Claude Code can implement:
|
| 109 |
-
Goal: ./sigrank --all runs each ccusage provider sequentially and loads results into the user's profile one at a time.
|
| 110 |
-
In sigrank.py:
|
| 111 |
-
|
| 112 |
-
# Add to argparser:
|
| 113 |
-
p.add_argument("--all", action="store_true",
|
| 114 |
-
help="run all providers (claude + codex) sequentially")
|
| 115 |
-
|
| 116 |
-
# In main(), before the existing try block:
|
| 117 |
-
if args.all:
|
| 118 |
-
for provider, is_codex in [("claude", False), ("codex", True)]:
|
| 119 |
-
sub_args = type("a", (), {
|
| 120 |
-
"file": None, "stdin": False, "codex": is_codex,
|
| 121 |
-
"name": args.name, "no_color": args.no_color,
|
| 122 |
-
"stdin_dash": None
|
| 123 |
-
})()
|
| 124 |
-
try:
|
| 125 |
-
raw, how = _grab_usage(sub_args)
|
| 126 |
-
# Build operator_profile from Claude data if running Codex
|
| 127 |
-
op_profile = None
|
| 128 |
-
if is_codex:
|
| 129 |
-
# Try to get Claude's I/O ratio for Beta pathway
|
| 130 |
-
try:
|
| 131 |
-
claude_args = type("a", (), {"file": None, "stdin": False, "codex": False})()
|
| 132 |
-
c_raw, _ = _grab_usage(claude_args)
|
| 133 |
-
ci, co, _, _, _ = parse_ccusage(c_raw)
|
| 134 |
-
if co > 0:
|
| 135 |
-
op_profile = {"model_type": "claude", "io_ratio": ci / co}
|
| 136 |
-
except Exception:
|
| 137 |
-
pass
|
| 138 |
-
i, o, cw, cr, meta = ingest_meta(raw, operator_profile=op_profile)
|
| 139 |
-
m = compute(i, o, cw, cr, cost_usd=meta.get("cost"))
|
| 140 |
-
if meta.get("estimated"):
|
| 141 |
-
m["_caveat"] = meta.get("caveat")
|
| 142 |
-
print(render(args.name, m, how, color=not args.no_color))
|
| 143 |
-
except Exception as e:
|
| 144 |
-
print(f" [{provider}] skipped: {e}")
|
| 145 |
-
sys.exit(0)
|
| 146 |
-
Flow: ./sigrank --all → runs ccusage claude --json, prints profile → runs ccusage codex --json, prints profile with Alpha or Beta pathway applied. Each provider is independent — if one fails, the other still runs. find the users model via ccusage --help
|
| 147 |
-
That should be everything! PRs #5 and #6 cover the full importer overhaul. Let me know if you need anything else.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -182,18 +182,37 @@ def _extract_codex_totals(d):
|
|
| 182 |
return tot
|
| 183 |
|
| 184 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
def parse_codex_submission(payload, operator_profile=None):
|
| 186 |
"""
|
| 187 |
Parses Codex token payloads to estimate true high-signal user input.
|
| 188 |
|
| 189 |
-
Two pathways depending on operator telemetry:
|
| 190 |
-
|
| 191 |
-
Pathway Alpha (Standard): No Claude footprint -> 3:2:1 baseline.
|
| 192 |
-
estimated_user_input = outputTokens * 2.0
|
| 193 |
|
| 194 |
-
Pathway Beta (
|
| 195 |
-
|
| 196 |
-
estimated_user_input = outputTokens / 9.0
|
| 197 |
|
| 198 |
Returns (i, o, cw, cr, meta) mapped to the four pillars:
|
| 199 |
i = calibrated_user_input (high-signal core)
|
|
@@ -209,16 +228,8 @@ def parse_codex_submission(payload, operator_profile=None):
|
|
| 209 |
raw_cache = tot["cached"]
|
| 210 |
cost = tot["cost"] if tot["cost"] > 0 else None
|
| 211 |
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
estimated_user_input = raw_out / 9.0
|
| 215 |
-
parsing_mode = "Claude Closed-Loop Calibration (1:9)"
|
| 216 |
-
# Pathway Alpha: Fallback Standard (The Top 10 Wild Field Baseline)
|
| 217 |
-
else:
|
| 218 |
-
estimated_user_input = raw_out * 2.0
|
| 219 |
-
parsing_mode = "Standard Open-Loop Baseline (3:2:1)"
|
| 220 |
-
|
| 221 |
-
context_debt = max(0, raw_in - int(estimated_user_input))
|
| 222 |
|
| 223 |
meta = {
|
| 224 |
"source": "codex",
|
|
@@ -240,10 +251,10 @@ def ingest_meta(text, operator_profile=None):
|
|
| 240 |
- Text with named fields (extracts by field name, not position)
|
| 241 |
- Four bare numbers: input output cache_create cache_read
|
| 242 |
|
| 243 |
-
operator_profile: optional dict
|
| 244 |
when the submitting user has a verified Claude session profile. This
|
| 245 |
-
switches the Codex parser from the
|
| 246 |
-
|
| 247 |
"""
|
| 248 |
text=text.strip()
|
| 249 |
if not text: raise ValueError("empty")
|
|
@@ -284,13 +295,8 @@ def ingest_meta(text, operator_profile=None):
|
|
| 284 |
raw_in = int(float(m.group(1).replace(",", "")))
|
| 285 |
break
|
| 286 |
raw_out = o # already includes reasoning from _extract_by_name
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
parsing_mode = "Claude Closed-Loop Calibration (1:9)"
|
| 290 |
-
else:
|
| 291 |
-
est_input = raw_out * 2.0
|
| 292 |
-
parsing_mode = "Standard Open-Loop Baseline (3:2:1)"
|
| 293 |
-
context_debt = max(0, raw_in - int(est_input))
|
| 294 |
meta = {
|
| 295 |
"source": "codex", "estimated": True,
|
| 296 |
"parsing_mode": parsing_mode,
|
|
|
|
| 182 |
return tot
|
| 183 |
|
| 184 |
|
| 185 |
+
def _codex_input_estimate(raw_out, operator_profile):
|
| 186 |
+
"""Estimate Codex high-signal user input from output. Single source of truth
|
| 187 |
+
for both the JSON and named-field Codex paths (no duplicated magic numbers).
|
| 188 |
+
|
| 189 |
+
Codex never reports a fresh-vs-cache input split, so we estimate the
|
| 190 |
+
high-signal user input from the output (the real work product) via a ratio:
|
| 191 |
+
|
| 192 |
+
Beta (Codex + Claude present): use the operator's REAL Claude operating
|
| 193 |
+
ratio io_ratio = claude_input/claude_output -> est_input = output * io_ratio
|
| 194 |
+
(dynamic, never a constant — it's the operator's own measured behaviour).
|
| 195 |
+
|
| 196 |
+
Alpha (Codex alone, no Claude): AA-backed 2:1 baseline (input:output = 2),
|
| 197 |
+
supported by the wild corpus -> est_input = output * 2.0
|
| 198 |
+
|
| 199 |
+
Returns (est_input:int, parsing_mode:str).
|
| 200 |
+
"""
|
| 201 |
+
if (operator_profile and operator_profile.get("model_type") == "claude"
|
| 202 |
+
and operator_profile.get("io_ratio")):
|
| 203 |
+
ratio = operator_profile["io_ratio"] # claude input / output
|
| 204 |
+
return int(raw_out * ratio), f"Claude operating-ratio {ratio:.3f}:1 (input:output)"
|
| 205 |
+
return int(raw_out * 2.0), "AA 2:1 baseline (wild-corpus backed)"
|
| 206 |
+
|
| 207 |
+
|
| 208 |
def parse_codex_submission(payload, operator_profile=None):
|
| 209 |
"""
|
| 210 |
Parses Codex token payloads to estimate true high-signal user input.
|
| 211 |
|
| 212 |
+
Two pathways depending on operator telemetry (see _codex_input_estimate):
|
|
|
|
|
|
|
|
|
|
| 213 |
|
| 214 |
+
Pathway Beta (Codex + Claude): est_input = output * (claude_input/claude_output)
|
| 215 |
+
Pathway Alpha (Codex alone): est_input = output * 2.0 (AA 2:1 baseline)
|
|
|
|
| 216 |
|
| 217 |
Returns (i, o, cw, cr, meta) mapped to the four pillars:
|
| 218 |
i = calibrated_user_input (high-signal core)
|
|
|
|
| 228 |
raw_cache = tot["cached"]
|
| 229 |
cost = tot["cost"] if tot["cost"] > 0 else None
|
| 230 |
|
| 231 |
+
estimated_user_input, parsing_mode = _codex_input_estimate(raw_out, operator_profile)
|
| 232 |
+
context_debt = max(0, raw_in - estimated_user_input)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
meta = {
|
| 235 |
"source": "codex",
|
|
|
|
| 251 |
- Text with named fields (extracts by field name, not position)
|
| 252 |
- Four bare numbers: input output cache_create cache_read
|
| 253 |
|
| 254 |
+
operator_profile: optional dict {"model_type": "claude", "io_ratio": float}
|
| 255 |
when the submitting user has a verified Claude session profile. This
|
| 256 |
+
switches the Codex parser from the Alpha 2:1 baseline to the Beta pathway
|
| 257 |
+
that uses the operator's own Claude input/output ratio.
|
| 258 |
"""
|
| 259 |
text=text.strip()
|
| 260 |
if not text: raise ValueError("empty")
|
|
|
|
| 295 |
raw_in = int(float(m.group(1).replace(",", "")))
|
| 296 |
break
|
| 297 |
raw_out = o # already includes reasoning from _extract_by_name
|
| 298 |
+
est_input, parsing_mode = _codex_input_estimate(raw_out, operator_profile)
|
| 299 |
+
context_debt = max(0, raw_in - est_input)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
meta = {
|
| 301 |
"source": "codex", "estimated": True,
|
| 302 |
"parsing_mode": parsing_mode,
|
|
@@ -6,8 +6,9 @@ Her-style: reads YOUR usage on YOUR machine and prints your operator read. No
|
|
| 6 |
paste, no token, no upload. The hosted Space's paste box is the backup; this is
|
| 7 |
the real-app path.
|
| 8 |
|
| 9 |
-
python sigrank.py # auto-run `ccusage --json` (Claude Code)
|
| 10 |
python sigrank.py --codex # auto-run `ccusage codex --json`
|
|
|
|
| 11 |
python sigrank.py --file u.json # read a saved ccusage/codex json
|
| 12 |
python sigrank.py --name "you" # label your row
|
| 13 |
cat u.json | python sigrank.py - # read from stdin (backup)
|
|
@@ -137,6 +138,8 @@ def main(argv=None):
|
|
| 137 |
p.add_argument("stdin_dash", nargs="?", default=None, help="pass '-' to read JSON from stdin")
|
| 138 |
p.add_argument("--file", help="read a saved ccusage/codex json file")
|
| 139 |
p.add_argument("--codex", action="store_true", help="run `ccusage codex --json`")
|
|
|
|
|
|
|
| 140 |
p.add_argument("--name", default="you", help="label for your row")
|
| 141 |
p.add_argument("--no-color", action="store_true", help="plain output")
|
| 142 |
args = p.parse_args(argv)
|
|
@@ -144,7 +147,34 @@ def main(argv=None):
|
|
| 144 |
|
| 145 |
color = sys.stdout.isatty() and not args.no_color
|
| 146 |
|
| 147 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
operator_profile = None
|
| 149 |
if args.codex:
|
| 150 |
try:
|
|
@@ -154,7 +184,7 @@ def main(argv=None):
|
|
| 154 |
if _co > 0:
|
| 155 |
operator_profile = {"model_type": "claude", "io_ratio": _ci / _co}
|
| 156 |
except Exception:
|
| 157 |
-
pass # no Claude data — Alpha pathway (
|
| 158 |
|
| 159 |
try:
|
| 160 |
raw, how = _grab_usage(args)
|
|
|
|
| 6 |
paste, no token, no upload. The hosted Space's paste box is the backup; this is
|
| 7 |
the real-app path.
|
| 8 |
|
| 9 |
+
python sigrank.py # auto-run `ccusage claude --json` (Claude Code)
|
| 10 |
python sigrank.py --codex # auto-run `ccusage codex --json`
|
| 11 |
+
python sigrank.py --all # every provider in turn (claude, then codex)
|
| 12 |
python sigrank.py --file u.json # read a saved ccusage/codex json
|
| 13 |
python sigrank.py --name "you" # label your row
|
| 14 |
cat u.json | python sigrank.py - # read from stdin (backup)
|
|
|
|
| 138 |
p.add_argument("stdin_dash", nargs="?", default=None, help="pass '-' to read JSON from stdin")
|
| 139 |
p.add_argument("--file", help="read a saved ccusage/codex json file")
|
| 140 |
p.add_argument("--codex", action="store_true", help="run `ccusage codex --json`")
|
| 141 |
+
p.add_argument("--all", action="store_true",
|
| 142 |
+
help="run every provider in turn (claude, then codex)")
|
| 143 |
p.add_argument("--name", default="you", help="label for your row")
|
| 144 |
p.add_argument("--no-color", action="store_true", help="plain output")
|
| 145 |
args = p.parse_args(argv)
|
|
|
|
| 147 |
|
| 148 |
color = sys.stdout.isatty() and not args.no_color
|
| 149 |
|
| 150 |
+
# --all: run each provider sequentially and independently. Claude runs first;
|
| 151 |
+
# its measured input/output ratio is captured and handed to the Codex pass so
|
| 152 |
+
# Codex uses the Beta (operator-ratio) pathway. One provider failing (e.g. no
|
| 153 |
+
# Codex usage) never stops the others.
|
| 154 |
+
if args.all:
|
| 155 |
+
name = (args.name or "you").strip()[:24] or "you"
|
| 156 |
+
claude_profile = None
|
| 157 |
+
for provider, is_codex in (("claude", False), ("codex", True)):
|
| 158 |
+
try:
|
| 159 |
+
prov_args = type("a", (), {"file": None, "stdin": False, "codex": is_codex})()
|
| 160 |
+
raw, how = _grab_usage(prov_args)
|
| 161 |
+
prof = claude_profile if is_codex else None
|
| 162 |
+
i, o, cw, cr, meta = ingest_meta(raw, operator_profile=prof)
|
| 163 |
+
if i + o + cw + cr == 0:
|
| 164 |
+
print(f" [{provider}] no usage data — skipped")
|
| 165 |
+
continue
|
| 166 |
+
m = compute(i, o, cw, cr, cost_usd=meta.get("cost"))
|
| 167 |
+
if meta.get("estimated"):
|
| 168 |
+
m["_caveat"] = meta.get("caveat")
|
| 169 |
+
print(render(name, m, how, color))
|
| 170 |
+
if not is_codex and o > 0: # capture Claude ratio for the Codex pass
|
| 171 |
+
claude_profile = {"model_type": "claude", "io_ratio": i / o}
|
| 172 |
+
except Exception as e:
|
| 173 |
+
print(f" [{provider}] skipped: {e}")
|
| 174 |
+
return 0
|
| 175 |
+
|
| 176 |
+
# For Codex: detect the operator's real Claude I/O ratio so the parser uses
|
| 177 |
+
# the Beta pathway (output * claude_input/claude_output) instead of Alpha 2:1.
|
| 178 |
operator_profile = None
|
| 179 |
if args.codex:
|
| 180 |
try:
|
|
|
|
| 184 |
if _co > 0:
|
| 185 |
operator_profile = {"model_type": "claude", "io_ratio": _ci / _co}
|
| 186 |
except Exception:
|
| 187 |
+
pass # no Claude data — Alpha pathway (AA 2:1 baseline)
|
| 188 |
|
| 189 |
try:
|
| 190 |
raw, how = _grab_usage(args)
|