Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/LEARNING_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,53 @@ This file should be updated by Codex after each meaningful change.
### What to learn next
```

## 2026-05-22 - OPC UA demo namespace contract

### What changed

Added an intentionally small OPC UA-style namespace and data-contract reference
for the manufacturer demo. The doc defines context nodes, process and quality
tag names, node IDs, units, normal ranges, drift behavior, and example mapped
FactoryEvent payloads for the fill-weight drift scenario.

### Why it matters

The demo now has a clear bridge between future OPC UA simulator tags and the
existing FactoryEvent contracts without expanding into production namespace
browsing, connector configuration, or autonomous factory actions.

### How it works

The namespace mirrors the existing `fill_weight_drift_demo` scenario:
`filler_f_201.fill_weight` and `filler_f_201.filler_nozzle_pressure` map to
process measurement events, while `checkweigher_cw_201.final_fill_weight` maps
to the inline quality marker. Context nodes provide site, line, work order,
batch, and product identifiers for Process Sentinel and the demo talk track.

### How to run it

```bash
make demo
```

### How to test it

```bash
.venv/bin/python -m pytest services/simulator/tests/test_opc_ua_demo_namespace_docs.py
```

### Key files

- `docs/demo/OPC_UA_DEMO_NAMESPACE.md`
- `docs/demo/MANUFACTURER_DEMO_RUNBOOK.md`
- `services/simulator/tests/test_opc_ua_demo_namespace_docs.py`

### What to learn next

Use this namespace as the source for the future demo OPC UA simulator or adapter
issue, keeping the first implementation read-only and aligned with the current
FactoryEvent payloads.

## 2026-05-22 - Demo-safe copy guidelines

### What changed
Expand Down
4 changes: 4 additions & 0 deletions docs/demo/MANUFACTURER_DEMO_RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ during the local demo, see `docs/demo/OPERATIONS_WORKBENCH_DEMO_RUNBOOK.md`.
For approved demo terminology, words to avoid, and sample Workbench microcopy,
see `docs/demo/DEMO_SAFE_COPY_GUIDELINES.md`.

For the intentionally small OPC UA-style demo namespace and mapping from demo
tags to FactoryEvent process and quality events, see
`docs/demo/OPC_UA_DEMO_NAMESPACE.md`.

For the screen-by-screen user goal, component, data dependency, safety language,
risk, and success-criteria map, see
`docs/demo/MANUFACTURER_DEMO_USER_JOURNEY.md`.
Expand Down
206 changes: 206 additions & 0 deletions docs/demo/OPC_UA_DEMO_NAMESPACE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# OPC UA Demo Namespace and Data Contract

## Purpose

This document defines the minimum OPC UA-style namespace for the
simulator-backed manufacturer demo. It is intentionally small and demo-specific:
it exists to make the fill-weight drift story concrete, reviewable, and aligned
with the current `FactoryEvent` contracts.

This is not a production namespace-browsing design, not a general tag-mapping UI,
and not a full connector configuration framework. The demo remains read-only,
simulator-backed, advisory, and human-reviewed.

## Namespace Boundary

- Namespace URI: `urn:open-factory-initiative:factory-intelligence-platform:demo`
- Example namespace index: `ns=2`
- Demo site: `greenville_demo_site`
- Demo area: `packaging_area`
- Demo line: `line_2`
- Work order: `WO-DEMO-1007`
- Batch: `BATCH-DEMO-1007`
- Product: `ofi_demo_beverage` / `OFI Demo Beverage`

The namespace mirrors the current `fill_weight_drift_demo` scenario. Node IDs
are stable demo identifiers so a future OPC UA simulator can expose the same
source signals while preserving the existing event contract.

## Context Nodes

These nodes provide the line, work order, batch, and product context needed by
Process Sentinel and the demo talk track.

| Context | Node ID | Example value | FactoryEvent mapping |
| --- | --- | --- | --- |
| Site | `ns=2;s=OFI.Demo.Greenville.SiteId` | `greenville_demo_site` | `context.site_id` |
| Area | `ns=2;s=OFI.Demo.Greenville.Packaging.AreaId` | `packaging_area` | `context.area_id` |
| Line | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.LineId` | `line_2` | `context.line_id` |
| Work order | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.WorkOrderId` | `WO-DEMO-1007` | `context.work_order_id` |
| Batch | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.BatchId` | `BATCH-DEMO-1007` | `context.batch_id` |
| Product ID | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.ProductId` | `ofi_demo_beverage` | production work order and batch event payloads |
| Product name | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.ProductName` | `OFI Demo Beverage` | production work order and batch event payloads |

Process and quality measurement events carry site, area, line, asset, work
order, and batch context directly. Product context belongs to the demo scenario
and production work order or batch events rather than the process measurement
payload itself.

## Process and Quality Tags

| Demo tag name | Node ID | Browse name | Asset | Unit | Normal or spec range | Target | Normal example | Drifting example | Drift behavior | FactoryEvent mapping |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `filler_f_201.fill_weight` | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.FillerF201.FillWeight` | `FillWeight` | `filler_f_201` | `g` | `495.0` to `505.0` | `500.0` | `500.12` | `506.81` | Stable baseline for the first 8 samples, then about `+0.33 g` per sample with small noise. | `process.measurement.recorded` with `payload.signal_id=fill_weight`, `payload.signal_name=Fill Weight`, and `payload.tag_name=filler_f_201.fill_weight` |
| `filler_f_201.filler_nozzle_pressure` | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.FillerF201.NozzlePressure` | `NozzlePressure` | `filler_f_201` | `bar` | `1.9` to `2.4` | `2.1` | `2.10` | `2.31` | Stable baseline for the first 8 samples, then about `+0.01 bar` per sample with small noise. | `process.measurement.recorded` with `payload.signal_id=filler_nozzle_pressure`, `payload.signal_name=Filler Nozzle Pressure`, and `payload.tag_name=filler_f_201.filler_nozzle_pressure` |
| `checkweigher_cw_201.final_fill_weight` | `ns=2;s=OFI.Demo.Greenville.Packaging.Line2.CheckweigherCW201.FinalFillWeight` | `FinalFillWeight` | `checkweigher_cw_201` | `g` | `495.0` to `505.0` | none | `500.20 pass` | `506.70 fail` | Recorded every third sample as the inline quality marker that confirms fill-weight drift is visible in quality results. | `quality.measurement.recorded` with `payload.quality_check_type=inline_check` and `payload.measurement_name=Final Fill Weight` |

## Mapping Rules

1. OPC UA source values are normalized into existing `FactoryEvent` envelopes.
2. Process tags become `process.measurement.recorded` events.
3. Quality marker values become `quality.measurement.recorded` events.
4. `context.site_id`, `context.area_id`, `context.line_id`,
`context.work_order_id`, and `context.batch_id` come from the context nodes.
5. `context.asset_id` comes from the owning asset in the tag table.
6. Process event `payload.tag_name` uses the current simulator tag format:
`<asset_id>.<signal_id>`.
7. Quality events do not have a `payload.tag_name` field in the current
contract, so the OPC UA tag name is documented as source mapping metadata and
the FactoryEvent payload uses `measurement_name`.
8. In the existing local simulator path, events still use
`source.system=factory-simulator` and `source.adapter=simulator`. A future
demo OPC UA adapter can keep the same context and payload fields while
preserving the OPC UA node ID in `source.source_event_id` or adapter metadata.

## Example Normal Process Event

```json
{
"event_id": "evt_opcua_demo_fill_weight_normal",
"event_type": "process.measurement.recorded",
"schema_version": "1.0.0",
"timestamp": "2026-01-01T12:02:00Z",
"source": {
"system": "factory-simulator",
"adapter": "simulator",
"source_event_id": "ns=2;s=OFI.Demo.Greenville.Packaging.Line2.FillerF201.FillWeight@2026-01-01T12:02:00Z"
},
"context": {
"site_id": "greenville_demo_site",
"area_id": "packaging_area",
"line_id": "line_2",
"asset_id": "filler_f_201",
"batch_id": "BATCH-DEMO-1007",
"work_order_id": "WO-DEMO-1007"
},
"payload": {
"signal_id": "fill_weight",
"signal_name": "Fill Weight",
"tag_name": "filler_f_201.fill_weight",
"value": 500.12,
"unit": "g",
"quality": "good",
"normal_min": 495.0,
"normal_max": 505.0,
"target_value": 500.0
},
"metadata": {
"simulated": true,
"trace_id": "trace_opcua_demo_normal"
}
}
```

## Example Drifting Process Event

```json
{
"event_id": "evt_opcua_demo_fill_weight_drifting",
"event_type": "process.measurement.recorded",
"schema_version": "1.0.0",
"timestamp": "2026-01-01T12:28:00Z",
"source": {
"system": "factory-simulator",
"adapter": "simulator",
"source_event_id": "ns=2;s=OFI.Demo.Greenville.Packaging.Line2.FillerF201.FillWeight@2026-01-01T12:28:00Z"
},
"context": {
"site_id": "greenville_demo_site",
"area_id": "packaging_area",
"line_id": "line_2",
"asset_id": "filler_f_201",
"batch_id": "BATCH-DEMO-1007",
"work_order_id": "WO-DEMO-1007"
},
"payload": {
"signal_id": "fill_weight",
"signal_name": "Fill Weight",
"tag_name": "filler_f_201.fill_weight",
"value": 506.81,
"unit": "g",
"quality": "good",
"normal_min": 495.0,
"normal_max": 505.0,
"target_value": 500.0
},
"metadata": {
"simulated": true,
"trace_id": "trace_opcua_demo_drifting"
}
}
```

## Example Drifting Quality Event

```json
{
"event_id": "evt_opcua_demo_quality_drifting",
"event_type": "quality.measurement.recorded",
"schema_version": "1.0.0",
"timestamp": "2026-01-01T12:29:20Z",
"source": {
"system": "factory-simulator",
"adapter": "simulator",
"source_event_id": "ns=2;s=OFI.Demo.Greenville.Packaging.Line2.CheckweigherCW201.FinalFillWeight@2026-01-01T12:29:20Z"
},
"context": {
"site_id": "greenville_demo_site",
"area_id": "packaging_area",
"line_id": "line_2",
"asset_id": "checkweigher_cw_201",
"batch_id": "BATCH-DEMO-1007",
"work_order_id": "WO-DEMO-1007"
},
"payload": {
"quality_check_type": "inline_check",
"measurement_name": "Final Fill Weight",
"value": 506.7,
"unit": "g",
"result_status": "fail",
"result": "fail",
"severity": "high",
"spec_min": 495.0,
"spec_max": 505.0
},
"metadata": {
"simulated": true,
"trace_id": "trace_opcua_demo_quality"
}
}
```

## Process Sentinel Sufficiency

The namespace is sufficient for the current Process Sentinel fill-weight drift
detection because it exposes:

- The required `fill_weight` process signal on `filler_f_201`.
- The supporting `filler_nozzle_pressure` process signal on the same asset.
- The inline `Final Fill Weight` quality marker on `checkweigher_cw_201`.
- The Greenville demo site, packaging area, Line 2, work order, batch, and
product identifiers needed to explain the scenario.
- Normal ranges, target values, and example drifting values for evidence and
RCA/CAPA draft support.

No autonomous control, equipment writeback, QMS/MES writeback, production
namespace browsing, or production validation is implied by this demo namespace.
Loading
Loading