Skip to content

feat(amico-run): attribute CPU cost to principal and Lab using the solve unit's cgroup CPU, not process.cpuUsage() #2132

Open

Description

@aarontrowbridge

Why

Central-hub cost ledger (ADR 0041 §5; replaces the approach in #2121, which measured process.cpuUsage(): the engine process only, not the Julia child, so every solve would be costed at about zero). A1 runs each solve in its own transient unit amico-run-<id>.service, whose cgroup accounts the solve's real CPU including all child threads.

What

  1. Add principal, lab, cpu_seconds to ReceiptRecord (+ ledger-record.schema.json), and costTotals rollup by principal and Lab. Keep the optionality: unattributed runs roll up under (unattributed).
  2. Measure CPU from the unit's cgroup: on Linux read cpu.stat usage_usec of the run's cgroup (find it via the A1 run.lock unit name / 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().
  3. Cost = cpu_seconds x a rate read from a human-edited config 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.
  4. Never fail a run because accounting failed.

Acceptance Criteria

  • a test runs a real child process that burns CPU in a transient cgroup/unit (or a faithful temp cgroup fixture) and asserts cpu_seconds reflects the CHILD's CPU, and that a parent that only waits records ~0 for itself.
  • a test proves process.cpuUsage() is never used (a run whose engine process is idle but whose child burns 1+ s must record >= 1 s).
  • no rate configured => seconds recorded, 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.
  • accounting failure never fails or changes the exit code of a run.
  • schema validates the new fields.

Activity

  1. added
    0.4.1Fixes-only maintenance lane after 0.4.0 (v1 overlay frozen)
    on Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    0.4.1Fixes-only maintenance lane after 0.4.0 (v1 overlay frozen)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions