Skip to content

CAP-CRM-REG-006Determine an address’s geographic region

Markdown

CAP-CRM-REG-006

Determine an address’s geographic region

Markdown
  • DocumentDraft
  • Product intentProposed
  • ImplementationObserved

KindCapabilityProduct areaCRMModuleRegionsRevision2

Read atservices-crm a8d1364freact-console baf6dae3

The Formal Contract

The narrative above explains; the sections below are authoritative — the rules, scenarios and tests this document binds.

Outcomes
All placement paths share one geographic decision.Uncovered addresses receive no region.
Surfaces
jobapi
Intent sources
services-crm:docs/migrations/crm-regions/README.md#Behaviour changes, Not changed (kept as Rhythm 1.0 did; accepted by Andrew 2026-10-08)services-crm:docs/migrations/crm-regions/README.md#Behaviour changes (Andrew's requirement for the port: replace or remove stale calculated assignments)

Controls

13 controls apply, from the corpus control catalogue.

TC-DAT-001 TC-DAT-002 TC-DAT-003 TC-IAM-001 TC-IAM-005 TC-IAM-006 TC-LOG-005 TC-PI-001 TC-PRV-001 TC-PRV-002 TC-TEN-001 TC-TEN-002 TC-TEN-003

Business Rules

12 rules, 12 to be proved before approval. A rule's product intent is derived from its origin: 0 confirmed by a product decision, the rest inheriting this capability's proposed.

IdRuleKindEnforced atProvenance
01must prove
Proposed
The first matching enabled geographic rule in policy order supplies the region.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes, Not changed (kept as Rhythm 1.0 did; accepted by Andrew 2026-10-08)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › answers the first rule that matches when several would
02must prove
Proposed
Fallback rules are reserved until all geographic rules miss, and the last enabled fallback supplies the result when several exist.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes, Not changed (kept as Rhythm 1.0 did; accepted by Andrew 2026-10-08)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › tries the rest-of-the-world rule last wherever it sits in the order
03must prove
Proposed
Matching ignores disabled rules, including disabled fallback rules.
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/integration/services/region-assignment/region-assignment-rules.integration.spec.js#a rule staff turned off › skips the disabled rule and answers the next rule that matches
04must prove
Proposed
Postal ranges compare text with inclusive endpoints, accepting a ZIP+4 value within a five-digit interval and rejecting a value beyond its end.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes, Not changed (kept as Rhythm 1.0 did; accepted by Andrew 2026-10-08)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › compares postal codes as strings, so a ZIP+4 code inside the range matches
05must prove
Proposed
A country-restricted postal rule matches only that country, treating an omitted address country as the United States.
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/integration/services/region-assignment/region-assignment-rules.integration.spec.js#a postal code rule confined to a country › refuses the same postal code in another country
06must prove
Proposed
State matching uses exact stored text, including letter case.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes, Not changed (kept as Rhythm 1.0 did; accepted by Andrew 2026-10-08)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › matches states exactly, so a lower-case state is not the upper-case one
07must prove
Proposed
Country matching ignores letter case and treats a missing or blank address country as the United States.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes, Not changed (kept as Rhythm 1.0 did; accepted by Andrew 2026-10-08)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › counts an address with no country as US
08must prove
Proposed
Assignment reads addresses after save-time cleaning, allowing supported state and country names to match their stored codes.
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/integration/services/region-assignment/region-assignment.integration.spec.js#normalized address variants (the save-time cleaning, docs/migrations/contact-and-organization-cleaning/) › matches a state rule from the state written out in full
09must prove
Proposed
An address outside all enabled geographic rules has no region when no enabled fallback exists.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes (Andrew's requirement for the port: replace or remove stale calculated assignments)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › answers no region when nothing matches and there is no rest-of-the-world rule
10must prove
Proposed
An address absent or empty in every recognized field has no region even when a fallback exists.
origin: services-crm:docs/migrations/crm-regions/README.md#Behaviour changes (Andrew's requirement for the port: replace or remove stale calculated assignments)
no proof recorded yet
calculationservicetest
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › answers no region for no address even with a rest-of-the-world rule
11must prove
Proposed
Geographic criteria compare postal code, state and country, while any populated recognized address field can establish address presence for matching.
no proof recorded yet
calculationserviceobserved
services-crm:modules/regions/services/region-assignment/region-matching.ts:geographicAddressOf, hasAddress, matchRegionRule
12must prove
Proposed
Saving accepts a postal interval with its end before its start, but that interval cannot match a value.
no proof recorded yet
validationserviceinferred

Scenarios

IdGivenWhenThenProvenance
01Boston postal coverage precedes Massachusetts coverage and a fallback.Matching evaluates a Boston postal address.The postal rule supplies Boston’s region.test
services-crm:modules/regions/tests/integration/services/region-assignment/region-assignment.integration.spec.js#incomplete addresses and the matcher’s own comparisons › answers the first rule in order when two match (postal code before state)
02The policy also contains a fallback region.Matching evaluates an address in Paris.The fallback supplies the region after geographic rules miss.test
services-crm:modules/regions/tests/integration/services/region-assignment/region-assignment-rules.integration.spec.js#the rest of the world rule › gives an address no other rule matched the rest of the world region
03The policy has no fallback.Matching evaluates an uncovered Ontario address.The address receives no region.test
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › answers no region when nothing matches and there is no rest-of-the-world rule

Edge Cases

IdGivenWhenThenProvenance
04A state criterion uses lower-case letters.Matching evaluates the corresponding uppercase stored state.Exact comparison does not match the criterion.test
services-crm:modules/regions/tests/unit/region-matching.spec.js#region_for_address › matches states exactly, so a lower-case state is not the upper-case one
05An address contains a city but no country.Matching evaluates it against Canada-only coverage.The blank country is treated as the United States and Canada does not match.test
services-crm:modules/regions/tests/integration/services/region-assignment/region-assignment.integration.spec.js#incomplete addresses and the matcher’s own comparisons › gives an address with only a city no region (a blank country counts as US, which no rule names)

The Markdown files under specs/ in rhythmsoftware/rhythm-v2-docs are the canonical source of truth. This reader is a generated, read-only projection of them.