---
id: TST-PFM-DJE-168
title: Custom field data jobs
kind: integration
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: services-platform
files:
  - modules/data-jobs/tests/integration/services/jobs/custom-field-data-jobs.integration.spec.js
implements:
  - ATS-PFM-DJE-018-03
  - ATS-PFM-DJE-018-07
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 5
isolation: >-
  Suite-owned fixture records, job identifiers and workspace contexts; teardown removes the fixture
  data.
evidence:
  - >-
    services-platform:modules/data-jobs/tests/integration/services/jobs/custom-field-data-jobs.integration.spec.js
assertion_inventory:
  - 'platform.custom_fields data operation: loading a tenant’s definitions'
  - 'finishes the job, because every definition was written'
  - counts one applied item for each definition and nothing else
  - 'reports each item as created, under the record id a definition has: its object and its key'
  - 'writes the currency definition the metadata module’s own way, configuration and all'
  - 'keeps a retired list option, with the option marked archived rather than dropped'
  - 'leaves the definitions live, because nothing in the dataset asked for an archived one'
  - 'platform.custom_fields data operation: the same dataset delivered twice'
  - >-
    takes the second delivery as a job of its own, because no idempotency key said it was the first
    one again
  - >-
    skips every item of the second delivery as a duplicate, because the crosswalk already holds each
    source key
  - 'finishes the second job without writing anything, so nothing is counted applied or rejected'
  - 'leaves the definitions as the first delivery wrote them, at their first version'
  - 'platform.custom_fields data operation: a producer changes a definition'
  - >-
    reports the item as updated rather than created, because the source key named a definition that
    exists
  - changes the label
  - 'raises the definition’s version, so the record and the crosswalk’s applied version agree'
  - 'refuses the same change as an insert, naming the definition rather than writing a second one'
  - 'platform.custom_fields data operation: one definition the metadata module refuses'
  - >-
    completes the job with its rejections rather than failing it, because one bad record is a
    record’s problem and not the job’s
  - applies the two good definitions and rejects only the bad one
  - records the rejection as an invalid value against the item that carried it
  - 'commits the good definitions, so a rejected neighbour rolled back only its own item'
  - 'leaves no definition behind for the refused record, under the key it named'
  - 'platform.custom_fields data operation: one tenant’s load is its own'
  - >-
    leaves the other tenant with none of the definitions, though it is a tenant that exists and
    holds rows
  - 'answers the other tenant 404 for the job, rather than letting it read one it does not own'
  - lists the job for its own tenant and no job at all for the other
  - >-
    lets the other tenant load the same source keys of its own, because a key is a key within a
    tenant
  - 'platform.custom_fields data operation: validating before applying'
  - 'reaches validated, with every item reported as one that would apply and none rejected'
  - writes no definition while it is only validated
  - 'writes them when the job is applied, under the same frozen items'
  - 'platform.custom_fields data operation: who may submit one'
  - accepts a caller holding the bulk right and the per-record ones (the positive control)
  - refuses a caller who may create a definition but holds no bulk right
  - refuses a caller holding the bulk right but no right to create a definition
  - 'platform.custom_fields data operation: a load that calls itself the tenant’s initial import'
  - >-
    refuses an initial import for a tenant that is live, because that is not what an initial import
    is for
  - accepts the same submission once the tenant is in the lifecycle state a load runs in
  - 'platform.custom_fields data operation: what a tenant reset removes'
  - 'leaves rows in every table a load writes, so what the purge removes is something'
  - 'empties every one of them, in as many batches as the purge asks for'
  - 'removes a tenant’s rows only, leaving another tenant’s load untouched'
  - >-
    platform.custom_fields data operation: a serialization failure on every attempt of a batch run
    in the request
  - 'pauses the job with the failed_transient pause code, because nothing will run the batch again'
  - writes no definition while the database refuses them
  - 'finishes the job once resumed, because a resume requeues the batch that gave up'
  - >-
    platform.custom_fields data operation: applying a validated insert needs the digest its
    validation answered
  - 'refuses an apply that carries no digest, naming impact_digest_required'
  - 'refuses an apply that carries another digest, naming impact_digest_mismatch'
  - >-
    carries the refusal code in the message, which is all the response body holds (PLAT-M19,
    CO-ACC-0400)
  - leaves the job validated and writes no definition after the refusals
  - applies the job with the digest the validation answered (the positive control)
  - 'platform.custom_fields data operation: a cancel that arrives while a batch runs'
  - 'answers the cancel while the batch is still running, with the job cancelling'
  - settles the job cancelled with no failure code once the batch finishes
registration_note: Registration describes existing source; the suite is not executed by this documentation job.
---

# Custom field data jobs

## Verification Boundary

The suite checks the production service or shared engine against its database fixture. The structured assertion inventory records the checks present at the pinned revision.

## What This Suite Proves

The existing checks exercise custom field data jobs. The specification bindings identify the narrower outcomes supported by those assertions.

## What It Does Not Prove

Local execution does not establish deployed queue, storage or service behavior. Independent test cases do not establish a complete cross-feature process.

## Real Dependencies and Test Doubles

The owning service exercises production persistence and domain behavior against real Postgres. The fixture supplies caller contexts; queue delivery, storage and external calls are doubled where the file installs a test port.

## Must Not Be Doubled

The database effects, security context and production operation under examination remain real. Their outcomes cannot be replaced with canned success responses.
