56 KiB
\# Codex Implementation Specification
\## AquaCom Integration Gateway
\*\*Document type:\*\* Implementation specification
\*\*Target implementation agent:\*\* Codex
\*\*System:\*\* AquaCom Integration Gateway
\*\*Primary southbound interface:\*\* AquaCom
\*\*Primary northbound interface:\*\* OPC UA
\*\*Additional capability:\*\* Pluggable historical storage
\*\*Programming language:\*\* To be selected during implementation planning
\*\*Version:\*\* 0.1
\*\*Status:\*\* Draft
\---
\# 1. Purpose
This document defines how Codex shall implement the AquaCom Integration Gateway.
The gateway shall:
\- communicate with AquaCom-compatible devices;
\- acquire current process information;
\- acquire historical process information;
\- maintain a protocol-independent internal data model;
\- expose current values through OPC UA;
\- expose historical values through OPC UA Historical Access;
\- persist historical information through one or several configurable storage providers;
\- recover historical data after communication interruptions where AquaCom equipment supports this;
\- maintain diagnostic information;
\- provide a simulation environment for development and automated testing.
This document describes:
\- repository organization;
\- architectural boundaries;
\- required modules;
\- internal interfaces;
\- data contracts;
\- state machines;
\- configuration;
\- persistence;
\- testing;
\- milestones;
\- Codex working rules;
\- acceptance criteria.
It does not prescribe the implementation programming language.
\---
\# 2. Fundamental implementation rule
The implementation shall be based on the following processing architecture:
AquaCom
\  │
\  ▼
Transport
\  │
\  ▼
AquaCom protocol engine
\  │
\  ▼
Station/session manager
\  │
\  ▼
Canonical data model
\  │
\  ├──────────────► Current-state service
\  │ │
\  │ ▼
\  │ OPC UA DA
\  │
\  └──────────────► Historical pipeline
\  │
\  ┌──────────┼──────────────┐
\  │ │ │
\  ▼ ▼ ▼
\  Repository Storage A Storage B
\  │
\  ▼
\  OPC UA HA
No component above the AquaCom protocol layer shall parse or construct AquaCom telegrams.
No AquaCom component shall depend upon OPC UA.
No AquaCom component shall depend upon a particular database.
No storage adapter shall depend upon AquaCom telegram structure.
\---
\# 3. Codex implementation principles
Codex shall follow these principles throughout development.
\## 3.1 Do not invent AquaCom protocol details
Codex shall never invent:
\- byte positions;
\- telegram structure;
\- field identifiers;
\- checksums;
\- addressing rules;
\- commands;
\- response codes;
\- scaling;
\- timestamp encoding;
\- historical-data behavior.
Protocol behavior may only be implemented when supported by at least one of:
1\. authoritative AquaCom documentation;
2\. validated packet/serial captures;
3\. existing known-good implementation behavior;
4\. approved test vectors.
Unknown protocol details shall be represented as:
NOT\\\_IMPLEMENTED
or documented protocol gaps.
A compilation-successful guess is not an acceptable implementation.
\---
\# 4. Repository documentation strategy
The repository shall contain a short root AGENTS.md.
Detailed requirements shall live under docs/.
AGENTS.md shall primarily direct Codex to the authoritative project documentation rather than attempt to contain the complete project specification.
This follows current Codex guidance favoring concise repository instructions with deeper documentation maintained separately.
Complex implementation work shall use an execution plan maintained in the repository. OpenAI's current Codex guidance explicitly recommends plan documents for significant features or refactors.
\---
\# 5. Repository structure
The initial repository shall use the following logical organization:
/
├── AGENTS.md
├── README.md
├── ARCHITECTURE.md
├── CHANGELOG.md
├── LICENSE
│
├── docs/
│ ├── product/
│ │ └── software-specification.md
│ │
│ ├── architecture/
│ │ ├── overview.md
│ │ ├── data-flow.md
│ │ ├── live-data.md
│ │ ├── historical-data.md
│ │ ├── opcua.md
│ │ ├── storage.md
│ │ └── security.md
│ │
│ ├── protocol/
│ │ ├── aquacom.md
│ │ ├── known-operations.md
│ │ ├── protocol-gaps.md
│ │ └── test-vectors.md
│ │
│ ├── configuration/
│ │ └── configuration-reference.md
│ │
│ ├── operations/
│ │ ├── deployment.md
│ │ ├── diagnostics.md
│ │ ├── backup-recovery.md
│ │ └── troubleshooting.md
│ │
│ └── exec-plans/
│ ├── active/
│ └── completed/
│
├── schemas/
│ ├── gateway-config.schema.\\\*
│ ├── station-config.schema.\\\*
│ └── point-config.schema.\\\*
│
├── config/
│ └── examples/
│
├── src/
│ ├── core/
│ ├── aquacom/
│ ├── history/
│ ├── storage/
│ ├── opcua/
│ ├── diagnostics/
│ └── host/
│
├── tests/
│ ├── unit/
│ ├── integration/
│ ├── protocol/
│ ├── opcua/
│ ├── history/
│ └── acceptance/
│
├── simulator/
│
├── fixtures/
│ ├── aquacom/
│ ├── history/
│ └── configuration/
│
├── tools/
│
└── deployment/
File extensions shall be selected once the implementation language and configuration formats are chosen.
\---
\# 6. Root AGENTS.md
The root AGENTS.md shall contain approximately the following instructions.
\\# AquaCom Integration Gateway
Read ARCHITECTURE.md and the relevant documents under docs/ before
changing implementation behavior.
For substantial features, protocol changes, persistence changes, or
cross-module refactors, create or update an ExecPlan under
docs/exec-plans/active/.
\\## Non-negotiable architecture rules
1\\. AquaCom protocol parsing belongs only in src/aquacom.
2\\. OPC UA must never parse AquaCom telegrams.
3\\. Storage adapters consume canonical historical records only.
4\\. Historical samples must never be replayed as current process values.
5\\. Preserve source timestamps separately from gateway receipt timestamps.
6\\. Stable point IDs and OPC UA NodeIds must survive restart and renaming.
7\\. Do not invent undocumented AquaCom protocol behavior.
8\\. Every protocol implementation requires automated test vectors.
9\\. Every bug fix requires a regression test where practical.
10\\. Live acquisition takes priority over historical backfill.
\\## AquaCom protocol evidence
Protocol behavior may only be implemented using documented or validated
evidence stored or referenced from docs/protocol/.
If information is insufficient, document the gap in
docs/protocol/protocol-gaps.md instead of guessing.
\\## Testing
Run applicable unit, integration and acceptance tests before considering
a task complete.
Do not weaken or remove tests merely to make a change pass.
\\## Security
Never commit secrets, private keys, production certificates, passwords
or production network addresses.
OPC UA insecure modes must not become the production default.
\\## Documentation
Update relevant architecture or configuration documentation whenever
observable behavior changes.
Nested AGENTS.md files may later be added where a specific module requires additional constraints.
Codex supports hierarchical AGENTS.md instructions scoped to directory trees, making this suitable for stricter protocol or storage-specific rules if the repository grows.
\---
\# 7. Architecture document
ARCHITECTURE.md shall act as the primary architecture map.
It shall contain:
\- system purpose;
\- module diagram;
\- dependency direction;
\- canonical data model;
\- live-data flow;
\- historical-data flow;
\- security boundaries;
\- links to detailed documents.
The following dependency direction is mandatory:
\  ┌──────────────┐
\  │ host │
\  └──────┬───────┘
\  │
\  ┌────────────┼────────────┐
\  ▼ ▼ ▼
\  OPC UA history diagnostics
\  │ │
\  │ storage
\  │ │
\  └──────┬─────┘
\  ▼
\  core
\  ▲
\  │
\  aquacom
core shall contain no dependencies on AquaCom, OPC UA or a particular storage implementation.
\---
\# 8. Core domain module
The core module shall contain protocol-neutral data models.
Required logical entities include:
StationId
PointId
CurrentValue
HistoricalSample
DataQuality
AcquisitionSource
StationState
CommunicationState
HistorySynchronizationState
\---
\# 9. Stable identifiers
\## 9.1 StationId
StationId shall be an immutable logical gateway identifier.
It shall not depend solely upon:
\- IP address;
\- hostname;
\- serial port;
\- display name.
Example:
station:PS001
\---
\## 9.2 PointId
PointId shall be an immutable logical identifier.
Example:
station:PS001/point:LEVEL
Changing:
Wet well level
to:
Inlet sump level
shall not change PointId.
\---
\# 10. CurrentValue contract
The canonical current-value model shall conceptually contain:
CurrentValue
StationId
PointId
Value
DataType
Quality
SourceTimestamp?
ReceivedTimestamp
UpdatedTimestamp
AcquisitionSource
SourceTimestamp may be absent when AquaCom provides no trustworthy source timestamp.
ReceivedTimestamp shall always be gateway-generated.
\---
\# 11. HistoricalSample contract
Historical samples shall contain:
HistoricalSample
StationId
PointId
Value
DataType
Quality
SourceTimestamp
ReceivedTimestamp
AcquisitionSource
AcquisitionId?
Metadata?
SourceTimestamp is mandatory for normal process history.
A record without a reliable historical timestamp shall not silently be interpreted as historical process data.
\---
\# 12. DataQuality
Internal quality shall be independent of OPC UA.
At minimum:
GOOD
UNCERTAIN
BAD
UNKNOWN
Optional reason/substatus shall support values equivalent to:
COMMUNICATION\\\_FAILURE
STALE
INVALID\\\_VALUE
INVALID\\\_TIMESTAMP
CONFIGURATION\\\_ERROR
CONVERSION\\\_ERROR
SOURCE\\\_UNCERTAIN
HISTORY\\\_GAP
The OPC UA module shall map this model to OPC UA StatusCodes.
\---
\# 13. AcquisitionSource
Historical and current information shall identify origin.
Examples:
LIVE
AQUACOM\\\_HISTORY
AQUACOM\\\_REPORT
RECOVERY
IMPORT
SIMULATOR
Implementation shall permit additional values.
\---
\# 14. AquaCom transport interface
The AquaCom transport abstraction shall provide functions equivalent to:
open()
close()
send(bytes)
receive()
isConnected()
getDiagnostics()
The interface shall not interpret AquaCom fields.
Potential transport implementations may include:
\- TCP;
\- serial;
\- modem abstraction;
\- serial-over-IP.
The initial implementation only needs transports required by the target environment.
\---
\# 15. AquaCom protocol codec
The protocol codec shall provide deterministic transformation between:
raw transport bytes
and:
AquaComMessage
Logical interfaces:
encode(request) -> bytes
decode(bytes) -> message
validate(bytes) -> validation\\\_result
The codec shall have no network dependency.
This is required so protocol behavior can be exhaustively unit tested.
\---
\# 16. Protocol test vectors
Every implemented AquaCom telegram type shall have test fixtures.
Fixture format shall contain conceptually:
name
source
direction
raw-data
decoded-operation
decoded-fields
expected-validation
notes
Example source classifications:
SPECIFICATION
CAPTURE
KNOWN\\\_GOOD\\\_IMPLEMENTATION
SYNTHETIC\\\_FROM\\\_SPECIFICATION
The test suite shall prove both:
raw → decoded
and where applicable:
object → encoded raw
\---
\# 17. Protocol gap registry
docs/protocol/protocol-gaps.md shall maintain unresolved protocol issues.
Each entry shall contain:
Gap ID
Description
Affected operation
Evidence available
Evidence missing
Impact
Implementation status
Example:
AQ-GAP-007
Exact encoding of history timestamp field for controller type X
is not yet verified.
Impact:
History retrieval cannot be enabled for this controller type.
Required evidence:
Protocol specification or validated capture.
Codex shall not close a protocol gap without evidence.
\---
\# 18. AquaCom session manager
Each configured station shall use an independent session/state abstraction.
Conceptual states:
DISABLED
INITIALIZING
CONNECTING
ONLINE
DEGRADED
OFFLINE
RECOVERING
Basic transition:
\  successful communication
OFFLINE ──────────────────────────────► ONLINE
ONLINE
\  │
\  │ repeated communication failures
\  ▼
DEGRADED
\  │
\  │ threshold exceeded
\  ▼
OFFLINE
\  │
\  │ transport available
\  ▼
RECOVERING
\  │
\  │ successful synchronization
\  ▼
ONLINE
Thresholds shall be configurable.
\---
\# 19. Live acquisition scheduler
The live acquisition scheduler shall:
\- schedule AquaCom live requests;
\- apply per-station polling configuration;
\- prevent overlapping invalid station transactions;
\- prioritize live communication over history backfill;
\- implement retry policy;
\- update communication diagnostics.
The scheduler shall not write directly to OPC UA.
It shall publish canonical CurrentValue updates.
\---
\# 20. Current-state service
The Current-State Service shall maintain the latest accepted current value for each PointId.
Interface equivalent:
update(CurrentValue)
get(PointId)
getAll(StationId)
subscribe(PointId)
The service shall reject obsolete updates where appropriate.
A recovered historical sample shall not invoke:
CurrentState.update()
unless it has independently been determined to represent current state.
\---
\# 21. Historical acquisition manager
The Historical Acquisition Manager shall manage history retrieval from AquaCom stations.
Responsibilities:
\- determine retrieval windows;
\- initiate historical requests;
\- maintain synchronization watermark;
\- process partial responses;
\- resume interrupted synchronization;
\- throttle retrieval;
\- deduplicate;
\- send canonical historical samples to the historical pipeline.
Conceptual interface:
synchronize(station)
synchronize(station, start, end)
getSynchronizationState(station)
pause(station)
resume(station)
\---
\# 22. Synchronization watermark
Each station shall maintain persistent history synchronization state.
Example:
StationId
HistoryStreamId
LastCompleteTimestamp
LastAttemptTimestamp
LastSuccessfulTimestamp
SynchronizationState
The watermark shall only advance when the implementation has sufficient evidence that the interval has been processed successfully.
\---
\# 23. Historical recovery state machine
Conceptual history states:
IDLE
CHECK\\\_REQUIRED\\\_RANGE
REQUESTING
RECEIVING
PERSISTING
VERIFYING
COMPLETE
RETRY\\\_WAIT
FAILED
Typical sequence:
IDLE
\  │
\  ▼
CHECK\\\_REQUIRED\\\_RANGE
\  │
\  ▼
REQUESTING
\  │
\  ▼
RECEIVING
\  │
\  ▼
PERSISTING
\  │
\  ▼
VERIFYING
\  │
\  ├── incomplete ──► REQUESTING
\  │
\  └── complete ───► COMPLETE
A restart during synchronization shall resume from persistent state without requiring complete duplication of the historical interval.
\---
\# 24. Historical pipeline
The historical pipeline shall receive:
HistoricalSample
and perform:
validation
\  ↓
normalization
\  ↓
deduplication
\  ↓
durable enqueue
\  ↓
distribution
Conceptually:
HistoricalSample
\  │
\  ▼
Validator
\  │
\  ▼
Deduplicator
\  │
\  ▼
Durable spool
\  │
\ ┌─────┼─────────┐
\ ▼ ▼ ▼
Repo Store A Store B
\---
\# 25. Deduplication key
Default logical identity:
StationId
\\+
PointId
\\+
SourceTimestamp
If AquaCom supplies a stronger identity such as a sequence number, the implementation may include it.
The deduplication algorithm shall be deterministic.
Collision behavior shall be configurable:
KEEP\\\_FIRST
KEEP\\\_LAST
REJECT\\\_CONFLICT
VERSION\\\_CONFLICT
Recommended default:
REJECT\\\_CONFLICT
where conflicting values are stored diagnostically rather than silently overwritten.
\---
\# 26. History repository interface
A History Repository is a queryable source used by OPC UA Historical Access.
Required logical interface:
store(sample)
storeBatch(samples)
readRaw(
\  pointId,
\  startTime,
\  endTime,
\  limit,
\  continuation
)
readAtTime(
\  pointId,
\  timestamps
)
getBounds(pointId)
health()
The repository may be:
\- local;
\- external;
\- relational;
\- time-series;
\- industrial historian.
OPC UA shall interact only through this abstraction.
\---
\# 27. Storage sink interface
A storage sink is an independent history destination.
Required interface:
initialize()
write(sample)
writeBatch(samples)
flush()
health()
shutdown()
A storage sink does not need to support queries.
Examples:
SQL sink
time-series sink
industrial historian sink
file/archive sink
message-stream sink
\---
\# 28. Repository versus sink
These concepts shall remain distinct.
Repository
\  = historical data can be queried
Sink
\  = historical data can be delivered
A component may implement both interfaces.
Example:
Local historian:
\  Repository = yes
\  Sink = yes
Archive file:
\  Repository = no
\  Sink = yes
\---
\# 29. Durable spool
Historical delivery shall pass through persistent buffering.
Conceptual record:
SpoolRecord
RecordId
HistoricalSample
CreatedTimestamp
Destinations\\\[]
Acknowledgements\\\[]
RetryState
Example:
record 123
StorageLocal ACK
CentralHistorian PENDING
Archive ACK
Record 123 shall remain available until required delivery policy has been fulfilled.
\---
\# 30. Delivery policy
Configuration shall define whether a destination is:
REQUIRED
OPTIONAL
Example:
LocalHistory:
\  REQUIRED
CentralHistorian:
\  REQUIRED
ArchiveExport:
\  OPTIONAL
A failed optional destination shall generate diagnostics but shall not indefinitely block spool cleanup.
\---
\# 31. Storage failure handling
Each storage destination shall implement independent retry.
Recommended conceptual retry progression:
immediate
short delay
increasing delay
maximum delay
periodic retry
Exact timing shall be configurable.
Retries shall not block live acquisition.
\---
\# 32. OPC UA module
The OPC UA module shall contain:
Server lifecycle
Namespace manager
Node mapping
Current-value provider
Historical provider
StatusCode mapper
Security configuration
Diagnostics exposure
It shall depend upon:
core
current-state service
history repository
diagnostics
It shall not depend directly upon AquaCom transport or AquaCom codec.
\---
\# 33. OPC UA namespace mapping
Default structure:
AquaCom
│
├── Gateway
│ ├── Status
│ ├── Version
│ ├── StartTime
│ ├── ConfigurationVersion
│ ├── HistoricalQueueDepth
│ └── Storage
│
└── Stations
\  │
\  ├── PS001
\  │ ├── Process
\  │ │ ├── Level
\  │ │ ├── Pump01Running
\  │ │ └── Pump02Running
\  │ │
\  │ └── Diagnostics
\  │ ├── CommunicationState
\  │ ├── LastCommunication
\  │ ├── HistoryState
\  │ └── HistoryWatermark
\  │
\  └── PS002
Namespace generation shall be deterministic.
\---
\# 34. OPC UA NodeId generation
OPC UA NodeIds shall derive from stable internal identifiers.
Example:
ns=<gateway namespace>;s=station/PS001/point/LEVEL
The exact syntax may differ.
The critical requirement is:
same logical point
\  =
same NodeId
across:
\- restart;
\- upgrade;
\- rename;
\- transport address change.
\---
\# 35. OPC UA current-value mapping
For each configured live point:
CurrentValue.Value
\  → OPC UA Value
CurrentValue.SourceTimestamp
\  → OPC UA SourceTimestamp
gateway processing time
\  → OPC UA ServerTimestamp
CurrentValue.Quality
\  → OPC UA StatusCode
If communication fails, the node shall transition to a suitable non-Good status according to configuration.
\---
\# 36. OPC UA history provider
When an OPC UA client sends:
HistoryRead
the OPC UA layer shall call:
HistoryRepository.readRaw()
It shall never directly cause:
AquaCom history request
The following is prohibited:
OPC UA HistoryRead
\  │
\  ▼
AquaCom WGH request
\  │
\  ▼
wait for RTU
Correct behavior:
AquaCom synchronization
\  │
\  ▼
Repository
OPC UA HistoryRead
\  │
\  ▼
Repository
\---
\# 37. OPC UA historical continuation
The implementation shall support bounded historical reads.
Configuration:
maximumValuesPerHistoryRead
If more values exist than can be returned:
HistoryRead
\  │
\  ▼
batch 1 + continuation token
\  │
\  ▼
HistoryRead continuation
\  │
\  ▼
batch 2
Continuation state shall be resource-limited.
\---
\# 38. Time handling
Internal canonical timestamps shall be timezone-unambiguous.
Preferred internal representation:
UTC timestamp
Station configuration shall define AquaCom timezone interpretation where required.
Configuration fields shall include concepts equivalent to:
timezone
timestampSource
maximumFutureDeviation
maximumPastDeviation
dstPolicy
The raw source timestamp may optionally also be retained for diagnostics.
\---
\# 39. Configuration model
A gateway configuration shall contain approximately:
gateway
logging
opcua
history
storage
stations
security
diagnostics
\---
\# 40. Gateway configuration
Conceptual example:
gateway:
\  id: aquacom-gateway-01
\  site: central-ot
\  timezone: Europe/Stockholm
\---
\# 41. Station configuration
Conceptual configuration:
station:
\  id: PS001
\  enabled: true
\  transport:
\  type: tcp
\  ...
\  aquacom:
\  address: ...
\  profile: ...
\  acquisition:
\  live:
\  enabled: true
\  interval: ...
\  history:
\  enabled: true
\  synchronization: ...
\  points:
\  source: ...
Exact syntax shall be selected during technology selection.
\---
\# 42. Point configuration
Conceptual:
point:
\  id: LEVEL
\  name: Wet well level
\  source:
\  aquacomReference: ...
\  datatype: float
\  engineeringUnit: m
\  live:
\  enabled: true
\  history:
\  enabled: true
\  opcua:
\  enabled: true
\  historizing: true
\  storage:
\  enabled: true
\---
\# 43. Configuration schema validation
Machine-readable schemas shall validate configuration before startup.
Validation shall detect:
\- duplicate station IDs;
\- duplicate point IDs;
\- invalid references;
\- impossible polling intervals;
\- unsupported transports;
\- missing required storage;
\- invalid timezone;
\- duplicate OPC UA NodeIds;
\- invalid security configuration.
Invalid configuration shall fail safely.
\---
\# 44. Secrets
Secrets shall be supplied through an external secret mechanism appropriate to the selected deployment environment.
The repository shall never contain production:
passwords
private keys
API tokens
certificate private keys
database credentials
Example files shall use placeholders.
\---
\# 45. Diagnostics model
Gateway-level diagnostics:
GatewayState
Version
ConfigurationVersion
StartTime
Uptime
StationCount
OnlineStationCount
HistoricalQueueDepth
SpoolDiskUsage
OPCUAState
Per-station:
CommunicationState
LastRequest
LastResponse
LastSuccessfulCommunication
ConsecutiveFailures
ProtocolErrors
HistorySynchronizationState
HistoryWatermark
HistoricalBacklog
Per-storage destination:
State
LastSuccessfulWrite
LastFailure
PendingRecords
Retries
Latency
\---
\# 46. Logging requirements
Structured logging shall be preferred.
Every log record should support context equivalent to:
timestamp
severity
component
stationId?
pointId?
operation?
correlationId?
message
error?
Raw telegram logging shall be a separate debug facility.
Production default shall not log every telegram.
\---
\# 47. Correlation IDs
AquaCom transactions shall have a transaction/correlation identifier.
Example flow:
AQ transaction 81245
\  │
\  ├── send request
\  ├── receive response
\  ├── decode
\  ├── update values
\  └── diagnostics
This ID should be propagated through relevant diagnostics.
\---
\# 48. Metrics
The implementation shall expose or internally maintain metrics equivalent to:
aquacom\\\_requests\\\_total
aquacom\\\_errors\\\_total
aquacom\\\_request\\\_duration
station\\\_online
live\\\_values\\\_processed
history\\\_samples\\\_received
history\\\_samples\\\_deduplicated
history\\\_samples\\\_pending
storage\\\_writes\\\_total
storage\\\_write\\\_errors
opcua\\\_clients\\\_connected
opcua\\\_history\\\_reads
spool\\\_bytes
Specific metrics technology shall not be prescribed.
\---
\# 49. Simulator
A simulator shall be treated as a first-class component.
It shall support scripted station behavior.
Required simulation scenarios:
normal live operation
communication timeout
connection loss
malformed response
bad checksum
delayed response
historical values
historical gap
duplicate history
conflicting duplicate
station clock error
reconnect and backfill
The simulator shall not share parsing code with the production AquaCom decoder in ways that make protocol tests self-validating.
\---
\# 50. Test pyramid
The project shall implement:
\  Acceptance
\  /\\\\
\  / \\\\
\  Integration
\  / \\\\
\  / \\\\
\  Unit tests
The majority of tests should be deterministic unit and component tests.
\---
\# 51. Required unit tests
\## AquaCom codec
framing
checksum
address encoding
telegram decoding
invalid telegram rejection
unexpected field handling
\## Canonical model
quality mapping
timestamp validation
stable identifier handling
\## History
deduplication
watermark progression
gap handling
conflict handling
spool acknowledgement
\## OPC UA
NodeId mapping
quality mapping
timestamp mapping
history result conversion
\---
\# 52. Required integration tests
At minimum:
Simulator → AquaCom engine
AquaCom engine → Current State
AquaCom history → Historical pipeline
Historical pipeline → Repository
Historical pipeline → multiple sinks
Repository → OPC UA HistoryRead
Current state → OPC UA subscription
\---
\# 53. Restart recovery tests
Automated tests shall cover gateway restart during:
normal operation
history retrieval
database outage
spool backlog
partial delivery
reconnect recovery
Expected result:
No acknowledged historical data is silently lost.
\---
\# 54. End-to-end mandatory acceptance test
Scenario:
T0:
Station online.
Gateway receives live level values.
OPC UA client receives current values.
Values are persisted historically.
T1:
Station communication is interrupted.
Gateway marks communication degraded/bad.
Current OPC UA value is not falsely reported as newly valid.
T2:
Station continues local historical recording.
T3:
Communication returns.
Live acquisition resumes promptly.
T4:
Gateway identifies missing historical interval.
Gateway retrieves historical records.
T5:
Historical records retain their original timestamps.
They are delivered to all required storage destinations.
T6:
OPC UA current value remains the actual current process value.
T7:
OPC UA HistoryRead for T1–T4 returns recovered historical values.
T8:
Same historical interval is retrieved again.
No unintended duplicate historical records are created.
The system shall not be considered production-capable until this test passes.
\---
\# 55. Security tests
Tests shall verify:
untrusted OPC UA client certificate rejected
trusted client accepted
insecure OPC UA endpoint disabled by production configuration
invalid credentials rejected where user authentication is enabled
private keys not logged
unauthorized HistoryUpdate rejected
configuration containing secret placeholders validated appropriately
\---
\# 56. Fault injection
Integration testing shall permit fault injection including:
network disconnect
packet loss
delayed responses
storage timeout
storage exception
disk-full simulation
OPC UA client disconnect
process restart
corrupted local spool entry
\---
\# 57. CI requirements
Every change shall run:
format/lint checks
static validation
unit tests
integration tests suitable for CI
configuration schema validation
dependency/security checks where available
Protocol fixtures shall be testable without external network access.
\---
\# 58. Pull request completion criteria
Codex shall consider a development task complete only when:
implementation exists
tests exist
tests pass
relevant documentation is updated
configuration examples are updated if required
no known architectural boundary has been violated
new protocol behavior has supporting evidence
new failure modes have diagnostics
no production secrets have been introduced
Codex task prompts work best when scoped similarly to concrete issues or PRs with explicit files and expected outcomes.
\---
\# 59. ExecPlan requirement
Codex shall create an ExecPlan for work involving:
\- new AquaCom operations;
\- history synchronization;
\- storage architecture;
\- OPC UA namespace redesign;
\- security changes;
\- cross-module refactoring;
\- persistent-data migration;
\- changes affecting more than one architectural boundary.
ExecPlan structure:
Title
Purpose
Current state
Desired state
Constraints
Files/components affected
Implementation sequence
Data model changes
Failure handling
Testing
Migration/compatibility
Progress
Decisions
Unexpected findings
Acceptance evidence
The plan shall remain updated while implementation proceeds.
\---
\# 60. Development phases
Implementation shall proceed in controlled phases.
\---
\# Phase 0 – Repository and architecture
Deliver:
AGENTS.md
README.md
ARCHITECTURE.md
docs structure
CI skeleton
configuration skeleton
No AquaCom protocol implementation required.
Acceptance:
\- repository builds;
\- automated test runner works;
\- architecture dependencies documented.
\---
\# Phase 1 – Canonical core
Implement:
StationId
PointId
CurrentValue
HistoricalSample
DataQuality
AcquisitionSource
configuration domain
Acceptance:
\- unit tests;
\- serialization tests where applicable;
\- stable identifier behavior defined.
\---
\# Phase 2 – AquaCom transport abstraction
Implement:
transport interface
connection lifecycle
timeouts
retry primitives
diagnostics
Implement only required initial transport.
Acceptance:
\- mock transport tests;
\- connection-loss testing;
\- reconnect testing.
\---
\# Phase 3 – AquaCom codec framework
Implement:
frame abstraction
message abstraction
codec interfaces
validation framework
fixture framework
Only protocol elements with evidence may be implemented.
Acceptance:
captured/documented telegram
\  ↓
decoder
\  ↓
expected structured representation
\---
\# Phase 4 – AquaCom simulator
Implement simulator before depending on field equipment for normal development.
Acceptance:
\- successful transaction;
\- timeout;
\- malformed telegram;
\- configurable process values.
\---
\# Phase 5 – Station/session manager
Implement:
station lifecycle
communication state
poll scheduling
retry policy
diagnostics
Acceptance:
\- multiple simulated stations;
\- one station failing does not affect others.
\---
\# Phase 6 – Live acquisition
Implement:
live AquaCom operation
point mapping
scaling
canonical CurrentValue
current-state cache
Acceptance:
simulated AquaCom
\  ↓
CurrentValue
with correct value, quality and timestamps.
\---
\# Phase 7 – OPC UA live interface
Implement:
server
namespace
stable NodeIds
current reads
subscriptions
quality
timestamps
security
Acceptance:
An OPC UA test client can browse and subscribe to simulated AquaCom values.
\---
\# Phase 8 – Local historical repository
Implement the first queryable history repository.
The selected technology may be embedded or external, but shall implement the defined repository abstraction.
Acceptance:
store
query interval
query bounds
restart persistence
\---
\# Phase 9 – Historical pipeline
Implement:
validation
deduplication
durable spool
delivery
repository integration
Acceptance:
Multiple submissions of the same sample do not produce unintended duplicate records.
\---
\# Phase 10 – AquaCom historical acquisition
Implement only after sufficient protocol evidence is available.
Deliver:
history retrieval
watermark
reconnect synchronization
backfill
throttling
partial recovery
Acceptance:
The simulator's missing time interval is recovered after reconnection.
\---
\# Phase 11 – OPC UA Historical Access
Implement:
HistoryRead
raw values
timestamps
quality
continuation
Acceptance:
An OPC UA HA client can retrieve both originally stored and recovered historical values.
\---
\# Phase 12 – Multiple storage destinations
Implement storage sink abstraction plus second sink implementation.
Acceptance:
one HistoricalSample
\  │
\  ├── Repository A
\  └── Storage B
and failure of Storage B does not stop Repository A.
\---
\# Phase 13 – Store-and-forward resilience
Implement:
persistent spool
destination acknowledgements
retry
backpressure
disk limits
Acceptance:
A storage destination may be offline while history accumulates and receive the backlog when restored.
\---
\# Phase 14 – Production hardening
Implement and validate:
security
resource limits
performance
operations documentation
backup/recovery
deployment
certificate handling
structured diagnostics
long-duration tests
\---
\# 61. Codex task sizing
Implementation phases shall be divided into bounded tasks rather than requesting the complete gateway in one prompt.
Preferred task structure:
Goal
Relevant files
Required behavior
Constraints
Tests
Acceptance criteria
Example:
Implement the HistoricalSample deduplication service.
Relevant:
src/history
docs/architecture/historical-data.md
Requirements:
\\- identity based on StationId + PointId + SourceTimestamp
\\- conflicting value must be detected
\\- default conflict policy REJECT\\\_CONFLICT
Do not:
\\- introduce database-specific logic
\\- modify AquaCom codec
\\- modify OPC UA
Add unit tests covering:
\\- first sample
\\- exact duplicate
\\- conflicting duplicate
\\- different point
\\- different timestamp
\---
\# 62. Codex rule for incomplete requirements
When Codex encounters an implementation ambiguity, it shall classify it as:
A. Local implementation detail
B. Architectural decision
C. AquaCom protocol uncertainty
D. Safety/security uncertainty
For A:
Choose the simplest implementation consistent with architecture.
For B:
Record the decision in the current ExecPlan.
For C:
Do not guess. Add a protocol gap.
For D:
Choose the safer behavior and document the decision.
\---
\# 63. AquaCom source traceability
Every implemented protocol operation shall have traceability metadata in documentation.
Example:
Operation: HistoricalRead-X
Evidence:
AquaCom specification section 8.3
Capture fixture AQ-HIST-004
Validated against ControllerType-A
Implemented:
yes
Tests:
protocol/history\\\_read\\\_004
This traceability shall make it possible to audit why the implementation behaves as it does.
\---
\# 64. Protocol capture handling
Production captures used as test fixtures shall be:
\- sanitized;
\- stripped of unnecessary network identifiers;
\- documented;
\- immutable once used as reference fixtures.
Fixture modification requires justification.
Raw captures shall not automatically be committed if they contain sensitive operational information.
\---
\# 65. Storage migration rule
Storage schemas shall be versioned.
Schema changes shall have explicit migrations.
Application startup shall not silently destroy incompatible historical data.
Destructive migration requires explicit administrative action.
\---
\# 66. Configuration versioning
The configuration model shall include a schema version.
Example:
configVersion: 1
Future incompatible configuration changes shall provide validation and, where reasonable, migration tooling.
\---
\# 67. Software version exposure
Gateway software version shall be available through:
\- startup logs;
\- diagnostics;
\- OPC UA diagnostics namespace.
Build metadata should include where possible:
version
build identifier
source revision
configuration schema version
\---
\# 68. Compatibility strategy
The gateway shall distinguish:
protocol compatibility
configuration compatibility
storage compatibility
OPC UA namespace compatibility
Changes to any of these shall be considered independently.
Stable OPC UA NodeIds are particularly important and shall not change unnecessarily between releases.
\---
\# 69. Performance validation
Before production acceptance, test:
expected station count
expected point count
normal polling interval
normal historical rate
large backfill
simultaneous OPC UA subscriptions
large HistoryRead
storage unavailable
maximum expected spool backlog
The purpose is to establish capacity limits rather than merely demonstrate successful execution.
\---
\# 70. Live-priority scheduling
AquaCom scheduling shall conceptually prioritize:
1\\. connection/health-critical transactions
2\\. current/live acquisition
3\\. alarm/event retrieval when implemented
4\\. requested configuration operations
5\\. historical recovery
6\\. low-priority maintenance
Historical recovery shall be throttled if required to maintain live acquisition responsiveness.
\---
\# 71. Memory and queue limits
Every queue shall be bounded.
No component may create an unbounded:
message queue
history list
retry list
client response
log buffer
Queue-full behavior shall be explicitly defined.
\---
\# 72. Graceful shutdown
The application shall support controlled shutdown.
Order:
stop accepting administration changes
\  ↓
stop scheduling new acquisition
\  ↓
complete/cancel active AquaCom transactions
\  ↓
persist watermarks
\  ↓
flush durable state
\  ↓
stop OPC UA
\  ↓
close storage
\  ↓
terminate
\---
\# 73. Crash recovery
Following unclean shutdown:
load persistent state
\  ↓
validate spool
\  ↓
recover pending deliveries
\  ↓
restore synchronization watermarks
\  ↓
reconnect stations
\  ↓
resume live operation
\  ↓
continue required historical synchronization
Live communication shall normally resume before large backfill jobs.
\---
\# 74. Initial production scope
The first production release shall include:
AquaCom transport
AquaCom protocol framework
verified live-value acquisition
verified historical acquisition
multiple stations
canonical data model
live cache
historical pipeline
deduplication
durable spool
at least one history repository
storage adapter framework
at least two independently configurable storage targets
OPC UA Data Access
OPC UA Historical Access
OPC UA security
stable NodeIds
diagnostics
structured logging
simulator
automated tests
restart recovery
configuration validation
\---
\# 75. Explicitly excluded from first production release
Unless separately approved:
AquaCom remote pump control
AquaCom setpoint write
OPC UA control writes
OPC UA Methods for process control
OPC UA HistoryUpdate
automatic historian correction
clustered high availability
automatic protocol discovery
Read-only process integration shall be established before remote-control functionality is introduced.
\---
\# 76. Future process-control architecture
If control is later implemented, it shall use a separate command pipeline:
OPC UA
\  │
\  ▼
authorization
\  │
\  ▼
command validation
\  │
\  ▼
command service
\  │
\  ▼
AquaCom control operation
\  │
\  ▼
confirmation/readback
\  │
\  ▼
audit
Direct mapping:
OPC UA write → raw AquaCom telegram
shall not be permitted.
\---
\# 77. Definition of Done
The gateway implementation is complete for production evaluation when:
1\. All mandatory Phase 0–14 features are implemented.
2\. No implemented AquaCom operation depends on undocumented guessed protocol behavior.
3\. Current data is available through OPC UA.
4\. Historical data is available through OPC UA Historical Access.
5\. AquaCom history backfill does not alter current values.
6\. Historical source timestamps are preserved.
7\. Gateway restart does not lose acknowledged history.
8\. Temporary storage outage does not immediately cause historical loss.
9\. Multiple storage destinations operate independently.
10\. OPC UA NodeIds are stable.
11\. OPC UA security is enabled by default.
12\. Simulator-based end-to-end acceptance tests pass.
13\. Tests against real AquaCom equipment or validated traffic have passed.
14\. Operational deployment and recovery documentation exists.
15\. Remaining protocol gaps are explicitly documented.
\---
\# 78. Implementation objective
The resulting software shall behave as an integration platform:
\  AquaCom
\  │
\  ▼
\  ┌───────────────────────┐
\  │ AquaCom Gateway │
\  │ │
\  │ Protocol │
\  │ Acquisition │
\  │ State │
\  │ History recovery │
\  │ Normalization │
\  │ Diagnostics │
\  └───────┬───────┬───────┘
\  │ │
\  LIVE │ │ HISTORY
\  │ │
\  ▼ ▼
\  OPC UA Historical pipeline
\  │ │
\  │ ├─────────► Repository
\  │ ├─────────► Historian
\  │ ├─────────► Database
\  │ └─────────► Archive
\  │
\  └───────────────► OPC UA HA
The implementation shall remain usable even if:
\- the SCADA platform changes;
\- the historical database changes;
\- additional storage destinations are introduced;
\- AquaCom equipment is gradually replaced;
\- additional northbound interfaces are introduced.
The gateway's permanent value shall therefore be the normalized information and integration boundary, not merely its OPC UA endpoint.
\---
\# 79. First Codex execution sequence
The recommended first Codex tasks are:
Task 001
Create repository skeleton and architecture documents.
Task 002
Create core domain models and stable identifier rules.
Task 003
Create configuration model and schema validation.
Task 004
Create AquaCom transport abstraction and mock transport.
Task 005
Create AquaCom protocol codec framework without inventing protocol fields.
Task 006
Create protocol fixture/test-vector framework.
Task 007
Create AquaCom simulator architecture.
Task 008
Implement first documented live AquaCom operation.
Task 009
Implement Station Manager and live acquisition.
Task 010
Implement current-state service.
Task 011
Implement OPC UA live-value interface.
Task 012
Implement historical repository abstraction.
Task 013
Implement historical pipeline and deduplication.
Task 014
Implement durable spool.
Task 015
Implement first verified AquaCom historical operation.
Task 016
Implement backfill state machine.
Task 017
Implement OPC UA Historical Access.
Task 018
Implement second storage destination.
Task 019
Implement full reconnect/backfill acceptance test.
Task 020
Production hardening.
Each task shall result in a working repository state rather than leaving the main branch intentionally uncompilable or untestable.
\---
\# 80. Primary instruction to Codex
When implementing this system, prioritize correctness, traceability and recoverability over speed of implementation.
In particular:
Never compensate for missing AquaCom documentation by inventing plausible protocol behavior.
Build the architecture around the unknown portions first.
Add real AquaCom behavior only as verified protocol knowledge becomes available.
Every protocol feature shall be backed by evidence and automated tests.
Every architectural component shall be replaceable behind its documented interface.
Every historical sample shall retain its original process timestamp.
And no recovered historical value shall ever masquerade as a new live process value.