---
id: TST-MBR-STR-019
title: Date-rule calculations and validation
kind: unit
product_area: membership
module: structure
revision: 1
status: draft
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
repository: services-membership
files:
  - modules/terms/tests/unit/term-rules.spec.ts
implements:
  - ATS-MBR-STR-015-01
  - ATS-MBR-STR-015-03
  - ATS-MBR-STR-015-04
  - ATS-MBR-STR-015-05
  - ATS-MBR-STR-015-06
  - ATS-MBR-STR-015-07
  - ATS-MBR-STR-015-08
  - ATS-MBR-STR-015-09
environment: mock
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 1
isolation: Literal inputs and temporary fixtures created by this suite.
evidence:
  - 'services-membership:modules/terms/tests/unit/term-rules.spec.ts'
bindings:
  - scenario: ATS-MBR-STR-015-01
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      reports every problem of a rule at once
    provenance: test
  - scenario: ATS-MBR-STR-015-01
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      refuses a calendar term counted in anything but years
    provenance: test
  - scenario: ATS-MBR-STR-015-01
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      refuses a rule it cannot compute, naming what is wrong
    provenance: test
  - scenario: ATS-MBR-STR-015-03
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: the rules of 1.0 beyond
      its spec cases › extends an early renewal from the current end, whatever the basis
    provenance: test
  - scenario: ATS-MBR-STR-015-03
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: the rules of 1.0 beyond
      its spec cases › back-dates a late renewal to the day after the current end
    provenance: test
  - scenario: ATS-MBR-STR-015-03
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      starts a term fresh from the basis when the rule does not continue from the end (1.0 always
      continued)
    provenance: test
  - scenario: ATS-MBR-STR-015-04
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: the rules of 1.0 beyond
      its spec cases › continues a terminated term on the last day of its window
    provenance: test
  - scenario: ATS-MBR-STR-015-04
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: the rules of 1.0 beyond
      its spec cases › restarts a terminated term the day after its window closes
    provenance: test
  - scenario: ATS-MBR-STR-015-04
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: the rules of 1.0 beyond
      its spec cases › restarts a terminated term at once when the rule has no reinstatement window
    provenance: test
  - scenario: ATS-MBR-STR-015-05
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: 1.0
      calculate-expiration-date.spec.js › 1.0 lines 284-292: anniversary in years, should calculate
      properly for a single year › ends a purchase of 2019-04-03 at the end of the anniversary month,
      2020-04-30
    provenance: test
  - scenario: ATS-MBR-STR-015-05
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: 1.0
      calculate-expiration-date.spec.js › 1.0 lines 327-337: anniversary in years, should respect sell
      after month › moves a new term bought 2019-04-15 with the threshold 15 a month on, to 2020-05-31
    provenance: test
  - scenario: ATS-MBR-STR-015-05
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: 1.0
      calculate-expiration-date.spec.js › 1.0 lines 625-634: anniversary, should calculate properly for a
      single week › ends a month-end week bought 2019-01-01 seven days on, 2019-01-08, keeping the full
      count
    provenance: test
  - scenario: ATS-MBR-STR-015-06
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: 1.0
      calculate-expiration-date.spec.js › 1.0 lines 853-866: fixed expiration dates, simple in-year range
      › ends a purchase of 2023-04-03 in the window 03-01 to 05-31 on 2023-11-14
    provenance: test
  - scenario: ATS-MBR-STR-015-06
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      finds a February purchase in the window that began the previous October: 2021-12-31 (1.0 fell
      through to the plain rule: 2022-02-28)
    provenance: test
  - scenario: ATS-MBR-STR-015-06
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: fixed term ends ›
      places a renewal starting the day after a window’s end in that window (RB-2585)
    provenance: test
  - scenario: ATS-MBR-STR-015-07
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: 1.0
      calculate-expiration-date.spec.js › 1.0 lines 70-77: calendar, a standard year, should calculate
      properly for April › back-dates a purchase of 2019-04-03 to 2019-01-01 and ends it 2019-12-31
    provenance: test
  - scenario: ATS-MBR-STR-015-07
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      starts a late calendar renewal of a term ending 2023-04-30 on 2023-05-01 (1.0 back-dated it to
      2023-01-01, overlapping the old term)
    provenance: test
  - scenario: ATS-MBR-STR-015-08
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides › ends
      a calendar period ending in February on its last day in a leap year: 2024-02-29 (decided by Andrew
      2026-10-18: the real last day of the month; 1.0 added a year with Moment and ended it 2024-02-28)
    provenance: test
  - scenario: ATS-MBR-STR-015-09
    source: >-
      services-membership:modules/terms/tests/unit/term-rules.spec.ts#term rules: what 2.0 decides ›
      gives the same result twice for the same frozen inputs (1.0 turned the fixed dates into Moments in
      place, so a second call read other inputs)
    provenance: test
invocation: 'npm run test:unit'
coverage_limit: >-
  Bindings identify the concrete cases executed in this file. A compound specification may also depend on
  other registered suites or remain partly proposed; registration is not a passing execution result.
provenance: test
source:
  - 'services-membership:modules/terms/tests/unit/term-rules.spec.ts'
---

# Date-rule calculations and validation

## Verification Boundary

This suite evaluates local implementation decisions or declarations with controlled inputs. Date-rule calculations and validation defines the scope of its examples.

## What This Suite Proves

The suite executes the concrete examples named by its binding ledger. Those examples contribute to the linked capability or feature scenarios within the boundary of the test assertions.

## What It Does Not Prove

Registration supplies no fresh execution result or deployed conformance verdict. Browser behavior, deployed infrastructure and unasserted variants require separate evidence.

## Real Dependencies and Test Doubles

The tested calculation, declaration or source inspection runs locally with explicit fixtures. No deployed service participates.

## Must Not Be Doubled

The calculation, declaration or workflow decision under examination stays real; replacing it would remove the suite’s verification purpose.
