📝 Update spec and README
This commit is contained in:
@@ -567,6 +567,12 @@ unchanged whether or not CSV streaming is used.
|
||||
(6) scheduled steps due at this tick execute,
|
||||
(7) snapshots are taken if due.
|
||||
This order is part of the specification and shall be covered by tests.
|
||||
**With the plant environment (FR-8.2.14)**, the decision source sees this
|
||||
pipeline as one atomic `env` tick: `observe()` reads the state as of the
|
||||
start of the tick, `apply()` queues the decided outputs, and the engine
|
||||
then advances the pipeline once — outputs written by `apply()` land in
|
||||
the output image before the next tick's `observe()`, so every state the
|
||||
decision source sees is pipeline-consistent.
|
||||
- FR-8.2.13: **Logic-only continuous runs**: with no `datasets:` block at
|
||||
all, continuous mode shall work unchanged — demand profiles and other
|
||||
exogenous signals may be generated *inside* plant-model plugins (e.g., a
|
||||
@@ -574,6 +580,44 @@ unchanged whether or not CSV streaming is used.
|
||||
top-level `until:` bounding the run. All §8.3–8.4 machinery (degradation,
|
||||
invariants, rate limits, snapshots) applies identically, whether or not
|
||||
any CSV streaming is configured.
|
||||
- FR-8.2.14: **Plant environment abstraction** (requested 2026-10-04): the
|
||||
continuous engine exposes a gymnasium-style **environment object** —
|
||||
`PlantEnv` — as the single programmatic interface to the simulated plant.
|
||||
Per deterministic tick (the engine's fixed tick clock, FR-4.3.9 — never
|
||||
wall-clock), the cycle is:
|
||||
**`state = env.observe()`** → the caller (plant logic, an external
|
||||
agent, or the scenario) decides → **`env.apply(actions)`** writes the
|
||||
decided output values → the engine advances exactly one tick
|
||||
(edges, datasets, degradation, invariants — FR-8.2.12 order) → repeat.
|
||||
`observe()` returns the state of the **generic inputs** — the WAGO
|
||||
input process image in engineering units (all DI/DO/AI/AO channel
|
||||
values, per-type module/channel addressing, configurable channel
|
||||
names, plus the active aliases) — and `apply(actions)` maps decided
|
||||
values onto the **output process image** through the datastore's
|
||||
internal Modbus write paths, so mirrors, statistics, and watchdog
|
||||
behavior stay consistent (FR-9.2.6 semantics). The environment owns
|
||||
no policy: the plant model (physics, closed-loop control) is supplied
|
||||
by the caller, exactly like `gym.Env` vs. its agents.
|
||||
- FR-8.2.15: **Environment integration**: `PlantEnv` is the interface the
|
||||
per-tick plugins (FR-4.3.8) are migrated onto: a plugin becomes
|
||||
`env.observe()` → decide → `env.apply()` per tick, and a scenario may
|
||||
alternatively register an external `step(env)` agent — including a
|
||||
non-Python one (e.g., a trained RL policy) communicating over a
|
||||
socket/pipe — without touching the engine loop. The existing
|
||||
`plugins:` mechanism keeps working unchanged (thin adapter); the
|
||||
engine always owns the tick clock, and exactly one decision source
|
||||
may drive an output alias per tick (ownership conflicts are validation
|
||||
errors, extending FR-8.2.2).
|
||||
- FR-8.2.16: **Environment API surface** (concrete):
|
||||
`env.observe() -> PlantState` (channel values, names, I/O codes,
|
||||
ranges, sim-time, wear/parameters); `env.apply(actions) -> None`
|
||||
(actions keyed by I/O code or alias name; unknown keys are errors);
|
||||
`env.reset(config) -> PlantState` (fresh episode, deterministic
|
||||
seed); `env.tick_ms`, `env.sim_time_ms` (read-only clock); and the
|
||||
full §8.3/§8.4 machinery (parameters, degradation, invariants,
|
||||
snapshots) reachable as `env.parameters`, `env.invariants`. The same
|
||||
object is served over the scenario-run HTTP API in server mode (§9),
|
||||
so external agents can run against a live PLC-connected bench.
|
||||
|
||||
### 8.3 Requirements — degradation models (plant logic over time)
|
||||
|
||||
@@ -744,15 +788,20 @@ src/wago_sim/scenario/
|
||||
│ # time_factor — OPTIONAL driver in continuous mode
|
||||
├── degradation.py # WearCounters, DegradationModel registry, maintenance actions
|
||||
├── invariants.py # invariant & rate-limit evaluation, episode aggregation
|
||||
├── plantenv.py # PlantEnv: gym-style observe/apply/reset cycle over the
|
||||
│ # process images — the decision-source interface
|
||||
│ # (FR-8.2.14–16); plugins become thin adapters
|
||||
└── engine.py # mode: continuous, parameter() accessor, snapshot
|
||||
# scheduler; fixed tick pipeline per FR-8.2.12:
|
||||
# datasets -> edges -> plugins -> degradation ->
|
||||
# datasets -> edges -> plugins/env -> degradation ->
|
||||
# invariants -> scheduled steps -> snapshots
|
||||
```
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
ContinuousScenario ||--o{ Dataset : "datasets (optional)"
|
||||
ContinuousScenario ||--|| PlantEnv : "environment (FR-8.2.14)"
|
||||
PlantEnv ||--o{ DecisionSource : "plugins / external agents"
|
||||
Dataset ||--|{ ColumnMapping : "alias columns"
|
||||
ContinuousScenario ||--|{ PlantPlugin : "signal logic (always runs)"
|
||||
ContinuousScenario ||--|{ DegradationModel : degradation
|
||||
@@ -764,6 +813,7 @@ erDiagram
|
||||
ContinuousScenario ||--o{ Snapshot : "periodic dumps"
|
||||
PlantPlugin }o--|| DegradationModel : "reads parameters"
|
||||
PlantPlugin }o--o{ Alias : "reads dataset-driven + computes logic-driven"
|
||||
PlantEnv }o--|| ProcessImage : "observe/apply via datastore"
|
||||
```
|
||||
|
||||
### 8.7 Non-functional requirements (long-duration)
|
||||
@@ -809,6 +859,18 @@ erDiagram
|
||||
tick-order test.
|
||||
11. A continuous scenario with no datasets, no scheduled steps, and no
|
||||
`until:` is rejected at validation time (FR-8.2.1).
|
||||
12. **PlantEnv cycle** (FR-8.2.14): `observe()` returns every input channel
|
||||
(values, names, codes, ranges, sim-time); `apply()` lands the decided
|
||||
outputs in the output image before the next `observe()` — verified by a
|
||||
deterministic two-tick test where the decision source copies an input
|
||||
to an output and the second observation contains it.
|
||||
13. **Plugin parity** (FR-8.2.15): the same plant logic runs unchanged as
|
||||
a classic `plugins:` entry and as an `env.observe/apply` decision
|
||||
source — identical outputs over a 1000-tick headless run (regression
|
||||
gate for the adapter).
|
||||
14. **External agent**: a decision source stepping the env over a
|
||||
socket (non-Python agent) produces identical results to the in-process
|
||||
variant on the same scenario (FR-8.2.15).
|
||||
|
||||
---
|
||||
|
||||
@@ -1135,14 +1197,15 @@ This feature request closes that gap.
|
||||
- FR-11.2.5: A reconfiguration event is logged (sim-time, change
|
||||
description, new image sizes) and visible in the web UI's I/O Config
|
||||
page, mirroring the WBM SAVE CONFIG flow.
|
||||
- FR-11.2.6: **Module reordering** (requested 2026-10-04): the web UI's
|
||||
I/O configuration pane supports rearranging modules — move up/down
|
||||
controls per module slot. Reordering triggers the same process-image
|
||||
rebuild as any module change (FR-11.2.1–11.2.3) and persists the new
|
||||
order. Because I/O codes number modules per type (FR-4.3.11 v1.5),
|
||||
moving a module past a module of a different kind does not renumber
|
||||
the other kind's channels — only the relative order within the same
|
||||
type affects addressing.
|
||||
- FR-11.2.6: **Module reordering** (requested 2026-10-04, implemented
|
||||
same day): the web UI's I/O configuration pane supports rearranging
|
||||
modules two ways — drag-and-drop of module rows (HTML5 DnD) and
|
||||
move up/down arrow controls per slot; both are one gesture each and
|
||||
trigger the same process-image rebuild + persistence as any module
|
||||
change (FR-11.2.1–11.2.3). Because I/O codes number modules per type
|
||||
(FR-4.3.11 v1.5), moving a module past a module of a different kind
|
||||
does not renumber the other kind's channels — only the relative
|
||||
order within the same type affects addressing.
|
||||
|
||||
### 11.3 Requirements — address-selection DIP switch emulation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user