---
id: ATS-MBR-STR-013
scope: CAP-MBR-STR-013
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-013-01
    title: Submitted grants exclude own-program and oversized lists
    level: api
    proves:
      - BR-CAP-MBR-STR-013-01
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: Submit a grant to the package’s own program and separately submit eleven grants.
    expected: Each invalid list fails without saving its package changes.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
    category: boundary
  - id: ATS-MBR-STR-013-02
    title: Grant classifications match their target program
    level: api
    proves:
      - BR-CAP-MBR-STR-013-02
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: Pair a grant program with a classification from another program.
    expected: The refusal identifies the grant classification.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:tests/e2e/database-refusals.e2e.spec.ts#mistakes only the database catches,
        through the API › DEF-MBR-0086: a configuration write a check, a foreign key or an integer column
        refuses › refuses a grant whose type is not of the granted program 400 naming grants:
        membership_type_id, and writes no package
      - TST-MBR-STR-095
    provenance: test
    source: >-
      services-membership:tests/e2e/database-refusals.e2e.spec.ts#mistakes only the database catches,
      through the API › DEF-MBR-0086: a configuration write a check, a foreign key or an integer column
      refuses › refuses a grant whose type is not of the granted program 400 naming grants:
      membership_type_id, and writes no package
    category: validation
  - id: ATS-MBR-STR-013-03
    title: Independent grant rules must be computable
    level: api
    proves:
      - BR-CAP-MBR-STR-013-03
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: Submit an independently dated grant without a required length.
    expected: The package write fails and names the grant rule problem.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to: []
    provenance: proposed
    source: >-
      services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
    category: validation
  - id: ATS-MBR-STR-013-04
    title: Package unit rows report combined problems
    level: api
    proves:
      - BR-CAP-MBR-STR-013-05
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: 'Submit an affiliation-disabled kind, duplicate kinds and contradictory counts.'
    expected: One response identifies every detected unit-rule problem.
    negative: true
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
        package's unit rules override the program's counts: the Regular package demands a chapter the
        program leaves optional, a Section-only package names a type the program does not list, a region
        is refused, and clearing the rules hands control back to the program
      - TST-MBR-STR-044
    provenance: test
    source: >-
      services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
      package's unit rules override the program's counts: the Regular package demands a chapter the
      program leaves optional, a Section-only package names a type the program does not list, a region is
      refused, and clearing the rules hands control back to the program
    category: validation
  - id: ATS-MBR-STR-013-05
    title: Package requirements specialize program defaults
    level: api
    proves:
      - BR-CAP-MBR-STR-013-06
    preconditions: >-
      An isolated Membership-licensed workspace contains the relevant records, with caller permissions
      selected for the case.
    steps: 'Require chapters for Regular, add a package-only kind and then clear package requirements.'
    expected: 'Package-specific counts and kinds apply first, with program defaults restored after clearing.'
    negative: false
    data_needs: The FAA example records or equivalent records prepared within the isolated workspace.
    bound_to:
      - >-
        services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
        package's unit rules override the program's counts: the Regular package demands a chapter the
        program leaves optional, a Section-only package names a type the program does not list, a region
        is refused, and clearing the rules hands control back to the program
      - >-
        services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#the
        term affiliations in the database › refuses a Regular term with no chapter: the package needs one
        (unit_minimum)
      - >-
        services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#the
        term affiliations in the database › refuses a second chapter on a Student term: the package
        allows one (unit_maximum)
      - TST-MBR-STR-044
      - TST-MBR-STR-002
    provenance: test
    source: >-
      services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
      package's unit rules override the program's counts: the Regular package demands a chapter the
      program leaves optional, a Section-only package names a type the program does not list, a region is
      refused, and clearing the rules hands control back to the program
    category: interaction
  - id: ATS-MBR-STR-013-06
    title: Grant replacement creates new child identities
    category: transition
    level: api
    proves:
      - BR-CAP-MBR-STR-013-04
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: >-
      Save a package with one grant, replace that grant list with the same submitted content at the
      current version and read the result.
    expected: The grant content remains equivalent and its child identity changes.
    negative: false
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/configuration/services/persistence/membership-packages.ts:replacePackageChildren
  - id: ATS-MBR-STR-013-07
    title: Omission and clearing have distinct list outcomes
    category: edge
    level: api
    proves:
      - BR-CAP-MBR-STR-013-07
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: >-
      Save fixed ends, grants and unit rules; omit all three in one update and send empty lists in the
      next.
    expected: Omission retains each list; the later accepted update removes all three lists.
    negative: true
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
  - id: ATS-MBR-STR-013-08
    title: Independent grants require a valid date rule
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-STR-013-03
      - BR-CAP-MBR-STR-015-01
    preconditions: An isolated workspace contains the records and current versions needed for the case.
    steps: >-
      Submit a grant using its own anniversary rule but missing length, then correct the rule and
      calculate its period beside the primary term.
    expected: The invalid aggregate saves nothing; the corrected rule yields the separately expected period.
    negative: false
    data_needs: Separate fixture records for the accepted and refused operations.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
      - >-
        services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
        reports every problem of a rule at once
    exercises:
      - CAP-MBR-STR-013
      - CAP-MBR-STR-015
  - id: ATS-MBR-STR-013-09
    title: Workspace authority gates this capability
    category: permission
    level: api
    proves:
      - BR-CAP-MBR-STR-019-02
    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-013
      - CAP-MBR-STR-019
evidence:
  - 'services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts'
  - 'services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts'
  - 'services-membership:tests/e2e/database-refusals.e2e.spec.ts'
  - >-
    services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
  - >-
    services-membership:tests/e2e/database-refusals.e2e.spec.ts#mistakes only the database catches,
    through the API › DEF-MBR-0086: a configuration write a check, a foreign key or an integer column
    refuses › refuses a grant whose type is not of the granted program 400 naming grants:
    membership_type_id, and writes no package
  - >-
    services-membership:modules/configuration/services/persistence/membership-packages.ts:replacePackageChildren
  - >-
    services-membership:modules/configuration/services/configuration/configuration-records.ts:unitRuleProblems
  - 'services-membership:modules/memberships/services/affiliations/unit-rules.ts'
  - 'react-console:acceptance/membership/inventory/business-rules.json#RUL-MBR-CFG-019'
  - >-
    services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
    package's unit rules override the program's counts: the Regular package demands a chapter the program
    leaves optional, a Section-only package names a type the program does not list, a region is refused,
    and clearing the rules hands control back to the program
  - >-
    services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
    reports every problem of a rule at once
  - membership.configuration.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: 'gap: FND-MBR-STR-066'
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-MBR-STR-066'
  boundary: covered
  concurrency: 'gap: FND-MBR-STR-066'
  invariant: 'gap: FND-MBR-STR-066'
  interaction: covered
coverage_notes:
  rule: >-
    No dedicated scenario establishes this category across the capability’s declared operations and
    design obligations.
  failure: >-
    No dedicated scenario establishes this category across the capability’s declared operations and
    design obligations.
  concurrency: >-
    No dedicated scenario establishes this category across the capability’s declared operations and
    design obligations.
  invariant: >-
    No dedicated scenario establishes this category across the capability’s declared operations and
    design obligations.
unproved_rules: []
coverage_obligations:
  permissions:
    - key: membership.configuration.manage
      scenario_ids:
        - ATS-MBR-STR-019-02
      local_scenario_ids:
        - ATS-MBR-STR-013-09
      coverage: partial
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
      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-013-09
      coverage: partial
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
      note: >-
        These cases establish declared authority or representative admission; exhaustive operation and
        caller combinations remain open.
  state_models: []
  related:
    - capability: CAP-MBR-STR-015
      scenario: ATS-MBR-STR-013-08
      provenance: proposed
  invariants:
    - id: INV-DOM-MBR-STR-004-01
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
    - id: INV-DOM-MBR-STR-004-02
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
    - id: INV-DOM-MBR-STR-004-03
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
    - id: INV-DOM-MBR-STR-004-04
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
    - id: INV-DOM-MBR-STR-004-05
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
    - id: INV-DOM-MBR-STR-004-06
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
    - id: INV-DOM-MBR-STR-004-07
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
  workflows:
    - id: WF-MBR-STR-004
      scenarios:
        - ATS-MBR-STR-013-05
        - ATS-MBR-STR-013-08
      unproved_failure_and_concurrency: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
  workflow_interactions:
    - workflow: WF-MBR-STR-004
      capability: CAP-MBR-STR-012
      scenario_ids:
        - ATS-MBR-STR-012-11
      coverage: specified
      gap: null
      provenance: documented
      source:
        - ATS-MBR-STR-012-11
      note: Cross-capability examples are cited from their owning specifications.
    - workflow: WF-MBR-STR-004
      capability: CAP-MBR-STR-008
      scenario_ids: []
      coverage: gap
      gap: FND-MBR-STR-066
      provenance: unknown
      source: FND-MBR-STR-066
      note: >-
        The shared workflow names both capabilities, but a concrete interaction oracle is not established
        for this pairing.
rule_coverage:
  - rule: BR-CAP-MBR-STR-013-01
    scenarios:
      - ATS-MBR-STR-013-01
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
  - rule: BR-CAP-MBR-STR-013-02
    scenarios:
      - ATS-MBR-STR-013-02
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:tests/e2e/database-refusals.e2e.spec.ts#mistakes only the database catches,
        through the API › DEF-MBR-0086: a configuration write a check, a foreign key or an integer column
        refuses › refuses a grant whose type is not of the granted program 400 naming grants:
        membership_type_id, and writes no package
  - rule: BR-CAP-MBR-STR-013-03
    scenarios:
      - ATS-MBR-STR-013-03
      - ATS-MBR-STR-013-08
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
      - >-
        services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
      - >-
        services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
        reports every problem of a rule at once
  - rule: BR-CAP-MBR-STR-013-04
    scenarios:
      - ATS-MBR-STR-013-06
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/configuration/services/persistence/membership-packages.ts:replacePackageChildren
  - rule: BR-CAP-MBR-STR-013-05
    scenarios:
      - ATS-MBR-STR-013-04
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
        package's unit rules override the program's counts: the Regular package demands a chapter the
        program leaves optional, a Section-only package names a type the program does not list, a region
        is refused, and clearing the rules hands control back to the program
  - rule: BR-CAP-MBR-STR-013-06
    scenarios:
      - ATS-MBR-STR-013-05
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:tests/acceptance/configuration/MBR-ACC-0104.acceptance.ts#MBR-ACC-0104: A
        package's unit rules override the program's counts: the Regular package demands a chapter the
        program leaves optional, a Section-only package names a type the program does not list, a region
        is refused, and clearing the rules hands control back to the program
  - rule: BR-CAP-MBR-STR-013-07
    scenarios:
      - ATS-MBR-STR-013-07
    gap: null
    provenance: documented
    source:
      - >-
        services-membership:modules/configuration/services/configuration/configuration-records.ts:packageResource
narrative_sources:
  - section: Coverage
    provenance: documented
    source:
      - CAP-MBR-STR-013
      - FND-MBR-STR-066
  - section: Interactions With Related Capabilities
    provenance: proposed
    source:
      - ATS-MBR-STR-013-05
      - ATS-MBR-STR-013-08
---

# Bundle grants and package-specific unit requirements: 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-013-01` | `ATS-MBR-STR-013-01` |
| `BR-CAP-MBR-STR-013-02` | `ATS-MBR-STR-013-02` |
| `BR-CAP-MBR-STR-013-03` | `ATS-MBR-STR-013-03`, `ATS-MBR-STR-013-08` |
| `BR-CAP-MBR-STR-013-04` | `ATS-MBR-STR-013-06` |
| `BR-CAP-MBR-STR-013-05` | `ATS-MBR-STR-013-04` |
| `BR-CAP-MBR-STR-013-06` | `ATS-MBR-STR-013-05` |
| `BR-CAP-MBR-STR-013-07` | `ATS-MBR-STR-013-07` |

## Interactions With Related Capabilities

Independent grants require a valid date rule. Submit a grant using its own anniversary rule but missing length, then correct the rule and calculate its period beside the primary term.
