Skip to content

Implement the harel engine (Python reference implementation) #3

Description

@fruwe

Implement the harel statechart engine in Python (reference implementation).

The normative spec lives in fruwehq/harel (SPEC.md, draft v2) and is the source of truth; correctness is defined by its conformance suite (SPEC.md §2: "where prose and the suite disagree, the suite wins"). This repo is currently a scaffold.

Ready to start. The conformance suite (fruwehq/harel#6, complete) is your fixed correctness target — 22 engine cases (conformance/0122) plus conformance/cli/01. The spec (SPEC.md §0–§13) is complete.

Read first

fruwehq/harel: SPEC.md end to end, then schema/machine.schema.json, examples/minimal.yaml, examples/full.yaml, examples/contracts/, conformance/.

Methodology

The conformance suite in fruwehq/harel is your fixed correctness target — it was authored as part of the spec (harel#6), not by you, and its expected outputs are derived from the spec (PSiCC) rather than run by an engine. You are the first runtime cross-check: implement each capability until its cases pass; if a case and the spec genuinely disagree, that's a suite bug or spec ambiguity — open a spec PR to harel to fix it (reviewed there). Don't silently bend the engine to match a wrong expectation.

Build order (each gated by conformance cases)

  • 1. YAML 1.2 loader + JSON-Schema validation; honor reserved names (top, id, parent, event; events initial/entry/exit/env/error/done).
  • 2. esvs: typed, declared inside states, hierarchically scoped (inner shadows outer), initialized on entry before entry actions, destroyed on exit, re-init on re-entry; external esvs host-seeded, read-only, retained.
  • 3. Flat guarded leaf transitions (CEL guards over in-scope esvs + event + intrinsics id/parent).
  • 4. Hierarchy: LCA + exit/entry ordering (PSiCC; cases 07/08 pin it by recording entry/exit into a trail esv); internal/local/external; initial is a transition (transition_to + optional guard/action), distinct from entry.
  • 5. Composite + orthogonal (declared region order is normative) + the done completion event.
  • 6. Shallow/deep history; guarded transition lists (first passing guard wins; choice/junction pseudostates were dropped).
  • 7. Structured actions (assign/publish/refresh/spawn/stop) with CEL-valued args; typed event payloads + scope (internal/local/global), validated at delivery.
  • 8. Active objects: per-instance FIFO queue, single-threaded RTC, spawn tree; publish directed (to:, ignores scope) or undirected (subscribers within scope; self always receives its own internal publishes); termination + child cleanup + done to parent.
  • 9. external esvs + the env event + refresh ({} / { only: [...] }, valid only while handling env).
  • 10. defer as a deferred-set (edge-triggered reinsertion on state change; no busy-loop).
  • 11. Timers: after via an injected clock adapter; virtual clock advanced by advance: in tests (no wall-clock).
  • 12. Faults: atomic RTC; on error abort + dead-letter; deliver reserved error event if handled, else __faulted__; clock-adapter deadline for pluggable host languages.
  • 13. Contracts (static validator: required events/states/spawns).
  • 14. Snapshot round-trip (§8); versioning + safe-point migration (§10).
  • 15. export: Mermaid stateDiagram-v2 of a machine + an instance's state_config (§12), behind a pluggable exporter interface.
  • 16. Standard CLI (SPEC §13): the identical command surface every implementation exposes — validate / export / new <id> <machine> / send / advance / env / state / list / snapshot / restore — over a file-backed store (--store, default ./.harel), with normative --json shapes and exit codes and a virtual clock. CLI parity is pinned by conformance/cli/ (§13.6).

Locked decisions (in the spec — don't relitigate)

Guards = CEL (cel-python, or justify an alternative); actions = the structured set; YAML 1.2; esvs in-state + hierarchical; external esvs + env/refresh; top outermost state; initial as a transition; publish over a bus (directed + subscription + scope); faults via the error event; bus / queue / clock / store / observer are adapters with simple in-memory defaults; immutable versioned definitions + pinned instances + safe-point migration; Mermaid default export.

Consume the conformance suite from harel

Recommended: a git submodule pinned to a harel commit (single source of truth). Two harnesses: (1) engine cases — discover conformance/*/, load machine.yaml (or versioned v*.yaml), create the root as id root, run each test.yaml step (send/advance/upgrade) to quiescence, then check expect (config/esvs/published/spawned/rejected/status/dead_letter, per-instance instances:, plus the roundtrip: and static: modes) — all defined in SPEC §9; (2) CLI casesconformance/cli/*/cli.yaml, running your harel binary against a temp store (§13.6). Avoid copy-paste drift.

Tooling / CI

ruff + mypy + pytest; a GitHub Actions test workflow on ubuntu-24.04 and macos-latest. When CI is green, add a required_status_checks rule (those two contexts) to this repo's protect_main ruleset — it was intentionally omitted because no CI existed yet.

Workflow (enforced by protect_main on both repos)

No direct pushes to main; branch + PR; squash-merge only; linear history; resolve all review threads. Keep spec changes (harel) and implementation (harel-python) in separate PRs. No AI/assistant attribution anywhere — commits, PR bodies, comments, docs; no Co-Authored-By trailers.

If the spec is ambiguous or wrong

You own it: decide, encode the decision as a conformance case, and open a spec PR to harel. No outside review required.

Definition of done

Engine passes the full conformance suite (all of conformance/0122); schema validation enforced on load; CI green on both OSes; snapshot round-trip + migration cases passing; export produces valid Mermaid (static + current-state highlight); CLI matches the §13 surface and passes conformance/cli/.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions