Files
multica/server/pkg/db/generated/autopilot_quota.sql.go
3c23c491fa MUL-6924: feat(billing): notify workspaces about autopilot quota (#7681)
* feat(billing): notify workspaces about autopilot quota

Co-authored-by: multica-agent <[email protected]>

* fix(billing): isolate and throttle quota notices

Co-authored-by: multica-agent <[email protected]>

* fix(billing): tighten quota notice delivery

Co-authored-by: multica-agent <[email protected]>

* fix(billing): reuse quota admission snapshot

Co-authored-by: multica-agent <[email protected]>

* fix(autopilot): make quota notices actionable

Co-authored-by: multica-agent <[email protected]>

* fix(billing): align quota recovery notifications

Co-authored-by: multica-agent <[email protected]>

* fix(billing): align quota notice recipients

Co-authored-by: multica-agent <[email protected]>

* fix(billing): finish quota notice review

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: multica-agent <[email protected]>
Co-authored-by: Sol-Boy <[email protected]>
2026-09-02 12:59:26 +08:00

433 lines
14 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: autopilot_quota.sql
package db
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const consumeAutopilotQuotaReservation = `-- name: ConsumeAutopilotQuotaReservation :one
WITH locked AS (
SELECT qr.id, qr.workspace_id, qr.period_start, qr.period_end, qr.policy_revision, qr.subscription_version, qr.source, qr.idempotency_key, qr.state, qr.created_at, qr.finalized_at FROM autopilot_quota_reservation qr
WHERE qr.id = $1 AND qr.state = 'reserved'
FOR UPDATE
), changed AS (
UPDATE autopilot_quota_reservation AS r
SET state = 'consumed', finalized_at = now()
FROM locked
WHERE r.id = locked.id
AND EXISTS (
SELECT 1 FROM autopilot_quota_period p
WHERE p.workspace_id = locked.workspace_id
AND p.period_start = locked.period_start
AND p.period_end = locked.period_end
)
RETURNING locked.workspace_id, locked.period_start, locked.period_end
)
UPDATE autopilot_quota_period AS p
SET reserved_count = reserved_count - 1,
used_count = used_count + 1,
updated_at = now()
FROM changed
WHERE p.workspace_id = changed.workspace_id
AND p.period_start = changed.period_start
AND p.period_end = changed.period_end
RETURNING p.workspace_id, p.period_start, p.period_end, p.used_count, p.reserved_count, p.blocked_counts, p.created_at, p.updated_at, p.rejection_notified_at
`
// used_count is monotonic within a period: consuming a reserved slot is the
// only write that changes it, and no release path decrements it.
func (q *Queries) ConsumeAutopilotQuotaReservation(ctx context.Context, reservationID pgtype.UUID) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, consumeAutopilotQuotaReservation, reservationID)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}
const createAutopilotQuotaReservation = `-- name: CreateAutopilotQuotaReservation :one
INSERT INTO autopilot_quota_reservation (
workspace_id, period_start, period_end, policy_revision,
subscription_version, source, idempotency_key
) VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, workspace_id, period_start, period_end, policy_revision, subscription_version, source, idempotency_key, state, created_at, finalized_at
`
type CreateAutopilotQuotaReservationParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
PolicyRevision int64 `json:"policy_revision"`
SubscriptionVersion int64 `json:"subscription_version"`
Source string `json:"source"`
IdempotencyKey string `json:"idempotency_key"`
}
func (q *Queries) CreateAutopilotQuotaReservation(ctx context.Context, arg CreateAutopilotQuotaReservationParams) (AutopilotQuotaReservation, error) {
row := q.db.QueryRow(ctx, createAutopilotQuotaReservation,
arg.WorkspaceID,
arg.PeriodStart,
arg.PeriodEnd,
arg.PolicyRevision,
arg.SubscriptionVersion,
arg.Source,
arg.IdempotencyKey,
)
var i AutopilotQuotaReservation
err := row.Scan(
&i.ID,
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.PolicyRevision,
&i.SubscriptionVersion,
&i.Source,
&i.IdempotencyKey,
&i.State,
&i.CreatedAt,
&i.FinalizedAt,
)
return i, err
}
const ensureAutopilotQuotaPeriod = `-- name: EnsureAutopilotQuotaPeriod :one
INSERT INTO autopilot_quota_period (workspace_id, period_start, period_end)
VALUES ($1, $2, $3)
ON CONFLICT (workspace_id, period_start, period_end) DO UPDATE
SET updated_at = autopilot_quota_period.updated_at
RETURNING workspace_id, period_start, period_end, used_count, reserved_count, blocked_counts, created_at, updated_at, rejection_notified_at
`
type EnsureAutopilotQuotaPeriodParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
}
// The no-op update is intentional: ON CONFLICT UPDATE locks the period row for
// the caller's transaction, serialising admission for one workspace/period.
func (q *Queries) EnsureAutopilotQuotaPeriod(ctx context.Context, arg EnsureAutopilotQuotaPeriodParams) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, ensureAutopilotQuotaPeriod, arg.WorkspaceID, arg.PeriodStart, arg.PeriodEnd)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}
const getAutopilotQuotaPeriod = `-- name: GetAutopilotQuotaPeriod :one
SELECT workspace_id, period_start, period_end, used_count, reserved_count, blocked_counts, created_at, updated_at, rejection_notified_at FROM autopilot_quota_period
WHERE workspace_id = $1 AND period_start = $2 AND period_end = $3
`
type GetAutopilotQuotaPeriodParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
}
func (q *Queries) GetAutopilotQuotaPeriod(ctx context.Context, arg GetAutopilotQuotaPeriodParams) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, getAutopilotQuotaPeriod, arg.WorkspaceID, arg.PeriodStart, arg.PeriodEnd)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}
const getAutopilotQuotaReservationByKey = `-- name: GetAutopilotQuotaReservationByKey :one
SELECT id, workspace_id, period_start, period_end, policy_revision, subscription_version, source, idempotency_key, state, created_at, finalized_at FROM autopilot_quota_reservation
WHERE workspace_id = $1
AND period_start = $2
AND period_end = $3
AND idempotency_key = $4
AND state <> 'released'
`
type GetAutopilotQuotaReservationByKeyParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
IdempotencyKey string `json:"idempotency_key"`
}
func (q *Queries) GetAutopilotQuotaReservationByKey(ctx context.Context, arg GetAutopilotQuotaReservationByKeyParams) (AutopilotQuotaReservation, error) {
row := q.db.QueryRow(ctx, getAutopilotQuotaReservationByKey,
arg.WorkspaceID,
arg.PeriodStart,
arg.PeriodEnd,
arg.IdempotencyKey,
)
var i AutopilotQuotaReservation
err := row.Scan(
&i.ID,
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.PolicyRevision,
&i.SubscriptionVersion,
&i.Source,
&i.IdempotencyKey,
&i.State,
&i.CreatedAt,
&i.FinalizedAt,
)
return i, err
}
const incrementAutopilotQuotaBlocked = `-- name: IncrementAutopilotQuotaBlocked :one
UPDATE autopilot_quota_period
SET blocked_counts = jsonb_set(
blocked_counts,
ARRAY[$1::text],
to_jsonb(COALESCE((blocked_counts ->> $1::text)::bigint, 0) + 1),
true
),
updated_at = now()
WHERE workspace_id = $2
AND period_start = $3
AND period_end = $4
RETURNING workspace_id, period_start, period_end, used_count, reserved_count, blocked_counts, created_at, updated_at, rejection_notified_at
`
type IncrementAutopilotQuotaBlockedParams struct {
Source string `json:"source"`
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
}
func (q *Queries) IncrementAutopilotQuotaBlocked(ctx context.Context, arg IncrementAutopilotQuotaBlockedParams) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, incrementAutopilotQuotaBlocked,
arg.Source,
arg.WorkspaceID,
arg.PeriodStart,
arg.PeriodEnd,
)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}
const incrementAutopilotQuotaReserved = `-- name: IncrementAutopilotQuotaReserved :one
UPDATE autopilot_quota_period
SET reserved_count = reserved_count + 1,
updated_at = now()
WHERE workspace_id = $1 AND period_start = $2 AND period_end = $3
RETURNING workspace_id, period_start, period_end, used_count, reserved_count, blocked_counts, created_at, updated_at, rejection_notified_at
`
type IncrementAutopilotQuotaReservedParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
}
func (q *Queries) IncrementAutopilotQuotaReserved(ctx context.Context, arg IncrementAutopilotQuotaReservedParams) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, incrementAutopilotQuotaReserved, arg.WorkspaceID, arg.PeriodStart, arg.PeriodEnd)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}
const listRecoverableAutopilotQuotaReservations = `-- name: ListRecoverableAutopilotQuotaReservations :many
SELECT r.id, r.workspace_id, r.period_start, r.period_end, r.policy_revision, r.subscription_version, r.source, r.idempotency_key, r.state, r.created_at, r.finalized_at
FROM autopilot_quota_reservation r
LEFT JOIN autopilot_run ar ON ar.quota_reservation_id = r.id
WHERE r.state = 'reserved'
AND (
(
r.created_at < $1
AND (ar.id IS NULL OR ar.status IN ('completed', 'failed', 'skipped'))
)
OR (
-- Manual/API requests have no durable retry owner. Reclaim only an
-- hours-old partial run with neither a linked side effect nor even
-- an unlinked task row; schedule and webhook retries repair their
-- own partial state and are deliberately excluded.
r.created_at < $2
AND ar.source IN ('manual', 'api')
AND (
ar.status = 'pending'
OR (ar.status = 'issue_created' AND ar.issue_id IS NULL)
OR (ar.status = 'running' AND ar.task_id IS NULL)
)
AND NOT EXISTS (
SELECT 1
FROM agent_task_queue task
WHERE task.autopilot_run_id = ar.id
)
)
)
ORDER BY r.created_at
LIMIT $3
`
type ListRecoverableAutopilotQuotaReservationsParams struct {
TerminalCreatedBefore pgtype.Timestamptz `json:"terminal_created_before"`
PartialCreatedBefore pgtype.Timestamptz `json:"partial_created_before"`
RowLimit int32 `json:"row_limit"`
}
func (q *Queries) ListRecoverableAutopilotQuotaReservations(ctx context.Context, arg ListRecoverableAutopilotQuotaReservationsParams) ([]AutopilotQuotaReservation, error) {
rows, err := q.db.Query(ctx, listRecoverableAutopilotQuotaReservations, arg.TerminalCreatedBefore, arg.PartialCreatedBefore, arg.RowLimit)
if err != nil {
return nil, err
}
defer rows.Close()
items := []AutopilotQuotaReservation{}
for rows.Next() {
var i AutopilotQuotaReservation
if err := rows.Scan(
&i.ID,
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.PolicyRevision,
&i.SubscriptionVersion,
&i.Source,
&i.IdempotencyKey,
&i.State,
&i.CreatedAt,
&i.FinalizedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const markAutopilotQuotaRejectionNotified = `-- name: MarkAutopilotQuotaRejectionNotified :one
UPDATE autopilot_quota_period
SET rejection_notified_at = COALESCE(rejection_notified_at, now()),
updated_at = now()
WHERE workspace_id = $1
AND period_start = $2
AND period_end = $3
RETURNING workspace_id, period_start, period_end, used_count, reserved_count, blocked_counts, created_at, updated_at, rejection_notified_at
`
type MarkAutopilotQuotaRejectionNotifiedParams struct {
WorkspaceID pgtype.UUID `json:"workspace_id"`
PeriodStart pgtype.Timestamptz `json:"period_start"`
PeriodEnd pgtype.Timestamptz `json:"period_end"`
}
func (q *Queries) MarkAutopilotQuotaRejectionNotified(ctx context.Context, arg MarkAutopilotQuotaRejectionNotifiedParams) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, markAutopilotQuotaRejectionNotified, arg.WorkspaceID, arg.PeriodStart, arg.PeriodEnd)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}
const releaseAutopilotQuotaReservation = `-- name: ReleaseAutopilotQuotaReservation :one
WITH locked AS (
SELECT qr.id, qr.workspace_id, qr.period_start, qr.period_end, qr.policy_revision, qr.subscription_version, qr.source, qr.idempotency_key, qr.state, qr.created_at, qr.finalized_at FROM autopilot_quota_reservation qr
WHERE qr.id = $1 AND qr.state = 'reserved'
FOR UPDATE
), changed AS (
UPDATE autopilot_quota_reservation AS r
SET state = 'released', finalized_at = now()
FROM locked
WHERE r.id = locked.id
AND EXISTS (
SELECT 1 FROM autopilot_quota_period p
WHERE p.workspace_id = locked.workspace_id
AND p.period_start = locked.period_start
AND p.period_end = locked.period_end
)
RETURNING locked.workspace_id, locked.period_start, locked.period_end
)
UPDATE autopilot_quota_period AS p
SET reserved_count = reserved_count - 1,
updated_at = now()
FROM changed
WHERE p.workspace_id = changed.workspace_id
AND p.period_start = changed.period_start
AND p.period_end = changed.period_end
RETURNING p.workspace_id, p.period_start, p.period_end, p.used_count, p.reserved_count, p.blocked_counts, p.created_at, p.updated_at, p.rejection_notified_at
`
// Release is intentionally limited to still-reserved work. A consumed
// create_issue slot remains counted after cancellation, blocking, or deletion.
func (q *Queries) ReleaseAutopilotQuotaReservation(ctx context.Context, reservationID pgtype.UUID) (AutopilotQuotaPeriod, error) {
row := q.db.QueryRow(ctx, releaseAutopilotQuotaReservation, reservationID)
var i AutopilotQuotaPeriod
err := row.Scan(
&i.WorkspaceID,
&i.PeriodStart,
&i.PeriodEnd,
&i.UsedCount,
&i.ReservedCount,
&i.BlockedCounts,
&i.CreatedAt,
&i.UpdatedAt,
&i.RejectionNotifiedAt,
)
return i, err
}