Supervisor filtered only on enabled, so disabled-mode segments (e.g.
the OPS_SEED_TEMPLATES skeleton, which seeds mode='disabled' until an
operator finishes wiring) got a task spawned every 10 s only to exit
immediately on the task's own enable-check, spamming the log with
"segment X disabled or removed, task exiting" every supervisor tick.
Aligning the supervisor's filter with the task's exit condition lets
disabled-mode segments stay quiescent. Flipping mode away from
'disabled' via the config UI now reaches the engine within one
supervisor cycle (≤10 s), unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends ensure_default_templates to also seed the 5 公共段 (前端码车 /
前端放车 / 前端摆渡 / 窑尾摆渡 / 卸砖 / 回车) and their shared resource
declarations (transfer_front / transfer_tail / unload_position /
return_line / robot_arm) so operators have the full skeleton to bind
equipment + signals against.
Engine now runs a station signal-conflict check during the run-halt
phase: any station whose presence and vacancy are both true with Good
quality emits ops.alarm.signal_conflict + segment.fault_locked and
transitions the segment to Faulted. Closes the final P8 alarm type
from design doc §8.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EventInsert + EventRecord + record_event now carry the subject_type /
subject_id columns added by the P1 migration. Ops events populate
"segment" / "station" subjects so the timeline can be filtered without
parsing event_type strings. Platform SourceCreated / Updated / Deleted
attribute themselves to subject_type="source". Adds get_events_*_filtered
in core and exposes GET /api/event on ops with event_type /
event_type_prefix / subject_type / subject_id query params, closing
design doc §14 "event 表能按 ops.* 和 subject_type/subject_id 查到全链路事件".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds ResourceRegistry::sweep_stale and runs it on each supervisor tick
so a panicked or stuck segment task can't keep a shared resource
locked indefinitely. The per-segment task refreshes heartbeat on every
iteration for each key in runtime.held_resources, distinguishing live
owners from dead ones.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ensure_kiln_templates idempotently inserts 6 dry-kiln stations and 6
segments (infeed/step/outfeed × 2 kilns) with their canonical step
sequences from §10.1. Equipment and station-signal bindings stay
operator-owned through the CRUD APIs. Startup runs the seed only when
OPS_SEED_TEMPLATES=true|1, so production deployments don't accidentally
mutate config.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
step_executor gains three dispatch modes: pulse (default), hold
(hold_until_confirm), and value (transfer_move_to writes the target
station's code). The engine now sends step.stop_command_role whenever
cancel_on_fault is true on Faulted entry, and threads a target-station
lookup ahead of dispatch. A new simulate module patches the resolved
confirm signal after a short delay when SIMULATE_PLC is set, so
segments can be driven end-to-end without a real PLC.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Land design doc §12 P1 + P2: ops business tables plus station/segment
configuration endpoints. The engine (P3) consumes these as its inputs.
- Migration: six ops tables (station, station_signal, process_segment,
segment_step, segment_interlock, segment_resource) plus event attribution
columns (subject_type, subject_id).
- model.rs: FromRow structs and string-backed enum helpers
(StationType, StationSignalRole, SegmentMode, ActionKind, OnTimeout,
InterlockAppliesTo, RuleKind).
- service: station CRUD with signal-binding upsert; segment CRUD with
nested step/interlock CRUD and transactional resource replacement.
- handler: 13 endpoints covering design doc §9.1 config routes with
validator-based input checks and enum allowlists.
- router: wires the new routes; smoke tests cover station and segment
collection routes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires AppState with EventManager, SegmentRuntimeStore, ResourceRegistry
and an engine supervisor that idles until P1 lands the segment schema.
The run() bootstrap connects enabled sources, installs a Ctrl+C handler,
and disconnects on shutdown, matching the feeder app lifecycle. The
router exposes /ws/public, /ws/client/{id}, simple_logger middleware
and a permissive CORS layer.
AppEvent covers the full ops.* taxonomy from the spec; resource lease
tracking includes heartbeat timestamps for the §7 recovery strategy and
has two unit tests for acquire/release semantics.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Move source/point/equipment/tag/page handlers from feeder to plc_platform_core
using State<PlatformContext>; feeder re-exports via handler modules
- Keep batch_set_point_value in feeder (requires app-specific write key auth)
- Add PlatformEvent enum and persist_and_broadcast() in core for platform event
persistence to DB + WebSocket broadcast
- Add PlatformContext::emit_event() that handles both sink notification and
async persistence in one call
- Add platform_routes<S>() in core for centralized route registration;
both feeder and ops merge it instead of duplicating route definitions
- Implement FromRef<AppState> for PlatformContext in both apps
- Add FeederPlatformEventSink adapter bridging core events to feeder's
EventManager + ControlRuntimeStore
- Add event namespace prefixes: platform.source.created, feeder.unit.fault_locked, etc.
- Register full platform CRUD routes in ops app
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PlatformContext now holds pool, connection_manager, ws_manager
- bootstrap_platform returns PlatformBuilder for pre-Arc setup
- Feeder AppState embeds PlatformContext (state.platform.pool etc.)
- Ops AppState embeds PlatformContext with real DB connection
- Remove WebSocket type duplication: feeder re-exports from core
- Add subscribe_room/send_to_room/remove_room_if_empty to WebSocketManager
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>