Skip to content

feat(miner-hands): per-attempt cost/turn metering for CodingAgentDriver runs #4311

Description

@JSONbored

A coding-agent attempt (#4262's interface, #4266/#4267's implementations) has a real cost — tokens/turns/wall-clock — that needs to be measured per attempt and checked against a budget, both so a single runaway attempt can't burn unbounded spend and so the portfolio/governor layers have real numbers to work with. Two existing pure primitives in gittensory-engine are the natural composition points: packages/gittensory-engine/src/portfolio/queue.ts's PortfolioCaps (globalWipCap/perRepoWipCap, count-based concurrency caps — a different axis but the same "cap enforcement" family) and packages/gittensory-engine/src/governor/rate-limit.ts's evaluateLocalRateLimit/LocalRateLimitConfig (rolling-window rate limiting) plus jitteredBackoffMs (deterministic backoff, injected-random for testability). Neither module currently has any notion of "cost" or "turns" — this issue adds that dimension.

Deliverables

  • A pure metering module (packages/gittensory-engine/src/miner/attempt-metering.ts or similar, coordinated with feat(miner-hands): define the CodingAgentDriver interface seam #4262's src/miner/ home) that accumulates per-attempt cost/turn counters and evaluates them against a configured ceiling — the same "pure decision, no IO/enforcement" discipline governor/rate-limit.ts's header explicitly calls out ("This module computes numbers only — it does NOT store state, schedule, or gate any write action").
  • A defined unit for "cost" (tokens? dollars? both, with a per-model conversion table?) and "turns" (one tool-call? one full agent iteration?) — pin this down explicitly, since both CodingAgentDriver implementations (CLI-subprocess vs. Agent-SDK) report usage in different native shapes and need to normalize to the same metered unit.
  • Wire the metered totals into the attempt log (feat(miner-hands): driver-level structured attempt log (JSONL event trace per attempt) #4294, this batch) as structured payload fields, so a ceiling breach is auditable after the fact, not just enforced silently in memory.
  • A clear "what happens on breach" contract — does the driver get asked to stop gracefully, or killed outright? Coordinate with feat(miner-hands): CLI-subprocess CodingAgentDriver (reuse SpawnFn/redactSecrets/EFFORT_TIMEOUT_MS pattern) #4266's subprocess timeout/kill handling (src/selfhost/ai.ts:644-711's existing timer-based SIGKILL pattern is the closest precedent for a hard cutoff) and feat(miner-hands): Agent-SDK CodingAgentDriver (query() loop) #4267's query() loop (which likely has its own natural stop-iterating point for a graceful cutoff).
  • Unit tests for: normal accumulation under the ceiling, a breach mid-attempt, and the boundary case (exactly at the ceiling) — following evaluateLocalRateLimit's existing test-friendly, injected-clock discipline (nowMs as a parameter, never Date.now() read internally).

References

  • packages/gittensory-engine/src/portfolio/queue.ts:24-27 (PortfolioCaps — the existing cap-enforcement family, count-based not cost-based)
  • packages/gittensory-engine/src/governor/rate-limit.ts:1-9 (module header: "computes numbers only... does NOT store state, schedule, or gate any write action" — the discipline this new module should match)
  • packages/gittensory-engine/src/governor/rate-limit.ts:53-74 (evaluateLocalRateLimit), :84-101 (jitteredBackoffMs — injected-random testability pattern)
  • src/selfhost/ai.ts:644-711 (defaultSpawn's timer-based SIGKILL — closest existing hard-cutoff precedent for the CLI-subprocess driver side of a breach)
  • Depends on feat(miner-hands): define the CodingAgentDriver interface seam #4262 (this batch) for what usage data a driver run reports; coordinates with feat(miner-hands): driver-level structured attempt log (JSONL event trace per attempt) #4294 (attempt log) for persistence

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:featureGittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.help wantedExtra attention is needed

    Projects

    Status
    In Progress

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions