You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(amico-run): attribute CPU cost to principal and Lab from the solve unit cgroup, not process.cpuUsage() #2133
Central-hub cost ledger (ADR 0041 section 5). It replaces the approach in #2121, which measured process.cpuUsage(): that counts only the engine process, not the Julia child, so every solve would be costed at about zero. Since A1, each solve runs in its own transient unit amico-run-<id>.service, whose cgroup accounts the solve's real CPU including all child threads.
What
Add principal, lab and cpu_seconds to ReceiptRecord (and ledger-record.schema.json), plus a costTotals rollup by principal and Lab. Unattributed runs roll up under (unattributed).
Measure CPU from the unit's cgroup. On Linux read cpu.statusage_usec of the run's cgroup (find it via the A1 run.lock unit name, or systemctl --user show -p ControlGroup), read before the unit is torn down and again at settle; the delta is cpu_seconds. Where no cgroup is available (macOS, a run not in a unit), fall back to child rusage if obtainable, else record cpu_seconds absent and cost_basis: unmeasured. NEVER fall back to process.cpuUsage().
Cost = cpu_seconds x a rate read from a human-edited file (~/.amico/amicode/rates.json), default 0, so an unconfigured install records seconds and no invented dollars. Label every dollar figure basis: list_price_estimate.
Never fail a run because accounting failed.
Acceptance Criteria
a test runs a real child process that burns CPU in a transient cgroup or unit (or a faithful temp cgroup fixture) and asserts cpu_seconds reflects the CHILD's CPU.
a test proves process.cpuUsage() is never used: a run whose engine process is idle but whose child burns 1+ s must record at least 1 s.
no rate configured => seconds recorded and no cost_usd; rate configured => cost_usd = seconds x rate with basis list_price_estimate.
unattributed runs roll up under (unattributed); principal and Lab rollups sum to the total.
an accounting failure never fails a run or changes its exit code.
Activity
Merge pull request #2134 from harmoniqs/opencode/issue-2133
aarontrowbridge commentedon Nov 4, 2026
Merged via #2134. Independently verified against real transient units: workloads of 2/8/0 CPU-seconds measured 2.01/8.04/0.00.