---
id: TST-PFM-DJE-002
title: Admission planner
kind: unit
product_area: platform
module: data-job-engine
revision: 1
status: draft
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
repository: macroservice-libraries
files:
  - packages/data-jobs/src/admission-planner.spec.ts
implements:
  - ATS-PFM-DJE-014-06
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 1
isolation: In-memory fixtures and restored dependency doubles.
evidence:
  - 'macroservice-libraries:packages/data-jobs/src/admission-planner.spec.ts'
assertion_inventory:
  - '@rhythmsoftware/macroservice-data-jobs: the fair order of admission'
  - round-robin across tenants
  - gives the slots in turn to each tenant with batches waiting
  - gives a tenant with five jobs no more than a tenant with one (scenario 13)
  - >-
    gives the next slot to the tenant holding fewest in flight, so the rotation carries across
    rounds
  - counts a tenant's batches in flight on jobs with nothing left waiting
  - 'breaks a tie between equal tenants by the longest wait, then by the tenant id'
  - the oldest job first within a tenant
  - 'gives a tenant''s slots to its oldest job until that job''s ceiling, then to the next'
  - passes over an old job with nothing waiting
  - orders two jobs submitted at the same instant by their ids
  - 'no starvation: a job waiting more than ten minutes takes the next slot'
  - puts a starved job ahead of the round-robin
  - gives a starved job one slot and then returns it to the ordinary order
  - 'does not apply at exactly ten minutes, only past them'
  - serves several starved jobs longest-waiting first
  - 'never takes a slot past a ceiling: a starved job whose tenant is full waits'
  - 'treats a job with no `waitingSince` as served, however old'
  - takes the threshold the caller gives
  - the ceilings
  - 'holds each job to the per-job ceiling, counting what it has in flight'
  - holds each tenant to its own ceiling across its jobs
  - 'holds everyone to the global ceiling, counting what is in flight'
  - 'admits nothing, and asks for nothing back, when a ceiling is already exceeded'
  - admits no more than a job has waiting
  - 'admits nothing with no contenders, or a global ceiling of zero'
  - answers what `batchesToAdmit` answers for a job contending with no one
  - invariants over generated rounds
  - 'never passes a ceiling, and leaves no slot free that some job could have taken'
  - answers the same plan whatever the order of the contenders
  - gives every fair slot to a tenant holding no more than any other that could have taken it
  - rounds every five seconds
  - >-
    admits every job of five imports within the ten-minute rule, with the budget held throughout
    (scenario 13)
  - what it refuses
  - 'refuses a job listed twice, a tenant with no ceiling, and an instant that is not one'
registration_note: Registration describes existing source; the suite is not executed by this documentation job.
---

# Admission planner

## Verification Boundary

The suite checks an isolated production calculation, declaration or adapter. The structured assertion inventory records the checks present at the pinned revision.

## What This Suite Proves

The existing checks exercise admission planner. The specification bindings identify the narrower outcomes supported by those assertions.

## What It Does Not Prove

An isolated check does not establish a deployed workflow, database enforcement or complete feature acceptance.

## Real Dependencies and Test Doubles

The production function or declaration is exercised with in-memory inputs and dependency doubles. This boundary does not require a live database.

## Must Not Be Doubled

The production function under examination and its returned decisions remain real; replacing their answers defeats the check.
