---
id: TST-CRM-ENT-795
title: Effective definitions and workspace context integration
kind: integration
product_area: crm
module: entities
revision: 1
status: draft
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
repository: services-crm
files:
  - modules/entities/tests/integration/db/ephemeral-tenant-copy.integration.spec.js
  - modules/entities/tests/integration/db/layout-assignments.integration.spec.js
  - modules/entities/tests/integration/services/api/list-pages.integration.spec.js
  - >-
    modules/entities/tests/integration/services/effective-definitions/resolve-effective-definitions.integration.spec.js
  - modules/entities/tests/integration/services/persistence/layout-definitions.queries.integration.spec.js
  - modules/entities/tests/integration/services/persistence/tenants.integration.spec.js
  - modules/entities/tests/integration/services/persistence/tenants.queries.integration.spec.js
  - modules/entities/tests/integration/services/persistence/user-names.queries.integration.spec.js
implements:
  - VT-IMC-CRM-ENT-001-01
  - ATS-CRM-ENT-003-02
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: null
estimate_basis: No measured duration is available for this cohesive group; per-file allowances are not runtime estimates.
isolation: >-
  The group owns the definitions and context fixtures it introduces. Copy tests use scope-owned ephemeral
  destinations. Platform seed rows provide controlled premises, and teardown follows the source-declared
  cleanup; serial execution prevents temporary producer-table changes from affecting another group.
binding_scope: >-
  Bindings preserve the existing assertion contributions and exact source file. Composite scenarios still
  require every bound contribution and any unbound checks; consolidation does not certify conformance.
bindings:
  - scenario: ATS-CRM-ENT-003-02
    source: >-
      services-crm:modules/entities/tests/integration/services/api/list-pages.integration.spec.js#refuses a
      search longer than the hundred characters the parameter takes, as ObjectInvalid
evidence:
  - 'services-crm:modules/entities/tests/integration/db/ephemeral-tenant-copy.integration.spec.js'
  - 'services-crm:modules/entities/tests/integration/db/layout-assignments.integration.spec.js'
  - 'services-crm:modules/entities/tests/integration/services/api/list-pages.integration.spec.js'
  - >-
    services-crm:modules/entities/tests/integration/services/effective-definitions/resolve-effective-definitions.integration.spec.js
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/layout-definitions.queries.integration.spec.js
  - 'services-crm:modules/entities/tests/integration/services/persistence/tenants.integration.spec.js'
  - 'services-crm:modules/entities/tests/integration/services/persistence/tenants.queries.integration.spec.js'
  - >-
    services-crm:modules/entities/tests/integration/services/persistence/user-names.queries.integration.spec.js
source_observations:
  - provenance: test
    source: 'services-crm:modules/entities/tests/integration/db/ephemeral-tenant-copy.integration.spec.js'
    declared_test_titles:
      - 'the ephemeral tenant copy: the order of the tables it copies (integration)'
      - 'finds foreign keys of the copied tables, so the order below is judged against something'
      - 'names only tables the schema has, so a name the copy would fail on is named here instead'
      - 'copies every table a copied table references, before the table that references it'
      - the ephemeral tenant copy of a tenant holding regions and contact types (integration)
      - >-
        writes the organization of the source tenant in the region, so the copy below has a reference to
        satisfy
      - 'writes the contact of the source tenant with the region and the type, so the copy below has two more'
      - 'copies the region into the destination tenant, under the id the source gave it'
      - copies the contact type into the destination tenant
      - 'copies the organization, still naming the region the copy brought with it'
      - 'copies the contact, still naming the region and the contact type the copy brought with it'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: 'services-crm:modules/entities/tests/integration/db/layout-assignments.integration.spec.js'
    declared_test_titles:
      - 'page-layout assignments, what the database itself keeps and refuses (integration)'
      - the contact type trigger
      - 'records one row per assigned slot, and none for a slot the type leaves empty'
      - 'names the contacts purpose on the row, and puts the id in its own slot’s column'
      - moves the row to the new definition when the assignment changes
      - 'removes the row of a slot the update clears, and leaves the others'
      - removes every row of the type when the type is deleted
      - the organization type trigger
      - 'records the assignment under the organizations purpose, not the contacts one'
      - removes it when the type is deleted
      - the crm settings trigger
      - 'records the contacts section as its own referrer, under the contacts purpose'
      - 'records the organizations section as a referrer of its own, under the organizations purpose'
      - 'removes one section’s row when that section is cleared, and leaves the other'
      - removes both sections when the settings row is deleted
      - 'the registry’s foreign keys, with the application’s own check skipped entirely'
      - >-
        accepts the five definitions in their own slots, so every refusal below is about the slot and not the
        id
      - refuses an id no definition has
      - 'refuses another tenant’s id, though it is a definition of the right kind and purpose'
      - 'refuses a definition of the other purpose: an organizations page layout on a contact type'
      - 'refuses a definition of the wrong kind: a console form in the console page layout slot'
      - 'refuses a portal form in the console create form slot, by that slot’s own key'
      - 'refuses a portal form in the console edit form slot, by that slot’s own key'
      - refuses an organizations console form in the console edit form slot of a contact type
      - >-
        leaves no contact type behind for a refused assignment: the write and its registry row are one
        transaction
      - a definition Platform tries to delete while it is assigned
      - 'is assigned to begin with, so the refusal below is about the assignment'
      - 'refuses the delete while the contact type points at it, even to the table’s owner'
      - allows the delete once the assignment is cleared
      - crm.crm_settings itself
      - takes one row per tenant and no more
      - refuses a lock value that is not one of the two the standard allows
      - holds all ten defaults empty for a tenant that has saved none of them
      - 'is invisible to another tenant, by the forced tenant policy and no predicate in the read'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: 'services-crm:modules/entities/tests/integration/services/api/list-pages.integration.spec.js'
    declared_test_titles:
      - affiliatedWith
      - the contacts list page (integration)
      - >-
        answers the whole first page: the two contacts in number order, the count, and the cursor of the next
        page
      - 'answers a cursor that is the base64url of `n:` and the record number the page ended at'
      - 'answers the whole second page from the cursor the first page gave, beginning after the record it names'
      - answers no cursor at all on a last page the limit fills exactly
      - 'answers an empty page, no cursor and a count of nothing for a tenant with no contacts'
      - 'answers only the id and the fields ?fields= asks for, the cursor of the page unchanged'
      - 'leaves out a field of ?fields= that the record does not carry, answering the id and the ones it does'
      - 'answers the whole record of every contact when ?fields= is empty, projecting nothing'
      - 'refuses a cursor of another list, as InvalidRequest naming it'
      - 'refuses a query parameter this list does not take, rather than ignoring it'
      - the contacts list page narrowed by ?organization_id= and ?search= (integration)
      - >-
        gives each of the two affiliated contacts one affiliation under a generated id, and the third none
        (premise)
      - 'answers all three contacts without either parameter, so each case below is about the parameter'
      - 'answers the whole page of the organization ?organization_id= names, and nothing else'
      - 'answers the whole page the name ?search= matches, whatever its case'
      - 'applies both together, and pages and projects within them as any page does'
      - 'answers an empty page and a count of nothing when nothing matches, rather than the whole list'
      - 'refuses a search longer than the hundred characters the parameter takes, as ObjectInvalid'
      - 'takes an empty ?organization_id= as no filter at all, which is the whole page'
      - the organizations list page (integration)
      - >-
        answers the whole first page: the two organizations in number order, the second with its derived
        ancestry
      - 'answers a cursor that is the base64url of `n:` and the organization number the page ended at'
      - 'answers the whole second page from that cursor, and no cursor of its own, the limit filling it exactly'
      - >-
        answers only the id and the fields ?fields= asks for, the ancestry of the child among them when it is
        asked for
      - 'answers the whole page the name ?search= matches, whatever its case'
      - 'answers an empty page for a ?search= nothing matches, rather than the whole list'
      - 'refuses a cursor of another list, as InvalidRequest naming it'
      - 'takes no ?organization_id=: an organization is not narrowed by an organization'
      - the contact roles list page (integration)
      - >-
        answers the whole first page: the alphabetical fallback of the order, the count, and the cursor of the
        next page
      - 'answers a cursor that is the base64url of `d:` and the place, name and id the page ended at, as JSON'
      - >-
        answers the whole second page from that cursor: the shared name is not repeated, and no cursor follows
        it
      - answers only the id and the fields ?fields= asks for
      - >-
        takes no ?search=: the name search is the contacts and organizations lists’ own, and is refused rather
        than ignored
      - 'refuses a cursor of another list, as InvalidRequest naming it'
      - 'refuses the cursor the contact types list answered, whose position has the same shape (DEF-CRM-0337)'
      - the contact types list page (integration)
      - 'answers the whole first page: the two types alphabetically, the count, and the cursor of the next page'
      - 'answers a cursor that is the base64url of `d:` and the place, name and id the page ended at'
      - 'answers the whole second page from that cursor, and no cursor of its own, the limit filling it exactly'
      - answers only the id and the fields ?fields= asks for
      - 'refuses a cursor of another list, as InvalidRequest naming it'
      - 'refuses the cursor the contact roles list answered, whose position has the same shape (DEF-CRM-0337)'
      - the affiliation types list page (integration)
      - 'answers the whole first page: the two types in id order, the count, and the cursor of the next page'
      - 'answers the whole second page from that cursor, and no cursor of its own, the limit filling it exactly'
      - answers only the id and the fields ?fields= asks for
      - 'refuses a cursor of another list, as InvalidRequest naming it'
      - the organization types list page (integration)
      - >-
        answers the whole first page: the two types alphabetically, each with its composed template null, and
        the next cursor
      - 'answers a cursor that is the base64url of `d:` and the place, name and id the page ended at'
      - 'answers the whole second page from that cursor, and no cursor of its own, the limit filling it exactly'
      - >-
        answers only the id and the fields ?fields= asks for, the composed template among them when it is
        asked for
      - 'refuses a cursor of another list, as InvalidRequest naming it'
      - 'refuses the cursor the contact types list answered, whose position has the same shape (DEF-CRM-0337)'
      - the regions list page (integration)
      - >-
        answers the whole page: every region of the tenant in id order, the count, and no cursor when none
        follows
      - 'refuses ?fields= on this list, which takes no projection, as ObjectInvalid naming the parameter'
      - the descendant contacts list and its legacy projection (integration)
      - gives each of the three contacts one affiliation under a generated id (premise)
      - >-
        answers the whole record of the organization’s own contact and of the contact below it, the
        organization’s own first
      - 'answers only the id and the fields the legacy ?fieldsToReturn= asks for, of every contact of the walk'
      - leaves out the contact of an organization that is not below the one asked about
      - answers the organization’s own contact alone when nothing below it holds one
      - the limit every list page shares (integration)
      - answers twenty-five records and the cursor of the twenty-fifth when the query names no limit
      - 'answers one record and a cursor at the lower bound of the limit, 1'
      - 'answers every record of the tenant and no cursor at the upper bound of the limit, 100'
      - 'refuses a limit below the lower bound, as ObjectInvalid naming the limit'
      - 'refuses a limit above the upper bound, as ObjectInvalid naming the limit'
      - 'refuses a limit that is not a number at all, as ObjectInvalid naming the limit'
      - 'refuses a query parameter no list page takes, as ObjectInvalid naming the parameter'
      - 'defaults the contacts list to a page of twenty-five, asking its persistence service for nothing else'
      - defaults the organizations list to a page of twenty-five
      - defaults the contact roles list to a page of twenty-five
      - defaults the organization types list to a page of twenty-five
      - defaults the contact types list to a page of twenty-five
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/effective-definitions/resolve-effective-definitions.integration.spec.js
    declared_test_titles:
      - the effective page layouts and forms of a record (integration)
      - a type that assigns all five
      - answers the type’s own definition for every one of the five kinds
      - 'resolves the two console forms independently, so a type may override one and inherit the other'
      - 'says what it answered for, the tenant of the execution included'
      - a type that assigns one of the five
      - answers the type’s definition for the kind it assigns
      - 'answers the tenant’s default for each kind the type leaves empty: a null means inherit, never none'
      - answers the tenant’s defaults throughout for a type that assigns nothing
      - 'answers the tenant’s defaults when no type is named at all, and says so with a null type_id'
      - the organizations entity
      - 'answers under its own purpose, from its own type and its own section of the defaults'
      - >-
        says a kind neither its type nor its own section configures is not configured, though contacts
        configures it
      - a context the request names
      - answers only the three console kinds for ?context=console
      - answers only the two portal kinds for ?context=portal
      - answers all five when the request names no context
      - a tenant that has configured nothing
      - says every kind is not configured rather than failing or inventing one
      - reaches none of the first tenant’s defaults
      - a type_id the tenant does not have
      - is refused as not found rather than answered with the tenant’s defaults
      - 'is refused for another tenant’s type, which exists but not here'
      - is refused for a contact type asked about as an organization type
      - a definition deleted after it was assigned
      - says the kind is not configured rather than answering a definition that is not there
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/layout-definitions.queries.integration.spec.js
    declared_test_titles:
      - Platform’s page layouts and forms as CRM reads them (integration)
      - assert_layout_assignments
      - 'passes an assignment of one definition of each kind, all of this tenant and this purpose'
      - passes an assignment that states nothing at all
      - 'passes a field cleared with null, which states no id to check'
      - 'refuses an id no definition has, in the words the subject gives it'
      - 'names the edit slot in its own refusal, so a person is told which of the two console forms is wrong'
      - 'passes the same definition in both console form slots: the two are independent, not exclusive'
      - 'refuses another tenant’s definition, which the tenant policy hides rather than a predicate of ours'
      - refuses a definition of the other purpose
      - 'refuses a definition of the wrong kind, because each slot is read from its own table only'
      - 'names the section in the path when the subject has one, as the tenant’s defaults do'
      - 'names the first wrong id when more than one is wrong, so a person is given one thing to fix'
      - read_layout_definitions
      - 'answers the definition of each slot asked for, its name and the layout Platform stored'
      - 'reads each kind from its own table, so five slots answer five definitions'
      - 'answers each console form slot its own definition, though both are read from the one table'
      - 'answers nothing for a slot whose id is not a definition of this tenant, and the rest as they are'
      - answers an empty map when nothing is asked for
      - answers another tenant nothing for a definition of this one
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: 'services-crm:modules/entities/tests/integration/services/persistence/tenants.integration.spec.js'
    declared_test_titles:
      - crm reads a tenant from platform.tenants (integration)
      - read_tenant_time_zone
      - answers the zone the tenant row carries
      - a tenant whose zone Platform changes
      - answered the zone the row carried before the change
      - 'answers the new zone, because the operation reads the row on every call'
      - a tenant whose row Platform removes
      - answered its zone while Platform held the row
      - 'answers undefined once the row is gone, which the boundary turns into a refusal'
      - the tenant boundary
      - 'answers another tenant''s zone, because the tenant is the argument and not the execution''s'
      - 'answers outside a transaction, on a connection where a tenant-owned CRM table is confined to nothing'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: 'services-crm:modules/entities/tests/integration/services/persistence/tenants.queries.integration.spec.js'
    declared_test_titles:
      - 'crm tenant time zone: read from platform.tenants'
      - 'answers the tenant''s own zone, as the row carries it'
      - 'answers undefined for a tenant that does not exist, which the boundary refuses'
      - 'answers a zone on the other side of the world, the column being read and not a constant'
      - 'answers each tenant the zone of its own row, three tenants holding three different zones'
      - 'answers the zone of the tenant it was asked for, never the one asked for before it'
      - 'crm tenant lifecycle: read from platform.tenants'
      - 'answers both state columns of the row, as the row carries them'
      - answers the default state of a tenant nothing has moved
      - answers undefined for a tenant Platform has no row for
      - allows a purge of the tenant Platform has marked deleting
      - 'refuses a purge of a tenant in service, naming the state it is in'
      - refuses a purge of a tenant Platform has no row for
      - 'crm tenant list: every tenant Platform has'
      - answers the seeded tenants a merge of a contact could belong to
      - 'answers a tenant registered after the process started, the list being a read and not a constant'
      - 'answers each tenant once, in id order, which is the order a sweep enters them in'
      - 'answers the ids alone, so nothing of a tenant but its id leaves Platform’s table'
      - answers nothing of a tenant that has been removed
      - 'crm operational tenant list: the tenants a deployment reconciles'
      - 'answers the active, the loading and the failed-provisioning tenants, and no other state'
      - answers a seeded tenant in service
      - 'answers each tenant once, in id order'
      - 'answers a tenant again once its provisioning is over, the state being read and not remembered'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
  - provenance: test
    source: >-
      services-crm:modules/entities/tests/integration/services/persistence/user-names.queries.integration.spec.js
    declared_test_titles:
      - record stamp names read (integration)
      - a contact
      - 'answers the creator’s display name, trimmed, in the create answer'
      - 'answers the first and last name of a modifier whose display name is blank, in the update answer'
      - 'answers both names on a read by another caller of the tenant, beside both ids'
      - still answers the name of a user who has since been deleted
      - 'answers the name, never the id, of a user the caller cannot see'
      - answers null for an id no user row answers for
      - 'never holds an empty creator id to name, because the database refuses one'
      - an organization
      - 'answers the creator’s display name, trimmed, in the create answer'
      - 'answers the first and last name of a modifier whose display name is blank, in the update answer'
      - 'answers both names on a read by another caller of the tenant, beside both ids'
      - still answers the name of a user who has since been deleted
      - 'answers the name, never the id, of a user the caller cannot see'
      - answers null for an id no user row answers for
      - 'never holds an empty creator id to name, because the database refuses one'
    skipped_declarations: []
    dependency_summary: >-
      The prepared PostgreSQL database and its declared constraints, policies and transaction behavior are
      real dependencies.
command: >-
  npx mocha --timeout 60000 'modules/entities/tests/integration/db/ephemeral-tenant-copy.integration.spec.js'
  'modules/entities/tests/integration/db/layout-assignments.integration.spec.js'
  'modules/entities/tests/integration/services/api/list-pages.integration.spec.js'
  'modules/entities/tests/integration/services/effective-definitions/resolve-effective-definitions.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/layout-definitions.queries.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/tenants.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/tenants.queries.integration.spec.js'
  'modules/entities/tests/integration/services/persistence/user-names.queries.integration.spec.js'
retries: none
proves_controls: []
product_intent: proposed
implementation_evidence: observed
narrative:
  status: enriched
---

# Effective definitions and workspace context integration

## Verification Boundary

CRM effective-definition resolution, Platform-owned layout reads, workspace context reads and shared list-page behavior cross real local database seams.

## What This Suite Proves

The tests establish selection of the stored form or layout assignment, validation of assignment references and source-aware workspace calendar reads. Shared list-page tests exercise paging at the local service adapter. Workspace lifecycle reads distinguish operational workspaces from those being deleted; ephemeral-copy tests exercise the copy-specific stored premise.

## What It Does Not Prove

This boundary does not prove Platform provisioning, deletion orchestration or a complete console form. It does not prove a deployed explorer query. The workspace-context reads are supporting contracts, and their inclusion does not transfer Platform ownership of the workspace lifecycle to Entities.

## Level and Rationale

Resolution requires actual assignments and definitions; supplied form answers would conceal mismatched purpose or workspace ownership. Fresh context reads are essential when Platform changes a calendar or state after a prior request. Real local tables establish that CRM observes the changed source rather than cached state.

## Real Dependencies and Test Doubles

CRM query functions and PostgreSQL are real. The prepared database holds the Platform-side reference tables and local stand-ins used by CRM. These fixtures establish the consumer contract; they do not certify the deployed producer or every published form-engine behavior.

## Must Not Be Doubled

Keep the assignment validation and referenced definitions real. Do not replace the workspace-state read when proving changed state is observed. Shared list-page tests must preserve the production paging adapter rather than return a preassembled page.

## Fixtures and Isolation

The group owns the definitions and context fixtures it introduces. Copy tests use scope-owned ephemeral destinations. Platform seed rows provide controlled premises, and teardown follows the source-declared cleanup; serial execution prevents temporary producer-table changes from affecting another group.

## Determinism and Retries

Fixtures state the expected calendar zones, state vocabulary and page limits. They compare fresh reads after a source change. This register adds no automatic retries or performance threshold, because neither would prove the actual ownership and reference contracts.

## How It Runs

Run the command in the frontmatter from the service repository after preparing the test database. It selects every file in this aggregate register under the repository Mocha bootstrap and runs serially. This is the aggregate selection of the integration gate; the complete repository integration command includes other modules and is wider than this register.

## Coverage Gaps

This register is a local consumer integration boundary. Cross-module lifecycle and deployed form-rendering proof remain with Platform and browser suites. The component pass still owes a precise allocation of these consumers and their operational controls; no broad Platform control claim is inferred here.
