Commit Graph

216 Commits

Author SHA1 Message Date
caoqianming b84ce744d3 Ignore cl.ps1 / col.ps1 personal launcher scripts
Mirrors the existing cl.bat / col.bat entries — these are user-local
PowerShell wrappers that set HTTP_PROXY and shell out to claude / codex.
Not project artifacts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 10:07:19 +08:00
caoqianming 3667d64243 Add P10 ops config UI: stations + segments CRUD
Adds Monitor/Config tab switcher. Config view splits into stations
panel (inline create/edit/delete + per-station signal binding expand)
and segments panel (inline create/edit/delete + expandable detail with
step add/delete, interlock add/delete, and resource-keys replace).

UI talks to the existing ops CRUD endpoints exclusively; no engine
changes. node --check passes for all eight ops JS modules; backend
tests still green. Browser verification still required end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:56:26 +08:00
caoqianming e2248fa04f Add P9 segment monitor page for operation-system
Replaces the ops UI placeholder with a single-panel monitor: fetches
/api/runtime/overview to render one card per segment with state badge,
current step, fault / block note, and per-card Start / Stop / Ack-Fault
/ Reset buttons plus batch start/stop. WebSocket subscriber routes
app_event(app=operation-system, event_type=segment_runtime_changed)
into in-place card updates with exponential reconnect.

Note: UI not verified in-browser; the engine + WebSocket plumbing has
unit + smoke test coverage but the page itself needs runtime
validation by running app_operation_system and visiting /ui/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:19:20 +08:00
caoqianming 972938a8e6 Seed public segments and emit signal-conflict alarms
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>
2026-05-19 09:16:04 +08:00
caoqianming a7f5c85032 Persist event subject_type/subject_id and add ops event timeline API
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>
2026-05-19 08:57:40 +08:00
caoqianming ed1067f6e5 Reclaim stale resource leases and refresh heartbeats
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>
2026-05-19 08:49:27 +08:00
caoqianming e3e7917078 Seed dual-kiln segment templates behind OPS_SEED_TEMPLATES
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>
2026-05-19 08:47:18 +08:00
caoqianming aaf48a336d Add hold/value dispatch modes, cancel_on_fault, and SIMULATE_PLC injection
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>
2026-05-19 08:44:10 +08:00
caoqianming 63683a24c8 Implement operation-system engine MVP (P3)
Adds the segment supervisor + per-segment state machine driving
Idle → Checking → Executing → Confirming → Completed (plus Blocked /
Faulted / ManualAckRequired), interlock evaluator, action-kind step
executor, control + runtime HTTP handlers, and WebSocket runtime push
via AppEvent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 08:39:14 +08:00
caoqianming a33c013da5 Add operation-system config schema and CRUD API
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>
2026-05-19 08:17:34 +08:00
caoqianming fd028b1320 Bootstrap operation-system app skeleton
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>
2026-05-18 21:39:09 +08:00
caoqianming 19ace9c2be Move feeder unit model out of platform core
Lifts ControlUnit, UnitRuntime/State, ControlRuntimeStore and unit CRUD
into app_feeder_distributor; their feeder-specific semantics
(DistributorRunning state, run_time/stop_time/acc_time/bl_time pacing)
violated the shared-core invariant.

WsMessage drops the UnitRuntimeChanged variant in favor of a generic
AppEvent(AppWsEvent) carrying {app, event_type, data}. Feeder emits
"feeder"/"unit_runtime_changed"; the web client dispatches by app
namespace, leaving core free of business types. The equipment handler
keeps its friendly unit-exists check by issuing an inline EXISTS query
instead of pulling the unit service.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:38:52 +08:00
caoqianming 3467f203ca Add operation-system engine design spec
Spec covers station/segment/step/interlock domain model, segment state
machine (Idle..ManualAckRequired), action templates including persistent
commands, resource lease registry, ops.* event taxonomy, and the AppEvent
WebSocket envelope. Stage plan includes P-1 core cleanup before ops work
begins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:38:33 +08:00
caoqianming 2a6dde9e0e Restore SIMULATE_PLC chaos task and run feedback
Bring back crates/app_feeder_distributor/src/control/simulate.rs which
was dropped when feeder's local connection/telemetry/websocket modules
moved into core; the restored module reuses core's equivalents via
plc_platform_core::{connection, service, telemetry, websocket}.

Also restore the call sites that were lost alongside it:
- app.rs starts the chaos task when SIMULATE_PLC=true
- engine.rs fires simulate_run_feedback after each pulse command so
  the auto-control state machine sees the RUN bit transition it
  would get from a real PLC
- handler/control.rs does the same after manual start/stop commands

The SIMULATE_PLC flag is now read via simulate::enabled() from the
environment rather than state.config.simulate_plc (the old config
struct was removed with the module migration). To expose equipment
ids by kind (used for run feedback), build_equipment_maps now also
returns HashMap<kind, Uuid>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 10:33:51 +08:00
caoqianming 3b92c0028a Merge handle_control_event and persist_event_if_needed
The split existed only so handle_control_event could log
UnitStateChanged and then delegate; that's no longer worth its own
function. Co-locating the UnitStateChanged special case with the other
match arms makes its 'log-only, no persist' treatment self-evident,
and the call chain drops from handle → persist → record to handle →
record.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 08:39:17 +08:00
caoqianming 52cd3e630e Rename persist_and_broadcast to record_platform_event
After record_event became the primitive for INSERT + broadcast + tracing,
persist_and_broadcast no longer persists or broadcasts directly — it
translates a PlatformEvent into an EventInsert and delegates. The new
name makes the layering explicit (record_event is the primitive,
record_platform_event is the PlatformEvent translator).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 08:33:28 +08:00
caoqianming 6c8e5561dc Cache unit/equipment codes for event messages
Add MetadataCache to PlatformContext — a lazy-loaded, cross-app cache
of code fields used when formatting event messages. Each persisted
AppEvent previously did 1-2 extra SELECTs to look up the code for its
human-readable message; after this change the same id hits the cache
on all subsequent events.

Invalidation: the platform-owned equipment handler invalidates its
entry on update/delete; feeder's unit handler does the same for
units. Deletes are invalidated for hygiene only — no further events
should target a deleted id.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 08:21:46 +08:00
caoqianming 3e0d4c242b Emit tracing inside record_event and drop duplicate feeder match
record_event now logs at the matching tracing level (error/warn/info)
using the persisted message — giving every app uniform event logs for
free. Feeder's handle_control_event collapses from a 60-line match
(which just duplicated the persisted message with less-readable UUIDs)
to a single if-let for UnitStateChanged, which is the only AppEvent
that is intentionally not persisted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 20:11:59 +08:00
caoqianming 1c646dfaa7 Extract event persistence primitive to platform core
Move the INSERT + WebSocket broadcast mechanism out of the feeder app
and into plc_platform_core as pub record_event(pool, ws, EventInsert).
The event table schema is owned by core, so writing to it is a platform
capability — apps (feeder, future ops) should only decide what to emit,
not how to persist it. Also replaces the 7-tuple in core's
persist_and_broadcast with the named EventInsert struct for readability.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 20:04:25 +08:00
caoqianming 58fdb9f58e Clean up clippy warnings and improve code organization
- engine.rs: use is_none_or instead of map_or, remove redundant closures
- service/control.rs: move get_equipment_role_points before test module
- event.rs: replace complex 7-element tuple with PersistableEvent struct

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 19:49:27 +08:00
caoqianming 706fb4f72a Simplify imports in feeder control handler
Replace verbose fully-qualified paths with top-level use imports
for plc_platform_core types and services throughout control.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 19:45:46 +08:00
caoqianming 087f016f01 Remove dead handler re-exports from feeder
The feeder router uses platform_routes() directly from core,
making these re-export modules unused. The only actual dependency
(SignalRolePoint) now references plc_platform_core directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 19:32:20 +08:00
caoqianming dabcde1fca Remove unit change platform event plumbing 2026-04-21 19:12:09 +08:00
caoqianming a49f6adf9b Format feeder event module 2026-04-21 16:24:26 +08:00
caoqianming f8ba864a65 Clean feeder core dependency boundaries 2026-04-21 16:22:11 +08:00
caoqianming 24b1d3546b Move shared feeder plumbing into core 2026-04-21 16:04:03 +08:00
caoqianming 1317271e16 refactor(core): centralize telemetry, connection management, and event sink in platform
Move TelemetryProcessor (PointNewValue batching/dedup/broadcast) from feeder to
plc_platform_core. PlatformBuilder.build() now auto-wires telemetry processing and
reconnect task. PlatformContext.emit_event() handles connection management side effects
(connect/reconnect/disconnect/subscribe/unsubscribe) directly. Simplify PlatformEventSink
trait from 6 methods to single on_event(). Feeder's AppEvent now only contains business
events; FeederPlatformEventSink only handles UnitsChanged for control runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 15:30:45 +08:00
caoqianming 6814e9eae9 refactor: migrate platform handlers to core, centralize routes and event persistence
- 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>
2026-04-21 13:45:02 +08:00
caoqianming 093fc5035b docs: add next-steps plan after PlatformContext completion
Four remaining improvements for the dual-app split:
1. Migrate platform handlers (tag/page/source/point/equipment) to core
2. Add event namespace prefixes (platform.*/feeder.*/ops.*)
3. Register platform routes in ops app
4. Ops business logic (pending requirements)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 09:22:26 +08:00
caoqianming 429c2d0b17 refactor(core): fill PlatformContext with pool/connection/websocket
- 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>
2026-04-21 09:11:03 +08:00
caoqianming 368faf290a fix(web): restore all web UI files accidentally deleted
The web/core, web/feeder, and web/ops directories were mistakenly
committed as deletions. Restore from f8757a7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 08:43:02 +08:00
caoqianming 6102ed712f refactor(web): remove legacy feeder/ops/core web files after split
Clean up old web module files that were superseded by the per-app
split architecture. Includes plan documentation for the migration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 08:36:32 +08:00
caoqianming f8757a757e i18n(feeder): replace all English UI text with Chinese
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 09:12:15 +08:00
caoqianming 268c5f76af refactor(feeder): remove auto control buttons from unit cards
Start Auto / Stop Auto / Ack Fault belong in the ops view only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 09:04:27 +08:00
caoqianming 01d8418e5c refactor(feeder): remove start/stop buttons from equipment in platform config
Equipment start/stop operations belong in the ops view only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 09:03:35 +08:00
caoqianming 6b9e396044 refactor(feeder): remove batch set-unit from platform config
Batch equipment-unit assignment is now handled via the "选择设备"
modal in app-config. Remove the batch toolbar, checkbox selection,
and related JS/state from the equipment panel in platform config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 09:00:18 +08:00
caoqianming 3a9b52864b fix(feeder): compact card grid for units and equipment selection modal
- Fix unit-config-list grid by increasing specificity over .list flex
- Equipment selection modal uses card grid (auto-fill 150px) instead
  of one-per-line list
- Widen modal to accommodate card grid

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:56:01 +08:00
caoqianming 3e026e1b99 feat(feeder): unit card grid in app-config with equipment selection modal
- Unit cards in app-config use CSS grid (auto-fill 260px min) for
  compact card layout across the full page
- Each card shows bound equipment tags and a "选择设备" button
- Equipment selection modal allows multi-select with checkboxes,
  calls batch set-unit API to bind/unbind, then refreshes
- App-config loads both units and equipments on first switch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:43:59 +08:00
caoqianming 2db9fec081 Revert "feat(feeder): card layout for units in app-config, share equipment panel"
This reverts commit 521ccfb800.
2026-04-20 08:40:14 +08:00
caoqianming 521ccfb800 feat(feeder): card layout for units in app-config, share equipment panel
- Unit cards in app-config use CSS grid with auto-fill columns
- Equipment panel (with batch unit assignment) visible in both
  app-config and platform-config views
- App-config loads both units and equipments on first switch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:36:34 +08:00
caoqianming bc8b5a24ab fix(feeder): render units in app-config panel, remove from platform-config
- Delete feeder source-panel override (units no longer in platform config)
- Extract buildUnitCard() and render to both unitList and unitConfigList
- Guard null DOM refs for removed unit buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:31:10 +08:00
caoqianming 63cf3d8c67 docs: update API doc references for per-app split
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:20:29 +08:00
caoqianming cea7726106 feat(ops): register log and doc routes from shared core
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:19:21 +08:00
caoqianming b651b6af66 refactor(core): move doc handler to core and split API.md per app
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 08:18:51 +08:00
caoqianming 4761e88c81 refactor(core): move log handler to shared platform core
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 13:36:26 +08:00
caoqianming 9955498e24 feat(feeder): add three-tab UI (ops / app-config / platform-config)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 13:34:18 +08:00
caoqianming c961fc0298 refactor(web): create feeder overrides for unit-dependent pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 13:32:43 +08:00
caoqianming 7ff40c1aa3 refactor(web): remove unit references from core HTML pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 13:32:02 +08:00
caoqianming 837e648b7d docs: update README for workspace and web split layout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 08:41:47 +08:00
caoqianming a3bc280c0f chore: remove obsolete root src/ (migrated to crates)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 08:36:27 +08:00