BudgetRegistry.consume at lib/src/main/kotlin/dev/arcp/lease/BudgetRegistry.kt:24 returns BudgetCounter.Outcome.Ok whenever counters[jobId] is null, which is the same outcome it returns for a successful in-budget consume. Callers — most prominently ARCPRuntime.handleMetric at lib/src/main/kotlin/dev/arcp/runtime/ARCPRuntime.kt:305 — cannot distinguish "no budget was registered for this job" from "the budget had room". A job that was supposed to be lease-bound but slipped through registration (for example a delegated subjob if and when delegation is wired up) silently bypasses the budget enforcement that the rest of the system assumes is on.
Fix prompt: Add a third Outcome.Unregistered (or return Outcome? and let null mean "no counter") so the registry distinguishes a missing counter from a successful spend. Update ARCPRuntime.handleMetric to either ignore unregistered metrics with an info-level log (current behavior, but explicit) or reply with Nack(FAILED_PRECONDITION) when the runtime expects a budget for that job. Add a BudgetRegistryTest (none exists today) that exercises consume against an unregistered job and asserts the new outcome.
BudgetRegistry.consumeatlib/src/main/kotlin/dev/arcp/lease/BudgetRegistry.kt:24returnsBudgetCounter.Outcome.Okwhenevercounters[jobId]is null, which is the same outcome it returns for a successful in-budget consume. Callers — most prominentlyARCPRuntime.handleMetricatlib/src/main/kotlin/dev/arcp/runtime/ARCPRuntime.kt:305— cannot distinguish "no budget was registered for this job" from "the budget had room". A job that was supposed to be lease-bound but slipped through registration (for example a delegated subjob if and when delegation is wired up) silently bypasses the budget enforcement that the rest of the system assumes is on.Fix prompt: Add a third
Outcome.Unregistered(or returnOutcome?and letnullmean "no counter") so the registry distinguishes a missing counter from a successful spend. UpdateARCPRuntime.handleMetricto either ignore unregistered metrics with an info-level log (current behavior, but explicit) or reply withNack(FAILED_PRECONDITION)when the runtime expects a budget for that job. Add aBudgetRegistryTest(none exists today) that exercises consume against an unregistered job and asserts the new outcome.