Files
aquacom-gateway-suite/AGENTS.md
T
2026-10-05 20:32:13 +02:00

2039 lines
20 KiB
Markdown
Raw 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.
\# AquaCom Integration Gateway – Codex Instructions
This repository implements the \*\*AquaCom Integration Gateway\*\*.
The gateway communicates with AquaCom-compatible field equipment, normalizes live and historical process data, exposes data through OPC UA, and supports one or more historical storage destinations.
Before making architectural or behavioral changes, read:
\- `ARCHITECTURE.md`
\- `docs/product/software-specification.md`
\- `docs/architecture/`
\- `docs/protocol/`
\- `docs/configuration/configuration-reference.md`
For substantial work, also read or create the applicable ExecPlan under:
```text
docs/exec-plans/
```
\---
\## 1. Primary architecture
The intended architecture is:
```text
AquaCom
  │
  ▼
Transport
  │
  ▼
AquaCom Protocol Engine
  │
  ▼
Station / Session Manager
  │
  ▼
Canonical Data Model
  │
  ├──────────────► Current-State Service
  │ │
  │ ▼
  │ OPC UA
  │ Data Access
  │
  └──────────────► Historical Pipeline
  │
  ┌──────────┼──────────┐
  │ │ │
  ▼ ▼ ▼
  Repository Sink A Sink B
  │
  ▼
  OPC UA
  Historical Access
```
Maintain these boundaries.
\---
\## 2. Non-negotiable architecture rules
The following rules are mandatory.
\### 2.1 AquaCom isolation
All AquaCom-specific parsing, encoding, framing, checksum handling and protocol behavior belongs in the AquaCom modules.
No OPC UA, history repository or storage adapter shall parse AquaCom telegrams.
\### 2.2 OPC UA isolation
The OPC UA implementation shall consume canonical gateway data.
The OPC UA implementation shall not:
\- construct AquaCom requests;
\- decode AquaCom responses;
\- perform direct AquaCom history retrieval;
\- depend upon AquaCom telegram structures.
\### 2.3 Storage isolation
Storage implementations shall consume canonical historical records.
Storage adapters shall not depend upon:
\- AquaCom telegrams;
\- AquaCom addressing;
\- AquaCom command structures;
\- OPC UA node implementations.
\### 2.4 Canonical model
Data shall cross subsystem boundaries through the canonical gateway model.
Do not bypass the canonical model for convenience.
\### 2.5 Live and historical data are different
Historical samples shall never be replayed as current values merely because they were recently received.
For example:
```text
Gateway receives at: 18:30
Historical sample timestamp: 14:05
```
The value belongs to history at `14:05`.
It is not a new live value at `18:30`.
\### 2.6 Preserve timestamps
Keep at least the following concepts separate:
```text
SourceTimestamp
ReceivedTimestamp
```
Where applicable also maintain:
```text
ServerTimestamp
UpdatedTimestamp
```
Never silently replace a valid AquaCom source timestamp with gateway receipt time.
\### 2.7 Stable identifiers
`StationId`, `PointId` and OPC UA NodeIds must remain stable across:
\- process restart;
\- gateway restart;
\- software upgrade;
\- display-name changes;
\- transport-address changes.
Display names are not stable identifiers.
\### 2.8 Live acquisition priority
Normal live acquisition shall take priority over bulk historical backfill where both compete for limited AquaCom communication capacity.
\---
\## 3. Critical AquaCom rule
\*\*Never invent AquaCom protocol behavior.\*\*
Do not infer undocumented protocol fields merely because an implementation appears plausible.
Do not invent:
\- telegram fields;
\- byte positions;
\- ASCII fields;
\- framing rules;
\- checksum algorithms;
\- addressing behavior;
\- command codes;
\- response codes;
\- value scaling;
\- timestamp encoding;
\- alarm semantics;
\- historical-data semantics.
AquaCom behavior may only be implemented when supported by evidence.
Acceptable evidence includes:
1\. authoritative AquaCom documentation;
2\. validated traffic captures;
3\. validated behavior from an existing known-good implementation;
4\. approved protocol test vectors.
If required protocol information is unavailable:
1\. do not guess;
2\. leave the feature unimplemented;
3\. add an entry to:
```text
docs/protocol/protocol-gaps.md
```
4\. add interfaces, fixtures or simulation support around the missing implementation where useful.
Compilation success is not evidence that an AquaCom implementation is correct.
\---
\## 4. Protocol traceability
Every implemented AquaCom operation shall be traceable to its evidence.
Document protocol implementation under:
```text
docs/protocol/
```
Where practical record:
```text
Operation
Evidence source
Specification section
Capture/test-vector reference
Supported controller types
Implementation status
Associated tests
Known limitations
```
Every implemented telegram type shall have automated test vectors.
\---
\## 5. Protocol fixtures
Protocol fixtures belong under:
```text
fixtures/aquacom/
```
Fixtures derived from operational traffic shall be sanitized before being committed.
Do not commit unnecessary:
\- production IP addresses;
\- phone numbers;
\- station identifiers;
\- credentials;
\- private network information;
\- other operationally sensitive information.
Reference fixtures used for protocol validation should remain immutable unless there is a documented reason to change them.
\---
\## 6. Core data model
The core domain shall remain independent of AquaCom, OPC UA and storage technology.
Core concepts include:
```text
StationId
PointId
CurrentValue
HistoricalSample
DataQuality
AcquisitionSource
CommunicationState
StationState
HistorySynchronizationState
```
The core layer must not reference an OPC UA library or database-specific API.
\---
\## 7. CurrentValue requirements
A canonical current value shall conceptually contain:
```text
StationId
PointId
Value
DataType
Quality
SourceTimestamp?
ReceivedTimestamp
UpdatedTimestamp
AcquisitionSource
```
A missing source timestamp must remain distinguishable from a gateway-generated timestamp.
\---
\## 8. HistoricalSample requirements
A canonical historical sample shall conceptually contain:
```text
StationId
PointId
Value
DataType
Quality
SourceTimestamp
ReceivedTimestamp
AcquisitionSource
AcquisitionId?
Metadata?
```
A normal historical process sample requires a meaningful `SourceTimestamp`.
Do not fabricate one solely to make storage easier.
\---
\## 9. Historical processing
The historical pipeline shall logically follow:
```text
HistoricalSample
  │
  ▼
Validation
  │
  ▼
Normalization
  │
  ▼
Deduplication
  │
  ▼
Durable Spool
  │
  ├────► Repository
  ├────► Storage Sink A
  └────► Storage Sink B
```
Historical delivery shall be restart-safe.
\---
\## 10. Deduplication
Default historical identity is conceptually:
```text
StationId
\+
PointId
\+
SourceTimestamp
```
Use a stronger device-provided identity if verified and available.
Duplicate handling must be deterministic.
Do not silently overwrite conflicting historical values.
The preferred default for conflicting values is:
```text
REJECT\_CONFLICT
```
and generate diagnostics.
\---
\## 11. History synchronization
Historical synchronization state shall survive restart.
Do not advance a synchronization watermark until the implementation has sufficient evidence that the corresponding data interval has been successfully processed.
Historical synchronization shall support interruption and continuation.
Large backfills shall be throttleable.
\---
\## 12. OPC UA rules
OPC UA is a northbound interface to gateway information.
\### Current data
Map canonical current information approximately as:
```text
Value
  → OPC UA Value
SourceTimestamp
  → OPC UA SourceTimestamp
Gateway processing timestamp
  → OPC UA ServerTimestamp
DataQuality
  → OPC UA StatusCode
```
\### Historical data
OPC UA Historical Access shall query a History Repository abstraction.
Never implement:
```text
OPC UA HistoryRead
  ↓
synchronous AquaCom request
  ↓
wait for RTU
```
Implement:
```text
AquaCom history synchronization
  ↓
Historical Repository
OPC UA HistoryRead
  ↓
Historical Repository
```
The client-visible OPC UA history interface must remain decoupled from field-device communication latency.
\### NodeIds
OPC UA NodeIds shall be deterministic and stable.
Changing a point's display name shall not normally change its NodeId.
\### Writes
Process-control writes are outside the initial production scope unless explicitly approved.
OPC UA Historical Update shall be disabled by default.
\---
\## 13. Storage rules
Distinguish:
```text
Repository
```
from:
```text
Storage Sink
```
A \*\*Repository\*\* supports historical queries.
A \*\*Storage Sink\*\* accepts historical delivery but does not necessarily support queries.
One component may implement both.
Do not require every storage destination to become an OPC UA Historical Access source.
\---
\## 14. Multiple storage destinations
Historical data may be delivered to multiple destinations.
Each destination shall maintain independent:
\- health;
\- acknowledgement;
\- retry state;
\- diagnostics.
Failure of one storage destination shall not unnecessarily stop other destinations.
A destination may be configured as:
```text
REQUIRED
```
or:
```text
OPTIONAL
```
Required delivery behavior shall be explicit.
\---
\## 15. Durable spool
Historical data pending storage shall use persistent buffering.
The spool must not be an unbounded in-memory queue.
Spool state shall survive process restart.
Each destination shall acknowledge delivery independently.
Do not delete a record solely because one of several required destinations accepted it.
\---
\## 16. Configuration
Configuration shall be external, machine-readable and schema-validated.
Validate configuration before activating it.
Invalid configuration shall not silently replace the last known valid configuration.
Configuration shall support concepts including:
```text
gateway
stations
transports
points
live acquisition
historical acquisition
OPC UA
history repository
storage destinations
security
logging
diagnostics
```
Do not hard-code station-specific process definitions into protocol code.
\---
\## 17. Secrets
Never commit production:
\- passwords;
\- API tokens;
\- private keys;
\- OPC UA private keys;
\- database credentials;
\- secret connection strings.
Example configuration shall use placeholders.
\---
\## 18. Security
Production OPC UA configuration shall use secure endpoints by default.
Do not make insecure OPC UA operation the default merely to simplify development.
Keep development-only insecure behavior clearly separated and documented.
Administrative capabilities shall be authorized separately from ordinary data access.
If uncertain between a permissive and restrictive security behavior, prefer the restrictive behavior and document the decision.
\---
\## 19. Diagnostics
New failure modes shall include meaningful diagnostics where practical.
Diagnostics should allow operators to distinguish:
```text
transport failure
protocol failure
station offline
invalid response
history synchronization failure
storage failure
spool backlog
OPC UA failure
configuration failure
```
Avoid generic errors where useful context is available.
\---
\## 20. Logging
Prefer structured logging.
Include contextual information where available:
```text
component
stationId
pointId
operation
correlationId
error
```
Raw AquaCom telegram logging shall be separately configurable.
Do not enable full telegram logging as the normal production default.
\---
\## 21. Correlation
AquaCom request/response transactions should have correlation identifiers.
Where practical, propagate the correlation identifier into:
\- transport diagnostics;
\- protocol logs;
\- station diagnostics;
\- processing errors.
\---
\## 22. Simulator
The AquaCom simulator is a first-class project component.
Development and CI shall not require operational field equipment.
The simulator shall eventually support:
\- normal communication;
\- configurable live values;
\- historical values;
\- delayed response;
\- timeout;
\- disconnect;
\- malformed telegram;
\- invalid checksum;
\- duplicate history;
\- conflicting history;
\- clock anomalies;
\- reconnect/backfill.
Do not implement the simulator so that it merely calls the same decoder being tested to construct all expected protocol behavior. Avoid self-validating tests.
\---
\## 23. Testing rules
Every functional change shall have applicable automated tests.
Every bug fix should include a regression test where practical.
Do not weaken or remove tests merely to make a change pass.
Tests shall include appropriate combinations of:
```text
unit tests
protocol fixture tests
integration tests
restart/recovery tests
acceptance tests
```
Protocol tests must run without external network access.
\---
\## 24. Mandatory architecture tests
Maintain tests that demonstrate at least:
```text
AquaCom simulator
  → AquaCom decoder
AquaCom live acquisition
  → Current-State Service
Current-State Service
  → OPC UA current value
AquaCom history
  → Historical Pipeline
Historical Pipeline
  → Repository
Historical Pipeline
  → multiple storage destinations
Repository
  → OPC UA HistoryRead
```
\---
\## 25. Critical historical acceptance behavior
The following behavior must always remain valid:
```text
1\. Station communicates normally.
2\. Current value is exposed through OPC UA.
3\. Communication is lost.
4\. The device retains historical information.
5\. Communication returns.
6\. Live acquisition resumes.
7\. Missing history is retrieved.
8\. Historical samples retain original timestamps.
9\. Recovered historical samples are persisted.
10\. Recovered historical samples do NOT overwrite
  current state simply because they were just received.
11\. OPC UA HistoryRead returns the recovered values
  at their original timestamps.
12\. Re-retrieving the same historical interval does
  not produce unintended duplicates.
```
Any change that breaks this scenario is an architectural regression.
\---
\## 26. Bounded resources
Do not introduce unbounded:
\- queues;
\- history buffers;
\- retry lists;
\- logs;
\- response payloads;
\- continuation state;
\- caches.
Resource limits and overflow behavior shall be explicit.
\---
\## 27. Graceful shutdown
Shutdown shall preserve consistency.
Conceptual order:
```text
stop new administrative work
  ↓
stop scheduling new acquisition
  ↓
complete or cancel active transactions safely
  ↓
persist synchronization state
  ↓
flush durable state where possible
  ↓
stop OPC UA
  ↓
close storage destinations
  ↓
terminate
```
\---
\## 28. Restart behavior
Following restart:
```text
load configuration
  ↓
validate persistent state
  ↓
recover spool
  ↓
restore history watermarks
  ↓
resume AquaCom communication
  ↓
resume live acquisition
  ↓
resume historical synchronization
```
Prioritize restoration of live operation before large history recovery jobs.
\---
\## 29. Documentation requirements
Update documentation when observable behavior changes.
Relevant locations include:
```text
ARCHITECTURE.md
docs/architecture/
docs/protocol/
docs/configuration/
docs/operations/
```
Do not leave major architectural decisions only in source-code comments.
\---
\## 30. ExecPlan requirement
Create or update an ExecPlan for substantial work involving:
\- new AquaCom operations;
\- historical synchronization;
\- persistence;
\- storage architecture;
\- OPC UA namespace changes;
\- security;
\- configuration format changes;
\- cross-module refactoring;
\- data migration;
\- significant recovery behavior.
Store active plans under:
```text
docs/exec-plans/active/
```
Move completed plans to:
```text
docs/exec-plans/completed/
```
An ExecPlan should contain:
```text
Purpose
Current state
Desired state
Constraints
Affected components
Implementation sequence
Data-model changes
Failure handling
Testing
Compatibility/migration
Progress
Decisions
Unexpected findings
Acceptance evidence
```
Keep the plan current as implementation progresses.
\---
\## 31. Handling uncertainty
Classify uncertainties as:
\### A. Local implementation detail
Choose the simplest solution consistent with existing architecture.
\### B. Architectural decision
Record the decision and reasoning in the current ExecPlan.
\### C. AquaCom protocol uncertainty
Do not guess.
Record it in:
```text
docs/protocol/protocol-gaps.md
```
\### D. Security or safety uncertainty
Prefer the safer behavior and document the decision.
\---
\## 32. Task completion
Do not consider a task complete until applicable conditions are satisfied:
\- implementation is complete;
\- relevant tests exist;
\- tests pass;
\- lint/static checks pass;
\- configuration validation passes;
\- relevant documentation is updated;
\- architecture boundaries remain intact;
\- new AquaCom behavior has evidence;
\- new failure modes have diagnostics;
\- no secrets were introduced.
\---
\## 33. Initial scope
The initial production goal is primarily read-oriented integration.
Expected scope includes:
```text
AquaCom live acquisition
AquaCom historical acquisition
multiple stations
canonical data model
current-state cache
historical pipeline
deduplication
persistent synchronization state
durable spool
historical repository
multiple storage destinations
OPC UA Data Access
OPC UA Historical Access
security
diagnostics
simulation
automated testing
restart recovery
```
Unless explicitly approved, do not implement:
```text
remote pump control
setpoint changes
generic OPC UA process writes
OPC UA Methods for process control
OPC UA HistoryUpdate
```
\---
\## 34. Future control functionality
If process control is later introduced, use a separate command architecture:
```text
OPC UA/API
  │
  ▼
Authorization
  │
  ▼
Command validation
  │
  ▼
Command service
  │
  ▼
AquaCom control operation
  │
  ▼
Confirmation / readback
  │
  ▼
Audit
```
Never implement process control as:
```text
OPC UA write
  ↓
raw AquaCom telegram
```
without an explicit command-validation and authorization layer.
\---
\## 35. Guiding implementation principle
Optimize for:
1\. correctness;
2\. traceability;
3\. recoverability;
4\. testability;
5\. maintainability;
6\. operational diagnostics.
Do not optimize for implementation speed at the expense of protocol correctness.
When AquaCom knowledge is incomplete, build the interfaces, simulation, data model and tests around the missing area first.
Then implement real protocol behavior only when adequate evidence exists.
The central architectural rule remains:
> A historical value describes the process at its source timestamp, not at the time the gateway happened to receive it.
And the central protocol rule remains:
> Never invent undocumented AquaCom behavior.