• Stefy Lanza (nextime / spora )'s avatar
    runpod: hours nobody ledgered, and a flag the ledger threw away (v0.3.63) · d8984250
    Stefy Lanza (nextime / spora ) authored
    Two gaps I left open last night, both about the ledger telling the truth.
    
    **A pod that went away without a pool noticing was never billed to anyone.** A
    pool closes its own pods' bills — `_terminate` for one it retires, `forget` for
    one RunPod says is gone — and neither runs for a pod only the REGISTRY knew
    about: one orphaned by a restart, or terminated from the console or straight
    through the RunPod API. Observed: pod lgdgfs749chkib, killed by hand, never
    appeared in the ledger while two pods that went through coderai did.
    `close_bill_from_registry()` now computes the hours from the registry's own
    `created` — the only record of when a pod started once no handle exists — and
    records them against the pool it belonged to. Both reaper paths use it, so the
    "terminated as stale" and "vanished from the account" cases cannot drift apart,
    and a pod a pool still holds is deliberately skipped: `forget` ledgers that one,
    and counting it here as well would double-count every pod RunPod reclaims.
    
    **`record_spend` dropped the `reaped` flag it was being handed.** It keeps a
    deliberate allow-list, which is right — the file is persisted and pruned for
    every pod — but the list has to carry what distinguishes one kind of charge from
    another. A pod the reaper killed looked in the file exactly like one a pool
    retired on purpose. `reaped` and `reason` are kept now.
    
    Writing the test for the first fix found a third thing, and it was mine: v0.3.56
    made a stale registry entry stop counting as "known" so the reaper could kill the
    pod it named — but the reconcile was only ever asked about known ids, so that
    same change stopped stale entries being RECONCILED. An entry for a pod that no
    longer exists was then never pruned and its hours never attributed. The reaper
    now reconciles against the whole registry; `known` keeps its one job, which is
    deciding what is shielded from reaping.
    
    9 tests in tests/test_ledger_out_of_band.py, including the double-count guard
    and the pruning regression. test_runpod_client_scale's source anchor moves with
    the change and says why.
    Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01PxYHWbCAjjjD7A1rhFKtaW
    d8984250
runpod_ledger.py 4.94 KB