# Rule 8.6 — Elements That Count as One Word

> **Source:** Adapted from ASD-STE100 Issue 9, Rule 8.6

> **Source:** [master.md#sec8-rule8.6](ste-code/grouped/)

## Original Rule

**Rule 8.6** Count each of these elements as one word:

- Numbers
- Numbers together with units of measurement
- Abbreviations
- Alphanumeric identifiers
- Quoted text
- Titles, headings, and text on placards and labels
- Proper nouns of individuals, groups, organizations, and geopolitical entities.

When you count words for sentence length, count each of these as one word:

1. Numbers

   > **STE:** Do steps 13 thru 16 a minimum of three times. (10 words)

   ("13" and "16" are numbers and each of them counts as one word.)

   > **STE:** The spar box has twenty-one ribs. (6 words)

   ("Twenty-one" is a number and counts as one word.)

   Do not count numbers that identify paragraphs or work steps. These numbers are usually part of the document numbering systems.

2. Numbers together with units of measurement

   Units of measurement usually follow their related number (for example, 10 mA). When you write a number together with its unit of measurement, count them as one word.

   > **STE:** Make sure that the temperature in the room is 10 °C. (10 words)
   > **STE:** Make sure that the temperature in the room is 10 degrees Celsius. (10 words)
   > **STE:** The unit weighs 20 kg. (4 words)
   > **STE:** The unit weighs 20 kilograms. (4 words)
   > **STE:** The resistance must be 10 Ω. (5 words)
   > **STE:** The resistance must be 10 ohms. (5 words)

3. Abbreviations

   In technical texts, you can use abbreviations (also acronyms and initialisms) to make sentences shorter and easier to read. But these abbreviations only help the reader if the reader knows their meanings. Each abbreviation counts as one word.

   > **STE:** The maintenance team does a test of this system each day at 10 a.m. (13 words)

   ("a.m." is an abbreviation and counts as one word together with its number.)

   > **STE:** During this safety check, obey NASA protocols. (7 words)

   (NASA is an abbreviation (acronym) and counts as one word.)

   > **STE:** For remote access, use the VPN. (6 words)

   (VPN is an abbreviation (initialism) and counts as one word.)

4. Alphanumeric identifiers

   An alphanumeric identifier is a combination of letters and numbers that identifies something. Each alphanumeric identifier counts as one word.

   > **STE:** Examine the No. 1 bearing installation. (5 words)

   ("No. 1" is an alphanumeric identifier and counts as one word.)

   > **STE:** Tag circuit breaker 36L7. (4 words)

   ("36L7" is an alphanumeric identifier and counts as one word.)

5. Quoted text

   Quoted text is usually given in quotation marks ("..."). Words between quotation marks count as one word in a sentence. In some sentences, or parts of the document, uppercase letters or differences in font can also show quoted text. Such text also counts as one word.

   Examples in STE:

   > **STE:** Touch the "Service Overview" arrow to select the function page. (9 words)

   ("Service Overview" is quoted text and counts as one word.)

   > **STE:** Release the SHORT-CIRCUIT TEST switch. (4 words)

   (SHORT-CIRCUIT TEST is quoted text and counts as one word.)

   > **STE:** C = (A - B) - 0.063 mm (1 word)

   (In STE, a formula is quoted text and counts as one word.)

6. Titles, headings, and text on placards and labels

   In some texts, there are words or groups of words that you cannot change. These are:

   - Titles and headings
   - Text on placards (for example, a warning notice in a work area or public place)
   - Text on labels (for example, warning and caution labels that are attached to objects).

   Examples in STE:

   > **STE:** Before you start a repair, refer to the Structural Repair Manual for the applicable safety procedures and precautions. (16 words)

   ("Structure Repair Manual" is the title of the document and counts as one word.)

   > **STE:** Refer to Testing and Fault Isolation, page block 1001. (6 words)

   ("Testing and Fault Isolation" is the title of a section in a manual and counts as one word.)

   > **STE:** Refer to Requirements after Job Completion for the applicable procedures. (7 words)

   ("Requirements after Job Completion" is a heading in a data module and counts as one word.)

   > **STE:** This procedure is for the inspection of SSI No. 57-21-16, "Outer wing bottom skin lower surface spanwise skin joints at stringer 13 and stringer 20 between Rib 12 and Rib 27 excluding areas covered by flap track fairings 3, 4, and 5." (9 words)

   ("This procedure is for the inspection of" has 7 words. "SSI No. 57-21-16" is the reference number of the Structurally Significant Item (SSI) and counts as one word. The subsequent text given in quotation marks is the title of the SSI. It is not in STE, and it is not possible to change it. Thus, this text counts as one word. As a result, the full sentence has a total of 9 words.)

   > **STE:** "Interior hazards exist to such a degree that interior operations may be conducted only after full examination, and with extreme caution." (1 word)

   (The text given in quotation marks is not in STE. It comes from a placard, and it is not possible to change it. It counts as one word.)

   > **STE:** "FRAGILE - Please handle with care." (1 word)

   (The text given in quotation marks is not in STE. It comes from a label on shipping containers, and it is not possible to change it. It counts as one word.)

7. Proper nouns of individuals, groups, organizations, and geopolitical entities

   There are groups of words that you cannot change because they identify:

   - Individuals (for example, John Smith)
   - Groups or organizations (for example, World Health Organization)
   - Geopolitical entities (for example, Republic of Ireland).

   Examples in STE:

   > **STE:** The first president of the United States of America was George Washington. (8 words)

   ("United States of America" is the proper noun of a geopolitical entity and counts as one word. "George Washington" is a proper noun of an individual and counts as one word.)

   > **STE:** The owner of STE is the Aerospace, Security and Defence Industries Association of Europe. (7 words)

   ("Aerospace, Security and Defence Industries Association of Europe" is the proper noun of an organization and counts as one word.)

## STE-Code Adaptation

**Rule 8.6** In code documentation, count each of these elements as one word:

- Numbers
- Numbers together with units of measurement
- Abbreviations
- Alphanumeric identifiers
- Quoted text
- Titles, headings, and text on user interface elements and labels
- Proper nouns of individuals, groups, organizations, and geopolitical entities.

When you count words for sentence length, count each of these as one word:

1. Numbers

   > **STE:** Do steps 13 thru 16 a minimum of three times. (10 words)

   ("13" and "16" are numbers and each of them counts as one word.)

   > **STE:** The configuration file has twenty-one keys. (6 words)

   ("Twenty-one" is a number and counts as one word.)

   Do not count numbers that identify paragraphs or work steps. These numbers are usually part of the document numbering systems.

2. Numbers together with units of measurement

   Units of measurement usually follow their related number (for example, 10 ms). When you write a number together with its unit of measurement, count them as one word.

   > **STE:** Make sure that the timeout is 10 ms. (7 words)
   > **STE:** Make sure that the timeout is 10 milliseconds. (7 words)
   > **STE:** The payload is 20 MB. (4 words)
   > **STE:** The payload is 20 megabytes. (4 words)
   > **STE:** The latency must be 10 μs. (5 words)
   > **STE:** The latency must be 10 microseconds. (5 words)

3. Abbreviations

   In code documentation, you can use abbreviations (also acronyms and initialisms) to make sentences shorter and easier to read. But these abbreviations only help the reader if the reader knows their meanings. Each abbreviation counts as one word.

   > **STE:** The CI pipeline does a test of this module each day at 10 a.m. (13 words)

   ("a.m." is an abbreviation and counts as one word together with its number.)

   > **STE:** During this security check, obey OWASP guidelines. (7 words)

   (OWASP is an abbreviation (acronym) and counts as one word.)

   > **STE:** For remote access, use the VPN. (6 words)

   (VPN is an abbreviation (initialism) and counts as one word.)

4. Alphanumeric identifiers

   An alphanumeric identifier is a combination of letters and numbers that identifies something in code or documentation. Each alphanumeric identifier counts as one word.

   > **STE:** Examine the No. 1 handler installation. (5 words)

   ("No. 1" is an alphanumeric identifier and counts as one word.)

   > **STE:** Tag error code E36L7. (4 words)

   ("E36L7" is an alphanumeric identifier and counts as one word.)

5. Quoted text

   Quoted text is usually given in quotation marks ("..."). Words between quotation marks count as one word in a sentence. In code documentation, backtick-quoted text (`...`) and inline `<code>` text also count as quoted text. Uppercase letters or differences in font can also show quoted text. Such text also counts as one word.

   > **STE:** Touch the "Service Overview" button to select the function page. (9 words)

   ("Service Overview" is quoted text and counts as one word.)

   > **STE:** Release the SHORT-CIRCUIT TEST switch. (4 words)

   (SHORT-CIRCUIT TEST is quoted text and counts as one word.)

   > **STE:** `C = (A - B) - 0.063 mm` (1 word)

   (In STE-Code, a formula is quoted text and counts as one word.)

6. Titles, headings, and text on user interface elements and labels

   In some texts, there are words or groups of words that you cannot change. These are:

   - Titles and headings (for example, a document title or a section heading)
   - Text on user interface elements (for example, a button label, a menu item, or a dialog title)
   - Text on labels (for example, warning and caution labels that are shown in a web page or application).

   > **STE:** Before you start a deployment, refer to the Operations Runbook for the applicable safety procedures and precautions. (16 words)

   ("Operations Runbook" is the title of the document and counts as one word.)

   > **STE:** Refer to Error Handling and Recovery, page block 1001. (6 words)

   ("Error Handling and Recovery" is the title of a section in a manual and counts as one word.)

   > **STE:** Refer to Requirements after Job Completion for the applicable procedures. (7 words)

   ("Requirements after Job Completion" is a heading in a data module and counts as one word.)

   > **STE:** This procedure is for the inspection of API No. 57-21-16, "Rate limiter middleware integration with the gateway service across all regional edge nodes and the central traffic management controller excluding traffic routed through canary deployment slots." (9 words)

   ("This procedure is for the inspection of" has 7 words. "API No. 57-21-16" is the reference number of the API and counts as one word. The subsequent text given in quotation marks is the title of the API specification. It is not in STE-Code, and it is not possible to change it. Thus, this text counts as one word. As a result, the full sentence has a total of 9 words.)

   > **STE:** "Security vulnerability detected. Immediate administrator action required before system operations can resume." (1 word)

   (The text given in quotation marks is not in STE-Code. It comes from a user interface warning, and it is not possible to change it. It counts as one word.)

   > **STE:** "WARNING: This operation permanently deletes all user data." (1 word)

   (The text given in quotation marks is not in STE-Code. It comes from a label on a confirmation dialog, and it is not possible to change it. It counts as one word.)

7. Proper nouns of individuals, groups, organizations, and geopolitical entities

   There are groups of words that you cannot change because they identify:

   - Individuals (for example, John Smith)
   - Groups or organizations (for example, World Health Organization)
   - Geopolitical entities (for example, Republic of Ireland).

   > **STE:** The creator of Linux was Linus Torvalds. (6 words)

   ("Linus Torvalds" is a proper noun of an individual and counts as one word.)

   > **STE:** The maintainer of this library is the Apache Software Foundation. (7 words)

   ("Apache Software Foundation" is the proper noun of an organization and counts as one word.)

## Examples

> *Adapted from spec pair:* Non-STE: "The spar box has twenty-one ribs." | STE: "The configuration file has twenty-one keys." (number counts as one word) — and Non-STE: "During this safety check, obey NASA protocols." | STE: "During this security check, obey OWASP guidelines." (abbreviation counts as one word) — and Non-STE: "Before you start a repair, refer to the Structural Repair Manual for the applicable safety procedures and precautions." | STE: "Before you start a deployment, refer to the Operations Runbook for the applicable safety procedures and precautions." (document title counts as one word).

> **Non-STE:** The JSON Web Token authentication middleware must validate the signature of each incoming request using the public key obtained from the OpenID Connect identity provider, and the token must have an expiry time of not more than three hundred and sixty seconds to be valid for processing.
>
> **STE:** The JWT authentication middleware must validate the signature of each incoming request. The token must have an expiry time of not more than 360 seconds to be valid for processing. (11 words each)
>
> *Adapted from spec pattern: abbreviation counts as one word — "During this safety check, obey NASA protocols." — and number with unit counts as one word — "Make sure that the temperature in the room is 10 °C."*

("JWT" is an abbreviation and counts as one word. "360 seconds" is a number together with a unit of measurement and counts as one word.)

```python
# STE-Code compliant docstring for the split sentences above
def validate_token(token: "JWT", public_key: "RSAPublicKey") -> "bool":
    """Validate the signature of an incoming JWT.

    The token must have an expiry time of not more than 360 seconds
    to be valid for processing. Return True when the signature is
    valid and the token is not expired.
    """
    payload = decode(token, public_key, algorithms=["RS256"])
    return payload["exp"] - time.time() > 0
```

> **Non-STE:** Before you run the database migration script, refer to the document titled Migration Procedures and Rollback Strategies for PostgreSQL Version 15 Cluster Deployments for the applicable safety procedures and precautionary measures.
>
> **STE:** Before you run the migration, refer to the Migration Procedures and Rollback Strategies for the applicable safety procedures. (16 words)
>
> *Adapted from spec pair: "Before you start a repair, refer to the Structural Repair Manual for the applicable safety procedures and precautions." — document title counts as one word.*

("Migration Procedures and Rollback Strategies" is the title of the document and counts as one word.)

```sql
-- STE-Code compliant migration header comment
-- Before you run the migration, refer to the Migration Procedures
-- and Rollback Strategies for the applicable safety procedures.
BEGIN;
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMPTZ;
COMMIT;
```

> **Non-STE:** To configure the retry behavior of the HTTP client you must open the file named application.properties which is located in the resources directory and then change the property called http.client.retry.max.attempts to a numeric value of five and also set the property http.client.retry.backoff.millis to a numeric value of one thousand so that the client will retry failed requests five times with a one second delay between each attempt.
>
> **STE:** In `application.properties`, set `http.client.retry.max.attempts` to 5. Set `http.client.retry.backoff.millis` to 1000. The client retries failed requests 5 times with a 1 second delay. (11 words, 11 words, 14 words)
>
> *Adapted from spec pair: "Make sure that the timeout is 10 ms." (number with unit counts as one word) and "Tag circuit breaker 36L7." (alphanumeric identifier counts as one word).*

(The file path in backticks is quoted text, 1 word. Each property name is an alphanumeric identifier, 1 word. "5", "1000", and "1 second" are numbers or numbers with units, 1 word each.)

```properties
# application.properties — STE-Code compliant config comments
http.client.retry.max.attempts=5
http.client.retry.backoff.millis=1000
```

> **Non-STE:** When the payment service raises an exception of the type PaymentGatewayTimeoutException with the error code ERR_PG_TIMEOUT_0099 because the downstream credit card processor did not respond within the configured threshold of thirty seconds, the order orchestrator must publish an event with the name OrderPaymentFailed and include the correlation identifier that was generated at the start of the request.
>
> **STE:** The `PaymentGatewayTimeoutException` with code `ERR_PG_TIMEOUT_0099` occurs when the processor does not respond in 30 seconds. The orchestrator publishes the `OrderPaymentFailed` event with the request correlation identifier. (15 words, 16 words)
>
> *Adapted from spec pair: "Tag circuit breaker 36L7." (alphanumeric identifier) and "During this safety check, obey OWASP guidelines." (proper noun / abbreviation).*

("PaymentGatewayTimeoutException" and "ERR_PG_TIMEOUT_0099" are alphanumeric identifiers, 1 word each. "OrderPaymentFailed" is a proper noun, 1 word. "30 seconds" is a number with a unit, 1 word.)

```java
// STE-Code compliant exception javadoc
/**
 * The PaymentGatewayTimeoutException with code ERR_PG_TIMEOUT_0099 occurs
 * when the processor does not respond in 30 seconds.
 */
public class PaymentGatewayTimeoutException extends RuntimeException {
    public static final String CODE = "ERR_PG_TIMEOUT_0099";
}
```

> **Non-STE:** The function which the developer must call in order to retrieve the current user profile from the React application programming interface is named useUserProfile and it accepts a single argument which is the unique identifier of the user and it returns an object which contains the display name, the email address, and the list of roles that have been assigned to that user.
>
> **STE:** Call `useUserProfile(userId)` to get the current user profile. It returns an object with the `displayName`, the `email`, and the `roles` list. (14 words, 13 words)
>
> *Adapted from spec pattern: "Touch the 'Service Overview' button to select the function page." (quoted identifier counts as one word) and "Examine the No. 1 handler installation." (alphanumeric identifier).*

("useUserProfile(userId)" is quoted text, 1 word. "displayName", "email", and "roles" are quoted identifiers, 1 word each.)

```typescript
// STE-Code compliant hook documentation
/**
 * Call useUserProfile(userId) to get the current user profile.
 * It returns an object with the displayName, the email, and the roles list.
 */
function useUserProfile(userId: string): UserProfile { /* ... */ }
```

> **Non-STE:** In the Kubernetes manifest file you should make sure that the container which runs the checkout service has its resource requests set to two hundred and fifty millicores of CPU and five hundred and twelve mebibytes of memory and its resource limits set to five hundred millicores of CPU and one gibibyte of memory so that the scheduler can place the pod on a node that has enough capacity.
>
> **STE:** In the Kubernetes manifest, set the `checkout` container to 250m CPU and 512Mi memory. Set the limit to 500m CPU and 1Gi memory. (15 words, 12 words)
>
> *Adapted from spec pair: "The unit weighs 20 kg." (number with unit counts as one word).*

("checkout" is quoted text, 1 word. "250m CPU", "512Mi", "500m CPU", and "1Gi" are numbers with units, 1 word each.)

```yaml
# checkout-deployment.yaml — STE-Code compliant manifest comment
# In the Kubernetes manifest, set the checkout container to 250m CPU
# and 512Mi memory. Set the limit to 500m CPU and 1Gi memory.
resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: 500m
    memory: 1Gi
```

> **Non-STE:** The test suite must verify that when the cache layer returns a null value for a key that does not exist the repository implementation does not attempt to query the primary database and instead the method named getOrNull returns the value None and the test should also confirm that the recorded metric with the name cache.miss.count is increased by exactly one for each missing key.
>
> **STE:** The test must check that `getOrNull` returns `None` for a missing key. It must check that the `cache.miss.count` metric increases by 1 for each miss. (17 words, 16 words)
>
> *Adapted from spec pattern: "Tag circuit breaker 36L7." (alphanumeric identifier) and "C = (A - B) - 0.063 mm" (quoted text).*

("getOrNull" and "None" are quoted text, 1 word each. "cache.miss.count" is an alphanumeric identifier, 1 word. "1" is a number, 1 word.)

```go
// STE-Code compliant test comment
// The test must check that getOrNull returns None for a missing key.
// It must check that the cache.miss.count metric increases by 1 for each miss.
func TestGetOrNull_MissingKey(t *testing.T) {
    repo := NewCacheBackedRepository(emptyCache, primaryDB)
    if got := repo.getOrNull("absent"); got != None {
        t.Fatalf("expected None, got %v", got)
    }
    if metric("cache.miss.count") != 1 {
        t.Fatalf("expected cache.miss.count to increase by 1")
    }
}
```

## Code-Domain Explanation

This rule has a direct effect on how you count words for sentence-length limits in different types of code documentation. The maximum sentence length in STE-Code is 20 words for procedural sentences and 25 words for descriptive sentences. When you apply Rule 8.6 correctly, many sentences that seem too long become compliant because multi-word elements collapse into single-word counts.

### README Files

README files frequently contain project names, badge URLs, version numbers, and tool abbreviations. Each of these counts as one word under this rule.

A README sentence such as "This project uses GitHub Actions for CI/CD and deploys to AWS Lambda via the Serverless Framework" has these multi-word elements that each count as one word: "GitHub Actions" (proper noun, 1 word), "CI/CD" (abbreviation, 1 word), "AWS Lambda" (proper noun, 1 word), and "Serverless Framework" (proper noun, 1 word). The sentence appears to have 17 words but counts as only 12 words under Rule 8.6.

```markdown
# acme-cli

This project uses GitHub Actions for CI/CD and deploys to AWS Lambda via the
Serverless Framework. The badge `build-passing` shows the latest test result.
```

In the sentence above, "build-passing" (the badge name, quoted text) is also 1 word.

### API Documentation

API documentation contains endpoint paths, HTTP status codes, parameter names, and response field identifiers. Each of these is an alphanumeric identifier or quoted text and counts as one word.

An endpoint description such as "Send a POST request to `/api/v1/users/{userId}/orders` with the `X-API-Key` header" has `/api/v1/users/{userId}/orders` (quoted path, 1 word), `X-API-Key` (quoted identifier, 1 word), and `POST` (quoted method, 1 word). The sentence appears to have 14 words but counts as 10 words.

```http
POST /api/v1/users/{userId}/orders HTTP/1.1
Host: api.example.com
X-API-Key: <token>
Content-Type: application/json
```

### Docstrings and Inline Comments

Docstrings often reference parameter types, return types, and exception classes. These are proper nouns or alphanumeric identifiers.

A Python docstring such as "Raises `ValueError` if the input is not a positive `float` between `0.0` and `1.0`" has `ValueError` (proper noun, 1 word), `float` (quoted type name, 1 word), `0.0` (number, 1 word), and `1.0` (number, 1 word). The sentence appears to have 14 words but counts as 10 words.

```python
def normalize_ratio(value: float) -> float:
    """Return a number between 0.0 and 1.0.

    Raises ValueError if the input is not a positive float between
    0.0 and 1.0.
    """
```

### Commit Messages

Commit messages often contain issue tracker identifiers, branch names, and abbreviated command names. Each counts as one word under this rule.

A commit message such as "Fix NPE in `UserService.authenticate()` when `SecurityContext.getPrincipal()` returns null for OAuth2 tokens from Azure AD B2C" has `NPE` (abbreviation, 1 word), `UserService.authenticate()` (quoted identifier, 1 word), `SecurityContext.getPrincipal()` (quoted identifier, 1 word), `OAuth2` (proper noun, 1 word), and `Azure AD B2C` (proper noun, 1 word). The sentence appears to have 17 words but counts as 12 words.

```text
Fix NPE in UserService.authenticate() when SecurityContext.getPrincipal()
returns null for OAuth2 tokens from Azure AD B2C

Closes PROJ-4821
```

### Error Messages

Error messages shown to users or logged by systems often contain error codes, field names, and type identifiers. Each of these is an alphanumeric identifier and counts as one word.

An error message such as "Validation failed for field `email_address`: value must match pattern `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`" has `email_address` (quoted identifier, 1 word) and the regex pattern (quoted text, 1 word). The sentence appears to have 14 words but counts as 12 words.

```text
Validation failed for field email_address: value must match pattern
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
```

### Practical Impact on Sentence-Length Compliance

When you apply Rule 8.6 across all seven element categories, the average code documentation sentence reduces its word count by 3 to 8 words compared to a naive word count. This makes it easier to obey the 20-word procedural limit and the 25-word descriptive limit (Rule 8.7). The reduction is largest in API documentation and README files because these document types contain the highest density of identifiers, abbreviations, and proper nouns.

## Paradigm-Specific Guidance

### Object-Oriented Documentation (Java, C++, C#, Python Classes)

Object-oriented documentation contains class names, method signatures, interface names, and package names. Each of these is a proper noun or alphanumeric identifier and counts as one word.

Class hierarchy descriptions benefit from this rule. A sentence such as "The `AbstractUserRepository` implements `CrudRepository<User, Long>` and extends `PagingAndSortingRepository<User, Long>`" has `AbstractUserRepository` (proper noun, 1 word), `CrudRepository<User, Long>` (proper noun with type parameters as quoted text, 1 word), and `PagingAndSortingRepository<User, Long>` (proper noun with type parameters, 1 word).

Method signature documentation also benefits. A sentence such as "Call `buildQuery(SearchCriteria criteria, Pageable pageable, Sort.Direction direction)` to get a `TypedQuery<ResultDTO>`" has three identifiers that each count as one word.

Design pattern references are proper nouns: "This class uses the Abstract Factory Pattern" counts "Abstract Factory Pattern" as one word. "Apply the Dependency Inversion Principle" counts "Dependency Inversion Principle" as one word.

```java
// The AbstractUserRepository implements CrudRepository<User, Long> and
// extends PagingAndSortingRepository<User, Long>.
public abstract class AbstractUserRepository
        implements CrudRepository<User, Long>,
        PagingAndSortingRepository<User, Long> { }
```

### Functional Documentation (Haskell, Elixir, Clojure, Rust)

Functional documentation contains type signatures, pattern matches, monad names, and function compositions. Each type signature or monad stack counts as one word when quoted.

A Haskell type signature such as "`validate :: Config -> Either ValidationError Config`" counts as quoted text (1 word). A monad transformer stack such as "`ReaderT Env (ExceptT AppError IO) a`" counts as one word when quoted.

Function pipeline documentation benefits: "Pipe the input through `validate >>= normalize >>= persist`" has the pipeline as quoted text (1 word). Algebraic data type constructors such as "`Just value`" or "`Left error`" each count as one word when quoted.

```haskell
-- validate :: Config -> Either ValidationError Config
validate :: Config -> Either ValidationError Config
validate cfg = runValidate cfg >>= normalize >>= persist

-- ReaderT Env (ExceptT AppError IO) a
type App a = ReaderT Env (ExceptT AppError IO) a
```

### Procedural Documentation (C, Go, Bash)

Procedural documentation contains function names, struct tags, error codes, and signal names. Each counts as one word under the appropriate category.

C documentation: "Call `pthread_mutex_lock(&mtx)` before you access the shared buffer" has `pthread_mutex_lock(&mtx)` as quoted text (1 word). "The function returns `EAGAIN` when the operation would block" has `EAGAIN` as an alphanumeric identifier (1 word).

Go documentation: "The `context.Context` value carries deadlines and cancellation signals" has `context.Context` as a proper noun (1 word). "Wrap the error with `fmt.Errorf("user %s: %w", id, err)`" has the format string as quoted text (1 word).

Bash documentation: "Set `IFS=$'\n'` before you read the file line by line" has `IFS=$'\n'` as an alphanumeric identifier with assignment (1 word). "Trap `SIGINT` and `SIGTERM` to clean up temporary files" has two signal names that each count as one word.

```c
/* Call pthread_mutex_lock(&mtx) before you access the shared buffer.
   The function returns EAGAIN when the operation would block. */
pthread_mutex_lock(&mtx);
```

```bash
# Set IFS=$'\n' before you read the file line by line
IFS=$'\n'
trap 'rm -f "$TMPFILE"' SIGINT SIGTERM
```

### Declarative Documentation (SQL, Terraform, Kubernetes YAML)

Declarative documentation contains resource names, column identifiers, constraint names, and provider references. Each of these counts as one word.

SQL documentation: "Create an index on `users(email_address, created_at)` with the `CONCURRENTLY` option" has the column list as quoted text (1 word) and `CONCURRENTLY` as a keyword quoted for emphasis (1 word). "The foreign key `fk_orders_user_id` references `users(id) ON DELETE CASCADE`" has two identifiers and a clause that each count as one word.

Terraform documentation: "The `aws_lambda_function.main` resource depends on `aws_iam_role.lambda_exec`" has two resource identifiers that each count as one word. "Set `var.environment = "production"` in your `terraform.tfvars` file" has the assignment and filename as one word each.

Kubernetes documentation: "Apply the `nginx-ingress-controller` Deployment from the `ingress-nginx` namespace" has two proper nouns that each count as one word. "The `readinessProbe.httpGet.path` must return a 200 status code" has the field path as an alphanumeric identifier (1 word) and `200` as a number (1 word).

```sql
-- Create an index on users(email_address, created_at) with the CONCURRENTLY
-- option. The foreign key fk_orders_user_id references users(id)
-- ON DELETE CASCADE.
CREATE INDEX CONCURRENTLY idx_users_email ON users (email_address, created_at);
```

```hcl
# The aws_lambda_function.main resource depends on aws_iam_role.lambda_exec.
resource "aws_lambda_function" "main" {
  function_name = "api"
  depends_on    = [aws_iam_role.lambda_exec]
}
```

### Systems Documentation (Rust Ownership, C Memory)

Systems documentation contains lifetime annotations, ownership diagrams, memory layout descriptions, and unsafe block justifications. Each annotation or diagram counts as one word when quoted.

Rust ownership documentation: "The function signature `fn process<'a>(data: &'a [u8]) -> Cow<'a, str>`" counts as quoted text (1 word). "The borrow checker rejects this because `data` is borrowed as immutable at line 42 and as mutable at line 47" has line numbers that count as one word each.

C memory documentation: "The buffer at address `0x7fff5fbff8c0` must be freed after the call to `process_buffer(void *buf, size_t len)`" has the address and function call as one word each. "Use `valgrind --leak-check=full --show-leak-kinds=all ./program` to find memory leaks" has the full command as quoted text (1 word).

```rust
// The function signature fn process<'a>(data: &'a [u8]) -> Cow<'a, str>
// borrows data for the lifetime 'a.
fn process<'a>(data: &'a [u8]) -> Cow<'a, str> {
    String::from_utf8_lossy(data)
}
```

```bash
# Use valgrind --leak-check=full --show-leak-kinds=all ./program to find
# memory leaks.
valgrind --leak-check=full --show-leak-kinds=all ./program
```

## Extended Examples

### Example 1: Combining Multiple One-Word Elements in an API Reference

> **Non-STE:** The endpoint located at the uniform resource locator path of /api/v2/organizations/{organizationId}/repositories/{repositoryId}/branches accepts a Hypertext Transfer Protocol Secure GET request and requires an OAuth two point zero bearer token in the Authorization header with the format Bearer followed by a space and then the access token, and it returns a JavaScript Object Notation response body with a two hundred status code.
>
> **STE:** The `GET /api/v2/orgs/{orgId}/repos/{repoId}/branches` endpoint needs an OAuth 2.0 bearer token in the `Authorization` header. It returns a JSON response body with a 200 status code. (10 words, then 10 words)
>
> *Principles applied: P3 (use words only with approved meanings — "needs" not "requires"), P9 (prefer short, clear technical nouns — "orgId" not "organizationId"). The quoted path counts as 1 word. "OAuth 2.0" is a proper noun (1 word). "Authorization" is quoted text (1 word). "JSON" is an abbreviation (1 word). "200" is a number (1 word).*

```http
GET /api/v2/orgs/{orgId}/repos/{repoId}/branches HTTP/1.1
Authorization: Bearer <access-token>
```

### Example 2: Error Code and Stack Trace Documentation

> **Non-STE:** The NullPointerException error with the identifier ERR_NULL_REF_0042 is thrown by the processRequest method located in the class com.example.service.RequestHandler at line one hundred and twenty-seven when the incoming GraphQL query contains a null value for the required field named userContext, and the stack trace will also include frames from the DataFetcherExceptionHandler class and the ExecutionStrategy class.
>
> **STE:** The error `ERR_NULL_REF_0042` occurs in `RequestHandler.processRequest()` at line 127. The `GraphQL` query has a null value for the required field `userContext`. The stack trace includes `DataFetcherExceptionHandler` and `ExecutionStrategy`. (8 words, 12 words, 5 words)
>
> *Principles applied: P5 (technical code nouns are allowed — "GraphQL"), P7 (do not use technical nouns as verbs — "occurs" not "is thrown"). "ERR_NULL_REF_0042" and "RequestHandler.processRequest()" are alphanumeric/quoted identifiers (1 word each). "GraphQL" is a proper noun (1 word). "DataFetcherExceptionHandler" and "ExecutionStrategy" are proper nouns (1 word each).*

```text
com.example.service.RequestHandler.processRequest(RequestHandler.java:127)
  Caused by: ERR_NULL_REF_0042
  at DataFetcherExceptionHandler.handle(DataFetcherExceptionHandler.java:44)
  at ExecutionStrategy.execute(ExecutionStrategy.java:88)
```

### Example 3: Configuration File Documentation

> **Non-STE:** In the YAML Ain't Markup Language configuration file located at the path etc/application/configuration/production.yaml, set the property spring.datasource.hikari.maximumPoolSize to a value of fifty and set the property server.tomcat.maxThreads to a value of two hundred, then also make sure that the property logging.level.com.example is set to the value DEBUG and the property management.endpoints.web.exposure.include is set to the value health,info,metrics.
>
> **STE:** In `etc/application/config/production.yaml`, set `spring.datasource.hikari.maximumPoolSize` to 50. Set `server.tomcat.maxThreads` to 200. Set `logging.level.com.example` to `DEBUG`. Set `management.endpoints.web.exposure.include` to `health,info,metrics`. (8 words, 5 words, 6 words, 7 words)
>
> *Principles applied: P9 (prefer short, clear technical nouns — "config" not "configuration"), P12 (technical verbs like "set" are allowed). The file path is quoted text (1 word). Each property name is an alphanumeric identifier (1 word). "50" and "200" are numbers (1 word each).*

```yaml
# etc/application/config/production.yaml
spring:
  datasource:
    hikari:
      maximumPoolSize: 50
server:
  tomcat:
    maxThreads: 200
logging:
  level:
    com.example: DEBUG
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
```

### Example 4: Commit Message with Multiple Identifiers

> **Non-STE:** Implement the continuous integration and continuous delivery pipeline workflow for the automatic deployment of the user interface application to the Amazon Web Services Simple Storage Service bucket when a pull request is merged into the main branch, which triggers the GitHub Actions workflow file located at .github/workflows/deploy-ui-to-production.yml and uses the OpenID Connect protocol for authentication.
>
> **STE:** Add the CI/CD pipeline workflow for the UI app deployment to the AWS S3 bucket. The workflow triggers on pull request merges to `main`. It uses OIDC for authentication. (12 words, 8 words, 6 words)
>
> *Principles applied: P2 (use words only as their specified part of speech — "Add" as imperative verb), P3 (use words only with approved meanings — "triggers" not "is triggered"). "CI/CD" is an abbreviation (1 word). "AWS S3" is a proper noun (1 word). "main" is quoted text (1 word). "OIDC" is an abbreviation (1 word).*

```text
Add the CI/CD pipeline workflow for the UI app deployment to the AWS S3 bucket

The workflow triggers on pull request merges to main. It uses OIDC for
authentication.
```

### Example 5: Database Migration Documentation

> **Non-STE:** Execute the structured query language migration script with the filename V2_3_1__add_user_preferences_table.sql which creates a new relational database table called user_preferences that has a universally unique identifier primary key column, a foreign key column referencing the users table on the id column with a cascade on delete action, and a JavaScript Object Notation Binary column for storing the preference data with a default value of an empty JSON object represented by the characters opening curly brace followed by closing curly brace.
>
> **STE:** Run the migration `V2_3_1__add_user_preferences_table.sql`. It makes the `user_preferences` table with a UUID primary key. The table has a foreign key to `users(id) ON DELETE CASCADE`. It has a JSONB column with the default value `{}`. (9 words, 11 words, 8 words, 10 words)
>
> *Principles applied: P12 (technical verbs like "run" are allowed — "Run" not "Execute"), P1 (use approved words — "makes" not "creates"). "V2_3_1__add_user_preferences_table.sql" is an alphanumeric identifier (1 word). "user_preferences" is quoted text (1 word). "UUID" is an abbreviation (1 word). "JSONB" is an abbreviation (1 word).*

```sql
-- Run the migration V2_3_1__add_user_preferences_table.sql.
CREATE TABLE user_preferences (
    id UUID PRIMARY KEY,
    user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
    data JSONB DEFAULT '{}'::jsonb
);
```

### Example 6: Dependency Declaration

> **Non-STE:** This particular module depends on version two point one point zero or later of the org.springframework.boot.spring-boot-starter-web artifact, version one point eighteen point twenty-four of the com.google.guava.guava artifact, and version four point thirteen point two of the junit.junit artifact for testing purposes only using the test scope in Apache Maven.
>
> **STE:** This module uses `org.springframework.boot:spring-boot-starter-web` version 2.1.0 or later. It uses `com.google.guava:guava` version 1.18.24. It uses `org.junit:junit` version 4.13.2 for tests only. (9 words, 8 words, 9 words)
>
> *Principles applied: P1 (use approved words — "uses" not "depends on"), P8 (use standard, well-known technical nouns — "tests" not "testing purposes"). Each Maven coordinate is quoted text (1 word). Version numbers are numbers (1 word each when paired with "version").*

```xml
<!-- pom.xml — this module uses the dependencies below -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <version>2.1.0</version>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>1.18.24</version>
</dependency>
<dependency>
  <groupId>org.junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>
```

### Example 7: Test Specification with Assertion Identifiers

> **Non-STE:** The integration test must confirm that after the message broker delivers the event with the topic name order.created to the subscriber that is registered under the channel identifier orders.v1 and the payload contains a field called totalAmount that is greater than zero, the assertion framework records a pass result and writes the value of the correlation identifier to the test report file.
>
> **STE:** The test must check that the broker sends `order.created` to `orders.v1`. It must check that `totalAmount` is greater than 0. The framework records a pass and writes the correlation identifier to the report. (18 words, 15 words, 16 words)
>
> *Principles applied: P3 (use words only with approved meanings — "check" not "confirm"), P12 (technical verbs like "send" are allowed). "order.created" and "orders.v1" are quoted identifiers (1 word each). "totalAmount" is quoted text (1 word). "0" is a number (1 word).*

```go
// The test must check that the broker sends order.created to orders.v1.
// It must check that totalAmount is greater than 0.
func TestOrderCreated(t *testing.T) {
    broker.Publish("order.created", orders.v1, payload{totalAmount: 42})
    assert.Greater(t, payload.totalAmount, 0)
    assert.True(t, report.HasCorrelationID())
}
```

### Example 8: TypeScript Generic and React Component Documentation

> **Non-STE:** You should create a new component which is a generic version of the data table that accepts a type parameter called TRow that represents the shape of each row object and it also accepts the array of rows as a property named rows and a callback function as a property named onRowClick so that the parent component can respond when the user selects a specific row in the interface.
>
> **STE:** Make the `DataTable<TRow>` component. Pass the `rows` array and the `onRowClick` callback as props. The parent responds when the user selects a row. (13 words, 13 words, 11 words)
>
> *Principles applied: P2 (use "Make" as imperative verb), P9 (prefer short technical nouns — "props" not "properties"). "DataTable<TRow>" is quoted text (1 word). "rows" and "onRowClick" are quoted identifiers (1 word each).*

```tsx
// Make the DataTable<TRow> component. Pass the rows array and the
// onRowClick callback as props.
function DataTable<TRow>({ rows, onRowClick }: Props<TRow>) {
  return rows.map((row) => <Row key={row.id} onClick={onRowClick} />);
}
```

## Edge Cases

### Edge Case 1: Framework Names That Contain "Unapproved" Words

Some framework names contain words that are not in the STE-Code dictionary. For example, "Express" (a Node.js framework) and "Swift" (an Apple programming language) are also common English words. When these names appear in documentation, they are proper nouns and count as one word under category 7 of Rule 8.6. Do not apply Rule 1.1 (use approved words) to proper nouns.

A second concern: framework names sometimes contain verbs used as nouns, which would violate Rule 1.7. For example, "React" is a JavaScript library whose name is a verb. When your documentation says "Use React to build the user interface," treat "React" as a proper noun (1 word), not as a verb. Do not rewrite framework names to obey STE-Code word rules.

```tsx
// Use React to build the user interface. "React" is a proper noun (1 word).
import React from "react";
export const App = () => <main>Hello</main>;
```

### Edge Case 2: Code Keywords That Conflict with the Rule

Code keywords such as `class`, `function`, `return`, and `async` have specific meanings in programming languages. When you quote them in documentation, they count as one word under the quoted text category (category 5). Do not replace them with STE-Code synonyms.

The keyword `class` in Java or Python documentation should stay as `class`, not be replaced with "category" or "type." The keyword `return` should stay as `return`, not be replaced with "give back." These keywords are quoted text and count as one word.

However, when you use these words as part of your own prose — not as quoted code — apply the STE-Code dictionary normally. "The function returns a value" uses "returns" as a technical verb (Rule 1.12). "The class has three methods" uses "class" as a technical noun (Rule 1.5). Both are allowed.

```python
# The class has three methods. The function returns a value.
class Handler:
    def process(self) -> int:
        return 0
```

### Edge Case 3: Generated Code and Automated Documentation

Generated code comments and auto-generated API reference pages often contain long identifiers, fully qualified class names, and machine-generated descriptions. These are not written by a human author and cannot be changed. Apply Rule 8.6 category 6 (titles, headings, and text on labels) to these elements: they count as one word because they are not possible to change.

For example, a Javadoc `@see` tag such as `@see com.example.service.impl.UserServiceImpl#authenticate(String, char[])` counts as one word — it is generated text on a label. Similarly, an OpenAPI specification description auto-generated from code annotations counts as one word when you cannot change it.

When you write new documentation that wraps around generated text, count the generated portions as one word and apply STE-Code rules to your own prose.

```java
/**
 * Authenticates the given user.
 * @see com.example.service.impl.UserServiceImpl#authenticate(String, char[])
 */
public boolean login(String user, char[] password) { return true; }
```

### Edge Case 4: Nested Quoted Text and Backtick Escaping

Code documentation sometimes contains quoted text inside quoted text — for example, a shell command that includes a quoted string. The outer quoting mechanism (markdown backticks or HTML `<code>` tags) defines the quoted text boundary. Everything inside counts as one word.

A documentation sentence such as "Run `curl -H "Authorization: Bearer $TOKEN" https://api.example.com/v2/status` to check the service" has the entire backtick-quoted command as one word, even though the command itself contains double quotes.

When you write markdown documentation that shows how to use markdown code fences — a meta-documentation scenario — use four-backtick fences to escape three-backtick fences:

````
The README must include a ```` ```bash ```` code fence example.
````

In the outer sentence, the inner ```` ```bash ```` counts as quoted text (1 word).

```bash
# Run curl -H "Authorization: Bearer $TOKEN" https://api.example.com/v2/status
# to check the service.
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/v2/status
```

### Edge Case 5: Semantic Version Strings and Complex Identifiers

Semantic version strings such as `1.2.3-alpha.1+build.456` contain dots, hyphens, and plus signs. These are alphanumeric identifiers and count as one word under category 4 of Rule 8.6. The same applies to Git commit hashes (`a1b2c3d`), container image digests (`sha256:abc123...`), and package lockfile integrity hashes.

A sentence such as "The fix is in version `2.4.1-hotfix.3` and commit `a1b2c3d4e5f6`" has two alphanumeric identifiers that each count as one word. Version range expressions such as `>=1.0.0 <2.0.0` also count as one word when quoted.

Do not split a semantic version string into its components for word counting. "Version 1.2.3" is two words: "Version" (1 word) and "1.2.3" (1 word).

```text
# The fix is in version 2.4.1-hotfix.3 and commit a1b2c3d4e5f6
docker pull registry.example.com/api@sha256:abc123def456
```

### Edge Case 6: Numbers That Identify Document Parts

Rule 8.6 (category 1) says do not count numbers that identify paragraphs or work steps because they are part of the document numbering system. In code documentation this applies to:

- Rule or section numbers in cross-references (for example, "see Rule 8.7" — "8.7" is a document number, not counted).
- Step numbers in numbered procedures (for example, "Step 3: set the flag" — "3" is a step number, not counted).
- Issue or ticket IDs used as document references (for example, "fixes PROJ-4821" — treat "PROJ-4821" as an alphanumeric identifier, 1 word; it is not a count of quantity).

This exception keeps procedural documentation readable without inflating the word count for structural numbering that the reader skips.

```text
Step 3: set the feature flag. See Rule 8.7 for the sentence-length limit.
Fixes PROJ-4821.
```

## Cross-References

This rule works together with other STE-Code rules. Use these cross-references to apply Rule 8.6 correctly:

- **Rule 1.1 (Use approved words):** Proper nouns, quoted text, and alphanumeric identifiers are exempt from the approved-word requirement. Do not reject a sentence because a proper noun contains a non-approved word.
- **Rule 1.5 (Technical code nouns are allowed):** Framework names, library names, and tool names are technical nouns. They are also proper nouns under Rule 8.6 category 7 and count as one word.
- **Rule 1.6 (Non-approved words only when they are technical code nouns):** When a word is not in the STE-Code dictionary but is part of a proper noun, abbreviation, or quoted identifier, Rule 8.6 allows it. Do not flag it as a violation of Rule 1.6.
- **Rule 8.7 (Maximum sentence length):** Rule 8.6 makes it possible to write sentences that obey the 20/25-word limits. When you split a long procedural sentence, use Rule 8.6 to count the words in each new sentence. An identifier that spans two words in naive counting may let each split sentence stay under the limit. A sentence that appears to have 30 words may have only 22 words after applying Rule 8.6 and be compliant.
- **STE-Code Dictionary:** The dictionary lists approved words and their parts of speech. Proper nouns, abbreviations, and alphanumeric identifiers are not in the dictionary and do not need to be. They count as one word regardless.
- **Rule 1.14 (Use American English spelling):** When a proper noun uses British or another non-American spelling (for example, "Centre" in an organization name), do not change the spelling. The proper noun is exempt and counts as one word.

## Grammar Notes

### The Linguistic Principle Behind the Rule

Rule 8.6 is based on a principle from computational linguistics: a token is not always a word. In natural language processing, a tokenizer splits text on whitespace and punctuation. But a "word" for the purpose of sentence-length measurement is a unit of meaning, not a unit of whitespace separation.

In code documentation, the density of non-word tokens is much higher than in general prose. Identifiers such as `getUserById`, version strings such as `2.1.0`, and abbreviations such as `JWT` carry meaning as whole units. Splitting them into sub-tokens would inflate the word count without adding meaning.

### Why Multi-Word Proper Nouns Collapse

Proper nouns of organizations and geopolitical entities often contain function words (articles, prepositions, conjunctions). "The Apache Software Foundation" has five whitespace-separated tokens, but "The" and "of" carry no independent meaning in this context. The entire phrase identifies one entity. Counting each token separately would penalize sentences that reference well-known organizations — the opposite of what clear documentation requires.

### Abbreviations vs. Spelled-Out Forms

When you write an abbreviation, you choose to collapse a multi-word phrase into a single token. "JSON" replaces "JavaScript Object Notation" (three words becomes one). "CI/CD" replaces "continuous integration and continuous delivery" (five words becomes one). Rule 8.6 recognizes this intentional compression and counts the abbreviation as one word.

However, when you spell out the abbreviation on first use — for example, "JavaScript Object Notation (JSON)" — count the spelled-out form as its component words and the abbreviation separately. The full phrase "JavaScript Object Notation (JSON)" is a proper noun definition with a parenthetical abbreviation. Count "JavaScript Object Notation" as one word (proper noun, category 7) and "(JSON)" as one word (abbreviation with parentheses as quoted text, category 3).

### The Interaction with Sentence Splitting

Rule 8.6 is not only a counting rule. It is a design rule for sentence structure. When you know that identifiers, abbreviations, and proper nouns count as one word, you can include more technical precision in each sentence without violating length limits. This lets you write documentation that is both technically complete and easy to read.

A well-designed STE-Code sentence front-loads the action or condition, then places the multi-word element near the end: "Set the timeout to 30 seconds" (6 words) rather than "The timeout value that you should configure must be set to a duration of 30 seconds" (17 words). Rule 8.6 rewards this structure because the number-with-unit at the end counts as one word.

### Word-Count Verification Pattern

To verify that a sentence obeys Rule 8.6, use this step-by-step pattern:

1. Write the sentence.
2. Identify all numbers and replace each with a placeholder (1 word).
3. Identify all numbers with units and replace each pair with a placeholder (1 word).
4. Identify all abbreviations and replace each with a placeholder (1 word).
5. Identify all alphanumeric identifiers and replace each with a placeholder (1 word).
6. Identify all quoted text (including backtick-quoted text) and replace each with a placeholder (1 word).
7. Identify all document titles, headings, and UI text and replace each with a placeholder (1 word).
8. Identify all proper nouns and replace each with a placeholder (1 word).
9. Count the remaining words plus the placeholders.

This pattern is useful for automated word-count tools and linters that enforce Rule 8.7 sentence-length limits in documentation CI pipelines.

```python
# Word-count helper that applies Rule 8.6 (illustrative, not normative)
import re

ONE_WORD_PATTERNS = [
    r"`[^`]+`",                 # backtick-quoted text
    r'"[^"]+"',                 # double-quoted text
    r"\b[A-Za-z]+\d[A-Za-z0-9]*\b",  # alphanumeric identifier
    r"\d+\s*(?:ms|s|μs|MB|KB|GB|Mi|Gi|m|°C|kg|Ω)\b",  # number + unit
    r"\b\d+(?:\.\d+)*[A-Za-z]*\b",   # number or version
]

def count_ste_words(sentence: str) -> int:
    # Replace each one-word element with a single placeholder token.
    for pat in ONE_WORD_PATTERNS:
        sentence = re.sub(pat, " X ", sentence)
    return len(sentence.split())
```

## See also

> **See also:** Rule 1.1 — Use Approved Words
> **See also:** Rule 1.5 — Technical Code Nouns Are Allowed
> **See also:** Rule 1.6 — Non-Approved Words Only as Technical Code Nouns
> **See also:** Rule 1.14 — Use American English Spelling
> **See also:** Rule 8.7 — Maximum Sentence Length
