Skip to content

FE-738: Petri semantic lanes — two-lane subnet, compiler split, engine factory#148

Open
kostandinang wants to merge 6 commits into
ka/fe-730-orchestrator-poc-dual-enginefrom
ka/fe-738-petri-semantic-lanes
Open

FE-738: Petri semantic lanes — two-lane subnet, compiler split, engine factory#148
kostandinang wants to merge 6 commits into
ka/fe-730-orchestrator-poc-dual-enginefrom
ka/fe-738-petri-semantic-lanes

Conversation

@kostandinang
Copy link
Copy Markdown
Contributor

@kostandinang kostandinang commented May 21, 2026

Summary

Phase 1 of the petri orchestrator arc (umbrella H-6476). First frontier where petri models a distinction proc cannot express topologically: mechanical completion ≠ semantic completion. Stacks on FE-730 (#143).

Changes

  • Two-lane slice subnet — mechanical (evaluatewrite-testswrite-coderun-tests) and semantic (assess-semanticsemantic-satisfied), joined by a completion gate so PlanDoneAccepted is unreachable without both.
  • TransitionContract metadata on every transition (kind, lane, actor, guard).
  • §7 event vocabularytransition_fired, net_halted, net_deadlocked emitted by the interpreter.
  • Compiler splitcompileTopology(plan, policy) → NetBlueprint (pure data) + wireHandlers(blueprint, input, ctx) → PetriNet (closures). Adapter tests run on topology alone.
  • Engine factorycreateOrchestrator(policy) replaces duplicated PetriOrchestrator / ProceduralOrchestrator (~120 LOC).
  • HandlerDescriptor discriminated union — declarative branch outputs per transition (onPass / onFail / onTrue / onFalse / onSatisfied / onRejected).
  • Semantic rework budgetsemantic-budget place + reworkCount token prevents infinite rework loops (review finding Bump picomatch #8). Adds RunPolicy.maxSemanticReworks.

Verification

npm run verify clean — 1378 tests across 120 files.

Acceptance (per memory/PLAN.md)

(1)–(4), (6) met. (5) stale-graph routing to reconciliation deferred to follow-up slice.

Next

FE-743 / #149petri-parallel-execution (Phase 2, decision-gated on wall-clock improvement).

Copy link
Copy Markdown
Contributor Author

kostandinang commented May 21, 2026

@kostandinang kostandinang changed the title FE-738: two-lane subnet with semantic completion gate FE-738: Petri semantic lanes — two-lane subnet, compiler split, engine factory May 21, 2026
@kostandinang kostandinang marked this pull request as ready for review May 22, 2026 12:38
@cursor
Copy link
Copy Markdown

cursor Bot commented May 22, 2026

PR Summary

Medium Risk
Medium risk because it changes orchestrator execution topology and introduces new required action (assess-semantic) plus new halting paths (semantic rework exhaustion) that can affect completion behavior and event emission.

Overview
Implements a two-lane slice subnet by adding assess-semantic and gating return-done on semantic-satisfied, with a new semantic-budget/reworkCount mechanism and RunPolicy.maxSemanticReworks to halt slices that loop on semantic rejection.

Refactors compilation into a pure topology pass (compileTopology → NetBlueprint) plus a wiring pass (wireHandlers) driven by a new declarative HandlerDescriptor, and replaces the separate proc/petri engine classes with createOrchestrator('serial').

Extends the Petri interpreter with TransitionContract metadata on transitions and an optional §7-style event sink emitting transition_fired/net_halted/net_deadlocked; contract and adapter tests are updated/expanded accordingly, and planning docs are updated (including removal of memory/CARDS.md).

Reviewed by Cursor Bugbot for commit 1747538. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/orchestrator/src/cook-cli.ts
const hasTokens = [...this.places.values()].some((tokens) => tokens.length > 0);
if (hasTokens) {
eventSink?.emit({ kind: 'net_deadlocked', ts: new Date().toISOString() });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

False net_deadlocked on success

Medium Severity

When no transition is enabled, the interpreter emits net_deadlocked whenever any place still holds tokens. After a successful slice, idle test-agent and code-agent tokens remain, so completed runs can record a deadlock event alongside normal transition_fired events.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8e56a7c. Configure here.

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented May 22, 2026

🤖 Augment PR Summary

Summary: This PR evolves the Petri-net orchestrator by introducing distinct mechanical vs semantic completion lanes, and refactors compilation/execution so the net shape is testable as pure data.

Changes:

  • Introduces a two-lane slice subnet (mechanical TDD loop + semantic assessment) with a completion gate so slices can’t finish without semantic satisfaction.
  • Adds TransitionContract metadata to transitions (kind/lane/actor/guard) to classify execution without parsing IDs.
  • Splits the compiler into compileTopology(plan, policy) → NetBlueprint (pure topology) and wireHandlers(...) (runtime closures), plus a convenience compilePlan wrapper.
  • Consolidates engine entrypoints into createOrchestrator(firingPolicy), removing duplicated Petri/procedural engine classes.
  • Adds semantic rework budgeting via a semantic-budget token (reworkCount) and RunPolicy.maxSemanticReworks to prevent infinite semantic-rejection loops.
  • Defines §7-style interpreter events (transition_fired, net_halted, net_deadlocked) and updates adapter tests to assert event emission.
  • Updates engine contract tests to cover semantic-gate rework and semantic budget exhaustion scenarios.

Technical Notes: Topology-only adapter tests no longer require action handlers/test runners, and runtime wiring now interprets declarative handler descriptors from the blueprint.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

const budgetToken = consumed[1]!;
const reworkCount = budgetToken.reworkCount ?? 0;

const reportId = await actions[actionKey]!(actCtx);
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 22, 2026

Choose a reason for hiding this comment

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

wireHandlers() assumes actions[actionKey] exists (non-null asserted), but the compiled topology now includes an assess-semantic handler kind—createPiActions() currently doesn’t define assess-semantic, so brunch cook will throw once a slice reaches semantic assessment.

Severity: high

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.


const engine: Orchestrator =
opts.engine === 'petri' ? new PetriOrchestrator() : new ProceduralOrchestrator();
const engine = createOrchestrator('serial');
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 22, 2026

Choose a reason for hiding this comment

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

parseCookArgs() still accepts --engine proc|petri (and CookOptions.engine is populated), but runCook() now always constructs createOrchestrator('serial'), so the CLI engine selection is silently ignored.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@kostandinang kostandinang force-pushed the ka/fe-730-orchestrator-poc-dual-engine branch from b72d1ad to 934ea57 Compare May 22, 2026 14:14
@kostandinang kostandinang force-pushed the ka/fe-738-petri-semantic-lanes branch from 8e56a7c to f959557 Compare May 22, 2026 14:14
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f959557. Configure here.

const reworkCount = budgetToken.reworkCount ?? 0;

const reportId = await actions[actionKey]!(actCtx);
ctx.reportIds.push(reportId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing assess-semantic cook handler

High Severity

The subnet now requires an assess-semantic transition before return-done, and wireHandlers invokes actions['assess-semantic'], but createPiActions (used by brunch cook) never registers that handler. Real fixture runs halt or throw once mechanical work reaches semantic assessment.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f959557. Configure here.

kostandinang and others added 6 commits May 22, 2026 16:58
- Add semantic-gate and semantic-satisfied places per slice
- Add assess-semantic transition joining done-spec + semantic-gate
- On pass: produces semantic-satisfied → return-done proceeds
- On fail: routes to needs-more, forcing another TDD rework cycle
- return-done now consumes semantic-satisfied (not done-spec directly)
- PlanDoneAccepted is topologically unreachable without semantic satisfaction
- New contract test #10: semantic gate rejects then accepts
- Updated all call-order assertions and adapter test counts

Co-authored-by: Amp <amp@ampcode.com>
- Define TransitionContract type (kind, lane, actor, guard) in petri-net.ts
- Add contract field to TransitionDef (optional, no behavioral change)
- Populate contract metadata for all compiled transitions:
  mechanical-lane (evaluate, write-tests, write-code, run-tests),
  semantic-lane (assess-semantic, return-done),
  structural (slice-ready, epic-complete, epic-deps-met)
- Add getTransitions() accessor on PetriNet for inspection
- New adapter test verifies contract metadata classification

Co-authored-by: Amp <amp@ampcode.com>
- Define NetEvent, NetEventKind, NetEventSink types in petri-net.ts
- PetriNet.run() accepts optional event sink (backward compatible)
- Emits transition_fired with id, contract, consumed/produced places
- Emits net_halted when shouldHalt() triggers
- Emits net_deadlocked when no transition enabled but tokens remain
- New adapter tests: happy-path event capture + retry-exhaustion halt
- Note: deadlock detection is coarse (leftover resource tokens trigger
  it on clean completion); refined detection is future work

Co-authored-by: Amp <amp@ampcode.com>
…dget

- Split compilePlan into compileTopology (pure data → NetBlueprint) and
  wireHandlers (attaches fire closures). Adapter tests use topology-only.
- Consolidate identical PetriOrchestrator/ProceduralOrchestrator into
  createOrchestrator(policy) factory. Delete engine-petri.ts/engine-proc.ts.
- Move RunCtx from net-compiler.ts to types.ts (compiler is context-free).
- Add semantic-budget place + reworkCount token to prevent infinite rework
  loops when assess-semantic always rejects (Finding #8 correctness fix).
- HandlerDescriptor discriminated union (7 kinds) makes transition routing
  declarative in the blueprint. All descriptors carry actionKey explicitly.
- New net-blueprint.ts for NetBlueprint/TransitionSkeleton/HandlerDescriptor types.
- 1378 tests pass across 120 files.

Co-authored-by: Amp <amp@ampcode.com>
…compilation

Co-authored-by: Amp <amp@ampcode.com>
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.

1 participant