The interaction cases test how a shared holding, period, chapter connection or recorded change affects related work. Each case names its related capabilities and workflows in frontmatter. A composite case remains proposed until executable assertions establish every part of its expected outcome.
Coverage
Rulegap: FND-MBR-MEM-087
Transitiongap: FND-MBR-MEM-087
Validationcovered
Permissiongap: FND-MBR-MEM-087
Edgegap: FND-MBR-MEM-087
Failurecovered
Boundarycovered
Concurrencygap: FND-MBR-MEM-087
Invariantgap: FND-MBR-MEM-087
Interactioncovered
Test Scenarios
12 scenarios proving CAP-MBR-MEM-005; 9 bound to an existing test.
01Read standing across expiry and returnboundaryapitest
Sam has coverage separated by a lapse and a returning term.
Steps
[
{
"do": "Read Sam’s standing on dates during grace, during lapse and after his return.",
"expect": "Grace follows expiry, lapse follows the 60-day allowance, and return coverage is active.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/db/membership-functions.integration.spec.ts#answers Sam grace, lapsed, then active across the lapse and rejoin (scenario 4)",
"services-membership:modules/memberships/tests/integration/db/membership-functions.integration.spec.ts#answers Sam lapsed, not a member, on 2024-01-31 and active on 2024-12-31 in memberships_as_of",
"services-membership:tests/e2e/s04-lapse-and-rejoin.e2e.spec.ts#answers grace the day after the term ended and lapsed once the 60 days are over"
]
}
]
Expected
Grace follows expiry, lapse follows the 60-day allowance, and return coverage is active.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
Fixtures include empty, pending, future, current, non-benefit, grace, lapsed and suspended memberships.
Steps
[
{
"do": "Inspect each fixture’s derived standing and compare the non-benefit type’s result.",
"expect": "The fixtures return their expected standing, including active without benefits for the non-benefit type.",
"provenance": "test",
"source": [
"services-membership:tests/acceptance/memberships/MBR-ACC-0179.acceptance.ts#MBR-ACC-0179: Every status the engine can answer, from the terms and the type's or program's grace: none, pending, future, active, active without benefits, grace, lapsed and suspended, with the same answer from the SQL twins"
]
}
]
Expected
The fixtures return their expected standing, including active without benefits for the non-benefit type.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
services-membership:tests/acceptance/memberships/MBR-ACC-0179.acceptance.ts#MBR-ACC-0179: Every status the engine can answer, from the terms and the type's or program's grace: none, pending, future, active, active without benefits, grace, lapsed and suspended, with the same answer from the SQL twins
03Read current truth despite a stale cacheinvariantapitest
The clock has crossed expiry while saved status still reflects an earlier date.
Steps
[
{
"do": "Read the record before refreshing, then compare cached-status and current-status lists.",
"expect": "The record reflects expiry before a sweep; cached filtering can lag behind current filtering.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#answers the right status on each side of the expiry before any sweep runs (the resolver needs none)",
"services-membership:tests/acceptance/memberships/MBR-ACC-0178.acceptance.ts#MBR-ACC-0178: When the nightly sweep is missed the cached status lies but the record's status does not, lists filtered by the cache disagree with lists filtered by today's status, and only a catch-up repairs it"
]
}
]
Expected
The record reflects expiry before a sweep; cached filtering can lag behind current filtering.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
The previous sweep ran yesterday and one membership reaches an expiry boundary tonight.
Steps
[
{
"do": "Run the boundary sweep and inspect the examined count and refreshed status.",
"expect": "The boundary member is examined and refreshed to grace while mid-period memberships are omitted.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#examines only the memberships with a term at a boundary",
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#moves the cache to grace at the expiry boundary and records expired_detected"
]
}
]
Expected
The boundary member is examined and refreshed to grace while mid-period memberships are omitted.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
A dated period crosses expiry and grace-end boundaries, including a delayed sweep.
Steps
[
{
"do": "Sweep through expiry and repeat the day, then discover a lapse after its boundary.",
"expect": "Expiry retains the day after the term end; late lapse retains the day after grace, without duplicate detections.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#records lapsed_detected effective the day after grace ended, even when found late",
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#moves the cache to grace at the expiry boundary and records expired_detected",
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#records nothing twice when the same night is swept again"
]
}
]
Expected
Expiry retains the day after the term end; late lapse retains the day after grace, without duplicate detections.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
[
{
"do": "Run the next sweep and inspect its mode and every membership examined.",
"expect": "Catch-up examines all workspace memberships.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#catches up after a missed night, recomputing every membership"
]
}
]
Expected
Catch-up examines all workspace memberships.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
[
{
"do": "Repeat today’s on-demand sweep and inspect detection counts.",
"expect": "The repeat adds no new detections.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#records nothing twice when the same night is swept again",
"services-membership:tests/acceptance/memberships/MBR-ACC-0177.acceptance.ts#MBR-ACC-0177: An administrator runs the status sweep by hand: the first run catches up over every membership, later runs look only at today's boundaries, nothing is detected twice, and a cache-only change leaves no visible history"
]
}
]
Expected
The repeat adds no new detections.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
Sam’s returning term follows a gap longer than the continuity allowance.
Steps
[
{
"do": "Read the original join date and episode periods after the returning term.",
"expect": "The original join date is retained and two continuity episodes are returned.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/db/membership-functions.integration.spec.ts#answers Sam two continuity episodes (scenario 4)",
"services-membership:tests/e2e/s04-lapse-and-rejoin.e2e.spec.ts#keeps the original join date and restarts continuity at the rejoin (a gap of 437 days is more than 60)"
]
}
]
Expected
The original join date is retained and two continuity episodes are returned.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
A member belongs to multiple chapters under the same ancestor, with status and pagination fixtures.
Steps
[
{
"do": "List through ancestor and chapter filters, compare current and saved status, and exercise paging and malformed filters.",
"expect": "Each matching membership appears once per result set; paging follows id order and invalid filters are rejected by name.",
"provenance": "test",
"source": [
"services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#lists a member of two chapters once under their zone and region, and under each chapter",
"services-membership:tests/acceptance/memberships/MBR-ACC-0185.acceptance.ts#MBR-ACC-0185: Lists page by id in creation order with an opaque cursor, cap the page at 500, refuse a malformed limit, cursor, status, flag or date by name, and never silently ignore a parameter",
"services-membership:tests/acceptance/memberships/MBR-ACC-0178.acceptance.ts#MBR-ACC-0178: When the nightly sweep is missed the cached status lies but the record's status does not, lists filtered by the cache disagree with lists filtered by today's status, and only a catch-up repairs it"
]
}
]
Expected
Each matching membership appears once per result set; paging follows id order and invalid filters are rejected by name.
Data
Dated memberships, program and type settings, and the controlled clock or listing fixtures relevant to this case.
An officer reaches a chapter whose member has just expired.
Steps
[
{
"do": "Read and list the member with grace scope disabled and enabled, then move beyond the grace end.",
"expect": "Enabled grace includes the member during grace; the member leaves that reach after grace ends.",
"provenance": "proposed",
"source": [
"services-membership:modules/memberships/tests/integration/db/membership-functions.integration.spec.ts#answers Sam grace, lapsed, then active across the lapse and rejoin (scenario 4)",
"services-membership:modules/memberships/tests/unit/unit-scope.spec.ts#leaves a member in grace out when the roster rule excludes grace"
]
}
]
Expected
Enabled grace includes the member during grace; the member leaves that reach after grace ends.
Data
An isolated workspace with the specified membership, package, chapter and partner-port fixtures.
A member expires near month end and the status cache is stale.
Steps
[
{
"do": "Generate the monthly snapshot and compare its member row with the resolver at month end.",
"expect": "The row has the month-end standing rather than the stale cached value.",
"provenance": "proposed",
"source": [
"services-membership:modules/memberships/tests/integration/db/membership-functions.integration.spec.ts#answers Sam grace, lapsed, then active across the lapse and rejoin (scenario 4)",
"services-membership:modules/snapshots/tests/integration/snapshot-pipeline.integration.spec.ts#plans September’s first version for the tenant, once"
]
}
]
Expected
The row has the month-end standing rather than the stale cached value.
Data
An isolated workspace with the specified membership, package, chapter and partner-port fixtures.
A term has passed its final grace day without renewed coverage.
Steps
[
{
"do": "Run the status sweep after the lapse boundary, then repeat the same sweep.",
"expect": "The saved lapse detection and termination event retain the original last covered day and are not duplicated.",
"provenance": "proposed",
"source": [
"services-membership:modules/memberships/tests/integration/services/status-sweep.integration.spec.ts#records lapsed_detected effective the day after grace ended, even when found late",
"services-membership:modules/events/tests/integration/business-events.integration.spec.ts#states one membership.term.terminated for a staff termination, with the person’s contact_id and the last day of rights"
]
}
]
Expected
The saved lapse detection and termination event retain the original last covered day and are not duplicated.
Data
An isolated workspace with the specified membership, package, chapter and partner-port fixtures.