---
id: ATS-MBR-STR-006
scope: CAP-MBR-STR-006
product_area: membership
module: structure
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-MBR-STR-006-01
    title: Unit codes distinguish records and reject malformed values
    level: api
    proves:
      - BR-CAP-MBR-STR-006-01
      - INV-DOM-MBR-STR-002-01
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: Attempt duplicate unit codes and a code containing uppercase letters.
    expected: Duplicate and malformed cases fail rather than creating another unit.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the refusals › refuses a code the tenant already has
      - TST-MBR-STR-006
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › the refusals › refuses a code the tenant already has
    category: validation
  - id: ATS-MBR-STR-006-02
    title: Detail replacement cannot relocate or reclassify
    level: api
    proves:
      - BR-CAP-MBR-STR-006-02
      - INV-DOM-MBR-STR-002-02
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: 'Include changed parent, kind and status alongside valid replacement details.'
    expected: The saved unit retains its structural fields.
    negative: false
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts#MBR-ACC-0032 a client
        that thinks PUT is a patch, and a unit deleted behind the service
      - TST-MBR-STR-089
    provenance: test
    source: >-
      services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts#MBR-ACC-0032 a client
      that thinks PUT is a patch, and a unit deleted behind the service
    category: invariant
  - id: ATS-MBR-STR-006-03
    title: E-mail normalization and validation are explicit
    level: api
    proves:
      - BR-CAP-MBR-STR-006-03
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: Compare a spaced mixed-case e-mail value with an invalid address.
    expected: The valid value returns normalized and the invalid value is refused.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to: []
    provenance: proposed
    source: 'services-membership:modules/structure/services/persistence/organizational-units.ts:attributeValues'
    category: validation
  - id: ATS-MBR-STR-006-04
    title: Geographic coordinates stay within their ranges
    level: api
    proves:
      - BR-CAP-MBR-STR-006-04
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: Attempt latitude above 90 and longitude below minus 180.
    expected: Each invalid coordinate fails and preserves the earlier unit.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-membership:modules/structure/db/organizational-units.table.ts:organizational_units_latitude_check
    category: boundary
  - id: ATS-MBR-STR-006-05
    title: Custom values validate and round-trip
    level: api
    proves:
      - BR-CAP-MBR-STR-006-06
      - INV-DOM-MBR-STR-002-08
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: 'Save, amend and clear configured values, then try unknown, archived and invalid fields.'
    expected: Allowed values return as saved and the invalid cases identify their fields.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0031.acceptance.ts#MBR-ACC-0031 every kind
        of custom field on a chapter
      - TST-MBR-STR-088
    provenance: test
    source: >-
      services-membership:tests/acceptance/structure/MBR-ACC-0031.acceptance.ts#MBR-ACC-0031 every kind
      of custom field on a chapter
    category: validation
  - id: ATS-MBR-STR-006-06
    title: Replacement defaults differ from custom-value omission
    level: api
    proves:
      - BR-CAP-MBR-STR-006-05
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: 'Omit phone and visibility in a current replacement, then reuse the previous version.'
    expected: >-
      Phone clears and visibility defaults to visible, omitted custom values remain and the stale write
      fails.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0007.acceptance.ts#MBR-ACC-0007 replacing
        a chapter: whole row for columns, patch for custom fields
      - TST-MBR-STR-066
    provenance: test
    source: >-
      services-membership:tests/acceptance/structure/MBR-ACC-0007.acceptance.ts#MBR-ACC-0007 replacing a
      chapter: whole row for columns, patch for custom fields
    category: concurrency
  - id: ATS-MBR-STR-006-07
    title: History is attributable and protected from direct writing
    level: api
    proves:
      - BR-CAP-MBR-STR-006-08
      - INV-DOM-MBR-STR-001-07
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: 'Create, replace and relocate a unit, then attempt an application-role write to its versions.'
    expected: Retained versions identify actors and the direct history write fails.
    negative: false
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the versions › writes a version of the unit for its creation, its update
        and its move, each with the actor of its context
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the versions › refuses the application role a direct write to a version
        table
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0030.acceptance.ts#MBR-ACC-0030 who
        changed what and when
      - TST-MBR-STR-006
      - TST-MBR-STR-087
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › the versions › writes a version of the unit for its creation, its update
      and its move, each with the actor of its context
    category: invariant
  - id: ATS-MBR-STR-006-08
    title: Custom values appear only in detailed reads
    category: rule
    level: api
    proves:
      - BR-CAP-MBR-STR-006-07
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: 'Create a unit with one configured custom value; read its details, flat list and branch tree.'
    expected: The detail answer contains the value and ordinary collection answers omit it.
    negative: false
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
  - id: ATS-MBR-STR-006-09
    title: Welcome selection remains a stored choice
    category: edge
    level: api
    proves:
      - BR-CAP-MBR-STR-006-09
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: Save a unit with a welcome-template selection and then replace it with another selection.
    expected: Each detail read returns the selected template; this case makes no claim that a message is sent.
    negative: true
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the versions › writes a version of the unit for its creation, its update
        and its move, each with the actor of its context
  - id: ATS-MBR-STR-006-10
    title: Unit details and organization history keep separate versions
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-STR-006-08
      - BR-CAP-MBR-STR-007-09
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: Save a unit detail change and then end one of its organization links; inspect both histories.
    expected: >-
      Unit versions describe the detail edit and link versions describe the ending with their respective
      actors.
    negative: false
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:getOrganizationalUnit
      - 'services-membership:docs/migrations/structure/README.md#Tables and migrations'
    exercises:
      - CAP-MBR-STR-006
      - CAP-MBR-STR-007
  - id: ATS-MBR-STR-006-11
    title: Finance replacement preserves unit structure
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-STR-006-02
      - BR-CAP-MBR-STR-008-06
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: >-
      Save financial settings, replace unit contact details and then replace financial settings at their
      own version.
    expected: The settings use their own version and the unit retains its kind and placement.
    negative: false
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
      - >-
        services-membership:modules/structure/services/persistence/organizational-unit-financial-settings.ts:setFinancialSettings
    exercises:
      - CAP-MBR-STR-006
      - CAP-MBR-STR-008
  - id: ATS-MBR-STR-006-12
    title: Workspace authority gates this capability
    category: permission
    level: api
    proves:
      - BR-CAP-MBR-STR-019-01
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: >-
      Exercise the capability’s exposed operations with its read-only and management callers, then repeat
      with application access removed, an unlicensed workspace and an unavailable workspace.
    expected: >-
      Each named operation requires its declared authority; admission failures occur before any record or
      calculated result is exposed.
    negative: true
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:tests/unit/route-authorization.spec.ts#route authorization: every Membership
        operation names its permission › requires membership.structure.read of every structure read and
        membership.structure.manage of every change
      - >-
        services-membership:modules/configuration/aws/api/configuration.routes.ts:configurationModuleRoutes
      - >-
        services-membership:tests/e2e/terms-api.e2e.spec.ts#the terms API, end to end in process ›
        refuses a caller who holds no key in the tenant
    exercises:
      - CAP-MBR-STR-006
      - CAP-MBR-STR-019
evidence:
  - >-
    services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts
  - 'services-membership:tests/acceptance/structure/MBR-ACC-0007.acceptance.ts'
  - 'services-membership:tests/acceptance/structure/MBR-ACC-0030.acceptance.ts'
  - 'services-membership:tests/acceptance/structure/MBR-ACC-0031.acceptance.ts'
  - 'services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts'
  - >-
    services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
    units in the database › the refusals › refuses a code the tenant already has
  - >-
    services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
  - 'services-membership:modules/structure/services/persistence/organizational-units.ts:attributeValues'
  - >-
    services-membership:modules/structure/db/organizational-units.table.ts:organizational_units_latitude_check
  - 'services-membership:docs/migrations/structure/README.md#Tables and migrations'
  - >-
    services-membership:modules/structure/services/persistence/organizational-units.ts:insertOrganizationalUnit
  - >-
    services-membership:modules/structure/services/persistence/organizational-units.ts:getOrganizationalUnit
  - >-
    services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
    units in the database › the versions › writes a version of the unit for its creation, its update and
    its move, each with the actor of its context
  - 'services-membership:modules/structure/metadata/structure.objects.ts:organizationalUnitsObject'
  - >-
    services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts#MBR-ACC-0032 a client that
    thinks PUT is a patch, and a unit deleted behind the service
  - >-
    services-membership:tests/acceptance/structure/MBR-ACC-0031.acceptance.ts#MBR-ACC-0031 every kind of
    custom field on a chapter
  - >-
    services-membership:tests/acceptance/structure/MBR-ACC-0007.acceptance.ts#MBR-ACC-0007 replacing a
    chapter: whole row for columns, patch for custom fields
  - >-
    services-membership:modules/structure/services/persistence/organizational-unit-financial-settings.ts:setFinancialSettings
  - membership.structure.read
  - membership.structure.manage
  - membership.application.access
  - >-
    services-membership:tests/unit/route-authorization.spec.ts#route authorization: every Membership
    operation names its permission › requires membership.structure.read of every structure read and
    membership.structure.manage of every change
  - 'services-membership:modules/configuration/aws/api/configuration.routes.ts:configurationModuleRoutes'
  - >-
    services-membership:tests/e2e/terms-api.e2e.spec.ts#the terms API, end to end in process › refuses a
    caller who holds no key in the tenant
coverage:
  rule: covered
  transition: not-applicable
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-MBR-STR-059'
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  transition: >-
    This capability reads or changes facets without owning a standing transition; the owning lifecycle
    specification carries those transitions.
  failure: >-
    No dedicated scenario establishes this category across the capability’s declared operations and
    design obligations.
unproved_rules: []
coverage_obligations:
  permissions:
    - key: membership.structure.read
      scenario_ids:
        - ATS-MBR-STR-019-01
      local_scenario_ids:
        - ATS-MBR-STR-006-12
      coverage: partial
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
      note: >-
        These cases establish declared authority or representative admission; exhaustive operation and
        caller combinations remain open.
    - key: membership.structure.manage
      scenario_ids:
        - ATS-MBR-STR-019-01
      local_scenario_ids:
        - ATS-MBR-STR-006-12
      coverage: partial
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
      note: >-
        These cases establish declared authority or representative admission; exhaustive operation and
        caller combinations remain open.
    - key: membership.application.access
      scenario_ids:
        - ATS-MBR-STR-019-04
      local_scenario_ids:
        - ATS-MBR-STR-006-12
      coverage: partial
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
      note: >-
        These cases establish declared authority or representative admission; exhaustive operation and
        caller combinations remain open.
  state_models: []
  related:
    - capability: CAP-MBR-STR-007
      scenario: ATS-MBR-STR-006-10
      provenance: proposed
    - capability: CAP-MBR-STR-008
      scenario: ATS-MBR-STR-006-11
      provenance: proposed
  invariants:
    - id: INV-DOM-MBR-STR-002-01
      scenario_ids:
        - ATS-MBR-STR-006-01
      coverage: specified
      gap: null
      provenance: documented
      source:
        - >-
          services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
          units in the database › the refusals › refuses a code the tenant already has
    - id: INV-DOM-MBR-STR-002-02
      scenario_ids:
        - ATS-MBR-STR-006-02
      coverage: specified
      gap: null
      provenance: documented
      source:
        - >-
          services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts#MBR-ACC-0032 a client
          that thinks PUT is a patch, and a unit deleted behind the service
    - id: INV-DOM-MBR-STR-002-03
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
    - id: INV-DOM-MBR-STR-002-04
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
    - id: INV-DOM-MBR-STR-002-05
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
    - id: INV-DOM-MBR-STR-002-06
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
    - id: INV-DOM-MBR-STR-002-07
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
    - id: INV-DOM-MBR-STR-002-08
      scenario_ids:
        - ATS-MBR-STR-006-05
      coverage: specified
      gap: null
      provenance: documented
      source:
        - >-
          services-membership:tests/acceptance/structure/MBR-ACC-0031.acceptance.ts#MBR-ACC-0031 every
          kind of custom field on a chapter
    - id: INV-DOM-MBR-STR-002-09
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
  workflows:
    - id: WF-MBR-STR-001
      scenarios:
        - ATS-MBR-STR-006-06
        - ATS-MBR-STR-006-10
        - ATS-MBR-STR-006-11
      unproved_failure_and_concurrency: FND-MBR-STR-059
      provenance: unknown
      source: FND-MBR-STR-059
  workflow_interactions:
    - workflow: WF-MBR-STR-001
      capability: CAP-MBR-STR-002
      scenario_ids:
        - ATS-MBR-STR-002-15
      coverage: specified
      gap: null
      provenance: documented
      source:
        - ATS-MBR-STR-002-15
      note: Cross-capability examples are cited from their owning specifications.
rule_coverage:
  - rule: BR-CAP-MBR-STR-006-01
    scenarios:
      - ATS-MBR-STR-006-01
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the refusals › refuses a code the tenant already has
  - rule: BR-CAP-MBR-STR-006-02
    scenarios:
      - ATS-MBR-STR-006-02
      - ATS-MBR-STR-006-11
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0032.acceptance.ts#MBR-ACC-0032 a client
        that thinks PUT is a patch, and a unit deleted behind the service
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
      - >-
        services-membership:modules/structure/services/persistence/organizational-unit-financial-settings.ts:setFinancialSettings
  - rule: BR-CAP-MBR-STR-006-03
    scenarios:
      - ATS-MBR-STR-006-03
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:attributeValues
  - rule: BR-CAP-MBR-STR-006-04
    scenarios:
      - ATS-MBR-STR-006-04
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/structure/db/organizational-units.table.ts:organizational_units_latitude_check
  - rule: BR-CAP-MBR-STR-006-05
    scenarios:
      - ATS-MBR-STR-006-06
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0007.acceptance.ts#MBR-ACC-0007 replacing
        a chapter: whole row for columns, patch for custom fields
  - rule: BR-CAP-MBR-STR-006-06
    scenarios:
      - ATS-MBR-STR-006-05
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:tests/acceptance/structure/MBR-ACC-0031.acceptance.ts#MBR-ACC-0031 every kind
        of custom field on a chapter
  - rule: BR-CAP-MBR-STR-006-07
    scenarios:
      - ATS-MBR-STR-006-08
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
  - rule: BR-CAP-MBR-STR-006-08
    scenarios:
      - ATS-MBR-STR-006-07
      - ATS-MBR-STR-006-10
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the versions › writes a version of the unit for its creation, its update
        and its move, each with the actor of its context
      - >-
        services-membership:modules/structure/services/persistence/organizational-units.ts:getOrganizationalUnit
      - 'services-membership:docs/migrations/structure/README.md#Tables and migrations'
  - rule: BR-CAP-MBR-STR-006-09
    scenarios:
      - ATS-MBR-STR-006-09
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
        units in the database › the versions › writes a version of the unit for its creation, its update
        and its move, each with the actor of its context
narrative_sources:
  - section: Coverage
    provenance: documented
    source:
      - CAP-MBR-STR-006
      - FND-MBR-STR-059
  - section: Interactions With Related Capabilities
    provenance: proposed
    source:
      - ATS-MBR-STR-006-10
      - ATS-MBR-STR-006-11
---

# Maintain a unit’s identity and local details: Capability Test Specification

## Coverage

The coverage map distinguishes specified examples from missing proof. A covered category means an expected case is specified; executable bindings and their run results remain separate evidence. Each required rule has a proof link or an explicit coverage finding in the structured rule ledger.

| Required Rule | Scenario or Finding |
|---|---|
| `BR-CAP-MBR-STR-006-01` | `ATS-MBR-STR-006-01` |
| `BR-CAP-MBR-STR-006-02` | `ATS-MBR-STR-006-02`, `ATS-MBR-STR-006-11` |
| `BR-CAP-MBR-STR-006-03` | `ATS-MBR-STR-006-03` |
| `BR-CAP-MBR-STR-006-04` | `ATS-MBR-STR-006-04` |
| `BR-CAP-MBR-STR-006-05` | `ATS-MBR-STR-006-06` |
| `BR-CAP-MBR-STR-006-06` | `ATS-MBR-STR-006-05` |
| `BR-CAP-MBR-STR-006-07` | `ATS-MBR-STR-006-08` |
| `BR-CAP-MBR-STR-006-08` | `ATS-MBR-STR-006-07`, `ATS-MBR-STR-006-10` |
| `BR-CAP-MBR-STR-006-09` | `ATS-MBR-STR-006-09` |

## Interactions With Related Capabilities

Unit details and organization history keep separate versions. Save a unit detail change and then end one of its organization links; inspect both histories.

Finance replacement preserves unit structure. Save financial settings, replace unit contact details and then replace financial settings at their own version.
