Files
scadalink-design/docs/plans/phase-0-solution-skeleton.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

49 KiB

Phase 0: Solution Skeleton & Delivery Guardrails

Date: 2026-03-16 Status: Draft Components: Commons, Host, Solution Structure, CI Baseline


1. Scope

This phase establishes the buildable, testable baseline for the entire ScadaLink system before any domain logic is implemented. It delivers:

  • A .NET 10 solution with all 17 component projects and corresponding test projects, using the SLNX format.
  • The Commons component with its complete namespace/folder skeleton, shared data types, entity POCOs, repository interfaces, cross-cutting service interfaces, message contracts, and protocol abstraction interfaces.
  • A Host skeleton that boots by role from appsettings.json, demonstrates the extension method convention, and differentiates between central (WebApplication) and site (generic Host) startup paths.
  • Per-component options classes in their respective component projects.
  • Sample appsettings.json files for central and site topologies.

No business logic, actor systems, database connectivity, or web endpoints are implemented in this phase. The deliverable is a compiling solution with correct project references, enforceable architectural constraints, and a skeleton that subsequent phases build upon.


2. Prerequisites

  • None. This is the first phase.
  • Tooling: .NET 10 SDK, an IDE, Git.

3. Requirements Checklist

HighLevelReqs 13.1 — Timestamps (UTC)

  • [13.1-1] All timestamps throughout the system are stored, transmitted, and processed in UTC.
  • [13.1-2] Applies to: attribute value timestamps, alarm state change timestamps, audit log entries, event log entries, deployment records, health reports, store-and-forward message timestamps, and all inter-node messages.
  • [13.1-3] Local time conversion for display is a Central UI concern only — no other component performs timezone conversion.

REQ-COM-1: Shared Data Type System

  • [COM-1-1] DataType enum: Boolean, Int32, Float, Double, String, DateTime, Binary.
  • [COM-1-2] RetryPolicy: record or immutable class with max retries and fixed delay.
  • [COM-1-3] Result<T>: discriminated result type representing success or error.
  • [COM-1-4] InstanceState enum: Enabled, Disabled.
  • [COM-1-5] DeploymentStatus enum: Pending, InProgress, Success, Failed.
  • [COM-1-6] AlarmState enum: Active, Normal.
  • [COM-1-7] AlarmTriggerType enum: ValueMatch, RangeViolation, RateOfChange.
  • [COM-1-8] ConnectionHealth enum: Connected, Disconnected, Connecting, Error.
  • [COM-1-9] All types must be immutable and thread-safe.
  • [COM-1-10] Timestamp convention: all timestamps must use UTC (DateTime with DateTimeKind.Utc or DateTimeOffset with zero offset).
  • [COM-1-11] Timestamp convention applies to all stored timestamps (SQLite, MS SQL, audit entries), all message timestamps, and all wire-format timestamps.
  • [COM-1-12] Local time conversion is a UI display concern only (negative: no other component performs timezone conversion).

REQ-COM-2: Protocol Abstraction

  • [COM-2-1] IDataConnection interface for reading, writing, and subscribing to device data.
  • [COM-2-2] Related types: tag identifiers, read/write results, subscription callbacks, connection status enums, quality codes.
  • [COM-2-3] Interfaces must not reference any specific protocol implementation (negative).

REQ-COM-3: Domain Entity Classes (POCOs)

  • [COM-3-1] Plain C# classes with properties — no EF attributes, no EF base classes, no navigation property annotations.
  • [COM-3-2] May include navigation properties as plain collections (e.g., ICollection<TemplateAttribute>).
  • [COM-3-3] May include constructors that enforce invariants.
  • [COM-3-4] Must have no dependency on Entity Framework Core or any persistence library (negative).
  • [COM-3-5] Template & Modeling entities: Template, TemplateAttribute, TemplateAlarm, TemplateScript, TemplateComposition, Instance, InstanceAttributeOverride, InstanceConnectionBinding, Area.
  • [COM-3-6] Shared Scripts entities: SharedScript.
  • [COM-3-7] Sites & Data Connections entities: Site, DataConnection, SiteDataConnectionAssignment.
  • [COM-3-8] External Systems & Database Connections entities: ExternalSystemDefinition, ExternalSystemMethod, DatabaseConnectionDefinition.
  • [COM-3-9] Notifications entities: NotificationList, NotificationRecipient, SmtpConfiguration.
  • [COM-3-10] Inbound API entities: ApiKey, ApiMethod.
  • [COM-3-11] Security entities: LdapGroupMapping, SiteScopeRule.
  • [COM-3-12] Deployment entities: DeploymentRecord, SystemArtifactDeploymentRecord.
  • [COM-3-13] Audit entities: AuditLogEntry.

REQ-COM-4: Per-Component Repository Interfaces

  • [COM-4-1] ITemplateEngineRepository — templates, attributes, alarms, scripts, compositions, instances, overrides, connection bindings, areas.
  • [COM-4-2] IDeploymentManagerRepository — deployment records, deployed configuration snapshots, system-wide artifact deployment records.
  • [COM-4-3] ISecurityRepository — LDAP group mappings, site scoping rules.
  • [COM-4-4] IInboundApiRepository — API keys, API method definitions.
  • [COM-4-5] IExternalSystemRepository — external system definitions, method definitions, database connection definitions.
  • [COM-4-6] INotificationRepository — notification lists, recipients, SMTP configuration.
  • [COM-4-7] ICentralUiRepository — read-oriented queries spanning multiple domain areas.
  • [COM-4-8] All repository interfaces accept and return POCO entity classes.
  • [COM-4-9] All repository interfaces include SaveChangesAsync() or equivalent.
  • [COM-4-10] No dependency on Entity Framework Core — pure interfaces (negative).

REQ-COM-4a: Cross-Cutting Service Interfaces

  • [COM-4a-1] IAuditService with LogAsync(user, action, entityType, entityId, entityName, afterState).
  • [COM-4a-2] Defined in Commons so any central component can call it without depending on the audit implementation directly.

REQ-COM-5: Cross-Component Message Contracts

  • [COM-5-1] Deployment DTOs: configuration snapshots, deployment commands, deployment status, validation results.
  • [COM-5-2] Instance Lifecycle DTOs: disable, enable, delete commands and responses.
  • [COM-5-3] Health DTOs: health check results, site status reports, heartbeat messages, script error rates, alarm evaluation error rates.
  • [COM-5-4] Communication DTOs: site identity, connection state, routing metadata.
  • [COM-5-5] Attribute Stream DTOs: attribute value change messages (instance name, attribute path, value, quality, timestamp) and alarm state change messages (instance name, alarm name, state, priority, timestamp).
  • [COM-5-6] Debug View DTOs: subscribe/unsubscribe requests, initial snapshot, stream filter criteria.
  • [COM-5-7] Script Execution DTOs: script call requests (with recursion depth), return values, error results.
  • [COM-5-8] System-Wide Artifact DTOs: shared script packages, external system definitions, database connection definitions, notification list definitions.
  • [COM-5-9] All message types must be record types or immutable classes (negative: no mutable message types).
  • [COM-5-10] Commons must not depend on Akka.NET (negative), even though messages will be used as Akka messages.

REQ-COM-5a: Message Contract Versioning

  • [COM-5a-1] Additive-only evolution: new fields with defaults; existing fields must not be removed or have types changed (negative).
  • [COM-5a-2] Serialization must tolerate unknown fields (forward compatibility) and missing optional fields (backward compatibility).
  • [COM-5a-3] Breaking changes require a new message type and coordinated deployment.
  • [COM-5a-4] Akka.NET serialization binding must explicitly map message types to serializers (prevents binary serialization) — noted here but implemented in Phase 1/3A when Akka is bootstrapped.

REQ-COM-5b: Namespace & Folder Convention

  • [COM-5b-1] Top-level folders: Types/, Interfaces/, Entities/, Messages/.
  • [COM-5b-2] Types/ contains shared data types (REQ-COM-1) including Enums/ subfolder.
  • [COM-5b-3] Interfaces/Protocol/ for IDataConnection and related types.
  • [COM-5b-4] Interfaces/Repositories/ for per-component repository interfaces.
  • [COM-5b-5] Interfaces/Services/ for cross-cutting service interfaces (IAuditService).
  • [COM-5b-6] Entities/ subfolders by domain area: Templates, Instances, Sites, ExternalSystems, Notifications, InboundApi, Security, Deployment, Scripts, Audit.
  • [COM-5b-7] Messages/ subfolders by concern: Deployment, Lifecycle, Health, Communication, Streaming, DebugView, ScriptExecution, Artifacts.
  • [COM-5b-8] Namespaces mirror folder structure (e.g., ScadaLink.Commons.Entities.Templates).
  • [COM-5b-9] Interface names use I prefix.
  • [COM-5b-10] Entity classes named after domain concept — no Entity or Model suffixes.
  • [COM-5b-11] Message contracts named as commands, events, or responses.
  • [COM-5b-12] Enums use singular names.

REQ-COM-6: No Business Logic

  • [COM-6-1] Commons contains only: data structures (records, classes, structs), interfaces, enums, constants.
  • [COM-6-2] Must not contain business logic, service implementations, actor definitions, or orchestration code (negative).
  • [COM-6-3] Method bodies limited to trivial data-access logic (factory methods, constructor invariant validation).

REQ-COM-7: Minimal Dependencies

  • [COM-7-1] Depends only on core .NET libraries (System.*, Microsoft.Extensions.Primitives if needed).
  • [COM-7-2] Must not reference Akka.NET or Akka.* packages (negative).
  • [COM-7-3] Must not reference ASP.NET Core or Microsoft.AspNetCore.* packages (negative).
  • [COM-7-4] Must not reference Entity Framework Core or Microsoft.EntityFrameworkCore.* packages (negative).
  • [COM-7-5] Must not reference any third-party libraries requiring paid licenses (negative).

REQ-HOST-1: Single Binary Deployment

  • [HOST-1-1] Same compiled binary deployable to both central and site nodes.
  • [HOST-1-2] Node role determined solely by configuration in appsettings.json.
  • [HOST-1-3] No separate build targets, projects, or conditional compilation symbols for central vs. site (negative).

REQ-HOST-2: Role-Based Service Registration (Phase 0 skeleton)

  • [HOST-2-1] Host inspects configured node role at startup.
  • [HOST-2-2] Registers only component services appropriate for the role.
  • [HOST-2-3] Shared (both): ClusterInfrastructure, Communication, HealthMonitoring, ExternalSystemGateway, NotificationService.
  • [HOST-2-4] Central only: TemplateEngine, DeploymentManager, Security, AuditLogging, CentralUI, InboundAPI.
  • [HOST-2-5] Site only: SiteRuntime, DataConnectionLayer, StoreAndForward, SiteEventLogging.
  • [HOST-2-6] Components not applicable to the role must not be registered (negative).

REQ-HOST-3: Configuration Binding (Phase 0 skeleton)

  • [HOST-3-1] Bind configuration sections from appsettings.json to strongly-typed options classes using .NET Options pattern.
  • [HOST-3-2] Infrastructure sections: ScadaLink:Node (NodeOptions), ScadaLink:Cluster (ClusterOptions), ScadaLink:Database (DatabaseOptions).
  • [HOST-3-3] Per-component sections: DataConnection, StoreAndForward, HealthMonitoring, SiteEventLog, Communication, Security, InboundApi, Notification, Logging.
  • [HOST-3-4] Each component defines its own options class in its own project.
  • [HOST-3-5] Host binds via services.Configure<T>(configuration.GetSection("ScadaLink:<ComponentName>")).
  • [HOST-3-6] Components read options via IOptions<T> — never IConfiguration directly (negative).

REQ-HOST-7: ASP.NET vs Generic Host (Phase 0 skeleton)

  • [HOST-7-1] Central nodes use WebApplication.CreateBuilder (ASP.NET Core host with Kestrel).
  • [HOST-7-2] Site nodes use Host.CreateDefaultBuilder (generic IHost — no Kestrel, no HTTP, no web pipeline).
  • [HOST-7-3] Site nodes must never accept inbound HTTP connections (negative).

REQ-HOST-10: Extension Method Convention

  • [HOST-10-1] Each component exposes IServiceCollection.AddXxx() for DI registration.
  • [HOST-10-2] Each component with actors exposes AkkaConfigurationBuilder.AddXxxActors() (stub in Phase 0).
  • [HOST-10-3] CentralUI and InboundAPI expose WebApplication.MapXxx() (stub in Phase 0).
  • [HOST-10-4] Host's Program.cs calls these extension methods; component libraries own the registration logic.
  • [HOST-10-5] Host remains thin — no component-specific logic in Program.cs.

4. Design Constraints Checklist

From CLAUDE.md Key Design Decisions

  • [KDD-data-6] All timestamps are UTC throughout the system. → Enforced in type system (COM-1-10, COM-1-11, COM-1-12).
  • [KDD-code-1] Entity classes are persistence-ignorant POCOs in Commons; EF mappings in Configuration Database. → Phase 0 delivers the POCOs; Phase 1 delivers the EF mappings.
  • [KDD-code-2] Repository interfaces in Commons; implementations in Configuration Database. → Phase 0 delivers the interfaces; Phase 1 delivers implementations.
  • [KDD-code-3] Commons namespace hierarchy: Types/, Interfaces/, Entities/, Messages/ with domain area subfolders. → Directly maps to REQ-COM-5b.
  • [KDD-code-4] Message contracts follow additive-only evolution rules. → Directly maps to REQ-COM-5a.
  • [KDD-code-5] Per-component configuration via appsettings.json sections bound to options classes. → Directly maps to REQ-HOST-3.
  • [KDD-code-6] Options classes owned by component projects, not Commons. → Directly maps to HOST-3-4.

From Component-Commons.md

  • [CD-Commons-1] Commons is referenced by all component libraries and the Host — project reference structure must reflect this.
  • [CD-Commons-2] No EF navigation property annotations on POCOs (Fluent API only in Configuration Database).
  • [CD-Commons-3] Configuration Database implements repository interfaces and maps POCOs — Phase 0 establishes the interface contract; implementation deferred.

From Component-Host.md

  • [CD-Host-1] Host is the composition root — references every component project to call their extension methods.
  • [CD-Host-2] Configuration Database registration (DbContext, repository wiring) is a Host responsibility — Phase 0 includes ConfigurationDatabase in Host's AddXxx() call chain (skeleton); full DbContext/repository wiring in Phase 1.
  • [CD-Host-3] Component registration matrix defines which components register for which roles (14 components + ConfigurationDatabase).

From Resolved Questions (questions.md)

  • [Q1] .NET 10 LTS.
  • [Q3] Single monorepo with SLNX solution file.
  • [Q4] No CI/CD pipeline (build/test/format is local tooling only).

5. Work Packages

WP-0.1: Solution Structure

Description: Create the .NET 10 solution with all 17 component projects, their test projects, and the Host project using the SLNX format. Establish project references: all components reference Commons; Host references all components.

Acceptance Criteria:

  • 15 component class library projects exist under src/ (all components except Host and Commons: TemplateEngine, DeploymentManager, SiteRuntime, DataConnectionLayer, Communication, StoreAndForward, ExternalSystemGateway, NotificationService, CentralUI, Security, HealthMonitoring, SiteEventLogging, ClusterInfrastructure, InboundAPI, ConfigurationDatabase).
  • 1 Commons class library project exists under src/.
  • 1 Host project (console/web application) exists under src/.
  • 17 corresponding test projects exist under tests/ (one per component + Commons + Host, xUnit).
  • SLNX solution file at the repository root includes all 17 source projects and 17 test projects.
  • All 15 component library projects have a project reference to ScadaLink.Commons.
  • ScadaLink.Host has project references to all 15 component library projects + Commons (16 total).
  • dotnet build succeeds with zero errors and zero warnings.
  • dotnet test succeeds (no tests yet, but framework is wired).

Complexity: M

Requirements Traced: [HOST-1-1], [HOST-1-3], [CD-Host-1], [CD-Commons-1], [Q1], [Q3]


WP-0.2: Commons Namespace & Folder Skeleton

Description: Create the complete folder and namespace structure for Commons as specified by REQ-COM-5b. All folders exist with placeholder files or namespace declarations as appropriate.

Acceptance Criteria:

  • Top-level folders exist: Types/, Types/Enums/, Interfaces/, Interfaces/Protocol/, Interfaces/Repositories/, Interfaces/Services/, Entities/, Messages/.
  • Entity subfolders exist: Templates/, Instances/, Sites/, ExternalSystems/, Notifications/, InboundApi/, Security/, Deployment/, Scripts/, Audit/.
  • Message subfolders exist: Deployment/, Lifecycle/, Health/, Communication/, Streaming/, DebugView/, ScriptExecution/, Artifacts/.
  • Namespace conventions match folder structure (e.g., ScadaLink.Commons.Entities.Templates).

Complexity: S

Requirements Traced: [COM-5b-1], [COM-5b-2], [COM-5b-3], [COM-5b-4], [COM-5b-5], [COM-5b-6], [COM-5b-7], [COM-5b-8], [KDD-code-3]


WP-0.3: Commons Shared Data Types

Description: Implement all shared data types defined by REQ-COM-1, including enums, RetryPolicy, Result<T>, and the UTC timestamp convention.

Acceptance Criteria:

  • DataType enum with values: Boolean, Int32, Float, Double, String, DateTime, Binary.
  • RetryPolicy as a record or immutable class with MaxRetries (int) and Delay (TimeSpan) properties.
  • Result<T> as a discriminated result type with success/error states and factory methods (Success(T), Failure(string)).
  • InstanceState enum: Enabled, Disabled.
  • DeploymentStatus enum: Pending, InProgress, Success, Failed.
  • AlarmState enum: Active, Normal.
  • AlarmTriggerType enum: ValueMatch, RangeViolation, RateOfChange.
  • ConnectionHealth enum: Connected, Disconnected, Connecting, Error.
  • All types are immutable and thread-safe (record types for value objects — immutability guarantees thread safety; enums are inherently thread-safe).
  • A UtcTimestamp helper or convention document/attribute is provided to enforce UTC on DateTime/DateTimeOffset fields. Unit test verifies that constructing a DateTimeOffset with non-zero offset is rejected or documented as invalid.
  • Enum names are singular (not plural).
  • Unit tests verify: Result<T> success/error construction, pattern matching, immutability of RetryPolicy.

Complexity: S

Requirements Traced: [COM-1-1], [COM-1-2], [COM-1-3], [COM-1-4], [COM-1-5], [COM-1-6], [COM-1-7], [COM-1-8], [COM-1-9], [COM-1-10], [COM-1-11], [COM-1-12], [COM-5b-2], [COM-5b-12], [13.1-1], [13.1-2], [13.1-3], [KDD-data-6]


WP-0.4: Commons Domain Entity POCOs

Description: Implement all persistence-ignorant POCO entity classes organized by domain area, with appropriate properties, navigation collections, and constructor invariants.

Acceptance Criteria:

  • Templates/: Template (Id, Name, Description, ParentTemplateId, navigation to Attributes/Alarms/Scripts/Compositions), TemplateAttribute (Id, TemplateId, Name, Value, DataType, IsLocked, Description, DataSourceReference), TemplateAlarm (Id, TemplateId, Name, Description, PriorityLevel, IsLocked, TriggerType, TriggerConfig, OnTriggerScriptId), TemplateScript (Id, TemplateId, Name, IsLocked, Code, TriggerType, TriggerConfig, Parameters, ReturnDefinition, MinTimeBetweenRuns), TemplateComposition (Id, TemplateId, ComposedTemplateId, InstanceName).
  • Instances/: Instance (Id, TemplateId, SiteId, AreaId, UniqueName, State), InstanceAttributeOverride (Id, InstanceId, AttributeName, OverrideValue), InstanceConnectionBinding (Id, InstanceId, AttributeName, DataConnectionId), Area (Id, SiteId, Name, ParentAreaId, navigation to children).
  • Sites/: Site (Id, Name, SiteId), DataConnection (Id, Name, Protocol, Configuration), SiteDataConnectionAssignment (Id, SiteId, DataConnectionId).
  • ExternalSystems/: ExternalSystemDefinition (Id, Name, EndpointUrl, AuthType, AuthConfig, RetryPolicy), ExternalSystemMethod (Id, ExternalSystemDefinitionId, Name, Parameters, ReturnDefinition), DatabaseConnectionDefinition (Id, Name, ConnectionString, RetryPolicy).
  • Notifications/: NotificationList (Id, Name, navigation to recipients), NotificationRecipient (Id, NotificationListId, Name, EmailAddress), SmtpConfiguration (Id, Host, Port, AuthType, Credentials, FromAddress).
  • InboundApi/: ApiKey (Id, Name, KeyValue, IsEnabled), ApiMethod (Id, Name, Script, ApprovedApiKeyIds, Parameters, ReturnDefinition, TimeoutSeconds).
  • Security/: LdapGroupMapping (Id, LdapGroupName, Role), SiteScopeRule (Id, LdapGroupMappingId, SiteId).
  • Deployment/: DeploymentRecord (Id, InstanceId, Status, DeploymentId, RevisionHash, DeployedBy, DeployedAt, CompletedAt), SystemArtifactDeploymentRecord (Id, ArtifactType, DeployedBy, DeployedAt, PerSiteStatus).
  • Scripts/: SharedScript (Id, Name, Code, Parameters, ReturnDefinition).
  • Audit/: AuditLogEntry (Id, User, Action, EntityType, EntityId, EntityName, AfterStateJson, Timestamp).
  • All timestamp properties use DateTimeOffset (UTC).
  • No EF attributes ([Key], [ForeignKey], etc.) on any POCO.
  • No dependency on Microsoft.EntityFrameworkCore in the Commons .csproj.
  • Navigation properties use ICollection<T> or IReadOnlyCollection<T>.
  • Unit tests verify: timestamp properties are UTC-only (where enforced by constructor), no EF references in assembly metadata.

Complexity: L

Requirements Traced: [COM-3-1], [COM-3-2], [COM-3-3], [COM-3-4], [COM-3-5], [COM-3-6], [COM-3-7], [COM-3-8], [COM-3-9], [COM-3-10], [COM-3-11], [COM-3-12], [COM-3-13], [COM-5b-6], [COM-5b-10], [KDD-code-1], [CD-Commons-2]


WP-0.5: Commons Repository Interfaces

Description: Define all per-component repository interfaces with method signatures matching the data needs of their consuming components. Interfaces accept and return POCOs, include SaveChangesAsync(), and have no EF dependency.

Acceptance Criteria:

  • ITemplateEngineRepository with CRUD methods for templates, attributes, alarms, scripts, compositions, instances, overrides, connection bindings, areas. Includes SaveChangesAsync().
  • IDeploymentManagerRepository with methods for deployment records, deployed configuration snapshots, system-wide artifact deployment records. Includes SaveChangesAsync().
  • ISecurityRepository with methods for LDAP group mappings and site scope rules. Includes SaveChangesAsync().
  • IInboundApiRepository with methods for API keys and API method definitions. Includes SaveChangesAsync().
  • IExternalSystemRepository with methods for external system definitions, method definitions, and database connection definitions. Includes SaveChangesAsync().
  • INotificationRepository with methods for notification lists, recipients, and SMTP configuration. Includes SaveChangesAsync().
  • ICentralUiRepository with read-oriented query methods spanning multiple domain areas.
  • All methods accept and return POCO types from ScadaLink.Commons.Entities.*.
  • No using or reference to Microsoft.EntityFrameworkCore.* in any interface file.
  • All interfaces are in ScadaLink.Commons.Interfaces.Repositories namespace.
  • Interface names use I prefix.

Complexity: M

Requirements Traced: [COM-4-1], [COM-4-2], [COM-4-3], [COM-4-4], [COM-4-5], [COM-4-6], [COM-4-7], [COM-4-8], [COM-4-9], [COM-4-10], [COM-5b-4], [COM-5b-9], [KDD-code-2]


WP-0.6: Commons Cross-Cutting Service Interfaces

Description: Define the IAuditService interface in Commons for cross-cutting audit logging.

Acceptance Criteria:

  • IAuditService interface with LogAsync(string user, string action, string entityType, int entityId, string entityName, object? afterState) method (or equivalent signature).
  • Located in ScadaLink.Commons.Interfaces.Services namespace.
  • No dependency on Configuration Database or EF Core.
  • Interface is callable by any central component without depending on the audit implementation.

Complexity: S

Requirements Traced: [COM-4a-1], [COM-4a-2], [COM-5b-5]


WP-0.7: Commons Message Contracts

Description: Define all cross-component message contracts as record types organized by concern area. Establish the additive-only versioning convention with documentation.

Acceptance Criteria:

  • Deployment/: Records for DeployInstanceCommand, DeploymentStatusResponse, DeploymentValidationResult, FlattenedConfigurationSnapshot (or similar).
  • Lifecycle/: Records for DisableInstanceCommand, EnableInstanceCommand, DeleteInstanceCommand, InstanceLifecycleResponse.
  • Health/: Records for HealthCheckResult (per-metric check outcome), SiteStatusReport (aggregated site health snapshot), SiteHealthReport (periodic report with script error rates, alarm evaluation error rates, S&F buffer depths), HeartbeatMessage.
  • Communication/: Records for SiteIdentity, ConnectionStateMessage, RoutingMetadata.
  • Streaming/: Records for AttributeValueChanged (instance name, attribute path, value, quality, timestamp) and AlarmStateChanged (instance name, alarm name, state, priority, timestamp).
  • DebugView/: Records for SubscribeDebugView, UnsubscribeDebugView, DebugViewSnapshot, DebugViewFilterCriteria.
  • ScriptExecution/: Records for ScriptCallRequest (with recursion depth), ScriptCallResult, ScriptErrorResult.
  • Artifacts/: Records for SharedScriptPackage, ExternalSystemDefinitionArtifact, DatabaseConnectionDefinitionArtifact, NotificationListDefinitionArtifact.
  • All message types are record types (immutable by default).
  • No Akka.* references in Commons .csproj or any message file.
  • All timestamp fields use DateTimeOffset (UTC).
  • Message naming convention: commands, events, or responses (e.g., DeployInstanceCommand, AttributeValueChanged, DeploymentStatusResponse).
  • A VERSIONING.md or code comment documents the additive-only evolution rules: no field removal, no type changes, new fields must have defaults, breaking changes require new types.
  • Unit tests verify: all message types are records, all have init-only or constructor-set properties (immutability check).
  • Unit tests verify forward/backward compatibility convention: a representative message contract can be serialized to JSON then deserialized with an extra unknown field (forward compat) and with an optional field missing (backward compat) without error. This validates the structural design supports [COM-5a-2].

Complexity: M

Requirements Traced: [COM-5-1], [COM-5-2], [COM-5-3], [COM-5-4], [COM-5-5], [COM-5-6], [COM-5-7], [COM-5-8], [COM-5-9], [COM-5-10], [COM-5a-1], [COM-5a-2], [COM-5a-3], [COM-5b-7], [COM-5b-11], [KDD-code-4]


WP-0.8: Commons Protocol Abstraction

Description: Define the IDataConnection interface and related types for the Data Connection Layer's protocol abstraction.

Acceptance Criteria:

  • IDataConnection interface with methods for: connect, disconnect, subscribe to tag paths, unsubscribe, read tag value, write tag value.
  • Related types in Interfaces/Protocol/: TagIdentifier (tag path), TagValue (value + quality + timestamp), ReadResult (value or error), WriteResult (success/failure), SubscriptionCallback (delegate or interface for value change notifications), ConnectionStatus enum (mirrors ConnectionHealth: Connected, Disconnected, Connecting, Error), QualityCode enum (Good, Bad, Uncertain, etc.).
  • No protocol-specific references (no OPC UA types, no gRPC types) — pure abstraction.
  • Located in ScadaLink.Commons.Interfaces.Protocol namespace.
  • All timestamp fields use DateTimeOffset (UTC).

Complexity: S

Requirements Traced: [COM-2-1], [COM-2-2], [COM-2-3], [COM-5b-3]


WP-0.9: Commons Architectural Constraint Enforcement

Description: Verify and enforce that Commons has no business logic and minimal dependencies through tests and project configuration.

Acceptance Criteria:

  • Commons .csproj references only System.* and optionally Microsoft.Extensions.Primitives. No other package references.
  • An architectural test (using reflection or a test library) verifies:
    • No classes in Commons implement business logic (no service classes, no actor classes).
    • No reference to Akka.*, Microsoft.AspNetCore.*, or Microsoft.EntityFrameworkCore.* assemblies.
    • No reference to paid-license third-party packages.
  • All method bodies in entity classes are limited to: constructors (invariant enforcement), factory methods, property getters/setters, ToString() overrides, equality comparisons.
  • Test validates that no class in Commons has methods with complex logic (heuristic: methods with more than a configurable line threshold, excluding property accessors).

Complexity: S

Requirements Traced: [COM-6-1], [COM-6-2], [COM-6-3], [COM-7-1], [COM-7-2], [COM-7-3], [COM-7-4], [COM-7-5]


WP-0.10: Host Skeleton with Role-Based Startup

Description: Implement the Host Program.cs skeleton that reads node role from configuration and branches into WebApplication (central) or generic Host (site) startup paths. Wire the extension method convention with stub AddXxx() calls for all components, conditional on role.

Acceptance Criteria:

  • Program.cs reads ScadaLink:Node:Role from configuration.
  • When role is Central: uses WebApplication.CreateBuilder, calls AddXxx() for shared + central-only components, calls MapCentralUI() and MapInboundAPI() stubs.
  • When role is Site: uses Host.CreateDefaultBuilder, calls AddXxx() for shared + site-only components. Does not configure Kestrel, HTTP, or any web middleware.
  • Component registration follows the registration matrix exactly (14 components + ConfigurationDatabase on central).
  • Configuration binding: services.Configure<NodeOptions>(config.GetSection("ScadaLink:Node")) and equivalent for all component sections.
  • Each of the 15 component library projects exposes at minimum an AddXxx() extension method on IServiceCollection (can be empty body for Phase 0).
  • Each component that has actors (per registration matrix: ClusterInfrastructure, Communication, HealthMonitoring, ExternalSystemGateway, NotificationService, TemplateEngine, DeploymentManager, Security, SiteRuntime, DataConnectionLayer, StoreAndForward, SiteEventLogging) exposes an AddXxxActors() stub extension method. The method signature accepts the Akka configuration builder type (or a placeholder interface if Akka.Hosting is not yet referenced) and has an empty body in Phase 0.
  • CentralUI and InboundAPI expose MapCentralUI() and MapInboundAPI() stub extension methods on WebApplication (or IEndpointRouteBuilder).
  • Host Program.cs calls AddXxxActors() stubs for applicable components (conditional on role), and calls MapCentralUI()/MapInboundAPI() on central.
  • Host compiles and runs to completion with a minimal appsettings.json for both central and site roles.
  • Site-role startup does not open any network port (verified by test or manual check).
  • Unit test: host starts with central role config and does not throw; host starts with site role config and does not throw.

Complexity: M

Requirements Traced: [HOST-1-1], [HOST-1-2], [HOST-1-3], [HOST-2-1], [HOST-2-2], [HOST-2-3], [HOST-2-4], [HOST-2-5], [HOST-2-6], [HOST-7-1], [HOST-7-2], [HOST-7-3], [HOST-10-1], [HOST-10-2], [HOST-10-3], [HOST-10-4], [HOST-10-5], [CD-Host-1], [CD-Host-2], [CD-Host-3]


WP-0.11: Per-Component Options Classes

Description: Create strongly-typed options classes in each component project, matching the configuration sections defined in REQ-HOST-3. Wire binding in Host Program.cs.

Acceptance Criteria:

  • NodeOptions in Host project: Role (string/enum), NodeHostname (string), SiteId (string), RemotingPort (int).
  • ClusterOptions in ClusterInfrastructure project: SeedNodes (list), SplitBrainResolverStrategy, StableAfter, HeartbeatInterval, FailureDetectionThreshold, MinNrOfMembers.
  • DatabaseOptions in Host project: ConfigurationDb (string), MachineDataDb (string), SQLite paths.
  • DataConnectionOptions in DataConnectionLayer project: ReconnectInterval, TagResolutionRetryInterval, WriteTimeout.
  • StoreAndForwardOptions in StoreAndForward project: SqliteDbPath, ReplicationEnabled.
  • HealthMonitoringOptions in HealthMonitoring project: ReportInterval, OfflineTimeout.
  • SiteEventLogOptions in SiteEventLogging project: RetentionDays, MaxStorageMb, PurgeScheduleCron.
  • CommunicationOptions in Communication project: DeploymentTimeout, LifecycleTimeout, QueryTimeout, TransportHeartbeatInterval, TransportFailureThreshold.
  • SecurityOptions in Security project: LdapServer, LdapPort, LdapUseTls, JwtSigningKey, JwtExpiryMinutes, IdleTimeoutMinutes.
  • InboundApiOptions in InboundApi project: DefaultMethodTimeout.
  • NotificationOptions in NotificationService project (minimal — SMTP config is in config DB).
  • LoggingOptions in Host project: Serilog sink configuration, log level overrides.
  • All options classes are plain POCOs with public properties.
  • Options classes live in their respective component projects, not in Commons.
  • Host Program.cs binds all sections via services.Configure<T>().
  • Architectural test: no component library project (excluding Host) contains any using of Microsoft.Extensions.Configuration or accepts IConfiguration in its AddXxx() method signature. Components access configuration only via IOptions<T> / IOptionsSnapshot<T>.

Complexity: M

Requirements Traced: [HOST-3-1], [HOST-3-2], [HOST-3-3], [HOST-3-4], [HOST-3-5], [HOST-3-6], [KDD-code-5], [KDD-code-6]


WP-0.12: Local Dev Topology Documentation & Sample Configuration

Description: Create sample appsettings.json files for central and site roles demonstrating the full configuration structure. Document the local development topology.

Acceptance Criteria:

  • appsettings.Central.json with: ScadaLink:Node (Role=Central, NodeHostname, RemotingPort), ScadaLink:Cluster (seed nodes for 2-node central), ScadaLink:Database (ConfigurationDb and MachineDataDb connection strings pointing to local Docker SQL Server), and all per-component sections with sensible defaults.
  • appsettings.Site.json with: ScadaLink:Node (Role=Site, NodeHostname, SiteId, RemotingPort), ScadaLink:Cluster (seed nodes for 2-node site), ScadaLink:Database (SQLite paths), and all per-component sections with sensible defaults.
  • Both files are valid JSON and the Host loads them without error.
  • A brief topology comment block or accompanying doc section explains: 2-node central cluster, 2-node site cluster, what ports are used, how to run locally with different roles.

Complexity: S

Requirements Traced: [HOST-1-2], [HOST-3-2], [HOST-3-3]


6. Test Strategy

Unit Tests

Area Tests Work Package
Result<T> Success construction, error construction, map/bind, pattern matching WP-0.3
RetryPolicy Immutability, default values WP-0.3
Enums All enum values present and correctly named (singular) WP-0.3
Entity POCOs No EF attributes via reflection, timestamp properties are DateTimeOffset, navigation properties are ICollection<T> WP-0.4
Repository interfaces No EF references in assembly, all include SaveChangesAsync WP-0.5
Message contracts All are record types, all timestamp fields are DateTimeOffset, immutability check WP-0.7
Protocol abstraction No protocol-specific type references WP-0.8
Architectural constraints Commons has no forbidden dependencies, no business logic classes WP-0.9
Host startup Central role boots without error, site role boots without error WP-0.10
Options classes All options classes are POCOs, none in Commons project WP-0.11

Integration Tests

Area Tests Work Package
Solution build dotnet build zero errors, zero warnings WP-0.1
Host central boot Host starts with central appsettings, binds all config sections, no crash WP-0.10, WP-0.12
Host site boot Host starts with site appsettings, binds all config sections, no crash, no HTTP listener WP-0.10, WP-0.12

Negative Tests

Requirement Negative Test Work Package
[COM-3-4] No EF dependency Reflection test: Commons assembly does not reference EF Core WP-0.9
[COM-5-10] No Akka dependency Reflection test: Commons assembly does not reference Akka WP-0.9
[COM-6-2] No business logic Scan for service/actor classes in Commons — expect none WP-0.9
[COM-7-2] No Akka packages Verify Commons .csproj has no Akka PackageReference WP-0.9
[COM-7-3] No ASP.NET packages Verify Commons .csproj has no ASP.NET PackageReference WP-0.9
[COM-7-4] No EF packages Verify Commons .csproj has no EF PackageReference WP-0.9
[HOST-1-3] No conditional compilation Verify no #if directives in Host project WP-0.10
[HOST-2-6] Non-applicable components not registered Site boot does not register central-only services; central boot does not register site-only services WP-0.10
[HOST-7-3] Site nodes no HTTP Site boot does not listen on any port WP-0.10
[HOST-3-6] Components never read IConfiguration directly No component library AddXxx() method accepts IConfiguration; no using Microsoft.Extensions.Configuration in component libraries WP-0.11
[COM-1-12] / [13.1-3] No timezone conversion outside UI No ToLocalTime() calls in Commons or any non-UI component WP-0.9

7. Verification Gate

Phase 0 is complete when all of the following pass:

  1. dotnet build ScadaLink.slnx completes with zero errors and zero warnings.
  2. dotnet test ScadaLink.slnx passes all unit and integration tests.
  3. Host boots successfully in central role from appsettings.Central.json and exits cleanly.
  4. Host boots successfully in site role from appsettings.Site.json and exits cleanly.
  5. Site-role Host does not open any network port.
  6. All 17 component projects compile with correct references to Commons.
  7. Commons project has zero non-core-NET package references.
  8. All architectural constraint tests pass (no EF, no Akka, no ASP.NET in Commons).
  9. All entity POCOs use DateTimeOffset for timestamp fields.
  10. All message contracts are record types.
  11. Every item in the Requirements Checklist (Section 3) and Design Constraints Checklist (Section 4) maps to a work package with acceptance criteria.

8. Open Questions

# Question Context Impact Status
Q16 Should Result<T> use a OneOf-style library or be hand-rolled? Affects COM-7-1 (minimal dependencies). A hand-rolled Result<T> keeps zero external dependencies. Phase 0. Recommend hand-rolled to maintain zero-dependency constraint. Log for implementer's decision.
Q17 Should entity POCO properties be required (init-only) or settable? EF Core Fluent API mapping may need settable properties. POCOs must be persistence-ignorant but still mappable by Phase 1. Phase 0 / Phase 1 boundary. Recommend { get; set; } for EF compatibility, with constructor invariants for required fields. Log for implementer.
Q18 What QualityCode values should the protocol abstraction define? OPC UA has a rich quality model (Good, Uncertain, Bad with subtypes). Need to decide on a simplified shared set. Phase 0. Recommend: Good, Bad, Uncertain as the minimal set, with room to extend.
Q19 Should IDataConnection be IAsyncDisposable for connection cleanup? Affects DCL connection actor lifecycle. Phase 0 / Phase 3B boundary. Recommend yes — add IAsyncDisposable to support proper cleanup.

These questions have been added to docs/plans/questions.md.


9. Post-Generation Verification (Orphan Check)

Forward Check: Requirements → Work Packages

Every item in the Requirements Checklist (Section 3) and Design Constraints Checklist (Section 4) has been verified against work package mappings:

Requirement ID(s) Work Package Verified
[13.1-1], [13.1-2], [13.1-3] WP-0.3 (UTC in type system), WP-0.4 (DateTimeOffset on entities), WP-0.7 (DateTimeOffset on messages) Yes
[COM-1-1] through [COM-1-12] WP-0.3 Yes
[COM-2-1], [COM-2-2], [COM-2-3] WP-0.8 Yes
[COM-3-1] through [COM-3-13] WP-0.4 Yes
[COM-4-1] through [COM-4-10] WP-0.5 Yes
[COM-4a-1], [COM-4a-2] WP-0.6 Yes
[COM-5-1] through [COM-5-10] WP-0.7 Yes
[COM-5a-1] through [COM-5a-3] WP-0.7 Yes
[COM-5a-4] Explicitly deferred to Phase 1/3A (Akka serialization binding). Noted in plan; no Phase 0 work package. Yes (deferred)
[COM-5b-1] through [COM-5b-12] WP-0.2, WP-0.3, WP-0.4, WP-0.5, WP-0.6, WP-0.7, WP-0.8 Yes
[COM-6-1] through [COM-6-3] WP-0.9 Yes
[COM-7-1] through [COM-7-5] WP-0.9 Yes
[HOST-1-1] through [HOST-1-3] WP-0.1, WP-0.10 Yes
[HOST-2-1] through [HOST-2-6] WP-0.10 Yes
[HOST-3-1] through [HOST-3-6] WP-0.11 Yes
[HOST-7-1] through [HOST-7-3] WP-0.10 Yes
[HOST-10-1] through [HOST-10-5] WP-0.10 Yes
[KDD-data-6] WP-0.3, WP-0.4, WP-0.7 Yes
[KDD-code-1] WP-0.4 (POCOs), WP-0.9 (no EF) Yes
[KDD-code-2] WP-0.5 (interfaces), WP-0.9 (no EF) Yes
[KDD-code-3] WP-0.2 Yes
[KDD-code-4] WP-0.7 Yes
[KDD-code-5] WP-0.11 Yes
[KDD-code-6] WP-0.11 Yes
[CD-Commons-1] WP-0.1 Yes
[CD-Commons-2] WP-0.4 Yes
[CD-Commons-3] WP-0.5 (interface contract; implementation deferred) Yes
[CD-Host-1] WP-0.1, WP-0.10 Yes
[CD-Host-2] WP-0.10 (ConfigurationDatabase in Host AddXxx() call chain) Yes
[CD-Host-3] WP-0.10 Yes
[Q1], [Q3], [Q4] WP-0.1 Yes

Result: All requirements and design constraints map to at least one work package. No orphans found.

Reverse Check: Work Packages → Requirements

Work Package Requirements Traced Has Source Requirement Verified
WP-0.1 HOST-1-1, HOST-1-3, CD-Host-1, CD-Commons-1, Q1, Q3 Yes Yes
WP-0.2 COM-5b-1 through COM-5b-8, KDD-code-3 Yes Yes
WP-0.3 COM-1-1 through COM-1-12, COM-5b-2, COM-5b-12, 13.1-1 through 13.1-3, KDD-data-6 Yes Yes
WP-0.4 COM-3-1 through COM-3-13, COM-5b-6, COM-5b-10, KDD-code-1, CD-Commons-2 Yes Yes
WP-0.5 COM-4-1 through COM-4-10, COM-5b-4, COM-5b-9, KDD-code-2 Yes Yes
WP-0.6 COM-4a-1, COM-4a-2, COM-5b-5 Yes Yes
WP-0.7 COM-5-1 through COM-5-10, COM-5a-1 through COM-5a-4, COM-5b-7, COM-5b-11, KDD-code-4 Yes Yes
WP-0.8 COM-2-1, COM-2-2, COM-2-3, COM-5b-3 Yes Yes
WP-0.9 COM-6-1 through COM-6-3, COM-7-1 through COM-7-5 Yes Yes
WP-0.10 HOST-1-1 through HOST-1-3, HOST-2-1 through HOST-2-6, HOST-7-1 through HOST-7-3, HOST-10-1 through HOST-10-5, CD-Host-1, CD-Host-2, CD-Host-3 Yes Yes
WP-0.11 HOST-3-1 through HOST-3-6, KDD-code-5, KDD-code-6 Yes Yes
WP-0.12 HOST-1-2, HOST-3-2, HOST-3-3 Yes Yes

Result: All work packages trace to source requirements. No untraceable work.

Split-Section Check

Phase 0 covers only HighLevelReqs section 13.1 (Timestamps). This section is not split across phases — Phase 0 owns it entirely. All three bullets ([13.1-1], [13.1-2], [13.1-3]) are covered.

Phase 0 covers REQ-COM and REQ-HOST requirements. The following are split with other phases:

REQ ID Phase 0 Scope Other Phase(s) Scope
REQ-COM-2 Interface definition only Phase 3B: OPC UA and LmxProxy implementations
REQ-COM-4a Interface definition only Phase 1: IAuditService implementation in Configuration Database
REQ-COM-5a-4 Noted in plan; versioning rules documented Phase 1/3A: Akka serialization binding configuration
REQ-HOST-2 Skeleton role branching with stub AddXxx() calls Phase 1: Full service registration with real implementations
REQ-HOST-3 Options classes created and bound Phase 1: Startup validation of option values (REQ-HOST-4)
REQ-HOST-7 WebApplication vs generic Host branching Phase 1: Actual web endpoint mapping

Result: No unowned bullets. All split items have clear phase ownership.

Negative Requirement Check

Negative Requirement Acceptance Criterion Adequate
[COM-2-3] No protocol-specific references WP-0.8: "No protocol-specific references" in AC Yes
[COM-3-4] No EF dependency on POCOs WP-0.4 + WP-0.9: reflection test on assembly refs Yes
[COM-4-10] Repository interfaces no EF WP-0.5: no EF using or reference check Yes
[COM-5-9] Messages must be record/immutable (no mutable) WP-0.7: unit test verifies all are records Yes
[COM-5-10] Commons no Akka dependency WP-0.9: reflection test Yes
[COM-5a-1] No field removal, no type changes WP-0.7: versioning rules documented Yes (convention; runtime enforcement N/A at compile time)
[COM-6-2] No business logic/services/actors WP-0.9: scan for service/actor classes Yes
[COM-7-2] No Akka packages WP-0.9: csproj check Yes
[COM-7-3] No ASP.NET packages WP-0.9: csproj check Yes
[COM-7-4] No EF packages WP-0.9: csproj check Yes
[COM-7-5] No paid-license packages WP-0.9: csproj check Yes
[HOST-1-3] No separate build targets/conditional compilation WP-0.10: no #if directives check Yes
[HOST-2-6] Non-applicable components not registered WP-0.10: site boot test verifies no central services registered Yes
[HOST-3-6] Components never read IConfiguration directly WP-0.11: architectural test verifies no component library uses Microsoft.Extensions.Configuration or accepts IConfiguration in AddXxx() Yes
[HOST-7-3] Site nodes never accept HTTP WP-0.10: site boot no-port check Yes
[COM-1-12] / [13.1-3] No timezone conversion outside UI WP-0.9: no ToLocalTime() calls in non-UI code Yes

Result: All negative requirements have corresponding acceptance criteria that would catch violations. No weak checks identified.


Codex MCP Verification

Model: gpt-5.4 Date: 2026-03-16

Step 1: Requirements Coverage Review

Codex identified 10 findings. Disposition:

# Finding Disposition
1 Project count inconsistency (17 component projects + 1 Host = 18) Corrected. WP-0.1 now explicitly lists 15 component library projects + 1 Commons + 1 Host = 17 total source projects. The "17 components" in CLAUDE.md includes Host and Commons in the count.
2 COM-5a-4 (Akka serialization binding) not covered by Phase 0 work package Acknowledged. Correctly deferred to Phase 1/3A. Forward check updated to mark as explicitly deferred. COM-5a-4 requires Akka.NET which Phase 0 does not introduce.
3 13.1-2 partially covered (event log and S&F timestamps) Dismissed. Phase 0 establishes the UTC convention in the type system and on all entity/message timestamp fields. Specific event log and S&F entities created in Phase 0 (AuditLogEntry, DeploymentRecord, etc.) already use DateTimeOffset. The convention applies system-wide; later phases creating additional timestamp-bearing types must follow it.
4 COM-2-2 missing ReadResult and ConnectionStatus enum in WP-0.8 Corrected. WP-0.8 acceptance criteria now include ReadResult and ConnectionStatus enum.
5 COM-5-3 missing HealthCheckResult and SiteStatusReport DTOs Corrected. WP-0.7 Health section now requires HealthCheckResult, SiteStatusReport, SiteHealthReport, and HeartbeatMessage.
6 HOST-10-2 (AddXxxActors stubs) not in WP-0.10 acceptance criteria Corrected. WP-0.10 now explicitly requires AddXxxActors() stub extension methods for all actor-bearing components, and MapXxx() stubs for CentralUI/InboundAPI. Host Program.cs calls them.
7 HOST-3-6 (no IConfiguration in components) not testable Corrected. WP-0.11 now includes an architectural test: no component library uses Microsoft.Extensions.Configuration or accepts IConfiguration in its AddXxx() signature. Added to negative tests table.
8 CD-Host-2 weakly traced to WP-0.12 (sample configs) Corrected. CD-Host-2 retraced to WP-0.10 (Host skeleton includes ConfigurationDatabase AddConfigurationDatabase() in its call chain).
9 COM-1-9 thread safety not explicitly verified Dismissed. Immutable record types are inherently thread-safe in .NET. WP-0.3 AC updated to state "immutable and thread-safe (record types — immutability guarantees thread safety)." No additional runtime thread-safety test needed for data-only types.
10 COM-5a-1 through COM-5a-3 only documented, not tested Corrected. WP-0.7 now includes a JSON serialization round-trip test verifying forward compatibility (unknown fields tolerated) and backward compatibility (missing optional fields tolerated). Structural enforcement at Phase 0; full Akka serialization testing in Phase 1/3A.

Step 2: Negative Requirement Review

Not submitted separately — negative requirements were reviewed as part of Step 1 findings. All negative requirement acceptance criteria were evaluated as adequate by Codex (no findings on negative tests specifically).

Step 3: Split-Section Gap Review

Phase 0 covers HighLevelReqs 13.1 exclusively (not split). No split-section review needed for this phase.

Outcome: Pass with corrections. All 10 findings addressed (7 corrected, 3 dismissed with rationale).