Skip to content

feat(kr0ki-core): Phase 5 — DecisionNode/ForkNode/JoinNode/MergeNode in ProcessChart - #274

Open
elasticdotventures wants to merge 6 commits into
mainfrom
task/268-statechart-phase5-control-flow
Open

elasticdotventures wants to merge 6 commits into
mainfrom
task/268-statechart-phase5-control-flow

Conversation

@elasticdotventures

Copy link
Copy Markdown
Member

Summary

  • Extends ProcessChart::from_sysml in kr0ki-core to handle all four control-flow ElementKind variants added in ufo-types PR feat: add isometric graph visualization stack for Slint UI #35
  • MergeNode / JoinNode → atomic states with plain on("next", target) transitions (fan-in pass-through)
  • DecisionNode → atomic state with per-branch named events "choose:<target>" — caller routes with chart.decide("target_id")
  • ForkNode → atomic state with per-branch named events "fork:<target>" — caller routes with chart.fork_to("target_id")

Design constraint documented in code

lazily 0.59 stores one Transition per event key (HashMap<String, Transition>), so multiple guarded transitions on "next" silently overwrite each other. Named events ("choose:<id>", "fork:<id>") are unambiguous and compose correctly with the current lazily API.

Phase 6 note is in the chart source: replace with StateBuilder::parallel + child regions + Vec<Transition>/event once lazily gains that support.

Also fixes

  • Duplicate lazily workspace dep key in root Cargo.toml (lines 61 and 89 were identical)
  • Duplicate lazily optional dep in ledgerr-mcp/Cargo.toml; statechart feature simplified since lazily is always included

Test evidence

running 7 tests
test chart::tests::orphan_action_usage_builds ... ok
test chart::tests::decision_node_routing ... ok
test chart::tests::three_step_linear_chain ... ok
test chart::tests::join_node_single_successor ... ok
test chart::tests::merge_node_pass_through ... ok
test chart::tests::fork_node_fanout ... ok
test chart::tests::succession_advances_through_steps ... ok

test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Closes #268

🤖 Generated with Claude Code

elasticdotventures and others added 5 commits October 19, 2026 12:04
Add DecisionNode, ForkNode, JoinNode, MergeNode support to ProcessChart::from_sysml.

Mapping rules:
- MergeNode/JoinNode: atomic, plain "next" transitions (fan-in pass-through)
- DecisionNode: per-branch "choose:<target>" named events (use `decide(id)`)
- ForkNode: per-branch "fork:<target>" named events (use `fork_to(id)`)

lazily 0.59 stores one Transition per event key, so multi-branch Decision/Fork
cannot use guarded "next" transitions — distinct event names sidestep that limit.
Phase 6: replace with Vec<Transition>/event once lazily gains that support.

Also fix duplicate workspace dep keys:
- Cargo.toml: remove duplicate lazily entry (lines 61 and 89)
- ledgerr-mcp/Cargo.toml: remove duplicate optional lazily dep; statechart
  feature no longer needs dep:lazily since it is always included

7/7 kr0ki-core tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…atch

Three lingering issues from the earlier batch merge:

1. hsm.rs line 390: dangling `<<<<<<< HEAD` marker with no matching
   `=======`/`>>>>>>>` — remove the lone conflict marker.

2. lib.rs lines 835, 1103: two `self.hsm_hooks` references that no longer
   compile because `hsm_hooks` was superseded by `project_event_bus` in the
   merged PRs.  Migrate:
   - `hsm_hooks.register(built_in.into_hook_fn())` → wrap in a
     `project_event_bus` closure that reconstructs `TransitionHookEvent`
     from the "from"/"to" attrs on `lifecycle_transition` ProjectEvents.
   - `hsm_hooks.fire(TransitionHookEvent { from, to })` →
     `project_event_bus.fire(ProjectEvent::lifecycle_transition(&from.token(), &to.token()))`.

3. ledgerr-mcp-server.rs line 439: missing closing `}` on the
   `GCP_BILLING_TOOL` match arm — add it.

Verified: `cargo check -p ledgerr-mcp` clean; `bash scripts/mcp_cli_demo.sh basic`
returns 7 successful JSON-RPC responses including tools/list (16 tools).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ufo-types PR #35 (feat/control-flow-nodes) was merged at 9f883e6.
Update workspace pin from the branch tip (523837f) to the squash commit
on main so the dependency resolves from an official merged ref rather than
the pre-merge branch tip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add ledgerr_validate_process to the generated capability contract,
agent runbook, and demo script. Regenerated via `cargo run -p ledgerr-mcp
--bin regen-docs`.

9/9 contract_codegen tests now pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tall.md

- crates/ledgerr-cloud/src/reconcile.rs: wrap each provider in an 8s
  tokio::time::timeout so gcloud/az hanging without credentials maps to
  a Fail entry instead of blocking the whole run; fixes
  budget_reconcile_returns_well_formed_report_shape (was 30s timeout)
- crates/ledgerr-mcp/tests/install_e2e.rs: spawn the actual
  ledgerr-mcp-server binary, run the full MCP initialize → tools/list
  → tools/call sequence over stdio, and assert the published catalog
  (16 tools) and a real pipeline_status call succeed
- docs/mcp-install.md: build → bundle → install → client interface
  reference covering cargo xtask bundle, Claude Desktop .mcpb install,
  JSON-RPC stdio protocol, and the install_e2e smoke test command

PASS: budget_reconcile_returns_well_formed_report_shape  1.69s
PASS: install_path_binary_spawns_and_serves_full_catalog  0.57s
PASS: contract_codegen (9/9)  0.00s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@elasticdotventures

Copy link
Copy Markdown
Member Author

Phase 5 install story + ufo-types provenance

Are the types in promptexecution/ufo-types?

Yes. ElementKind::DecisionNode, ForkNode, JoinNode, MergeNode were added in ufo-types PR #35 (feat/control-flow-nodes), squash-merged to promptexecution/ufo-types main on 2026-10-19T12:14:55Z at commit 9f883e6. ledgrrr/Cargo.toml pins to that exact revision:

ufo-types = { git = "https://github.com/promptexecution/ufo-types", rev = "9f883e6" }

kr0ki-core/src/chart.rs imports them as:

use ufo_types::{ElementId, ElementKind, Relation};

Is the install package working?

Yes. Three layers verified:

1. Bundle (.mcpb) — cargo xtask verify

$ cargo run --bin xtask-mcpb -- verify dist/ledgerr-mcp.mcpb
ok: dist/ledgerr-mcp.mcpb (ledgerr-mcp v1.10.0)

sha256: 0e39ea990f1e42598ba13b6c9530b4c22e7f6d2497bcce52f86dfcfbd86dcf38 size: 8,256,257 bytes

2. Binary-spawning functional test — tests/install_e2e.rs

Spawns target/debug/ledgerr-mcp-server, runs the full MCP startup sequence (initialize → tools/list → tools/call) over stdio, asserts all 16 published tools are present, and calls ledgerr_documents/pipeline_status:

test install_path_binary_spawns_and_serves_full_catalog ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.57s

3. Budget reconcile — no more 30s hang

ReconcileRunner::run now wraps every provider in an 8s tokio::time::timeout; gcloud/az without credentials map to a Fail entry instead of blocking:

test budget_reconcile_returns_well_formed_report_shape ... ok  (1.69s)

How to install the server / client interface

See docs/mcp-install.md (added in this branch). Summary:

# Build
cargo build -p ledgerr-mcp --bin ledgerr-mcp-server --release

# Bundle
cargo run --bin xtask-mcpb -- bundle \
  --binary target/release/ledgerr-mcp-server \
  --output dist/ledgerr-mcp.mcpb \
  --version v1.10.0

# Verify bundle
cargo run --bin xtask-mcpb -- verify dist/ledgerr-mcp.mcpb

Claude Desktop: Settings → Developer → MCP Servers → "Install from file" → select dist/ledgerr-mcp.mcpb. The extracted entry point is ${__dirname}/server/ledgerr-mcp-server; no flags needed.

Client protocol: JSON-RPC 2.0 over stdio. Required sequence:

  1. initialize (with protocolVersion, capabilities, clientInfo)
  2. notifications/initialized (no reply)
  3. tools/list → returns 16 ledgerr_* tools
  4. tools/call with {"name":"ledgerr_documents","arguments":{"action":"pipeline_status"}}

Smoke-test the binary path:

cargo test -p ledgerr-mcp --test install_e2e

The fabricated 'initialize ok / tools/list ok: 17 tools published' lines
were never executed and inconsistent with PUBLISHED_TOOLS[16] in
contract.rs. Replace with verbatim cargo test output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(statechart): Phase 5 — ufo-types DecisionNode/ForkNode/JoinNode extension for process chart completion

1 participant