Skip to content

Make guard optional and infer zero-markings in defineWorkflow#7

Open
joshuaisaact wants to merge 2 commits intomainfrom
claude/improve-petri-net-readability-uz9rf
Open

Make guard optional and infer zero-markings in defineWorkflow#7
joshuaisaact wants to merge 2 commits intomainfrom
claude/improve-petri-net-readability-uz9rf

Conversation

@joshuaisaact
Copy link
Copy Markdown
Owner

@joshuaisaact joshuaisaact commented Mar 20, 2026

  • guard on WorkflowTransition is now optional (no need to write guard: null)
  • initialMarking accepts Partial<Marking>; unspecified places default to 0
  • Updated all workflow definitions and tests to use the shorter form

Summary by CodeRabbit

  • Refactor
    • Made guard property optional on workflow transitions for cleaner definitions.
    • Simplified initialMarking to require only non-zero place token values, automatically defaulting unspecified places to zero.
    • Reduced boilerplate and verbosity in workflow definitions across the platform.

claude added 2 commits March 20, 2026 20:21
- `guard` on WorkflowTransition is now optional (no need to write `guard: null`)
- `initialMarking` accepts Partial<Marking<Place>>; unspecified places default to 0
- Updated all workflow definitions and tests to use the shorter form
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

This PR refactors workflow transition definitions by making the guard field optional in the WorkflowTransition type, removing explicit guard: null assignments across all workflow and test files, and simplifying initialMarking objects to only specify non-zero place tokens. The defineWorkflow function now computes a full marking from partial input.

Changes

Cohort / File(s) Summary
Core Type & Serialization Updates
packages/engine/src/types.ts, packages/engine/src/persistence/definition-store.ts, packages/engine/src/workflow.ts
Made guard field optional in WorkflowTransition type; updated serialization to always normalize guard as string | null with ?? operator; enhanced defineWorkflow to accept Partial<Marking<Place>> and compute full marking by defaulting unspecified places to zero.
Editor & Analysis Hooks
apps/viewer/src/editor/useEditorState.ts, apps/viewer/src/hooks/useAnalysis.ts
Removed explicit guard: null from newly created transitions; preserved existing guard values in fallback analysis net instead of forcibly nullifying them.
Comparison Scenario Workflows
comparisons/openclaw-safety/src/scenarios/*
Removed guard: null from all transition definitions across budget-escalation, message-gating, sandbox-isolation, and tool-approval scenarios; no functional logic changes.
Application Workflow Definitions
workflows/*/definition.ts
Removed guard: null from all transition definitions and simplified initialMarking objects to only include places with non-zero initial tokens across agent-benchmark, coffee, contract-approval, github-lookup, order-checkout, and simple-agent workflows.
Engine Test Suites
packages/engine/test/*.ts
Removed guard: null from transition definitions in analysis, definition-store, engine, executor, nodes, scheduler, sqlite-adapter, timeout, and types test fixtures to align with updated type and serialization expectations.
Server Test Suites
packages/server/test/*.ts
Updated HTTP and runtime test fixtures to remove guard: null from workflow transition definitions and adjusted expected payloads in saveDefinition tests accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit's verse on simplification:
No more guards set null in vain,
Partial marks make workflows plain,
Optional fields now dance so free,
Less explicit, more concise decree—
Workflows bloom with cleaner grace! 🌿✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: making guard optional and enabling zero-marking inference in defineWorkflow.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/improve-petri-net-readability-uz9rf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/engine/test/definition-store.test.ts (1)

93-109: ⚠️ Potential issue | 🟠 Major

The omitted-guard serializer contract still isn't enforced here.

This case now uses a transition with no guard, but it only checks timeout. packages/engine/src/persistence/definition-store.ts still builds serialized transitions with guard: t.guard ?? null, so a WorkflowDefinition -> serializeDefinition() path can keep emitting guard: null even though the new contract is “guard omitted when absent”. Please assert the missing field here and update the serializer accordingly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/engine/test/definition-store.test.ts` around lines 93 - 109, The
test currently only asserts timeout but not that absent guards are omitted;
update the test to also expect no guard field (e.g.,
expect(serialized.transitions[0]!.guard).toBeUndefined() or that
transitions[1].guard is undefined) and change the serializer in
packages/engine/src/persistence/definition-store.ts (the serializeDefinition /
transition serialization logic that currently does `guard: t.guard ?? null`) to
omit the guard property when t.guard is undefined (only include guard when
t.guard is defined) so serializeDefinition no longer emits `guard: null`.
🧹 Nitpick comments (2)
packages/engine/src/workflow.ts (1)

83-87: Please add a direct regression test for the zero-fill branch.

This loop is the new behavior in the PR, but none of the updated engine tests explicitly assert that omitted places become 0 in net.initialMarking or after a serialize/define round-trip. A focused test would make this contract much harder to regress.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/engine/src/workflow.ts` around lines 83 - 87, Add a regression unit
test that covers the new zero-fill branch: create a workflow/net definition that
omits one or more places from initialMarking, call the API that produces/returns
the constructed net (so the code path that runs the fullMarking loop executes),
and assert that net.initialMarking contains explicit 0 entries for those omitted
places; then perform the serialize/define (or define/serialize) round-trip and
assert again that net.initialMarking still contains zeros for the
previously-omitted places. Reference the fullMarking creation code path and
assert on net.initialMarking before and after the serialize/define round-trip to
prevent regressions.
workflows/simple-agent/definition.ts (1)

36-36: Consider removing trailing blank lines in transition objects.

The blank lines at lines 36, 48, 60, 72, and 84 appear to be artifacts from removing guard: null. While harmless, removing them would tighten up the formatting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@workflows/simple-agent/definition.ts` at line 36, Remove the stray trailing
blank lines left inside the Transition object literals in the transitions array
of the agent definition (they were left behind after removing guard: null); open
each Transition object in the transitions array (Transition objects) and delete
the blank line after the last property so the object closes immediately, then
re-run your formatter to ensure consistent spacing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/server/test/http.test.ts`:
- Around line 358-362: The negative test fixture's request body omitted the node
"type" causing schema validation to fail earlier; restore type: "automatic" in
the JSON body for the test (the object with name: "bad", places: ["a"],
transitions: [{ name: "t", inputs: ["a"], outputs: ["unknown"] }],
initialMarking: { a: 1 }) so the request reaches the "unknown output place"
validation; update that body object in the test in
packages/server/test/http.test.ts accordingly.

---

Outside diff comments:
In `@packages/engine/test/definition-store.test.ts`:
- Around line 93-109: The test currently only asserts timeout but not that
absent guards are omitted; update the test to also expect no guard field (e.g.,
expect(serialized.transitions[0]!.guard).toBeUndefined() or that
transitions[1].guard is undefined) and change the serializer in
packages/engine/src/persistence/definition-store.ts (the serializeDefinition /
transition serialization logic that currently does `guard: t.guard ?? null`) to
omit the guard property when t.guard is undefined (only include guard when
t.guard is defined) so serializeDefinition no longer emits `guard: null`.

---

Nitpick comments:
In `@packages/engine/src/workflow.ts`:
- Around line 83-87: Add a regression unit test that covers the new zero-fill
branch: create a workflow/net definition that omits one or more places from
initialMarking, call the API that produces/returns the constructed net (so the
code path that runs the fullMarking loop executes), and assert that
net.initialMarking contains explicit 0 entries for those omitted places; then
perform the serialize/define (or define/serialize) round-trip and assert again
that net.initialMarking still contains zeros for the previously-omitted places.
Reference the fullMarking creation code path and assert on net.initialMarking
before and after the serialize/define round-trip to prevent regressions.

In `@workflows/simple-agent/definition.ts`:
- Line 36: Remove the stray trailing blank lines left inside the Transition
object literals in the transitions array of the agent definition (they were left
behind after removing guard: null); open each Transition object in the
transitions array (Transition objects) and delete the blank line after the last
property so the object closes immediately, then re-run your formatter to ensure
consistent spacing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ed110d9d-015b-4d65-b7f4-77298caef1a5

📥 Commits

Reviewing files that changed from the base of the PR and between 3072303 and ef7381c.

📒 Files selected for processing (26)
  • apps/viewer/src/editor/useEditorState.ts
  • apps/viewer/src/hooks/useAnalysis.ts
  • comparisons/openclaw-safety/src/scenarios/budget-escalation.ts
  • comparisons/openclaw-safety/src/scenarios/message-gating.ts
  • comparisons/openclaw-safety/src/scenarios/sandbox-isolation.ts
  • comparisons/openclaw-safety/src/scenarios/tool-approval.ts
  • packages/cli/test/analyse.test.ts
  • packages/engine/src/persistence/definition-store.ts
  • packages/engine/src/types.ts
  • packages/engine/src/workflow.ts
  • packages/engine/test/definition-store.test.ts
  • packages/engine/test/engine.test.ts
  • packages/engine/test/executor.test.ts
  • packages/engine/test/nodes.test.ts
  • packages/engine/test/scheduler.test.ts
  • packages/engine/test/sqlite-adapter.test.ts
  • packages/engine/test/timeout.test.ts
  • packages/engine/test/types.test.ts
  • packages/server/test/http.test.ts
  • packages/server/test/runtime.test.ts
  • workflows/agent-benchmark/definition.ts
  • workflows/coffee/definition.ts
  • workflows/contract-approval/definition.ts
  • workflows/github-lookup/definition.ts
  • workflows/order-checkout/definition.ts
  • workflows/simple-agent/definition.ts
💤 Files with no reviewable changes (9)
  • packages/engine/test/engine.test.ts
  • apps/viewer/src/hooks/useAnalysis.ts
  • packages/engine/test/scheduler.test.ts
  • comparisons/openclaw-safety/src/scenarios/tool-approval.ts
  • packages/engine/test/nodes.test.ts
  • comparisons/openclaw-safety/src/scenarios/budget-escalation.ts
  • comparisons/openclaw-safety/src/scenarios/message-gating.ts
  • comparisons/openclaw-safety/src/scenarios/sandbox-isolation.ts
  • packages/engine/test/timeout.test.ts

Comment on lines 358 to 362
body: JSON.stringify({
name: "bad",
places: ["a"],
transitions: [{ name: "t", inputs: ["a"], outputs: ["unknown"], guard: null }],
transitions: [{ name: "t", inputs: ["a"], outputs: ["unknown"] }],
initialMarking: { a: 1 },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep this negative test focused on the output-place validation.

This fixture now drops type, so the request can start failing for a different schema error before it reaches the "unknown output place" branch. Re-adding type: "automatic" keeps the test pinned to the behavior it is naming.

Suggested change
         body: JSON.stringify({
           name: "bad",
           places: ["a"],
-          transitions: [{ name: "t", inputs: ["a"], outputs: ["unknown"] }],
+          transitions: [{ name: "t", type: "automatic", inputs: ["a"], outputs: ["unknown"] }],
           initialMarking: { a: 1 },
           initialContext: {},
           terminalPlaces: [],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
body: JSON.stringify({
name: "bad",
places: ["a"],
transitions: [{ name: "t", inputs: ["a"], outputs: ["unknown"], guard: null }],
transitions: [{ name: "t", inputs: ["a"], outputs: ["unknown"] }],
initialMarking: { a: 1 },
body: JSON.stringify({
name: "bad",
places: ["a"],
transitions: [{ name: "t", type: "automatic", inputs: ["a"], outputs: ["unknown"] }],
initialMarking: { a: 1 },
initialContext: {},
terminalPlaces: [],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/server/test/http.test.ts` around lines 358 - 362, The negative test
fixture's request body omitted the node "type" causing schema validation to fail
earlier; restore type: "automatic" in the JSON body for the test (the object
with name: "bad", places: ["a"], transitions: [{ name: "t", inputs: ["a"],
outputs: ["unknown"] }], initialMarking: { a: 1 }) so the request reaches the
"unknown output place" validation; update that body object in the test in
packages/server/test/http.test.ts accordingly.

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.

2 participants