Skip to content

Add a shared quota-burn invocation path over scheduled tasks with a countPending contract #6378

Description

@atomantic

Problem / Goal

Once a burn step is a reference to a scheduled task, the runner needs a way to invoke that task. server/services/quotaBurnJobs/agentPrompt.js currently queues directly through cosTaskStore.js with a synthesized free-form task, bypassing canonical task generation and its gates. #6372 requires a shared invocation path instead — and explicitly rules out an HTTP loopback or a synthetic task.

Scope

Shared invocation path. Resolve and validate the reference, reuse canonical task generation (server/services/taskSchedule.js#triggerOnDemandTask and cosTaskGenerator.js for built-ins; the autonomous-job generation in server/services/autonomousJobs/skillTemplates.js for custom jobs), and pass the step's immutable run overrides through to the resulting task. Add a distinct quota-burn origin to ON_DEMAND_ORIGINS (server/services/taskSchedule.js), carrying family, limiting-reset, burn-step id, and request/task identity.

Gates that must survive. Built-in master Improve gate, enabled state, instance-feature gate, scope, and invocation eligibility; custom-job approval and lifecycle rules. server/routes/cosJobRoutes.js's manual endpoint deliberately bypasses approval and revives/force-spawns tasks — an automated burn must not inherit those privileges. force may bypass the existing quota gates only, never task eligibility or approval.

Finite semantics. Selecting a perpetual task must invoke it once; it must not restart or drain its perpetual loop.

Picker eligibility. Restrict selectable references to eligible AI agent tasks plus the explicitly supported programmatic scheduled handlers. Exclude shell jobs, unrelated scripts, and system-managed-only actions.

countPending contract. Define a shared countPending(reference) → { count, detail, context? } on resolved references, matching the existing job-module contract documented in server/services/quotaBurnJobs/index.js:

  • an eligible AI agent task reports one ready unit after eligibility and pending/running checks;
  • an ineligible or already-active task reports zero with its reason;
  • a programmatic handler supplies its domain backlog count.

server/services/quotaBurnRunner.js keeps first-enabled-unspent-with-positive-count selection; zero-work steps are skipped. Reuse the single gate ladder in server/services/quotaBurn.js (evaluateFamily, selectBurnCandidates, evaluateFamilies) that the runner and the status page already share — do not add a second ladder. getQuotaBurnStatus must keep stripping the opaque probe context from the wire. Probes must enqueue nothing and call no AI provider.

Acceptance criteria

  • Service tests: resolved effective settings (overrides layered over the task's saved settings), scope validation, and refusal paths for disabled task, feature off, master-Improve off, missing custom-job approval, wrong-family provider pin, and dangling reference — each with a distinct reason and no dispatch.
  • A burn invocation of a custom job does not get the manual endpoint's approval bypass or force-spawn/revive behavior; asserted directly.
  • force: true bypasses the quota gate but still refuses an ineligible or unapproved task.
  • Invoking a perpetual task runs exactly one unit and leaves its perpetual loop untouched.
  • The generated task carries the quota-burn origin (family, limiting reset, burn-step id, request/task identity) and it survives persistence.
  • countPending returns one unit for an eligible agent task, zero-with-reason for an inactive/missing/already-active one, and the domain backlog count for a programmatic handler; ordered selection in the runner is preserved.
  • A probe test asserts zero writes, zero enqueues, and zero provider calls.

Notes

Depends on the burn-step reference model child. Blocks the accounting, audit-mode, migration, and editor children.


Part of #6372

When this ships, tick its box in the ## Decomposed into checklist on #6372. If it is the last unchecked box, close #6372.

Activity

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

    area:cos-agentsChief-of-Staff autonomous agentseffort:highDispatch reasoning effort: highenhancementNew feature or requestmodel:heavyDispatch capability: strongest available coding modelplanTracked by /do:replanplanner:opus-5Plan authored by the opus-5 model

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions