## ADDED Requirements

### Requirement: Discord webhook delivery
The Discord notification service SHALL remain a `BoundNotificationService` that is fully configured at construction from a non-null structurally valid canonical Discord incoming-webhook `ΩRestEndpointΩ` and a non-null positive `Duration`. It SHALL make no construction-time network request, follow no HTTP redirects, and SHALL NOT expose a raw `URL` or raw `String` constructor.

The endpoint SHALL be an absolute HTTPS URI with a case-insensitive `discord.com` host, no user-info, fragment, query, or non-HTTPS port, and either an unversioned `/api/webhooks/{id}/{token}` path or a versioned `/api/v{version}/webhooks/{id}/{token}` path using a non-discontinued Discord API version from 6 through 10, with non-blank ID and token segments. Constructor validation diagnostics SHALL NOT disclose the endpoint or token.

Every public `push(...)` entry point SHALL reject a null, empty, blank, or over-2,000-character `ΩNotificationMessageΩ` with `IllegalArgumentException` before JSON serialization, request construction, or transport work. For every valid message, the service SHALL synchronously send exactly one POST to the configured endpoint with `wait=true`, the configured request timeout, JSON UTF-8 content and accept headers, a `DiscordBot (url, version)` User-Agent identifying Nenjim, and a safely serialized JSON object whose `content` preserves the message exactly. The webhook token SHALL be the only authentication mechanism.

Every 2xx HTTP response SHALL return normally. Every non-2xx response, including redirects and 429 responses, and every communication or request-preparation failure SHALL cause `IOException` without retrying, waiting, or sending another request. Response failures SHALL include the HTTP status and useful response body when available, without disclosing the endpoint or token. When synchronous HTTP delivery is interrupted, the service SHALL restore the thread interrupt flag and throw an `IOException` retaining the `InterruptedException` as its cause.

#### Scenario: Fully configured construction
- **WHEN** a caller constructs the service with a canonical Discord webhook endpoint and positive timeout
- **THEN** it receives a bound notification service without a network request

#### Scenario: Invalid endpoint or timeout is rejected
- **WHEN** a caller supplies a null or structurally invalid endpoint, or a null, zero, or negative timeout
- **THEN** construction throws `IllegalArgumentException` without disclosing the endpoint token

#### Scenario: Invalid notification message is rejected before delivery
- **WHEN** a caller pushes a null, empty, blank, or over-2,000-character message
- **THEN** the service throws `IllegalArgumentException` before serialization or HTTP work

#### Scenario: Valid message is synchronously confirmed
- **WHEN** a caller pushes a valid notification message and Discord returns a 2xx response
- **THEN** the service sends one synchronous JSON POST with `wait=true` and returns normally

#### Scenario: Discord rejects delivery
- **WHEN** Discord returns a non-2xx response, including 429 or a redirect
- **THEN** the service throws `IOException` containing the status and does not retry or follow the redirect

#### Scenario: Delivery communication fails
- **WHEN** preparing or sending the webhook request fails
- **THEN** the service throws `IOException` without exposing the webhook endpoint or token

#### Scenario: Delivery is interrupted
- **WHEN** synchronous webhook delivery is interrupted
- **THEN** the service restores the thread interrupt status and throws `IOException` with the interruption as its cause

#### Scenario: Webhook secret remains protected
- **WHEN** validation or delivery reports an error
- **THEN** no log or exception message includes the complete webhook endpoint or token

## REMOVED Requirements

### Requirement: Discord delivery remains unimplemented
**Reason**: Discord incoming-webhook delivery is now implemented synchronously.
**Migration**: Construct `DiscordNotificationService` with a canonical Discord webhook `ΩRestEndpointΩ` and a positive `Duration`, then use it through `BoundNotificationService`.
