The Rules section is one record table grouped by kind, Limit then Boolean, on fixed columns, edited in place: Edit opens a row's controls in their columns, Add rule opens a dense row above the table, and every change is staged into a tray that lists the deltas with Undo and applies them as one rule-change act. The reduction policy is a column of the rule beside its limit. History shows counts only. Group rows are a quiet heading rather than a divider, the maintainer's pick from four rounds of outside-model ideation. Dense rows align to the top and render each error under its control in every form family (design D16), replacing the below-row error block; the forms library gains the batch form (rows plus one tray) and the RowField dense and label-hidden options. Migration 00019 records the governing reduction policy on effect rows. Archive staged-rule-changes with its spec updates (entitlement-set- management, entitlement-set-history, entitlements, form-library, form-conventions, ui-quality-gate). Screens accepted 2026-09-19.
214 lines
10 KiB
SQL
214 lines
10 KiB
SQL
-- The act rows (core.entitlement_set_changes) and the effect rows
|
|
-- (core.entitlement_set_change_effects) are append-only: nothing in this file
|
|
-- updates or deletes one. Both are written by core.commit_rule_change and
|
|
-- core.settle_obligation, so no Create query exists for any of the three
|
|
-- tables. The obligations are the one mutable table, a work list rather than
|
|
-- history, and only its status columns move.
|
|
|
|
-- name: CommitRuleChange :one
|
|
-- The only write path to core.entitlement_set_rules. The calling transaction
|
|
-- must hold the exclusive materialization rendezvous, which the function
|
|
-- asserts: open it with BeginRuleChange.
|
|
SELECT (r).change_id::uuid AS change_id,
|
|
(r).rule_id::uuid AS rule_id,
|
|
(r).sync_path::varchar AS sync_path,
|
|
(r).pool_count::integer AS pool_count,
|
|
(r).org_count::integer AS org_count,
|
|
(r).suspended_only_count::integer AS suspended_only_count
|
|
FROM core.commit_rule_change(
|
|
sqlc.arg(set_id)::uuid,
|
|
sqlc.arg(change_kind)::varchar,
|
|
sqlc.narg(rule_id)::uuid,
|
|
sqlc.arg(rule)::jsonb,
|
|
sqlc.arg(actor_type)::varchar,
|
|
sqlc.narg(actor_person_id)::uuid,
|
|
sqlc.narg(actor_service_account_id)::uuid,
|
|
sqlc.narg(note)::text,
|
|
sqlc.narg(request_id)::varchar,
|
|
sqlc.arg(effective_at)::timestamptz,
|
|
sqlc.arg(sync_cap)::integer
|
|
) AS r;
|
|
|
|
-- name: SettleObligation :one
|
|
-- Records what one pool's recomputation did and marks the obligation. The
|
|
-- calling transaction must hold the rendezvous in either mode.
|
|
SELECT core.settle_obligation(
|
|
sqlc.arg(change_id)::uuid,
|
|
sqlc.arg(pool_id)::uuid,
|
|
sqlc.arg(effects)::jsonb,
|
|
NULL
|
|
)::integer AS effects_written;
|
|
|
|
-- name: MarkObligationFailed :exec
|
|
-- The failure half of the same function: no effect rows, the attempt and its
|
|
-- error recorded, and the row failed once attempts reach max_attempts.
|
|
SELECT core.settle_obligation(
|
|
sqlc.arg(change_id)::uuid,
|
|
sqlc.arg(pool_id)::uuid,
|
|
'[]'::jsonb,
|
|
sqlc.arg(failure)::text,
|
|
sqlc.arg(max_attempts)::integer
|
|
);
|
|
|
|
-- name: ListPendingObligations :many
|
|
-- The drain's work list for one change. failed is the dead letter: the drain
|
|
-- never picks one up again, and only RequeueFailedObligations, which the
|
|
-- operator's Retry calls, returns it to pending.
|
|
SELECT change_id, pool_id, status, attempts, last_attempt_at, last_error, settled_at, created_at
|
|
FROM core.entitlement_set_change_obligations
|
|
WHERE change_id = $1 AND status = 'pending'
|
|
ORDER BY pool_id ASC
|
|
LIMIT $2;
|
|
|
|
-- name: ListChangesWithUnsettledObligations :many
|
|
-- The poller's entry point, oldest act first: changes that still owe a
|
|
-- pending pool. A change whose remaining rows are all failed owes the drain
|
|
-- nothing until an operator's Retry requeues them.
|
|
SELECT DISTINCT o.change_id, c.set_id, MIN(o.created_at)::timestamptz AS oldest_created_at
|
|
FROM core.entitlement_set_change_obligations o
|
|
JOIN core.entitlement_set_changes c ON c.change_id = o.change_id
|
|
WHERE o.status = 'pending'
|
|
GROUP BY o.change_id, c.set_id
|
|
ORDER BY oldest_created_at ASC, o.change_id ASC
|
|
LIMIT $1;
|
|
|
|
-- name: CountUnsettledObligationsBySet :one
|
|
-- What the set's Rules section reads: still draining and failed, separately.
|
|
SELECT
|
|
COUNT(*) FILTER (WHERE o.status = 'pending')::BIGINT AS pending_count,
|
|
COUNT(*) FILTER (WHERE o.status = 'failed')::BIGINT AS failed_count
|
|
FROM core.entitlement_set_change_obligations o
|
|
JOIN core.entitlement_set_changes c ON c.change_id = o.change_id
|
|
WHERE c.set_id = $1;
|
|
|
|
-- name: CountFailedObligationsBySets :many
|
|
-- The same count for a page of sets in one query rather than one per row.
|
|
SELECT c.set_id, COUNT(*)::BIGINT AS failed_count
|
|
FROM core.entitlement_set_change_obligations o
|
|
JOIN core.entitlement_set_changes c ON c.change_id = o.change_id
|
|
WHERE c.set_id = ANY(sqlc.arg(set_ids)::uuid[]) AND o.status = 'failed'
|
|
GROUP BY c.set_id
|
|
ORDER BY c.set_id ASC;
|
|
|
|
-- name: ListFailedObligations :many
|
|
SELECT o.change_id, o.pool_id, o.attempts, o.last_attempt_at, o.last_error,
|
|
rp.org_id, org.name AS org_name, c.resource_key, c.resource_label
|
|
FROM core.entitlement_set_change_obligations o
|
|
JOIN core.entitlement_set_changes c ON c.change_id = o.change_id
|
|
JOIN core.resource_pools rp ON rp.pool_id = o.pool_id
|
|
JOIN core.organizations org ON org.org_id = rp.org_id
|
|
WHERE c.set_id = $1 AND o.status = 'failed'
|
|
ORDER BY org.name ASC, o.pool_id ASC
|
|
LIMIT $2;
|
|
|
|
-- name: RequeueFailedObligations :exec
|
|
-- The Retry control: failed rows go back on the work list with their attempt
|
|
-- count reset, so the drain gives each a fresh run of recomputeMaxAttempts.
|
|
UPDATE core.entitlement_set_change_obligations o
|
|
SET status = 'pending', attempts = 0, last_error = NULL
|
|
FROM core.entitlement_set_changes c
|
|
WHERE c.change_id = o.change_id AND c.set_id = $1 AND o.status = 'failed';
|
|
|
|
-- name: ListEntitlementSetChanges :many
|
|
-- The paged History of one set. The per-change counts are correlated
|
|
-- subqueries over the obligations and the effects, not stored columns.
|
|
SELECT c.change_id, c.set_id, c.set_name, c.change_kind, c.rule_id,
|
|
c.resource_key, c.resource_label, c.rule_before, c.rule_after, c.rule_type,
|
|
c.value_before, c.value_after, c.per_unit_before, c.per_unit_after,
|
|
c.actor_type, c.actor_person_id, c.actor_service_account_id,
|
|
c.note, c.request_id, c.sync_path, c.effective_at, c.created_at,
|
|
(SELECT COUNT(*) FROM core.entitlement_set_change_obligations o
|
|
WHERE o.change_id = c.change_id)::BIGINT AS pools_enumerated,
|
|
(SELECT COUNT(*) FROM core.entitlement_set_change_obligations o
|
|
WHERE o.change_id = c.change_id AND o.status = 'settled')::BIGINT AS pools_settled,
|
|
(SELECT COUNT(*) FROM core.entitlement_set_change_obligations o
|
|
WHERE o.change_id = c.change_id AND o.status = 'failed')::BIGINT AS pools_failed,
|
|
(SELECT COUNT(DISTINCT e.pool_id) FROM core.entitlement_set_change_effects e
|
|
WHERE e.change_id = c.change_id)::BIGINT AS pools_with_effects,
|
|
(SELECT COUNT(DISTINCT e.pool_id) FROM core.entitlement_set_change_effects e
|
|
WHERE e.change_id = c.change_id AND e.over_usage)::BIGINT AS pools_over_usage
|
|
FROM core.entitlement_set_changes c
|
|
WHERE c.set_id = $1
|
|
ORDER BY c.effective_at DESC, c.created_at DESC, c.change_id DESC
|
|
LIMIT $2 OFFSET $3;
|
|
|
|
-- name: CountEntitlementSetChanges :one
|
|
SELECT COUNT(*)::BIGINT AS change_count
|
|
FROM core.entitlement_set_changes
|
|
WHERE set_id = $1;
|
|
|
|
-- name: ListEntitlementSetChangeEffects :many
|
|
-- The History row's expander: what one change did, per organization and key.
|
|
SELECT e.effect_id, e.change_id, e.pool_id, e.org_id, e.org_name,
|
|
e.resource_key, e.resource_label,
|
|
e.limit_before, e.limit_after, e.granted_before, e.granted_after,
|
|
e.usage_at_effect, e.over_usage, e.was_over_before, e.reduction_policy, e.created_at,
|
|
e.governing_policy
|
|
FROM core.entitlement_set_change_effects e
|
|
WHERE e.change_id = $1
|
|
ORDER BY e.org_name ASC, e.resource_key ASC
|
|
LIMIT $2;
|
|
|
|
-- name: ListEntitlementSetChangeEffectsByOrg :many
|
|
-- The organization's trail: every rule change that moved one of its pools.
|
|
-- This is the effect row's audit projection (entitlement-set-history, "The
|
|
-- change row and every effect row project onto the audit view shape"): the
|
|
-- pool as the resource, the act's actor triple and occurrence reached through
|
|
-- the foreign key, and the payload's fields, which carry both policies, the
|
|
-- rule's own and the one that governed the pool and key.
|
|
SELECT e.effect_id, e.change_id, e.pool_id, e.org_id, e.org_name,
|
|
e.resource_key, e.resource_label,
|
|
e.limit_before, e.limit_after, e.granted_before, e.granted_after,
|
|
e.usage_at_effect, e.over_usage, e.was_over_before,
|
|
e.reduction_policy, e.governing_policy, e.created_at,
|
|
c.set_id, c.set_name, c.change_kind, c.effective_at,
|
|
c.note, c.actor_type, c.actor_person_id, c.actor_service_account_id
|
|
FROM core.entitlement_set_change_effects e
|
|
JOIN core.entitlement_set_changes c ON c.change_id = e.change_id
|
|
WHERE e.org_id = $1
|
|
ORDER BY e.created_at DESC, e.effect_id DESC
|
|
LIMIT $2 OFFSET $3;
|
|
|
|
-- name: CountEntitlementSetChangeEffectsByOrg :one
|
|
SELECT COUNT(*)::BIGINT AS effect_count
|
|
FROM core.entitlement_set_change_effects
|
|
WHERE org_id = $1;
|
|
|
|
-- name: GetRuleChangeStamp :one
|
|
-- The changed rule's resource key and reduction policy. The policy is
|
|
-- stamped on that key's effect row alone (doc-47 §5.2: the reduction policy
|
|
-- is the changed rule's, where the key is the rule's), so the key comes back
|
|
-- with it. The drain reads the pair once per change.
|
|
SELECT r.resource_key, r.tier_reduction_policy
|
|
FROM core.entitlement_set_changes c
|
|
JOIN core.entitlement_set_rules r ON r.rule_id = c.rule_id
|
|
WHERE c.change_id = $1;
|
|
|
|
-- name: GetObligationStatus :one
|
|
-- One obligation's state, which the drain reads before it does any work: an
|
|
-- obligation already settled is returned to a redispatched drain untouched.
|
|
SELECT status, attempts
|
|
FROM core.entitlement_set_change_obligations
|
|
WHERE change_id = $1 AND pool_id = $2;
|
|
|
|
-- name: ListChangesSharingRequest :many
|
|
-- The acts of one applied batch: the change named and every other act on the
|
|
-- same set carrying the same request identifier, which is what relates them
|
|
-- (entitlement-set-history, "Every committed act writes one change row and
|
|
-- one effect row per pool and key that moved"). Each comes back with its
|
|
-- rule's key and reduction policy, so the drain stamps and routes from one
|
|
-- read. The order is the commit's own, resource key ascending under the C
|
|
-- collation, which is the byte order Go sorted the deltas by, so the drain
|
|
-- re-derives the order the acts were filed in whatever the database's own
|
|
-- collation is; the first row is then the batch's first act, the one a
|
|
-- movement on a key no act names hangs off. A change with no request
|
|
-- identifier returns itself alone.
|
|
SELECT c.change_id, r.resource_key, r.tier_reduction_policy
|
|
FROM core.entitlement_set_changes c
|
|
JOIN core.entitlement_set_rules r ON r.rule_id = c.rule_id
|
|
JOIN core.entitlement_set_changes named ON named.change_id = sqlc.arg(change_id)::uuid
|
|
WHERE c.set_id = named.set_id
|
|
AND (c.change_id = named.change_id
|
|
OR (named.request_id IS NOT NULL AND c.request_id = named.request_id))
|
|
ORDER BY r.resource_key COLLATE "C" ASC NULLS FIRST, c.change_id ASC;
|