Files
scadalink-design/docs/plans/phase-7-integrations.md
Joseph Doherty 021817930b Generate all 11 phase implementation plans with bullet-level requirement traceability
All phases (0-8) now have detailed implementation plans with:
- Bullet-level requirement extraction from HighLevelReqs sections
- Design constraint traceability (KDD + Component Design)
- Work packages with acceptance criteria mapped to every requirement
- Split-section ownership verified across phases
- Orphan checks (forward, reverse, negative) all passing
- Codex MCP (gpt-5.4) external verification completed per phase

Total: 7,549 lines across 11 plan documents, ~160 work packages,
~400 requirements traced, ~25 open questions logged for follow-up.
2026-03-16 15:34:54 -04:00

505 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 7: Integration Surfaces
**Date**: 2026-03-16
**Status**: Plan complete
**Goal**: External systems can call in and site scripts can call out.
---
## Scope
**Components**:
- Inbound API (full runtime)
- External System Gateway (full site-side execution)
- Notification Service (full site-side delivery)
**Features**:
- Inbound API: ASP.NET endpoint, X-API-Key auth, method routing, parameter validation, script execution on central, Route.To() cross-site calls, batch attribute operations, error handling, failures-only logging
- External System Gateway: HTTP/REST client, API key + Basic Auth, per-system timeout, dual call modes (Call/CachedCall), error classification, database access (synchronous + cached write), dedicated blocking I/O dispatcher
- Notification Service: SMTP with OAuth2 Client Credentials (M365) + Basic Auth, token lifecycle, BCC delivery plain text, timeout + max connections, error classification, S&F integration
---
## Prerequisites
| Phase | What must be complete |
|-------|-----------------------|
| Phase 1 | Security & Auth (API key storage in config DB), Configuration Database |
| Phase 2 | Template Engine (instance/template model for Route.To resolution) |
| Phase 3A | Cluster Infrastructure, Site Runtime (Instance Actor, Script Actor, Script Execution Actor) |
| Phase 3B | Communication Layer (integration routing pattern), Site Runtime (script runtime API framework, Script Execution Actor lifecycle, dedicated dispatcher) |
| Phase 3C | Store-and-Forward Engine (buffering, retry, parking, replication) |
| Phase 4 | API key management UI (Admin role) |
| Phase 5 | External system definition UI, DB connection definition UI, notification list UI, inbound API method definition UI |
---
## Requirements Checklist
### Section 5.1 — External System Definitions (runtime portion)
- [ ] `[5.1-1-rt]` Definitions are deployed uniformly to all sites — site-side can load deployed definitions
- [ ] `[5.1-2-rt]` Connection details (URL, auth, protocol) used at runtime for HTTP calls
### Section 5.2 — Site-to-External-System Communication
- [ ] `[5.2-1]` Sites communicate with external systems directly (not through central)
- [ ] `[5.2-2]` Scripts invoke external system methods by referencing predefined definitions
### Section 5.3 — Store-and-Forward for External Calls (integration portion)
- [ ] `[5.3-1-int]` If external system unavailable, message buffered locally at site
- [ ] `[5.3-2-int]` Retry per message — individual failed messages retry independently
- [ ] `[5.3-3-int]` Configurable retry settings: max retry count, fixed time between retries
- [ ] `[5.3-4-int]` After max retries exhausted, message is parked
- [ ] `[5.3-5-int]` No maximum buffer size
### Section 5.5 — Database Connections (runtime portion)
- [ ] `[5.5-1-rt]` Definitions deployed to sites and loadable at runtime
- [ ] `[5.5-2-rt]` Retry settings applied to cached writes
### Section 5.6 — Database Access Modes
- [ ] `[5.6-1]` Real-time (synchronous): `Database.Connection("name")` returns raw MS SQL client connection (ADO.NET)
- [ ] `[5.6-2]` Full ADO.NET control: queries, updates, transactions, stored procedures
- [ ] `[5.6-3]` Cached write (store-and-forward): `Database.CachedWrite("name", "sql", parameters)`
- [ ] `[5.6-4]` Cached entry stores: database connection name, SQL statement, parameter values
- [ ] `[5.6-5]` If database unavailable, write buffered locally and retried per retry settings
- [ ] `[5.6-6]` After max retries exhausted, cached write is parked
### Section 6.1 — Notification Lists (runtime portion)
- [ ] `[6.1-1-rt]` Notification lists deployed to sites and loadable at runtime
- [ ] `[6.1-2-rt]` List name resolves to recipients at site
### Section 6.2 — Email Support
- [ ] `[6.2-1]` Predefined support for sending email as notification delivery mechanism
- [ ] `[6.2-2]` SMTP settings defined centrally and deployed to all sites
### Section 6.3 — Script API
- [ ] `[6.3-1]` `Notify.To("list name").Send("subject", "message")` — simplified script API
- [ ] `[6.3-2]` Available to instance scripts, alarm on-trigger scripts, and shared scripts
### Section 6.4 — Store-and-Forward for Notifications
- [ ] `[6.4-1]` If email server unavailable, notifications buffered locally
- [ ] `[6.4-2]` Same retry pattern: configurable max retry count, fixed time between retries
- [ ] `[6.4-3]` After max retries exhausted, notification parked
- [ ] `[6.4-4]` No maximum buffer size
### Section 7.1 — Inbound API Purpose
- [ ] `[7.1-1]` Web API on central cluster for external systems to call in
- [ ] `[7.1-2]` Counterpart to outbound External System Gateway
### Section 7.2 — API Key Management (already in Phase 4; Phase 7 uses the keys)
- [ ] `[7.2-rt]` API keys stored in config DB and retrievable at runtime for validation
### Section 7.3 — Authentication
- [ ] `[7.3-1]` Inbound requests authenticated via API key (not LDAP/AD)
- [ ] `[7.3-2]` API key included with each request
- [ ] `[7.3-3]` Invalid or disabled keys rejected
### Section 7.4 — API Method Definitions (runtime portion)
- [ ] `[7.4-1-rt]` Method definitions loadable at runtime for routing and validation
- [ ] `[7.4-2-rt]` Approved API keys checked at runtime per method
- [ ] `[7.4-3-rt]` Parameter validation enforced at runtime (type checking against definitions)
- [ ] `[7.4-4-rt]` Return value serialized per return definition
- [ ] `[7.4-5-rt]` Timeout enforced per method (max execution time including routed calls)
- [ ] `[7.4-6-rt]` Implementation script executed on central cluster
- [ ] `[7.4-7-rt]` Route.To() routes calls to any instance at any site
- [ ] `[7.4-8-rt]` API scripts cannot call shared scripts directly (shared scripts are site-only)
### Section 7.5 — Availability
- [ ] `[7.5-1]` Inbound API hosted only on central cluster (active node)
- [ ] `[7.5-2]` On central failover, API becomes available on new active node
### Section 4.4 — Script Capabilities (Phase 7 portion)
- [ ] `[4.4-6]` `ExternalSystem.Call()` — synchronous request/response
- [ ] `[4.4-7]` `ExternalSystem.CachedCall()` — fire-and-forget with S&F on transient failure
- [ ] `[4.4-8]` Send notifications via `Notify.To().Send()`
- [ ] `[4.4-9]` `Database.Connection()` for raw ADO.NET access; `Database.CachedWrite()` for S&F delivery
---
## Design Constraints Checklist
| ID | Constraint | Source | Mapped WP |
|----|-----------|--------|-----------|
| KDD-ext-1 | External System Gateway: HTTP/REST only, JSON serialization, API key + Basic Auth | CLAUDE.md | WP-6 |
| KDD-ext-2 | Dual call modes: Call() synchronous and CachedCall() store-and-forward | CLAUDE.md | WP-7 |
| KDD-ext-3 | Error classification: HTTP 5xx/408/429/connection = transient; other 4xx = permanent | CLAUDE.md | WP-8 |
| KDD-ext-4 | Notification Service: SMTP with OAuth2 Client Credentials (M365) or Basic Auth. BCC delivery, plain text | CLAUDE.md | WP-10, WP-11 |
| KDD-ext-5 | Inbound API: POST /api/{methodName}, X-API-Key header, flat JSON, extended type system (Object/List) | CLAUDE.md | WP-1, WP-2, WP-3 |
| KDD-sf-4 | CachedCall idempotency is the caller's responsibility | CLAUDE.md | WP-7 |
| CD-ESG-1 | ESG acts as HTTP client; base URL + method relative path | Component-ESG | WP-6 |
| CD-ESG-2 | Request params serialized as JSON body (POST/PUT) or query params (GET/DELETE) | Component-ESG | WP-6 |
| CD-ESG-3 | Credentials (API key header or Basic Auth) attached to every request | Component-ESG | WP-6 |
| CD-ESG-4 | Per-system timeout applies to all method calls | Component-ESG | WP-8 |
| CD-ESG-5 | CachedCall: on transient failure, routed to S&F. Script does not block | Component-ESG | WP-7 |
| CD-ESG-6 | CachedCall: on permanent failure (4xx), error returned synchronously. No retry | Component-ESG | WP-7 |
| CD-ESG-7 | Dedicated dispatcher for Script Execution Actors to isolate blocking I/O | Component-ESG | WP-9 |
| CD-ESG-8 | Database connections use standard ADO.NET connection pooling per named connection | Component-ESG | WP-14 |
| CD-ESG-9 | Synchronous DB failures return error to calling script | Component-ESG | WP-14 |
| CD-NS-1 | Single email per Send() call, all recipients in BCC, from address in To | Component-NotificationService | WP-11 |
| CD-NS-2 | No per-recipient deduplication | Component-NotificationService | WP-11 |
| CD-NS-3 | Transient SMTP failures (connection refused, timeout, SMTP 4xx) → S&F. Script does not block | Component-NotificationService | WP-12 |
| CD-NS-4 | Permanent SMTP failures (5xx) → error returned synchronously. No retry | Component-NotificationService | WP-12 |
| CD-NS-5 | No application-level rate limiting; SMTP server throttling handled as transient failure | Component-NotificationService | WP-11 |
| CD-NS-6 | OAuth2 token lifecycle: fetch, cache, refresh on expiry | Component-NotificationService | WP-10 |
| CD-NS-7 | Connection timeout (default 30s) and max concurrent connections (default 5) | Component-NotificationService | WP-10 |
| CD-IA-1 | All calls are POST — RPC-style, not RESTful | Component-InboundAPI | WP-1 |
| CD-IA-2 | Parameters as top-level JSON fields in request body | Component-InboundAPI | WP-3 |
| CD-IA-3 | Success: 200 with return value JSON. Failure: 4xx/5xx with error object | Component-InboundAPI | WP-5 |
| CD-IA-4 | Only failures (500) logged centrally. Successful calls not logged | Component-InboundAPI | WP-5 |
| CD-IA-5 | No rate limiting | Component-InboundAPI | WP-1 |
| CD-IA-6 | Route.To() resolves instance site from config DB, routes via Communication Layer | Component-InboundAPI | WP-4 |
| CD-IA-7 | Route.To() calls are synchronous from API caller perspective — blocks until site responds or timeout | Component-InboundAPI | WP-4 |
| CD-IA-8 | No S&F buffering for inbound API calls — site unreachable = error to caller | Component-InboundAPI | WP-4 |
| CD-IA-9 | Route.To().GetAttributes/SetAttributes batch operations | Component-InboundAPI | WP-4 |
| CD-IA-10 | Database.Connection() available to Inbound API scripts for central DB access | Component-InboundAPI | WP-4 |
---
## Work Packages
### WP-1: Inbound API — ASP.NET Endpoint Registration (M)
**Description**: Register the `POST /api/{methodName}` ASP.NET Core endpoint on central. Wire into Host via `MapInboundAPI()`.
**Acceptance Criteria**:
- `POST /api/{methodName}` endpoint registered and reachable (`[7.1-1]`, `KDD-ext-5`, `CD-IA-1`)
- API hosted only on central cluster active node (`[7.5-1]`)
- On central failover, API becomes available on new active node (`[7.5-2]`)
- No rate limiting (`CD-IA-5`)
- Content-Type: application/json
**Complexity**: M
**Traces**: `[7.1-1]`, `[7.1-2]`, `[7.5-1]`, `[7.5-2]`, KDD-ext-5, CD-IA-1, CD-IA-5
---
### WP-2: Inbound API — X-API-Key Authentication (S)
**Description**: Extract and validate API key from the `X-API-Key` header. Check key exists, is enabled, and is approved for the method.
**Acceptance Criteria**:
- API key extracted from `X-API-Key` HTTP header (`[7.3-2]`, `KDD-ext-5`)
- Key validated against config DB: exists and is enabled (`[7.3-1]`, `[7.3-3]`, `[7.2-rt]`)
- Key checked against method's approved list (`[7.4-2-rt]`)
- Invalid key → 401 Unauthorized
- Valid key but not approved for method → 403 Forbidden
- Disabled key → 401 Unauthorized
**Complexity**: S
**Traces**: `[7.2-rt]`, `[7.3-1]``[7.3-3]`, `[7.4-2-rt]`, KDD-ext-5
---
### WP-3: Inbound API — Method Routing & Parameter Validation (M)
**Description**: Resolve method by name, validate and deserialize parameters against definitions (extended type system).
**Acceptance Criteria**:
- Method resolved by name from URL path segment (`[7.4-1-rt]`)
- Parameters validated against method definition: count, names, data types (`[7.4-3-rt]`, `CD-IA-2`)
- Extended type system (Object, List) supported for parameters (`KDD-ext-5`)
- Invalid parameters → 400 Bad Request
- Unknown method → 404 Not Found
**Complexity**: M
**Traces**: `[7.4-1-rt]`, `[7.4-3-rt]`, KDD-ext-5, CD-IA-2
---
### WP-4: Inbound API — Script Execution & Route.To() (L)
**Description**: Execute the method's C# implementation script on central. Implement Route.To() for cross-site calls and batch attribute operations.
**Acceptance Criteria**:
- Implementation script executed on central cluster (`[7.4-6-rt]`)
- Per-method timeout enforced (including routed calls to sites) (`[7.4-5-rt]`)
- `Route.To("instanceCode").Call("scriptName", params)` routes to site via Communication Layer (`[7.4-7-rt]`, `CD-IA-6`)
- Route.To() resolves instance site from config DB (`CD-IA-6`)
- Calls are synchronous from caller perspective — blocks until response or timeout (`CD-IA-7`)
- No S&F buffering — site unreachable returns error to caller (`CD-IA-8`)
- `Route.To().GetAttribute()` / `Route.To().GetAttributes()` batch read (`CD-IA-9`)
- `Route.To().SetAttribute()` / `Route.To().SetAttributes()` batch write (`CD-IA-9`)
- `Database.Connection("name")` available for central DB access (`CD-IA-10`)
- API scripts cannot call shared scripts directly (`[7.4-8-rt]`)
- Return value serialized per return definition (`[7.4-4-rt]`)
**Complexity**: L
**Traces**: `[7.4-4-rt]``[7.4-8-rt]`, CD-IA-6CD-IA-10
---
### WP-5: Inbound API — Error Handling & Logging (S)
**Description**: Implement error response format and failures-only logging.
**Acceptance Criteria**:
- Success: 200 with return value JSON (`CD-IA-3`)
- Failure responses: error object with "error" and "code" fields (`CD-IA-3`)
- 401 for invalid/disabled key, 403 for unapproved key, 400 for invalid params, 500 for script failure
- Only 500 errors logged centrally (`CD-IA-4`)
- Successful calls not logged (audit log reserved for config changes) (`CD-IA-4`)
- Script execution errors: safe error message, no internal details exposed
**Complexity**: S
**Traces**: CD-IA-3, CD-IA-4
---
### WP-6: External System Gateway — HTTP/REST Client (M)
**Description**: Implement the HTTP client that executes external system API calls with JSON serialization.
**Acceptance Criteria**:
- HTTP/REST only, JSON serialization (`KDD-ext-1`, `CD-ESG-1`)
- Base URL from definition + method relative path (`CD-ESG-1`)
- Request params serialized as JSON body for POST/PUT, query params for GET/DELETE (`CD-ESG-2`)
- Response body deserialized from JSON into method return type
- Authentication: API key header or Basic Auth per system definition (`KDD-ext-1`, `CD-ESG-3`)
- Sites communicate directly with external systems (not through central) (`[5.2-1]`)
- Scripts invoke methods by referencing predefined definitions (`[5.2-2]`)
- Deployed definitions loaded at site runtime (`[5.1-1-rt]`, `[5.1-2-rt]`)
**Complexity**: M
**Traces**: `[5.1-1-rt]`, `[5.1-2-rt]`, `[5.2-1]`, `[5.2-2]`, KDD-ext-1, CD-ESG-1, CD-ESG-2, CD-ESG-3
---
### WP-7: External System Gateway — Dual Call Modes (M)
**Description**: Implement `ExternalSystem.Call()` (synchronous) and `ExternalSystem.CachedCall()` (S&F) in the script runtime API.
**Acceptance Criteria**:
- `ExternalSystem.Call("system", "method", params)` — synchronous. Script blocks until response or timeout. All failures return to script (`[4.4-6]`, `KDD-ext-2`)
- `ExternalSystem.CachedCall("system", "method", params)` — fire-and-forget. On transient failure, routed to S&F Engine. Script does not block (`[4.4-7]`, `KDD-ext-2`, `CD-ESG-5`)
- CachedCall on permanent failure (4xx except 408/429): error returned synchronously to script. No retry (`CD-ESG-6`)
- CachedCall on success: response discarded (fire-and-forget)
- CachedCall idempotency is caller's responsibility — documented (`KDD-sf-4`)
- S&F integration: buffered, retried per system's retry settings, parked after max retries (`[5.3-1-int]``[5.3-5-int]`)
**Complexity**: M
**Traces**: `[4.4-6]`, `[4.4-7]`, `[5.3-1-int]``[5.3-5-int]`, KDD-ext-2, KDD-sf-4, CD-ESG-5, CD-ESG-6
---
### WP-8: External System Gateway — Error Classification & Timeout (S)
**Description**: Implement transient/permanent error classification and per-system timeout enforcement.
**Acceptance Criteria**:
- Per-system timeout applied to all HTTP calls (`CD-ESG-4`)
- Transient failures: connection refused, timeout, HTTP 408, 429, 5xx (`KDD-ext-3`)
- Permanent failures: HTTP 4xx except 408/429 (`KDD-ext-3`)
- Transient → CachedCall buffers for retry; Call returns error to script
- Permanent → always returned to calling script regardless of call mode
- Permanent failures logged to Site Event Logging
**Complexity**: S
**Traces**: KDD-ext-3, CD-ESG-4
---
### WP-9: Blocking I/O Dispatcher Isolation (S)
**Description**: Configure a dedicated Akka.NET dispatcher for Script Execution Actors to isolate blocking I/O (HTTP calls, DB operations) from the default dispatcher.
**Acceptance Criteria**:
- Dedicated dispatcher configured for Script Execution Actors (`CD-ESG-7`)
- HTTP calls and database operations execute on dedicated dispatcher threads
- Default dispatcher (used by coordination actors) is not starved by blocking I/O
**Complexity**: S
**Traces**: CD-ESG-7
---
### WP-10: Notification Service — SMTP Client (M)
**Description**: Implement the SMTP client with support for OAuth2 Client Credentials (M365) and Basic Auth.
**Acceptance Criteria**:
- SMTP client supports OAuth2 Client Credentials flow: Tenant ID, Client ID, Client Secret (`KDD-ext-4`)
- OAuth2 token lifecycle: fetch on first use, cache, refresh on expiry (`CD-NS-6`)
- SMTP client supports Basic Auth (username/password) (`KDD-ext-4`)
- TLS modes: None, StartTLS, SSL
- Connection timeout configurable (default 30s) (`CD-NS-7`)
- Max concurrent connections configurable (default 5) (`CD-NS-7`)
- SMTP settings loaded from deployed configuration (`[6.2-1]`, `[6.2-2]`)
- Deployed notification lists loadable at runtime (`[6.1-1-rt]`, `[6.1-2-rt]`)
**Complexity**: M
**Traces**: `[6.1-1-rt]`, `[6.1-2-rt]`, `[6.2-1]`, `[6.2-2]`, KDD-ext-4, CD-NS-6, CD-NS-7
---
### WP-11: Notification Service — Email Delivery Behavior (S)
**Description**: Implement the email composition and delivery behavior: BCC, plain text, from address.
**Acceptance Criteria**:
- `Notify.To("listName").Send("subject", "message")` script API implemented (`[6.3-1]`)
- Available to instance scripts, alarm on-trigger scripts, and shared scripts (`[6.3-2]`, `[4.4-8]`)
- Single email per Send() call with all recipients in BCC (`CD-NS-1`, `KDD-ext-4`)
- From address placed in To field (`CD-NS-1`)
- Plain text only, no HTML (`KDD-ext-4`)
- No per-recipient deduplication (`CD-NS-2`)
- No application-level rate limiting (`CD-NS-5`)
**Complexity**: S
**Traces**: `[4.4-8]`, `[6.3-1]`, `[6.3-2]`, KDD-ext-4, CD-NS-1, CD-NS-2, CD-NS-5
---
### WP-12: Notification Service — Error Classification & S&F Integration (S)
**Description**: Implement transient/permanent SMTP error classification and integration with the Store-and-Forward Engine.
**Acceptance Criteria**:
- Transient failures (connection refused, timeout, SMTP 4xx): notification handed to S&F Engine. Script does not block (`CD-NS-3`, `[6.4-1]`)
- Permanent failures (SMTP 5xx): error returned synchronously to script. No retry (`CD-NS-4`)
- S&F retry per SMTP config retry settings: max retry count, fixed interval (`[6.4-2]`)
- After max retries exhausted, notification parked (`[6.4-3]`)
- No maximum buffer size (`[6.4-4]`)
**Complexity**: S
**Traces**: `[6.4-1]``[6.4-4]`, CD-NS-3, CD-NS-4
---
### WP-13: End-to-End Integration Tests (L)
**Description**: End-to-end tests covering the full integration paths.
**Acceptance Criteria**:
- **Test 1**: External system calls Inbound API → Route.To() → site script executes → response flows back (`[7.1-1]`, `[7.4-7-rt]`)
- **Test 2**: Script calls `ExternalSystem.Call()` → HTTP request → response returned to script (`[4.4-6]`)
- **Test 3**: Script calls `ExternalSystem.CachedCall()` → transient failure → S&F buffer → retry → success (`[4.4-7]`, `[5.3-1-int]`)
- **Test 4**: Script calls `Notify.To().Send()` → SMTP delivery succeeds (`[4.4-8]`, `[6.3-1]`)
- **Test 5**: Script calls `Notify.To().Send()` → SMTP unavailable → S&F buffer → retry → success (`[6.4-1]`)
- **Test 6**: Script calls `Database.Connection()` → ADO.NET query succeeds (`[4.4-9]`, `[5.6-1]`, `[5.6-2]`)
- **Test 7**: Script calls `Database.CachedWrite()` → DB unavailable → S&F buffer → retry → success (`[5.6-3]``[5.6-6]`)
- **Test 8**: CachedCall permanent failure (4xx) → error returned to script, not buffered
- **Test 9**: Inbound API → site unreachable → error returned to external caller (`CD-IA-8`)
- **Test 10**: Inbound API → disabled API key → 401 (`[7.3-3]`)
- **Test 11**: Batch attribute operations via Route.To().GetAttributes/SetAttributes (`CD-IA-9`)
**Complexity**: L
**Traces**: All requirements from this phase
---
### WP-14: Database Access — Connection() and CachedWrite() (M)
**Description**: Implement `Database.Connection()` for synchronous ADO.NET access and `Database.CachedWrite()` for S&F database writes in the script runtime API.
**Acceptance Criteria**:
- `Database.Connection("name")` returns raw ADO.NET SqlConnection (`[4.4-9]`, `[5.6-1]`)
- Full ADO.NET control: queries, updates, transactions, stored procedures (`[5.6-2]`)
- Standard ADO.NET connection pooling per named connection (`CD-ESG-8`)
- Synchronous DB failures return error to calling script (`CD-ESG-9`)
- `Database.CachedWrite("name", "sql", params)` submits to S&F Engine (`[5.6-3]`)
- Cached entry stores: connection name, SQL statement, parameter values (`[5.6-4]`)
- If DB unavailable, write buffered and retried per connection retry settings (`[5.6-5]`, `[5.5-2-rt]`)
- After max retries, cached write parked (`[5.6-6]`)
- Deployed database connection definitions loaded at site runtime (`[5.5-1-rt]`)
**Complexity**: M
**Traces**: `[4.4-9]`, `[5.5-1-rt]`, `[5.5-2-rt]`, `[5.6-1]``[5.6-6]`, CD-ESG-8, CD-ESG-9
---
## Test Strategy
### Unit Tests
- API key validation logic (valid, invalid, disabled, not approved for method)
- Method routing and parameter validation (type checking, missing params, extra params)
- Extended type system serialization/deserialization (Object, List)
- Error classification: transient vs. permanent for HTTP status codes
- Error classification: transient vs. permanent for SMTP status codes
- OAuth2 token fetch, cache, refresh-on-expiry logic
- BCC email composition
- Database.Connection() pooling behavior
- Database.CachedWrite() S&F submission
### Integration Tests
- Inbound API full flow: auth → route → method resolve → script execute → return
- External System Gateway: HTTP client against test REST server (infra/restapi)
- Notification Service: SMTP client against Mailpit test server (infra)
- Store-and-Forward integration: CachedCall → buffer → retry → deliver
- Database access: Connection() query against test MS SQL, CachedWrite() with simulated failure
- Route.To() cross-site call via Communication Layer
### Negative Tests
- `ExternalSystem.Call()` with unreachable system → error returned to script (no buffer)
- `ExternalSystem.CachedCall()` with permanent 4xx → error returned synchronously, not buffered
- Inbound API with invalid key → 401
- Inbound API with unapproved key → 403
- Inbound API with bad params → 400
- Inbound API script failure → 500 with safe error message, no internal details
- Inbound API script calls shared script → fails (shared scripts site-only)
- Inbound API route to unreachable site → error, no S&F
- `Notify.To().Send()` with SMTP 5xx → error returned to script, not buffered
- `Database.Connection()` with unreachable server → error returned to script
### Failover Tests
- Central failover → Inbound API becomes available on new active node
- Site failover → S&F buffer takeover for pending external calls, notifications, DB writes
---
## Verification Gate
Phase 7 is complete when:
1. All 14 work packages pass acceptance criteria
2. All unit, integration, negative, and failover tests pass
3. External systems can call `POST /api/{method}` with API key auth and receive scripted responses
4. Site scripts can call external systems via both `Call()` and `CachedCall()` modes
5. Notifications send via SMTP with both OAuth2 and Basic Auth
6. Database access works synchronously and via CachedWrite with S&F
7. Error classification correctly routes transient failures to S&F and permanent failures to the script
8. End-to-end integration paths verified (all 11 test scenarios in WP-13)
---
## Open Questions
| # | Question | Context | Impact | Status |
|---|----------|---------|--------|--------|
| Q12 | What Microsoft 365 tenant/app registration is available for SMTP OAuth2 testing? | Affects Notification Service OAuth2 implementation. | Phase 7. | Deferred — implement against Basic Auth first; OAuth2 tested when tenant available. |
(Existing question from questions.md — no new questions discovered.)
---
## Split-Section Verification
| Section | Phase 7 Bullets | Other Phase(s) | Other Phase Bullets |
|---------|----------------|-----------------|---------------------|
| 4.4 | `[4.4-6]``[4.4-9]` (external calls, notifications, DB access) | Phase 3B | `[4.4-1]``[4.4-5]`, `[4.4-10]` (read/write/call scripts) |
| 5.1 | `[5.1-1-rt]`, `[5.1-2-rt]` (runtime) | Phase 5 | `[5.1-1]``[5.1-5]` (definition UI) |
| 5.3 | `[5.3-1-int]``[5.3-5-int]` (integration) | Phase 3C | S&F Engine infrastructure |
| 5.5 | `[5.5-1-rt]`, `[5.5-2-rt]` (runtime) | Phase 5 | `[5.5-1]``[5.5-5]` (definition UI) |
| 6.1 | `[6.1-1-rt]`, `[6.1-2-rt]` (runtime) | Phase 5 | `[6.1-1]``[6.1-5]` (definition UI) |
| 7.4 | `[7.4-1-rt]``[7.4-8-rt]` (runtime) | Phase 5 | `[7.4-1]``[7.4-8]` (definition UI) |
---
## Orphan Check Result
**Forward check**: Every Requirements Checklist item and Design Constraints Checklist item maps to at least one work package with acceptance criteria that would fail if the requirement were not implemented. PASS.
**Reverse check**: Every work package traces back to at least one requirement or design constraint. No untraceable work. PASS.
**Split-section check**: All split sections verified above. Phase 7 covers runtime execution for all integration components. Definition management UI is in Phase 5. S&F infrastructure is in Phase 3C. Core script capabilities (read/write/call) are in Phase 3B. No unassigned bullets found. PASS.
**Negative requirement check**: The following negative requirements have explicit acceptance criteria:
- `[7.4-8-rt]` API scripts cannot call shared scripts directly → tested in WP-4 and negative tests
- `[4.4-10]` (Phase 3B) Scripts cannot access other instances → not this phase's concern
- `CD-IA-8` No S&F for inbound API calls → tested in WP-4 and WP-13 test 9
- `CD-NS-2` No per-recipient deduplication → verified in WP-11
- `CD-NS-5` No application-level rate limiting → verified in WP-11
- `CD-IA-5` No rate limiting on inbound API → verified in WP-1
- `CD-IA-4` Successful calls not logged → verified in WP-5
PASS.
**Codex MCP verification**: Skipped — external tool verification deferred.